From svnnotify ¡÷ sourceforge.jp Tue Apr 1 12:42:48 2008 From: svnnotify ¡÷ sourceforge.jp (svnnotify ¡÷ sourceforge.jp) Date: Tue, 01 Apr 2008 12:42:48 +0900 Subject: [Slashdotjp-dev 1033] [561] make upstream/2.5.0.198 branch Message-ID: <1207021368.418114.27669.nullmailer@users.sourceforge.jp> Revision: 561 http://svn.sourceforge.jp/cgi-bin/viewcvs.cgi?root=slashdotjp&view=rev&rev=561 Author: tach Date: 2008-04-01 12:42:48 +0900 (Tue, 01 Apr 2008) Log Message: ----------- make upstream/2.5.0.198 branch Added Paths: ----------- slashjp/branches/upstream/2.5.0.198/ -------------- next part -------------- Copied: slashjp/branches/upstream/2.5.0.198 (from rev 560, slashjp/branches/upstream/current) From svnnotify ¡÷ sourceforge.jp Tue Apr 1 12:48:35 2008 From: svnnotify ¡÷ sourceforge.jp (svnnotify ¡÷ sourceforge.jp) Date: Tue, 01 Apr 2008 12:48:35 +0900 Subject: [Slashdotjp-dev 1034] [562] merged from 2.5.0.192 branch Message-ID: <1207021715.863864.1412.nullmailer@users.sourceforge.jp> Revision: 562 http://svn.sourceforge.jp/cgi-bin/viewcvs.cgi?root=slashdotjp&view=rev&rev=562 Author: tach Date: 2008-04-01 12:48:35 +0900 (Tue, 01 Apr 2008) Log Message: ----------- merged from 2.5.0.192 branch Modified Paths: -------------- slashjp/trunk/Slash/Utility/Environment/Environment.pm slashjp/trunk/plugins/FireHose/FireHose.pm slashjp/trunk/plugins/Tags/tagbox.pl slashjp/trunk/plugins/Zoo/zoo_run_people_log.pl slashjp/trunk/tagboxes/FHEditorPop/FHEditorPop.pm slashjp/trunk/tagboxes/FHPopularity/FHPopularity.pm slashjp/trunk/tagboxes/FHPopularity2/FHPopularity2.pm slashjp/trunk/tagboxes/FireHoseScores/FireHoseScores.pm -------------- next part -------------- Modified: slashjp/trunk/Slash/Utility/Environment/Environment.pm =================================================================== --- slashjp/trunk/Slash/Utility/Environment/Environment.pm 2008-04-01 03:42:48 UTC (rev 561) +++ slashjp/trunk/Slash/Utility/Environment/Environment.pm 2008-04-01 03:48:35 UTC (rev 562) @@ -467,7 +467,6 @@ } else { $form = $static_form; } - map { $form->{$_} =~ s/\p{BidiControl}|\p{Unassigned}|\p{JoinControl}//g } keys(%$form); return defined $value ? $form->{$value} : $form; } @@ -1878,8 +1877,10 @@ sid => sub { $_[0] = '' unless $_[0] =~ Slash::Utility::Data::regexSid() }, flags => sub { $_[0] =~ s|[^a-z0-9_,]||g }, - query => sub { $_[0] =~ s|[\000-\040<>\177-\377]+| |g; + query => sub { $_[0] =~ s|[\000-\040<>\177\p{BidiControl}\p{Unassigned}\p{JoinControl}]+| |g; $_[0] =~ s|\s+| |g; }, + q => sub { $_[0] =~ s|[\000-\040<>\177\p{BidiControl}\p{Unassigned}\p{JoinControl}]+| |g; + $_[0] =~ s|\s+| |g; }, colorblock => sub { $_[0] =~ s|[^\w#,]+||g }, # What I actually want to do for userfield is allow it to match # [\w.]+, or pass emailValid(), or be changed to the return value @@ -1963,8 +1964,6 @@ $data = fixint($data); } elsif (exists $alphas{$key}) { $data =~ s|[^a-zA-Z0-9_]+||g; - } elsif (exists $special{$key}) { - $special{$key}->($data); } else { for my $ri (@regints) { $data = fixint($data) if $ri =~ $key; @@ -1982,6 +1981,10 @@ } } } + if (exists $special{$key}) { + $special{$key}->($data); + } + $data =~ s/\p{BidiControl}|\p{Unassigned}|\p{JoinControl}//g; return $data; } Modified: slashjp/trunk/plugins/FireHose/FireHose.pm =================================================================== --- slashjp/trunk/plugins/FireHose/FireHose.pm 2008-04-01 03:42:48 UTC (rev 561) +++ slashjp/trunk/plugins/FireHose/FireHose.pm 2008-04-01 03:48:35 UTC (rev 562) @@ -188,7 +188,7 @@ my $popularity = defined $options->{popularity} ? $options->{popularity} : $type eq "feed" - ? $self->getEntryPopularityForColorLevel(6) + ? $self->getEntryPopularityForColorLevel(7) : $self->getEntryPopularityForColorLevel(7); my $activity = defined $options->{activity} ? $options->{activity} : 1; Modified: slashjp/trunk/plugins/Tags/tagbox.pl =================================================================== --- slashjp/trunk/plugins/Tags/tagbox.pl 2008-04-01 03:42:48 UTC (rev 561) +++ slashjp/trunk/plugins/Tags/tagbox.pl 2008-04-01 03:48:35 UTC (rev 562) @@ -282,7 +282,8 @@ sub insert_feederlog { my($tagbox, $feeder_ar) = @_; for my $feeder_hr (@$feeder_ar) { -main::tagboxLog("addFeederInfo: tbid=$tagbox->{tbid} tagid=$feeder_hr->{tagid} affected_id=$feeder_hr->{affected_id} imp=$feeder_hr->{importance}"); +main::tagboxLog("addFeederInfo: tbid=$tagbox->{tbid} tagid=$feeder_hr->{tagid} affected_id=$feeder_hr->{affected_id} imp=$feeder_hr->{importance}") + if (defined($feeder_hr->{tagid})); $tagboxdb->addFeederInfo($tagbox->{tbid}, $feeder_hr); } } Modified: slashjp/trunk/plugins/Zoo/zoo_run_people_log.pl =================================================================== --- slashjp/trunk/plugins/Zoo/zoo_run_people_log.pl 2008-04-01 03:42:48 UTC (rev 561) +++ slashjp/trunk/plugins/Zoo/zoo_run_people_log.pl 2008-04-01 03:48:35 UTC (rev 562) @@ -3,7 +3,7 @@ # $Id$ use strict; -use Slash::Constants qw( :messages :slashd :people ); +use Slash::Constants qw( :messages :slashd ); use Slash::Display; use vars qw( %task $me ); Modified: slashjp/trunk/tagboxes/FHEditorPop/FHEditorPop.pm =================================================================== --- slashjp/trunk/tagboxes/FHEditorPop/FHEditorPop.pm 2008-04-01 03:42:48 UTC (rev 561) +++ slashjp/trunk/tagboxes/FHEditorPop/FHEditorPop.pm 2008-04-01 03:48:35 UTC (rev 562) @@ -167,7 +167,7 @@ } elsif ($type eq 'urls') { $extra_pop = $self->sqlCount('bookmarks', "url_id=$target_id_q") || 0; $color_level = $self->sqlCount("firehose", "type='feed' AND url_id=$target_id") - ? 6 # feed + ? 7 # feed : 7; # nonfeed } elsif ($type eq "stories") { my $story = $self->getStory($target_id); Modified: slashjp/trunk/tagboxes/FHPopularity/FHPopularity.pm =================================================================== --- slashjp/trunk/tagboxes/FHPopularity/FHPopularity.pm 2008-04-01 03:42:48 UTC (rev 561) +++ slashjp/trunk/tagboxes/FHPopularity/FHPopularity.pm 2008-04-01 03:48:35 UTC (rev 562) @@ -153,7 +153,7 @@ } elsif ($type eq 'urls') { $extra_pop = $self->sqlCount('bookmarks', "url_id=$target_id_q") || 0; $color_level = $self->sqlCount("firehose", "type='feed' AND url_id=$target_id") - ? 6 # feed + ? 7 # feed : 7; # nonfeed } elsif ($type eq "stories") { my $story = $self->getStory($target_id); Modified: slashjp/trunk/tagboxes/FHPopularity2/FHPopularity2.pm =================================================================== --- slashjp/trunk/tagboxes/FHPopularity2/FHPopularity2.pm 2008-04-01 03:42:48 UTC (rev 561) +++ slashjp/trunk/tagboxes/FHPopularity2/FHPopularity2.pm 2008-04-01 03:48:35 UTC (rev 562) @@ -150,7 +150,7 @@ } elsif ($type eq 'urls') { $extra_pop = $self->sqlCount('bookmarks', "url_id=$target_id_q") || 0; $color_level = $self->sqlCount("firehose", "type='feed' AND url_id=$target_id") - ? 6 # feed + ? 7 # feed : 7; # nonfeed } elsif ($type eq "stories") { my $story = $self->getStory($target_id); Modified: slashjp/trunk/tagboxes/FireHoseScores/FireHoseScores.pm =================================================================== --- slashjp/trunk/tagboxes/FireHoseScores/FireHoseScores.pm 2008-04-01 03:42:48 UTC (rev 561) +++ slashjp/trunk/tagboxes/FireHoseScores/FireHoseScores.pm 2008-04-01 03:48:35 UTC (rev 562) @@ -268,7 +268,7 @@ # XXX should modify next line by users' vote clout $extra_pop = $self->sqlCount('bookmarks', "url_id=$target_id_q") || 0; $color_level = $self->sqlCount("firehose", "type='feed' AND url_id=$target_id") - ? 6 # feed + ? 7 # feed : 7; # nonfeed } elsif ($type eq "stories") { my $story = $self->getStory($target_id); From svnnotify ¡÷ sourceforge.jp Tue Apr 1 12:35:14 2008 From: svnnotify ¡÷ sourceforge.jp (svnnotify ¡÷ sourceforge.jp) Date: Tue, 01 Apr 2008 12:35:14 +0900 Subject: [Slashdotjp-dev 1035] [560] merged from upstream T_2_5_0_198 Message-ID: <1207020914.977425.21394.nullmailer@users.sourceforge.jp> Revision: 560 http://svn.sourceforge.jp/cgi-bin/viewcvs.cgi?root=slashdotjp&view=rev&rev=560 Author: tach Date: 2008-04-01 12:35:14 +0900 (Tue, 01 Apr 2008) Log Message: ----------- merged from upstream T_2_5_0_198 Modified Paths: -------------- slashjp/branches/upstream/current/AUTHORS slashjp/branches/upstream/current/INSTALL slashjp/branches/upstream/current/Slash/DB/MySQL/MySQL.pm slashjp/branches/upstream/current/Slash/Hook/Hook.pm slashjp/branches/upstream/current/Slash/Slash.pm slashjp/branches/upstream/current/Slash/Utility/Comments/Comments.pm slashjp/branches/upstream/current/Slash/Utility/Environment/Environment.pm slashjp/branches/upstream/current/bin/install-slashsite slashjp/branches/upstream/current/docs/INSTALL.pod slashjp/branches/upstream/current/plugins/Admin/Admin.pm slashjp/branches/upstream/current/plugins/Admin/admin.pl slashjp/branches/upstream/current/plugins/Admin/templates/editStory;admin;default slashjp/branches/upstream/current/plugins/Admin/templates/signoff;misc;default slashjp/branches/upstream/current/plugins/Admin/templates/signoff_stats;misc;default slashjp/branches/upstream/current/plugins/Ajax/PLUGIN slashjp/branches/upstream/current/plugins/Ajax/htdocs/ajax.pl slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/admin.js slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/common.js slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/nodnix.js slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/sd_autocomplete.js slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/sectionprefs.js slashjp/branches/upstream/current/plugins/Ajax/mysql_dump.sql slashjp/branches/upstream/current/plugins/Ajax/templates/edit_comment;ajax;default slashjp/branches/upstream/current/plugins/Ajax/templates/prefs_d2;ajax;default slashjp/branches/upstream/current/plugins/Email/templates/dispStory;email;default slashjp/branches/upstream/current/plugins/FAQSlashdot/faq/friends.shtml slashjp/branches/upstream/current/plugins/FireHose/FireHose.pm slashjp/branches/upstream/current/plugins/FireHose/PLUGIN slashjp/branches/upstream/current/plugins/FireHose/firehose.css slashjp/branches/upstream/current/plugins/FireHose/templates/firehose_tags_top;misc;default slashjp/branches/upstream/current/plugins/Messages/templates/dailyheadlines;messages;default slashjp/branches/upstream/current/plugins/Messages/templates/dailynews;messages;default slashjp/branches/upstream/current/plugins/Moderation/Moderation.pm slashjp/branches/upstream/current/plugins/Rating/Rating.pm slashjp/branches/upstream/current/plugins/ResKey/mysql_dump.sql slashjp/branches/upstream/current/plugins/Submit/submit.pl slashjp/branches/upstream/current/plugins/TagModeration/TagModeration.pm slashjp/branches/upstream/current/plugins/Tags/PLUGIN slashjp/branches/upstream/current/plugins/Tags/Tags.pm slashjp/branches/upstream/current/plugins/Tags/mysql_dump.sql slashjp/branches/upstream/current/plugins/Tags/mysql_schema.sql slashjp/branches/upstream/current/plugins/Tags/tagbox.pl slashjp/branches/upstream/current/plugins/Tags/templates/tagsstorydivtagbox;misc;default slashjp/branches/upstream/current/sql/mysql/defaults.sql slashjp/branches/upstream/current/sql/mysql/upgrades slashjp/branches/upstream/current/tagboxes/Despam/Despam.pm slashjp/branches/upstream/current/themes/slashcode/THEME slashjp/branches/upstream/current/themes/slashcode/htdocs/comments.pl slashjp/branches/upstream/current/themes/slashcode/htdocs/images/comments.js slashjp/branches/upstream/current/themes/slashcode/htdocs/images/dumper.js slashjp/branches/upstream/current/themes/slashcode/templates/dispComment;misc;default slashjp/branches/upstream/current/themes/slashcode/templates/dispLinkComment;misc;default slashjp/branches/upstream/current/themes/slashcode/templates/dispStory;misc;default slashjp/branches/upstream/current/themes/slashcode/templates/errors;comments;default slashjp/branches/upstream/current/themes/slashcode/templates/html-header;misc;default slashjp/branches/upstream/current/themes/slashcode/templates/modCommentLog;misc;default slashjp/branches/upstream/current/themes/slashcode/templates/printCommComments;misc;default slashjp/branches/upstream/current/themes/slashcode/templates/printCommentsMain;misc;default Added Paths: ----------- slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/jquery-1.2.3.js slashjp/branches/upstream/current/plugins/FireHose/templates/tagsnodnixuser;misc;default slashjp/branches/upstream/current/plugins/Tags/tags_tagnamecache.pl Removed Paths: ------------- slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/prototype.js slashjp/branches/upstream/current/themes/slashcode/htdocs/images/comments2.js -------------- next part -------------- Modified: slashjp/branches/upstream/current/AUTHORS =================================================================== --- slashjp/branches/upstream/current/AUTHORS 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/AUTHORS 2008-04-01 03:35:14 UTC (rev 560) @@ -8,6 +8,7 @@ Cliff Wood cliff ¡÷ slashdot.org Jamie McCarthy jamie ¡÷ mccarthy.vg Tim Vroom vroom ¡÷ slashdot.org + Scott Collins scc ¡÷ slashdot.org Special thanks to some of the outstanding contributors to Slash, who have helped with various kinds of feedback, all of it invaluable. @@ -36,5 +37,5 @@ chromatic chromatic ¡÷ rmci.net Dan Stahlke dans ¡÷ infoinsights.com -# $Id: AUTHORS,v 1.10 2005/03/11 19:57:18 pudge Exp $ +# $Id: AUTHORS,v 1.11 2008/03/17 02:20:35 scc Exp $ Modified: slashjp/branches/upstream/current/INSTALL =================================================================== --- slashjp/branches/upstream/current/INSTALL 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/INSTALL 2008-04-01 03:35:14 UTC (rev 560) @@ -71,7 +71,7 @@ The version of this file that you are currently reading is: - $Id: INSTALL,v 1.55 2008/02/20 17:46:57 jamiemccarthy Exp $ + $Id: INSTALL,v 1.56 2008/03/12 17:02:02 jamiemccarthy Exp $ If there are more recent versions of this file, you can find a list of those changes at: @@ -261,6 +261,14 @@ cpan> o conf prerequisites_policy follow cpan> o conf commit + Data::JavaScript::Anon + There are bugs in versions earlier than 1.00 that break our + JS. Unfortunately, CPAN seems to prefer version 0.9 even + though 1.00 is available. You may have to install a better + version in CPAN by hand: + + cpan> install A/AD/ADAMK/Data-JavaScript-Anon-1.00.tar.gz + Additional Libraries You must have certain libraries existing on your system before building, for Compress::Zlib, XML::Parser, DBI and @@ -1475,5 +1483,5 @@ https://lists.sourceforge.net/lists/listinfo/slashcode-announce VERSION - $Id: INSTALL,v 1.55 2008/02/20 17:46:57 jamiemccarthy Exp $ + $Id: INSTALL,v 1.56 2008/03/12 17:02:02 jamiemccarthy Exp $ Modified: slashjp/branches/upstream/current/Slash/DB/MySQL/MySQL.pm =================================================================== --- slashjp/branches/upstream/current/Slash/DB/MySQL/MySQL.pm 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/Slash/DB/MySQL/MySQL.pm 2008-04-01 03:35:14 UTC (rev 560) @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. # Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: MySQL.pm,v 1.1008 2008/02/13 17:00:41 jamiemccarthy Exp $ +# $Id: MySQL.pm,v 1.1010 2008/03/21 03:05:35 pudge Exp $ package Slash::DB::MySQL; use strict; @@ -20,7 +20,7 @@ use base 'Slash::DB::Utility'; use Slash::Constants ':messages'; -($VERSION) = ' $Revision: 1.1008 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.1010 $ ' =~ /\$Revision:\s+([^\s]+)/; # Fry: How can I live my life if I can't tell good from evil? @@ -513,7 +513,7 @@ my $page = $user->{currentPage}; my $skin = getCurrentSkin('name'); my $admin = $user->{is_admin}; - my $theme = $user->{simpledesign} ? "light" : $user->{css_theme}; + my $theme = ($user->{simpledesign} || $user->{pda}) ? "light" : $user->{css_theme}; my $constants = getCurrentStatic(); my $expire_time = $constants->{css_expire} || 3600; @@ -532,7 +532,7 @@ $css_skins_ref = $self->getCSSValuesHashForCol('skin') if !$css_skins_ref; $css_themes_ref= $self->getCSSValuesHashForCol('theme') if !$css_themes_ref; - my $lowbandwidth = $user->{lowbandwidth} ? "yes" : "no"; + my $lowbandwidth = ($user->{lowbandwidth} || $user->{pda}) ? "yes" : "no"; $page = '' if !$css_pages_ref->{$page}; $skin = '' if !$css_skins_ref->{$skin}; @@ -7914,15 +7914,16 @@ } sub getSignoffCountHashForStoids { - my($self, $stoids) = @_; + my($self, $stoids, $adminsonly) = @_; return {} if !@$stoids; my $stoid_list = join ',', @$stoids; + my $user_limit_clause = $adminsonly ? ' AND seclev >= 100' : ''; my $signoff_hash = $self->sqlSelectAllHashref( "stoid", - "stoid, COUNT(DISTINCT uid) AS cnt", - "signoff", - "stoid in ($stoid_list)", + "stoid, COUNT(DISTINCT signoff.uid) AS cnt", + "signoff, users", + "users.uid = signoff.uid AND stoid IN ($stoid_list) $user_limit_clause", "GROUP BY stoid" ); Modified: slashjp/branches/upstream/current/Slash/Hook/Hook.pm =================================================================== --- slashjp/branches/upstream/current/Slash/Hook/Hook.pm 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/Slash/Hook/Hook.pm 2008-04-01 03:35:14 UTC (rev 560) @@ -1,13 +1,10 @@ # This code is a part of Slash, and is released under the GPL. # Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Hook.pm,v 1.11 2008/02/28 19:26:58 pudge Exp $ +# $Id: Hook.pm,v 1.12 2008/03/04 21:49:10 pudge Exp $ package Slash::Hook; use strict; -use DBIx::Password; -use Slash; -use Slash::DB; use Slash::Utility::Environment; # avoid cross-caller issues use vars qw($VERSION); @@ -16,7 +13,7 @@ use base 'Exporter'; use vars qw($VERSION @EXPORT); -($VERSION) = ' $Revision: 1.11 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.12 $ ' =~ /\$Revision:\s+([^\s]+)/; @EXPORT = qw(slashHook); my %classes; Modified: slashjp/branches/upstream/current/Slash/Slash.pm =================================================================== --- slashjp/branches/upstream/current/Slash/Slash.pm 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/Slash/Slash.pm 2008-04-01 03:35:14 UTC (rev 560) @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. # Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Slash.pm,v 1.348 2008/02/21 01:01:52 pudge Exp $ +# $Id: Slash.pm,v 1.349 2008/03/18 20:40:15 tvroom Exp $ package Slash; @@ -217,6 +217,7 @@ && $story->{rendered} && !$options->{force_cache_freshen} && !$form->{simpledesign} && !$user->{simpledesign} && !$form->{lowbandwidth} && !$user->{lowbandwidth} + && !$form->{pda} && !$user->{pda} && (!$form->{ssi} || $form->{ssi} ne 'yes') && !$user->{noicons} && !$form->{issue} Modified: slashjp/branches/upstream/current/Slash/Utility/Comments/Comments.pm =================================================================== --- slashjp/branches/upstream/current/Slash/Utility/Comments/Comments.pm 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/Slash/Utility/Comments/Comments.pm 2008-04-01 03:35:14 UTC (rev 560) @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. # Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Comments.pm,v 1.2 2008/02/28 19:26:58 pudge Exp $ +# $Id: Comments.pm,v 1.9 2008/03/20 07:30:29 pudge Exp $ package Slash::Utility::Comments; @@ -34,11 +34,11 @@ use base 'Exporter'; use vars qw($VERSION @EXPORT); -($VERSION) = ' $Revision: 1.2 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.9 $ ' =~ /\$Revision:\s+([^\s]+)/; @EXPORT = qw( constrain_score dispComment displayThread printComments jsSelectComments commentCountThreshold commentThresholds discussion2 - tempUofmLinkGenerate tempUofmCipherObj selectComments + tempUofmLinkGenerate tempUofmCipherObj selectComments preProcessReplyForm getPoints preProcessComment postProcessComment prevComment saveComment ); @@ -405,8 +405,9 @@ my $anon_thresh = Data::JavaScript::Anon->anon_dump($thresh_totals || {}); s/\s+//g for ($anon_thresh, $anon_roots, $anon_rootsh); - $user->{is_anon} ||= 0; - $user->{is_admin} ||= 0; + $user->{is_anon} ||= 0; + $user->{is_admin} ||= 0; + $user->{is_subscriber} ||= 0; my $extra = ''; if ($d2_seen_0) { @@ -442,6 +443,7 @@ user_uid = $user->{uid}; user_is_anon = $user->{is_anon}; user_is_admin = $user->{is_admin}; +user_is_subscriber = $user->{is_subscriber}; user_threshold = $threshold; user_highlightthresh = $highlightthresh; @@ -534,6 +536,17 @@ my($value, $hashref, $nocomm) = @_; $hashref ||= {}; $hashref->{value} = $value; + + # this is a cheap hack to NOT print titlebar in getError if we + # are calling from ajax.pl ... easier than reorganizing the code + # for now -- pudge 2008/03/04 + for (0..9) { + if ((caller($_))[1] =~ /\bajax\.pl$/) { + $hashref->{no_titlebar} = 1; + last; + } + } + return slashDisplay('errors', $hashref, { Return => 1, Nocomm => $nocomm, Page => 'comments' }); } @@ -587,7 +600,7 @@ # Adjust reasons. Do we need a reason? # Are you threatening me? - if ($reasons) { + if ($reasons && $C->{reason}) { my $reason_name = $reasons->{$C->{reason}}{name}; if ($reason_name && $user->{"reason_alter_$reason_name"}) { $hr->{reason_bonus} = @@ -599,7 +612,7 @@ # Keep your friends close but your enemies closer. # Or ignore them, we don't care. - if ($user->{uid} != $C->{uid}) { + if ($user->{people} && $user->{uid} != $C->{uid}) { if ($user->{people}{FRIEND()}{$C->{uid}}) { $hr->{people_bonus_friend} = $user->{people_bonus_friend}; @@ -1322,6 +1335,18 @@ #======================================================================== +sub preProcessReplyForm { + my($form, $reply) = @_; + return if !$form->{pid} || !$reply->{subject} || $form->{postersubj}; + + $form->{postersubj} = decode_entities($reply->{subject}); + $form->{postersubj} =~ s/^Re://i; + $form->{postersubj} =~ s/\s\s/ /g; + $form->{postersubj} = "Re:$form->{postersubj}"; +} + +#======================================================================== + sub preProcessComment { my($comm, $user, $discussion, $error_message) = @_; # probably $comm = $form my $constants = getCurrentStatic(); @@ -1336,7 +1361,7 @@ my $tempSubject = strip_notags($comm->{postersubj}); my $tempComment = $comm->{postercomment}; - $comm->{anon} = 0; + $comm->{anon} = $user->{is_anon}; if ($comm->{postanon} && $reader->checkAllowAnonymousPosting && $user->{karma} > -1 @@ -1407,22 +1432,23 @@ $comm->{comment} = parseDomainTags($comm->{comment}, !$comm->{anon} && $comm->{fakeemail}); -# my $discussion = $slashdb->getDiscussion($comm->{sid}) || 0; my $extras = []; my $disc_skin = $slashdb->getSkin($discussion->{primaryskid}); $extras = $slashdb->getNexusExtrasForChosen( { $disc_skin->{nexus} => 1 }, { content_type => "comment" }) if $disc_skin && $disc_skin->{nexus}; - + my $preview = { - nickname => $comm->{postanon} + nickname => $comm->{anon} ? getCurrentAnonymousCoward('nickname') : $comm->{nickname}, + uid => $comm->{anon} + ? getCurrentAnonymousCoward('uid') + : $comm->{uid}, pid => $comm->{pid}, - uid => $comm->{postanon} ? '' : $comm->{uid}, - homepage => $comm->{postanon} ? '' : $comm->{homepage}, - fakeemail => $comm->{postanon} ? '' : $comm->{fakeemail}, + homepage => $comm->{anon} ? '' : $comm->{homepage}, + fakeemail => $comm->{anon} ? '' : $comm->{fakeemail}, journal_last_entry_date => $comm->{journal_last_entry_date} || '', 'time' => $slashdb->getTime, subject => $comm->{subject}, @@ -1567,7 +1593,7 @@ my $moddb = getObject("Slash::$constants->{m1_pluginname}"); if ($moddb) { my $text = $moddb->checkDiscussionForUndoModeration($comm->{sid}); - # XXX + # XXX doesn't work for D2 print $text if $text; } @@ -1600,13 +1626,16 @@ my $users = $messages->checkMessageCodes(MSG_CODE_COMMENT_REPLY, [$parent->{uid}]); if (_send_comment_msg($users->[0], \%users, $pts, $clean_comment)) { my $data = { - template_name => 'reply_msg', - subject => { template_name => 'reply_msg_subj' }, - reply => $reply, - parent => $parent, - discussion => $discussion, + template_name => 'reply_msg', + template_page => 'comments', + subject => { + template_name => 'reply_msg_subj', + template_page => 'comments', + }, + reply => $reply, + parent => $parent, + discussion => $discussion, }; - $messages->create($users->[0], MSG_CODE_COMMENT_REPLY, $data); $users{$users->[0]}++; } @@ -1617,10 +1646,14 @@ my $users = $messages->checkMessageCodes(MSG_CODE_JOURNAL_REPLY, [$discussion->{uid}]); if (_send_comment_msg($users->[0], \%users, $pts, $clean_comment)) { my $data = { - template_name => 'journrep', - subject => { template_name => 'journrep_subj' }, - reply => $reply, - discussion => $discussion, + template_name => 'journrep', + template_page => 'comments', + subject => { + template_name => 'journrep_subj', + template_page => 'comments', + }, + reply => $reply, + discussion => $discussion, }; $messages->create($users->[0], MSG_CODE_JOURNAL_REPLY, $data); @@ -1633,10 +1666,14 @@ my $users = $messages->getMessageUsers(MSG_CODE_NEW_COMMENT); my $data = { - template_name => 'commnew', - subject => { template_name => 'commnew_subj' }, - reply => $reply, - discussion => $discussion, + template_name => 'commnew', + template_page => 'comments', + subject => { + template_name => 'commnew_subj', + template_page => 'comments', + }, + reply => $reply, + discussion => $discussion, }; my @users_send; @@ -1845,12 +1882,18 @@ $time_to_display = timeCalc($comment->{date}); unless ($user->{noscores}) { - $score_to_display .= " (Score:"; - $score_to_display .= length($comment->{points}) ? $comment->{points} : "?"; + $score_to_display .= "Score:"; + if (length $comment->{points}) { + $score_to_display .= $comment->{points}; + $score_to_display = qq[$score_to_display] + if $constants->{modal_prefs_active} && !$user->{is_anon}; + } else { + $score_to_display .= '?'; + } if ($reasons && $comment->{reason}) { $score_to_display .= ", $reasons->{$comment->{reason}}{name}"; } - $score_to_display .= ")"; + $score_to_display = " ($score_to_display)"; } if ($comment->{sid} && $comment->{cid}) { @@ -1931,14 +1974,14 @@ && $comment->{nickname} ne "-") { # this last test probably useless my @link = ( ); - push @link, linkComment({ + push @link, (qq'' . linkComment({ sid => $comment->{sid}, pid => $comment->{cid}, op => 'Reply', subject => 'Reply to This', subject_only => 1, - onclick => (($discussion2 && $user->{test_code}) ? "replyTo($comment->{cid}); return false;" : '') - }) unless $user->{state}{discussion_archived}; + onclick => (($discussion2 && (!$constants->{subscribe} || $user->{is_subscriber})) ? "replyTo($comment->{cid}); return false;" : '') + }) . '') unless $user->{state}{discussion_archived}; push @link, linkComment({ sid => $comment->{sid}, @@ -2138,6 +2181,7 @@ # some commonly-used proxy ports to access our own site. # If we can, they're coming from an open HTTP proxy, which # we don't want to allow to post. + # XXX : this can become a reskey check -- pudge 2008-03 if ($constants->{comments_portscan} && ( $constants->{comments_portscan} == 2 || $constants->{comments_portscan} == 1 && $user->{is_anon} ) @@ -2490,4 +2534,4 @@ =head1 VERSION -$Id: Comments.pm,v 1.2 2008/02/28 19:26:58 pudge Exp $ +$Id: Comments.pm,v 1.9 2008/03/20 07:30:29 pudge Exp $ Modified: slashjp/branches/upstream/current/Slash/Utility/Environment/Environment.pm =================================================================== --- slashjp/branches/upstream/current/Slash/Utility/Environment/Environment.pm 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/Slash/Utility/Environment/Environment.pm 2008-04-01 03:35:14 UTC (rev 560) @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. # Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Environment.pm,v 1.234 2008/02/28 19:26:58 pudge Exp $ +# $Id: Environment.pm,v 1.235 2008/03/18 20:39:17 tvroom Exp $ package Slash::Utility::Environment; @@ -33,7 +33,7 @@ use base 'Exporter'; use vars qw($VERSION @EXPORT); -($VERSION) = ' $Revision: 1.234 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.235 $ ' =~ /\$Revision:\s+([^\s]+)/; @EXPORT = qw( dbAvailable @@ -1554,7 +1554,7 @@ my @defaults = ( ['mode', 'thread'], qw[ savechanges commentsort threshold - posttype noboxes lowbandwidth simpledesign + posttype noboxes lowbandwidth simpledesign pda ]); for my $param (@defaults) { @@ -3526,4 +3526,4 @@ =head1 VERSION -$Id: Environment.pm,v 1.234 2008/02/28 19:26:58 pudge Exp $ +$Id: Environment.pm,v 1.235 2008/03/18 20:39:17 tvroom Exp $ Modified: slashjp/branches/upstream/current/bin/install-slashsite =================================================================== --- slashjp/branches/upstream/current/bin/install-slashsite 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/bin/install-slashsite 2008-04-01 03:35:14 UTC (rev 560) @@ -2,7 +2,7 @@ # This code is a part of Slash, and is released under the GPL. # Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: install-slashsite,v 1.49 2007/08/30 20:54:21 jamiemccarthy Exp $ +# $Id: install-slashsite,v 1.50 2008/03/07 15:58:53 jamiemccarthy Exp $ # This is the uber install script. # -Brian (brian ¡÷ tangent.org) @@ -20,13 +20,13 @@ use Slash::DB; use Slash::Install; -(my $VERSION) = ' $Revision: 1.49 $ ' =~ /\$Revision:\s+([^\s]+)/; +(my $VERSION) = ' $Revision: 1.50 $ ' =~ /\$Revision:\s+([^\s]+)/; my $PROGNAME = basename($0); (my $SLASH_PREFIX = $Bin) =~ s|/[^/]+/?$||; my %opts; # Remember to doublecheck these match usage()! -usage('Options used incorrectly') unless getopts('hvu:H:n:xRL:i:T:P:a:e:p:o:g:', \%opts); +usage('Options used incorrectly') unless getopts('hvfu:H:n:xRL:i:T:P:a:e:p:o:g:', \%opts); usage() if !$opts{'u'} and ($opts{'h'} or !keys %opts); # if invoked with both -u and -h, call usage() later, after we load Slash::Install version() if $opts{'v'}; Modified: slashjp/branches/upstream/current/docs/INSTALL.pod =================================================================== --- slashjp/branches/upstream/current/docs/INSTALL.pod 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/docs/INSTALL.pod 2008-04-01 03:35:14 UTC (rev 560) @@ -104,7 +104,7 @@ The version of this file that you are currently reading is: -$Id: INSTALL.pod,v 1.64 2008/02/19 18:29:04 scc Exp $ +$Id: INSTALL.pod,v 1.65 2008/03/12 15:16:09 scc Exp $ If there are more recent versions of this file, you can find a list of those changes at: @@ -311,6 +311,14 @@ cpan> o conf prerequisites_policy follow cpan> o conf commit +=item B + +There are bugs in versions earlier than 1.00 that break our JS. Unfortunately, +CPAN seems to prefer version 0.9 even though 1.00 is available. You may +have to install a better version in CPAN by hand: + + cpan> install A/AD/ADAMK/Data-JavaScript-Anon-1.00.tar.gz + =item B You must have certain libraries existing on your system before building, @@ -1757,5 +1765,5 @@ =head1 VERSION -$Id: INSTALL.pod,v 1.64 2008/02/19 18:29:04 scc Exp $ +$Id: INSTALL.pod,v 1.65 2008/03/12 15:16:09 scc Exp $ Modified: slashjp/branches/upstream/current/plugins/Admin/Admin.pm =================================================================== --- slashjp/branches/upstream/current/plugins/Admin/Admin.pm 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/plugins/Admin/Admin.pm 2008-04-01 03:35:14 UTC (rev 560) @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. # Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Admin.pm,v 1.38 2007/12/13 21:22:53 pudge Exp $ +# $Id: Admin.pm,v 1.39 2008/03/18 16:13:45 tvroom Exp $ package Slash::Admin; @@ -16,7 +16,7 @@ use base 'Slash::DB::Utility'; use base 'Slash::DB::MySQL'; -($VERSION) = ' $Revision: 1.38 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.39 $ ' =~ /\$Revision:\s+([^\s]+)/; # On a side note, I am not sure if I liked the way I named the methods either. # -Brian @@ -221,7 +221,7 @@ my $slashdb = getCurrentDB(); my $form = getCurrentForm(); my $user = getCurrentUser(); - return unless $user->{is_admin}; + return unless $user->{is_admin} || $user->{acl}{signoff_allowed}; my $stoid = $form->{stoid}; my $uid = $user->{uid}; @@ -326,11 +326,11 @@ my($self, $days) = @_; my $days_q = $self->sqlQuote($days); my $signoff_info = $self->sqlSelectAllHashrefArray( - "stories.stoid, users.uid, (unix_timestamp(min(signoff_time)) - unix_timestamp(stories.time)) / 60 AS min_to_sign, users.nickname", + "stories.stoid, users.uid, (unix_timestamp(min(signoff_time)) - unix_timestamp(stories.time)) / 60 AS min_to_sign, users.nickname, users.seclev", "stories, story_topics_rendered, signoff, users", "stories.stoid = story_topics_rendered.stoid AND signoff.stoid=stories.stoid AND users.uid = signoff.uid AND stories.time <= NOW() AND stories.time > DATE_SUB(NOW(), INTERVAL $days_q DAY)", - "GROUP BY signoff.uid, signoff.stoid" + "GROUP BY signoff.uid, signoff.stoid ORDER BY users.seclev DESC" ); return $signoff_info; Modified: slashjp/branches/upstream/current/plugins/Admin/admin.pl =================================================================== --- slashjp/branches/upstream/current/plugins/Admin/admin.pl 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/plugins/Admin/admin.pl 2008-04-01 03:35:14 UTC (rev 560) @@ -2,7 +2,7 @@ # This code is a part of Slash, and is released under the GPL. # Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: admin.pl,v 1.331 2008/02/27 19:00:15 jamiemccarthy Exp $ +# $Id: admin.pl,v 1.332 2008/03/18 16:13:45 tvroom Exp $ use strict; use File::Temp 'tempfile'; @@ -1882,7 +1882,7 @@ } my $usersignoffs = $slashdb->getUserSignoffHashForStoids($user->{uid}, $stoid_list); - my $storysignoffcnt = $slashdb->getSignoffCountHashForStoids($stoid_list); + my $storysignoffcnt = $slashdb->getSignoffCountHashForStoids($stoid_list, 1); my $needed_signoffs = $slashdb->getActiveAdminCount; @@ -2601,15 +2601,22 @@ my $signoff_info = $admin->getSignoffData($days); foreach (@$signoff_info) { $author_info->{$_->{uid}}{nickname} = $_->{nickname}; + $author_info->{$_->{uid}}{uid} = $_->{uid}; $author_info->{$_->{uid}}{$days}{cnt}++; $author_info->{$_->{uid}}{$days}{tot_time} += $_->{min_to_sign}; + $author_info->{$_->{uid}}{seclev} = $_->{seclev}; $stoids_for_days{$days}{$_->{stoid}}++; push @{$author_info->{$_->{uid}}{$days}{mins}}, $_->{min_to_sign}; } } + my @author_array = values %$author_info; + + @author_array = sort { $b->{seclev} <=> $a->{seclev} } @author_array; + slashDisplay("signoff_stats", { author_info => $author_info, + author_array => \@author_array, stoids_for_days => \%stoids_for_days, num_days => $num_days }); Modified: slashjp/branches/upstream/current/plugins/Admin/templates/editStory;admin;default =================================================================== --- slashjp/branches/upstream/current/plugins/Admin/templates/editStory;admin;default 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/plugins/Admin/templates/editStory;admin;default 2008-04-01 03:35:14 UTC (rev 560) @@ -248,7 +248,7 @@ Media Files associated with this story - + [% FOREACH mfile = story_static_files %] [% bigfile = mfile.name %] [% IF mfile.filetype != "image" || (mfile.filetype == "image" && bigfile.match('-thumb\.')) %] @@ -269,11 +269,18 @@ [% height = height.int %] [% END %] [% bigfile = bigfile.replace('-thumb') %] - + [% ELSE %] Add [% filename %] [% END %] + [% END %] [% END %] @@ -293,6 +300,7 @@ +
[% ispell_comments.bodytext %]
[% PROCESS editbuttons %] @@ -305,4 +313,4 @@ __seclev__ 10000 __version__ -$Id: editStory;admin;default,v 1.81 2007/11/29 16:53:20 entweichen Exp $ +$Id: editStory;admin;default,v 1.83 2008/03/19 17:45:03 tvroom Exp $ Modified: slashjp/branches/upstream/current/plugins/Admin/templates/signoff;misc;default =================================================================== --- slashjp/branches/upstream/current/plugins/Admin/templates/signoff;misc;default 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/plugins/Admin/templates/signoff;misc;default 2008-04-01 03:35:14 UTC (rev 560) @@ -18,10 +18,9 @@ [% IF storylink %]
  • [% END %] , [% UNLESS signed %]unsigned[% END %] -[% PROCESS ajax_reskey_signoff reskey_label => 'signoff-reskey-' _ stoid, reskey_name => 'ajax_admin' %] [% IF storylink %]
  • [% END %] [% END %] __seclev__ 10000 __version__ -$Id: signoff;misc;default,v 1.15 2007/07/30 18:46:15 tvroom Exp $ +$Id: signoff;misc;default,v 1.16 2008/03/18 16:13:45 tvroom Exp $ Modified: slashjp/branches/upstream/current/plugins/Admin/templates/signoff_stats;misc;default =================================================================== --- slashjp/branches/upstream/current/plugins/Admin/templates/signoff_stats;misc;default 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/plugins/Admin/templates/signoff_stats;misc;default 2008-04-01 03:35:14 UTC (rev 560) @@ -23,16 +23,22 @@ [% END %] - -[% FOREACH author = author_info.keys %] - +[% seen_admin = 0 %] +[% separator = 0 %] +[% FOREACH author = author_array %] + [% IF author.seclev >= 100; seen_admin = 1; END %] + [% IF seen_admin && author.seclev < 100 && !separator %] + + [% separator = 1; %] + [% END %] + [% FOREACH days = num_days %] [% num_stories = stoids_for_days.$days.keys.size || 0 %] - [% cnt = author_info.$author.$days.cnt || 0 %] + [% cnt = author.$days.cnt || 0 %]
    Select
    Thumb
    Click to
    add to body
    Select
    Thumb
    Click to
    add to body
    Click to add
    to media
    + [% IF mfile.filetype == "image" %] + + [% ELSE %] + Add [% filename %] + [% END %] +
    [% author_info.$author.nickname %]
    Non-Admins
    [% author.nickname %][% cnt %] of [% num_stories %] [% IF cnt > 0 %] - [% avg_time = author_info.$author.$days.tot_time / cnt %] + [% avg_time = author.$days.tot_time / cnt %] [% avg_time.int %] m [% ELSE %] N/A @@ -43,5 +49,5 @@ [% END %]
    __version__ -$Id: signoff_stats;misc;default,v 1.3 2006/02/27 18:44:08 tvroom Exp $ +$Id: signoff_stats;misc;default,v 1.4 2008/03/18 16:13:45 tvroom Exp $ Modified: slashjp/branches/upstream/current/plugins/Ajax/PLUGIN =================================================================== --- slashjp/branches/upstream/current/plugins/Ajax/PLUGIN 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/plugins/Ajax/PLUGIN 2008-04-01 03:35:14 UTC (rev 560) @@ -1,4 +1,4 @@ -# $Id: PLUGIN,v 1.40 2008/02/28 19:26:58 pudge Exp $ +# $Id: PLUGIN,v 1.41 2008/03/14 15:48:06 scc Exp $ name=Ajax description="Ajax (Asynchronous Javascript and XML)" mysql_dump=mysql_dump.sql @@ -28,7 +28,7 @@ htdoc=htdocs/images/slashbox.js htdoc=htdocs/images/common.js htdoc=htdocs/images/nodnix.js -htdoc=htdocs/images/prototype.js +htdoc=htdocs/images/jquery-1.2.3.js htdoc=htdocs/images/sectionprefs.js requiresplugin=ResKey template=templates/ajax_reskey_signoff;misc;default Modified: slashjp/branches/upstream/current/plugins/Ajax/htdocs/ajax.pl =================================================================== --- slashjp/branches/upstream/current/plugins/Ajax/htdocs/ajax.pl 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/plugins/Ajax/htdocs/ajax.pl 2008-04-01 03:35:14 UTC (rev 560) @@ -2,7 +2,7 @@ # This code is a part of Slash, and is released under the GPL. # Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: ajax.pl,v 1.74 2008/02/28 19:26:58 pudge Exp $ +# $Id: ajax.pl,v 1.77 2008/03/19 08:25:31 pudge Exp $ use strict; use warnings; @@ -14,7 +14,7 @@ use Slash::Utility; use vars qw($VERSION); -($VERSION) = ' $Revision: 1.74 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.77 $ ' =~ /\$Revision:\s+([^\s]+)/; ################################################################## sub main { @@ -54,6 +54,8 @@ # print STDERR "AJAX5 $$: $user->{uid}, $op\n"; + my $options = {}; + if ($reskey_name ne 'NA') { my $reskey = getObject('Slash::ResKey'); my $rkey = $reskey->key($reskey_name); @@ -61,6 +63,7 @@ print STDERR scalar(localtime) . " ajax.pl main no rkey for op='$op' name='$reskey_name'\n"; return; } + $options->{rkey} = $rkey; if ($ops->{$op}{reskey_type} eq 'createuse') { $rkey->createuse; } elsif ($ops->{$op}{reskey_type} eq 'touch') { @@ -85,7 +88,6 @@ } # print STDERR "AJAX6 $$: $user->{uid}, $op\n"; - my $options = {}; my $retval = $ops->{$op}{function}->( $slashdb, $constants, $user, $form, $options ); @@ -273,6 +275,23 @@ my $pid = $form->{pid} || 0; my $sid = $form->{sid} or return; + $user->{state}{ajax_accesslog_op} = 'comments_submit_reply'; + + my($error_message, $saved_comment); + my $discussion = $slashdb->getDiscussion($sid); + my $comment = preProcessComment($form, $user, $discussion, \$error_message); + if (!$error_message) { + $options->{rkey}->use or $error_message = $options->{rkey}->errstr; + } + $saved_comment = saveComment($form, $comment, $user, $discussion, \$error_message) + unless $error_message; + my $cid = $saved_comment && $saved_comment ne '-1' ? $saved_comment->{cid} : 0; + + $options->{content_type} = 'application/json'; + my %to_dump = ( cid => $cid, error => $error_message ); +#use Data::Dumper; print STDERR Dumper \%to_dump; + + return Data::JavaScript::Anon->anon_dump(\%to_dump); } sub previewReply { @@ -282,14 +301,24 @@ $user->{state}{ajax_accesslog_op} = 'comments_preview_reply'; + my($error_message, $preview, $html); my $discussion = $slashdb->getDiscussion($sid); - my $comment = preProcessComment($form, $user, $discussion); - my $preview = postProcessComment({ %$comment, %$user }, 0, $discussion); - my $html = prevComment($preview, $user); + my $comment = preProcessComment($form, $user, $discussion, \$error_message); + if ($comment && $comment ne '-1') { + $preview = postProcessComment({ %$comment, %$form, %$user }, 0, $discussion); + $html = prevComment($preview, $user); + } - + $error_message ||= 'This comment will not be saved until you click the Submit button below.'; $options->{content_type} = 'application/json'; - my %to_dump = (html => { "replyto_preview_$pid" => $html }); + my %to_dump = ( + error => $error_message, + ); + $to_dump{html} = { "replyto_preview_$pid" => $html } if $html; + $to_dump{eval_first} = "\$('gotmodwarning_$pid').value = 1;" + if $form->{gotmodwarning} || ($error_message && $error_message eq + Slash::Utility::Comments::getError("moderations to be lost") + ); #use Data::Dumper; print STDERR Dumper \%to_dump; return Data::JavaScript::Anon->anon_dump(\%to_dump); @@ -304,8 +333,10 @@ $user->{state}{ajax_accesslog_op} = 'comments_reply_form'; my($reply, $pid_reply); + my $discussion = $slashdb->getDiscussion($sid); $reply = $slashdb->getCommentReply($sid, $pid) if $pid; $pid_reply = prepareQuoteReply($reply) if $pid && $reply; + preProcessReplyForm($form, $reply); my $reskey = getObject('Slash::ResKey'); my $rkey = $reskey->key('comments', { nostate => 1 }); @@ -314,10 +345,11 @@ my %to_dump; if ($rkey->success) { my $reply_html = slashDisplay('edit_comment', { - sid => $sid, - pid => $pid, - reply => $reply, - rkey => $rkey + discussion => $discussion, + sid => $sid, + pid => $pid, + reply => $reply, + rkey => $rkey }, { Return => 1 }); %to_dump = (html => { "replyto_$pid" => $reply_html }); } else { @@ -326,7 +358,6 @@ $options->{content_type} = 'application/json'; $to_dump{eval_first} = "comment_body_reply[$pid] = '$pid_reply';" if $pid_reply; - #use Data::Dumper; print STDERR Dumper \%to_dump; return Data::JavaScript::Anon->anon_dump(\%to_dump); @@ -711,6 +742,22 @@ { Page => 'misc', Skin => 'idle', Return => 1 } ); + } elsif ($form->{'section'} eq 'modcommentlog') { + my $moddb = getObject("Slash::$constants->{m1_pluginname}"); + if ($moddb) { + # we hijack "tabbed" as our cid -- pudge + return $moddb->dispModCommentLog('cid', $form->{'tabbed'}, { + show_m2s => ($constants->{m2} + ? (defined($form->{show_m2s}) + ? $form->{show_m2s} + : $user->{m2_with_comm_mod} + ) : 0), + need_m2_form => $constants->{m2}, + need_m2_button => $constants->{m2}, + title => " " + }); + } + } else { return @@ -731,7 +778,7 @@ my $url = URI->new('//e.a/?' . $form->{'data'}); my %params = $url->query_form; - # D2 display + # D2 display my $user_edits_table; if ($params{'formname'} eq 'd2_display') { $user_edits_table = { @@ -744,7 +791,7 @@ }; } - # D2 posting + # D2 posting if ($params{'formname'} eq 'd2_posting') { $user_edits_table = { emaildisplay => $params{'emaildisplay'} || undef, @@ -758,7 +805,17 @@ }; } - # Messages + # Messages + if ($params{'formname'} eq 'metamoderate') { + if ($constants->{m2} && $user->{is_admin}) { + # metaModerate uses $form ... whether it should or not! -- pudge + @$form{keys %params} = values %params; + my $metamod_db = getObject('Slash::Metamod'); + $metamod_db->metaModerate($user->{is_admin}) if $metamod_db; + } + } + + # Messages if ($params{'formname'} eq 'messages') { my $messages = getObject('Slash::Messages'); my $messagecodes = $messages->getDescriptions('messagecodes'); @@ -1043,9 +1100,9 @@ my %mainops = ( comments_submit_reply => { - function => \&previewReply, + function => \&submitReply, reskey_name => 'comments', - reskey_type => 'use', + reskey_type => 'touch', }, comments_preview_reply => { function => \&previewReply, Modified: slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/admin.js =================================================================== --- slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/admin.js 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/admin.js 2008-04-01 03:35:14 UTC (rev 560) @@ -1,7 +1,7 @@ -// $Id: admin.js,v 1.44 2007/12/20 18:46:05 tvroom Exp $ +// $Id: admin.js,v 1.48 2008/03/18 16:28:44 tvroom Exp $ function um_ajax(the_behaviors, the_events) { - var params =[]; + var params = {}; params['op'] = 'um_ajax'; params['behaviors'] = the_behaviors; params['events'] = the_events; @@ -9,32 +9,20 @@ } function um_fetch_settings() { - var params =[]; + var params = {}; params['op'] = 'um_fetch_settings'; ajax_update(params, 'links-vendors-content'); } function um_set_settings(behavior) { - var params =[]; + var params = {}; params['op'] = 'um_set_settings'; params['behavior'] = behavior; ajax_update(params, 'links-vendors-content'); } -function admin_signoff(stoid, type, id) { - var params = []; - var reskeyel = $('signoff-reskey-' + stoid); - params['op'] = 'admin_signoff'; - params['stoid'] = stoid; - params['reskey'] = reskeyel.value; - ajax_update(params, 'signoff_' + stoid); - if (type == "firehose") { - firehose_collapse_entry(id); - } -} - function admin_neverdisplay(stoid, type, fhid) { - var params = []; + var params = {}; params['op'] = 'admin_neverdisplay'; params['reskey'] = reskey_static; params['stoid'] = stoid; @@ -48,22 +36,22 @@ } function admin_submit_memory(fhid) { - var params = []; + var params = {}; params['op'] = 'admin_submit_memory'; params['reskey'] = reskey_static; - params['submatch'] = $('submatch-'+fhid).value; - params['subnote'] = $('subnote-'+fhid).value; + params['submatch'] = $dom('submatch-'+fhid).value; + params['subnote'] = $dom('subnote-'+fhid).value; ajax_update(params, 'sub_mem_message-'+fhid); } function adminTagsCommands(id, type) { - var toggletags_message_id = 'toggletags-message-' + id; - var toggletags_message_el = $(toggletags_message_id); + var toggletags_message_id = '#toggletags-message-' + id; + var toggletags_message_el = jQuery(toggletags_message_id)[0]; if (toggletags_message_el) { toggletags_message_el.innerHTML = 'Executing commands...'; } - var params = []; + var params = {}; type = type || "stories"; params['op'] = 'tags_admin_commands'; if (type == "stories") { @@ -74,9 +62,9 @@ params['id'] = id; } params['type'] = type; - var tags_admin_commands_el = $('tags_admin_commands-' + id); + var tags_admin_commands_el = $dom('tags_admin_commands-' + id); params['commands'] = tags_admin_commands_el.value; - var reskeyel = $('admin_commands-reskey-' + id); + var reskeyel = $dom('admin_commands-reskey-' + id); params['reskey'] = reskeyel.value; ajax_update(params, 'tags-admin-' + id); @@ -84,7 +72,7 @@ } function tagsHistory(id, type) { - var params = []; + var params = {}; type = type || "stories"; params['type'] = type; params['op'] = 'tags_history'; @@ -103,17 +91,17 @@ } function remarks_create() { - var reskey = $('remarks_reskey'); - var remark = $('remarks_new'); + var reskey = $dom('remarks_reskey'); + var remark = $dom('remarks_new'); if (!remark || !remark.value || !reskey || !reskey.value) { return false; } - var params = []; + var params = {}; params['op'] = 'remarks_create'; params['remark'] = remark.value; params['reskey'] = reskey.value; - remarks_max = $('remarks_max'); + remarks_max = $dom('remarks_max'); if (remarks_max && remarks_max.value) { params['limit'] = remarks_max.value; } @@ -121,7 +109,7 @@ } function remarks_fetch(secs, limit) { - var params = []; + var params = {}; params['op'] = 'remarks_fetch'; params['limit'] = limit; // run it every 30 seconds; don't need to call again @@ -129,7 +117,7 @@ } function remarks_popup() { - var params = []; + var params = {}; params['op'] = 'remarks_config'; var title = "Remarks Config "; var buttons = createPopupButtons('[X]'); @@ -140,11 +128,11 @@ } function remarks_config_save() { - var params = []; - var reskey = $('remarks_reskey'); - var min_priority = $('remarks_min_priority'); - var limit = $('remarks_limit'); - var filter = $('remarks_filter'); + var params = {}; + var reskey = $dom('remarks_reskey'); + var min_priority = $dom('remarks_min_priority'); + var limit = $dom('remarks_limit'); + var filter = $dom('remarks_filter'); params['op'] = 'remarks_config_save'; if (!reskey && !reskey.value) { return false; @@ -158,7 +146,7 @@ if (filter) { params['filter'] = filter.value; } - var message = $('remarksconfig-message'); + var message = $dom('remarksconfig-message'); if (message) { message.innerHTML = "Saving..."; } @@ -166,31 +154,31 @@ } function admin_slashdbox_fetch(secs) { - var params = []; + var params = {}; params['op'] = 'admin_slashdbox'; ajax_periodic_update(secs, params, "slashdbox-content"); } function admin_perfbox_fetch(secs) { - var params = []; + var params = {}; params['op'] = 'admin_perfbox'; ajax_periodic_update(secs, params, "performancebox-content"); } function admin_authorbox_fetch(secs) { - var params = []; + var params = {}; params['op'] = 'admin_authorbox'; ajax_periodic_update(secs, params, "authoractivity-content"); } function admin_storyadminbox_fetch(secs) { - var params = []; + var params = {}; params['op'] = 'admin_storyadminbox'; ajax_periodic_update(secs, params, "storyadmin-content"); } function admin_recenttagnamesbox_fetch(secs) { - var params = []; + var params = {}; params['op'] = 'admin_recenttagnamesbox'; ajax_periodic_update(secs, params, "recenttagnames-content"); } @@ -202,7 +190,7 @@ return; } - var params = []; + var params = {}; params['op'] = 'console_update' var handlers = { onComplete: json_handler @@ -216,11 +204,11 @@ } function firehose_usage() { - var params = []; + var params = {}; params['op'] = 'firehose_usage' var interval = 300000; ajax_update(params, 'firehose_usage-content'); - setTimeout("firehose_usage()", interval); + setTimeout(firehose_usage, interval); } function make_spelling_correction(misspelled_word, form_element) { @@ -234,7 +222,7 @@ // Either learning a word or making a correction. if (selected_index >= 1) { if (selected_index == 1) { - var params = []; + var params = {}; params['op'] = 'admin_learnword'; params['word'] = misspelled_word; ajax_update(params); @@ -265,8 +253,8 @@ } function firehose_reject (el) { - var params = []; - var fh = $('firehose-' + el.value); + var params = {}; + var fh = $dom('firehose-' + el.value); params['op'] = 'firehose_reject'; params['id'] = el.value; params['reskey'] = reskey_static; @@ -275,19 +263,19 @@ } function firehose_open_note(id) { - var nf = $('note-form-'+id); - var nt = $('note-text-'+id); - var ni = $('note-input-'+id); + var nf = $dom('note-form-'+id); + var nt = $dom('note-text-'+id); + var ni = $dom('note-input-'+id); nf.className=""; ni.focus(); nt.className="hide"; } function firehose_save_note(id) { - var nf = $('note-form-'+id); - var nt = $('note-text-'+id); - var ni = $('note-input-'+id); - var params = []; + var nf = $dom('note-form-'+id); + var nt = $dom('note-text-'+id); + var ni = $dom('note-input-'+id); + var params = {}; params['op'] = 'firehose_save_note'; params['note'] = ni.value; params['id'] = id; @@ -297,30 +285,43 @@ } function firehose_get_admin_extras(id) { - var params=[]; + var params = {}; params['id'] = id; params['op'] = 'firehose_get_admin_extras'; var handlers = { - onComplete: json_handler + onComplete: function(transport) { + json_handler(transport); + if (firehoseIsInWindow(id)) { + scrollToWindowFirehose(id); + } + } }; ajax_update(params, '', handlers); } function firehose_get_and_post(id) { - var params=[]; + var params = {}; params['id'] = id; params['op'] = 'firehose_get_form'; firehose_collapse_entry(id); var handlers = { - onComplete: function() { $('postform-'+id).submit();} + onComplete: function() { $dom('postform-'+id).submit();} }; ajax_update(params, 'postform-'+id, handlers); } function appendToBodytext(text) { - var obj = $('admin-bodytext'); + var obj = $dom('admin-bodytext'); if (obj) { obj.className = "show"; obj.value = obj.value + text; } } + +function appendToMedia(text) { + var obj = $dom('admin-media'); + if (obj) { + obj.className = "show"; + obj.value = obj.value + text; + } +} Modified: slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/common.js =================================================================== --- slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/common.js 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/common.js 2008-04-01 03:35:14 UTC (rev 560) @@ -1,6 +1,10 @@ // _*_ Mode: JavaScript; tab-width: 8; indent-tabs-mode: true _*_ -// $Id: common.js,v 1.174 2008/02/28 19:26:58 pudge Exp $ +// $Id: common.js,v 1.183 2008/03/18 16:28:44 tvroom Exp $ +function $dom( id ) { + return document.getElementById(id); +} + // global settings, but a firehose might use a local settings object instead var firehose_settings = {}; firehose_settings.startdate = ''; @@ -25,6 +29,8 @@ firehose_removals = null; firehose_future = null; + var firehose_cur = 0; + // globals we haven't yet decided to move into |firehose_settings| var fh_play = 0; var fh_is_timed_out = 0; @@ -43,9 +49,6 @@ var is_ie = ua.match("/MSIE/"); -// eventually add site specific constants like this to a separate .js -var sitename = "Slashdot"; - function createPopup(xy, titlebar, name, contents, message, onmouseout) { var body = document.getElementsByTagName("body")[0]; var div = document.createElement("div"); @@ -88,7 +91,7 @@ } function closePopup(id, refresh) { - var el = $(id); + var el = $dom(id); if (el) { el.parentNode.removeChild(el); } @@ -131,8 +134,9 @@ } function getXYForId(id, addWidth, addHeight) { - var div = $(id); - var xy = Position.cumulativeOffset(div); + var div = $dom(id); + var offset = jQuery(div).offset(); + var xy = [ offset.left, offset.top ]; if (addWidth) { xy[0] = xy[0] + div.offsetWidth; } @@ -143,7 +147,7 @@ } function firehose_toggle_advpref() { - var obj = $('fh_advprefs'); + var obj = $dom('fh_advprefs'); if (obj.className == 'hide') { obj.className = ""; } else { @@ -152,12 +156,12 @@ } function firehose_open_prefs() { - var obj = $('fh_advprefs'); + var obj = $dom('fh_advprefs'); obj.className = ""; } function toggleId(id, first, second) { - var obj =$(id); + var obj = $dom(id); if (obj.className == first) { obj.className = second; } else if (obj.className == second) { @@ -168,8 +172,8 @@ } function toggleIntro(id, toggleid) { - var obj = $(id); - var toggle = $(toggleid); + var obj = $dom(id); + var toggle = $dom(toggleid); if (obj.className == 'introhide') { obj.className = "intro" toggle.innerHTML = "[-]"; @@ -183,7 +187,7 @@ function tagsToggleStoryDiv(id, is_admin, type) { var bodyid = 'toggletags-body-' + id; - var tagsbody = $(bodyid); + var tagsbody = $dom(bodyid); if (tagsbody.className == 'tagshide') { tagsShowBody(id, is_admin, '', type); } else { @@ -194,22 +198,22 @@ function tagsHideBody(id) { // Make the body of the tagbox vanish var tagsbodyid = 'toggletags-body-' + id; - var tagsbody = $(tagsbodyid); + var tagsbody = $dom(tagsbodyid); tagsbody.className = "tagshide" // Make the title of the tagbox change back to regular var titleid = 'tagbox-title-' + id; - var title = $(titleid); + var title = $dom(titleid); title.className = "tagtitleclosed"; // Make the tagbox change back to regular. var tagboxid = 'tagbox-' + id; - var tagbox = $(tagboxid); + var tagbox = $dom(tagboxid); tagbox.className = "tags"; // Toggle the button back. var tagsbuttonid = 'toggletags-button-' + id; - var tagsbutton = $(tagsbuttonid); + var tagsbutton = $dom(tagsbuttonid); tagsbutton.innerHTML = "[+]"; } @@ -228,35 +232,35 @@ // Toggle the button to show the click was received var tagsbuttonid = 'toggletags-button-' + id; - var tagsbutton = $(tagsbuttonid); + var tagsbutton = $dom(tagsbuttonid); tagsbutton.innerHTML = "[-]"; // Make the tagbox change to the slashbox class var tagboxid = 'tagbox-' + id; - var tagbox = $(tagboxid); + var tagbox = $dom(tagboxid); tagbox.className = "tags"; // Make the title of the tagbox change to white-on-green var titleid = 'tagbox-title-' + id; - var title = $(titleid); + var title = $dom(titleid); title.className = "tagtitleopen"; // Make the body of the tagbox visible var tagsbodyid = 'toggletags-body-' + id; - var tagsbody = $(tagsbodyid); + var tagsbody = $dom(tagsbodyid); tagsbody.className = "tagbody"; // If the tags-user div hasn't been filled, fill it. var tagsuserid = 'tags-user-' + id; - var tagsuser = $(tagsuserid); + var tagsuser = $dom(tagsuserid); if (tagsuser.innerHTML == "") { // The tags-user-123 div is empty, and needs to be // filled with the tags this user has already // specified for this story, and a reskey to allow // the user to enter more tags. tagsuser.innerHTML = "Retrieving..."; - var params = []; + var params = {}; if (type == "stories") { params['op'] = 'tags_get_user_story'; params['sidenc'] = id; @@ -272,7 +276,7 @@ var handlers = { onComplete: function() { var textid = 'newtags-' + id; - var input = $(textid); + var input = $dom(textid); input.focus(); } } @@ -287,7 +291,7 @@ // user is not actually an admin. if (is_admin) { var tagsadminid = 'tags-admin-' + id; - params = []; + params = {}; if (type == "stories") { params['op'] = 'tags_get_admin_story'; params['sidenc'] = id; @@ -308,7 +312,7 @@ // We can't do that by passing it in, so do it // manually now. var textinputid = 'newtags-' + id; - var textinput = $(textinputid); + var textinput = $dom(textinputid); textinput.value = textinput.value + ' ' + newtagspreloadtext; textinput.focus(); } @@ -382,12 +386,12 @@ } function createTag(tag, id, type) { - var params = []; + var params = {}; params['id'] = id; params['type'] = type; if ( fh_is_admin && ("_#)^*".indexOf(tag[0]) != -1) ) { params['op'] = 'tags_admin_commands'; - params['reskey'] = $('admin_commands-reskey-' + id).value; + params['reskey'] = $dom('admin_commands-reskey-' + id).value; params['command'] = tag; } else { params['op'] = 'tags_create_tag'; @@ -402,15 +406,15 @@ function tagsCreateForStory(id) { var toggletags_message_id = 'toggletags-message-' + id; - var toggletags_message_el = $(toggletags_message_id); + var toggletags_message_el = $dom(toggletags_message_id); toggletags_message_el.innerHTML = 'Saving tags...'; - var params = []; + var params = {}; params['op'] = 'tags_create_for_story'; params['sidenc'] = id; - var newtagsel = $('newtags-' + id); + var newtagsel = $dom('newtags-' + id); params['tags'] = newtagsel.value; - var reskeyel = $('newtags-reskey-' + id); + var reskeyel = $dom('newtags-reskey-' + id); params['reskey'] = reskeyel.value; ajax_update(params, 'tags-user-' + id); @@ -421,15 +425,15 @@ function tagsCreateForUrl(id) { var toggletags_message_id = 'toggletags-message-' + id; - var toggletags_message_el = $(toggletags_message_id); + var toggletags_message_el = $dom(toggletags_message_id); toggletags_message_el.innerHTML = 'Saving tags...'; - var params = []; + var params = {}; params['op'] = 'tags_create_for_url'; params['id'] = id; - var newtagsel = $('newtags-' + id); + var newtagsel = $dom('newtags-' + id); params['tags'] = newtagsel.value; - var reskeyel = $('newtags-reskey-' + id); + var reskeyel = $dom('newtags-reskey-' + id); params['reskey'] = reskeyel.value; ajax_update(params, 'tags-user-' + id); @@ -440,7 +444,7 @@ //Firehose functions begin function setOneTopTagForFirehose(id, newtag) { - var params = []; + var params = {}; params['op'] = 'firehose_update_one_tag'; params['id'] = id; params['tags'] = newtag; @@ -450,15 +454,15 @@ function tagsCreateForFirehose(id) { var toggletags_message_id = 'toggletags-message-' + id; - var toggletags_message_el = $(toggletags_message_id); + var toggletags_message_el = $dom(toggletags_message_id); toggletags_message_el.innerHTML = 'Saving tags...'; - var params = []; + var params = {}; params['op'] = 'tags_create_for_firehose'; params['id'] = id; - var newtagsel = $('newtags-' + id); + var newtagsel = $dom('newtags-' + id); params['tags'] = newtagsel.value; - var reskeyel = $('newtags-reskey-' + id); + var reskeyel = $dom('newtags-reskey-' + id); params['reskey'] = reskeyel.value; ajax_update(params, 'tags-user-' + id); @@ -466,16 +470,19 @@ } function toggle_firehose_body(id, is_admin) { - var params = []; + var params = {}; setFirehoseAction(); params['op'] = 'firehose_fetch_text'; params['id'] = id; - var fhbody = $('fhbody-'+id); - var fh = $('firehose-'+id); + var fhbody = $dom('fhbody-'+id); + var fh = $dom('firehose-'+id); var usertype = fh_is_admin ? " adminmode" : " usermode"; if (fhbody.className == "empty") { var handlers = { - onComplete: function() { + onComplete: function() { + if(firehoseIsInWindow(id)) { + scrollToWindowFirehose(id); + } firehose_get_admin_extras(id); } }; @@ -503,7 +510,7 @@ } function toggleFirehoseTagbox(id) { - var fhtb = $('fhtagbox-'+id); + var fhtb = $dom('fhtagbox-'+id); if (fhtb.className == "hide") { fhtb.className = "tagbox"; } else { @@ -521,7 +528,7 @@ ["mode", "full", "abbrev", "full", "fulltitle"], ["mode", "fulltitle", "full", "abbrev", "full"] ]; - var params = []; + var params = {}; params['op'] = 'firehose_set_options'; params['reskey'] = reskey_static; var theForm = document.forms["firehoseform"]; @@ -548,7 +555,7 @@ } if (classname) { - var els = document.getElementsByClassName(classname, $('firehoselist')); + var els = document.getElementsByClassName(classname, $dom('firehoselist')); var classval = classname; if (value) { classval = classval + " hide"; @@ -572,12 +579,12 @@ var el = pairs[i]; if (name == el[0] && value == el[1]) { firehose_settings[name] = value; - if ($(el[2])) { - $(el[2]).id = el[3]; - if($(el[3])) { + if ($dom(el[2])) { + $dom(el[2]).id = el[3]; + if($dom(el[3])) { var namenew = el[0]; var valuenew = el[4]; - $(el[3]).firstChild.onclick = function() { firehose_set_options(namenew, valuenew); return false;} + $dom(el[3]).firstChild.onclick = function() { firehose_set_options(namenew, valuenew); return false;} } } } @@ -587,7 +594,7 @@ if (name == "mode") { fh_view_mode = value; } - if ($('firehoselist')) { + if ($dom('firehoselist')) { // set page page = 0; @@ -598,12 +605,12 @@ var myAnim = new YAHOO.util.Anim("firehoselist", attributes); myAnim.duration = 1; myAnim.onComplete.subscribe(function() { - $('firehoselist').style.opacity = "1"; + $dom('firehoselist').style.opacity = "1"; }); myAnim.animate(); } // remove elements - setTimeout("firehose_remove_all_items()", 600); + setTimeout(firehose_remove_all_items, 600); } } } @@ -623,11 +630,11 @@ firehose_settings.page = 0; var issuedate = firehose_settings.issue.substr(5,2) + "/" + firehose_settings.issue.substr(8,2) + "/" + firehose_settings.issue.substr(10,2); - if ($('fhcalendar')) { - $('fhcalendar')._widget.setDate(issuedate, "day"); + if ($dom('fhcalendar')) { + $dom('fhcalendar')._widget.setDate(issuedate, "day"); } - if ($('fhcalendar_pag')) { - $('fhcalendar_pag')._widget.setDate(issuedate, "day"); + if ($dom('fhcalendar_pag')) { + $dom('fhcalendar_pag')._widget.setDate(issuedate, "day"); } } if (name == "color") { @@ -662,7 +669,7 @@ } function firehose_remove_all_items() { - var fhl = $('firehoselist'); + var fhl = $dom('firehoselist'); var children = fhl.childNodes; for (var i = children.length -1 ; i >= 0; i--) { var el = children[i]; @@ -677,7 +684,7 @@ if (!check_logged_in()) return; setFirehoseAction(); - var params = []; + var params = {}; var handlers = { onComplete: json_handler }; @@ -685,7 +692,7 @@ params['id'] = id; params['reskey'] = reskey_static; params['dir'] = dir; - var updown = $('updown-' + id); + var updown = $dom('updown-' + id); ajax_update(params, '', handlers); if (updown) { if (dir == "+") { @@ -702,7 +709,7 @@ function firehose_remove_tab(tabid) { setFirehoseAction(); - var params = []; + var params = {}; var handlers = { onComplete: json_handler }; @@ -718,39 +725,34 @@ // firehose functions end // helper functions -function ajax_update(params, onsucc, options, url) { - var h = $H(params); +function ajax_update(request_params, id, handlers, request_url) { + // make an ajax request to request_url with request_params, on success, + // update the innerHTML of the element with id - if (!url) - url = '/ajax.pl'; + var opts = { + url: request_url || '/ajax.pl', + data: request_params, + type: 'POST', + contentType: 'application/x-www-form-urlencoded', + }; - if (!options) - options = {}; + if ( id ) { + opts['success'] = function(html){ + jQuery('#'+id).html(html); + } + } - options.method = 'post'; - options.parameters = h.toQueryString(); + if ( handlers && handlers.onComplete ) { + opts['complete'] = handlers.onComplete; + } - var ajax = new Ajax.Updater( - { success: onsucc }, - url, - options - ); + jQuery.ajax(opts); } -function ajax_periodic_update(secs, params, onsucc, options, url) { - var h = $H(params); - - if (!url) - url = '/ajax.pl'; - - if (!options) - options = {}; - - options.frequency = secs; - options.method = 'post'; - options.parameters = h.toQueryString(); - - var ajax = new Ajax.PeriodicalUpdater({ success: onsucc }, url, options); +function ajax_periodic_update(interval_in_seconds, request_params, id, handlers, request_url) { + setInterval(function(){ + ajax_update(request_params, id, handlers, request_url); + }, interval_in_seconds*1000); } function eval_response(transport) { @@ -766,6 +768,7 @@ function json_handler(transport) { var response = eval_response(transport); json_update(response); + return response; } function json_update(response) { @@ -779,35 +782,35 @@ if (response.html) { for (el in response.html) { - if ($(el)) - $(el).innerHTML = response.html[el]; + if ($dom(el)) + $dom(el).innerHTML = response.html[el]; } } if (response.value) { for (el in response.value) { - if ($(el)) - $(el).value = response.value[el]; + if ($dom(el)) + $dom(el).value = response.value[el]; } } if (response.html_append) { for (el in response.html_append) { - if ($(el)) - $(el).innerHTML = $(el).innerHTML + response.html_append[el]; + if ($dom(el)) + $dom(el).innerHTML = $dom(el).innerHTML + response.html_append[el]; } } if (response.html_append_substr) { for (el in response.html_append_substr) { - if ($(el)) { - var this_html = $(el).innerHTML; - var i = $(el).innerHTML.search(/ ?<\/span>[\s\S]*$/i); + if ($dom(el)) { + var this_html = $dom(el).innerHTML; + var i = $dom(el).innerHTML.search(/ ?<\/span>[\s\S]*$/i); if (i == -1) { - $(el).innerHTML += response.html_append_substr[el]; + $dom(el).innerHTML += response.html_append_substr[el]; } else { - $(el).innerHTML = $(el).innerHTML.substr(0, i) + + $dom(el).innerHTML = $dom(el).innerHTML.substr(0, i) + response.html_append_substr[el]; } } @@ -830,16 +833,14 @@ var fh = 'firehose-' + el[1]; var wait_interval = 800; if(el[0] == "add") { - if (firehose_before[el[1]] && $('firehose-' + firehose_before[el[1]])) { - new Insertion.After('firehose-' + firehose_before[el[1]], el[2]); - - - } else if (firehose_after[el[1]] && $('firehose-' + firehose_after[el[1]])) { - new Insertion.Before('firehose-' + firehose_after[el[1]], el[2]); + if (firehose_before[el[1]] && jQuery('#firehose-' + firehose_before[el[1]]).size()) { + jQuery('#firehose-' + firehose_before[el[1]]).after(el[2]); + } else if (firehose_after[el[1]] && jQuery('#firehose-' + firehose_after[el[1]]).size()) { + jQuery('#firehose-' + firehose_after[el[1]]).before(el[2]); } else if (insert_new_at == "bottom") { - new Insertion.Bottom('firehoselist', el[2]); + jQuery('#firehoselist').append(el[2]); } else { - new Insertion.Top('firehoselist', el[2]); + jQuery('#firehoselist').prepend(el[2]); } var toheight = 50; @@ -871,8 +872,8 @@ } myAnim.onComplete.subscribe(function() { - if ($(fh)) { - $(fh).style.height = ""; + if ($dom(fh)) { + $dom(fh).style.height = ""; if (fh_use_jquery) { jQuery("#" + fh + " h3 a[class!='skin']").click( function(){ @@ -886,7 +887,7 @@ }); myAnim.animate(); } else if (el[0] == "remove") { - var fh_node = $(fh); + var fh_node = $dom(fh); if (fh_is_admin && fh_view_mode == "fulltitle" && fh_node && fh_node.className == "article" ) { // Don't delete admin looking at this in expanded view } else { @@ -919,7 +920,7 @@ }); myAnim.animate(); } else { - var elem = $(fh); + var elem = $dom(fh); wait_interval = 25; if (elem && elem.parentNode) { elem.parentNode.removeChild(elem); @@ -927,7 +928,7 @@ } } } - setTimeout("firehose_handle_update()", wait_interval); + setTimeout(firehose_handle_update, wait_interval); } else { firehose_reorder(); firehose_get_next_updates(); @@ -936,32 +937,28 @@ function firehose_reorder() { if (firehose_ordered) { - var fhlist = $('firehoselist'); + var fhlist = $dom('firehoselist'); if (fhlist) { var item_count = 0; for (i = 0; i < firehose_ordered.length; i++) { if (/^\d+$/.test(firehose_ordered[i])) { item_count++; } - var fhel = $('firehose-' + firehose_ordered[i]); + var fhel = $dom('firehose-' + firehose_ordered[i]); if (fhlist && fhel) { fhlist.appendChild(fhel); } if ( firehose_future[firehose_ordered[i]] ) { - if ($("ttype-" + firehose_ordered[i])) { - $("ttype-" + firehose_ordered[i]).className = "future"; + if ($dom("ttype-" + firehose_ordered[i])) { + $dom("ttype-" + firehose_ordered[i]).className = "future"; } } else { - if ($("ttype-" + firehose_ordered[i]) && $("ttype-" + firehose_ordered[i]).className == "future") { - $("ttype-" + firehose_ordered[i]).className = "story"; + if ($dom("ttype-" + firehose_ordered[i]) && $dom("ttype-" + firehose_ordered[i]).className == "future") { + $dom("ttype-" + firehose_ordered[i]).className = "story"; } } } - if (console_updating) { - document.title = sitename + " - Console (" + item_count + ")"; - } else { - document.title = sitename + " - Firehose (" + item_count + ")"; - } + document.title = "[% sitename %] - " + (console_updating ? "Console" : "Firehose") + " (" + item_count + ")"; } } @@ -971,13 +968,13 @@ var interval = getFirehoseUpdateInterval(); //alert("fh_get_next_updates"); fh_is_updating = 0; - firehose_add_update_timerid(setTimeout("firehose_get_updates()", interval)); + firehose_add_update_timerid(setTimeout(firehose_get_updates, interval)); } function firehose_get_updates_handler(transport) { - if ($('busy')) { - $('busy').className = "hide"; + if ($dom('busy')) { + $dom('busy').className = "hide"; } var response = eval_response(transport); var processed = 0; @@ -1008,7 +1005,7 @@ } function firehose_get_item_idstring() { - var fhl = $('firehoselist'); + var fhl = $dom('firehoselist'); var str = ""; var children; if (fhl) { @@ -1033,7 +1030,7 @@ options = options || {}; run_before_update(); if ((fh_play == 0 && !options.oneupdate) || fh_is_updating == 1) { - firehose_add_update_timerid(setTimeout("firehose_get_updates()", 2000)); + firehose_add_update_timerid(setTimeout(firehose_get_updates, 2000)); // alert("wait loop: " + fh_is_updating); return; } @@ -1042,7 +1039,7 @@ while(id = fh_update_timerids.pop()) { clearTimeout(id) }; } fh_is_updating = 1 - var params = []; + var params = {}; var handlers = { onComplete: firehose_get_updates_handler }; @@ -1058,8 +1055,8 @@ params['embed'] = 1; } params['fh_pageval'] = firehose_settings.pageval; - if ($('busy')) { - $('busy').className = ""; + if ($dom('busy')) { + $dom('busy').className = ""; } ajax_update(params, '', handlers); } @@ -1103,8 +1100,8 @@ var secs = getSecsSinceLastFirehoseAction(); if (secs > inactivity_timeout) { fh_is_timed_out = 1; - if ($('message_area')) - $('message_area').innerHTML = "Automatic updates have been slowed due to inactivity"; + if ($dom('message_area')) + $dom('message_area').innerHTML = "Automatic updates have been slowed due to inactivity"; //firehose_pause(); } } @@ -1113,15 +1110,15 @@ fh_play = 1; setFirehoseAction(); firehose_set_options('pause', '0'); - var pausepanel = $('pauseorplay'); - if ($('message_area')) - $('message_area').innerHTML = ""; + var pausepanel = $dom('pauseorplay'); + if ($dom('message_area')) + $dom('message_area').innerHTML = ""; if (pausepanel) { pausepanel.innerHTML = "Updated"; } - var pause = $('pause'); + var pause = $dom('pause'); - var play_div = $('play'); + var play_div = $dom('play'); if (play_div) { play_div.className = "hide"; } @@ -1130,14 +1127,18 @@ } } +function is_firehose_playing() { + return YAHOO.util.Dom.hasClass('play', 'hide'); +} + function firehose_pause() { fh_play = 0; - var pause = $('pause'); - var play_div = $('play'); + var pause = $dom('pause'); + var play_div = $dom('play'); pause.className = "hide"; play_div.className = "show"; - if ($('pauseorplay')) { - $('pauseorplay').innerHTML = "Paused"; + if ($dom('pauseorplay')) { + $dom('pauseorplay').innerHTML = "Paused"; } firehose_set_options('pause', '1'); } @@ -1147,8 +1148,8 @@ } function firehose_collapse_entry(id) { - var fhbody = $('fhbody-'+id); - var fh = $('firehose-'+id); + var fhbody = $dom('fhbody-'+id); + var fh = $dom('firehose-'+id); if (fhbody && fhbody.className == "body") { fhbody.className = "hide"; } @@ -1160,7 +1161,7 @@ } function firehose_remove_entry(id) { - var fh = $('firehose-' + id); + var fh = $dom('firehose-' + id); if (fh) { var attributes = { height: { to: 0 } @@ -1205,7 +1206,7 @@ fh_slider_init_set = 1; } var color = fh_colors[ newVal / fh_ticksize ]; - $('fh_slider_img').title = "Firehose filtered to " + color; + $dom('fh_slider_img').title = "Firehose filtered to " + color; if (fh_slider_init_set) { firehose_set_options("color", color) } @@ -1222,7 +1223,7 @@ function pausePopVendorStory(id) { vendor_popup_id=id; closePopup('vendorStory-26-popup'); - vendor_popup_timerids[id] = setTimeout("vendorStoryPopup()", 500); + vendor_popup_timerids[id] = setTimeout(vendorStoryPopup, 500); } function clearVendorPopupTimers() { @@ -1242,7 +1243,7 @@ } }; createPopup(getXYForId('sponsorlinks', 0, 0), title, "vendorStory-" + id, "Loading", "", closepopup ); - var params = []; + var params = {}; params['op'] = 'getTopVendorStory'; params['skid'] = id; ajax_update(params, "vendorStory-" + id + "-contents"); @@ -1251,7 +1252,7 @@ function pausePopVendorStory2(id) { vendor_popup_id=id; closePopup('vendorStory-26-popup'); - vendor_popup_timerids[id] = setTimeout("vendorStoryPopup2()", 500); + vendor_popup_timerids[id] = setTimeout(vendorStoryPopup2, 500); } function vendorStoryPopup2() { @@ -1267,14 +1268,14 @@ } }; createPopup(getXYForId('sponsorlinks2', 0, 0), title, "vendorStory-" + id, "Loading", "", closepopup ); - var params = []; + var params = {}; params['op'] = 'getTopVendorStory'; params['skid'] = id; ajax_update(params, "vendorStory-" + id + "-contents"); } function logToDiv(id, message) { - var div = $(id); + var div = $dom(id); if (div) { div.innerHTML = div.innerHTML + message + "
    "; } @@ -1282,19 +1283,19 @@ function firehose_open_tab(id) { - var tf = $('tab-form-'+id); - var tt = $('tab-text-'+id); - var ti = $('tab-input-'+id); + var tf = $dom('tab-form-'+id); + var tt = $dom('tab-text-'+id); + var ti = $dom('tab-input-'+id); tf.className=""; ti.focus(); tt.className="hide"; } function firehose_save_tab(id) { - var tf = $('tab-form-'+id); - var tt = $('tab-text-'+id); - var ti = $('tab-input-'+id); - var params = []; + var tf = $dom('tab-form-'+id); + var tt = $dom('tab-text-'+id); + var ti = $dom('tab-input-'+id); + var params = {}; var handlers = { onComplete: json_handler }; @@ -1375,8 +1376,8 @@ var modal_inst = 0; function init_modal_divs() { - modal_cover = $('modal_cover'); - modal_box = $('modal_box'); + modal_cover = $dom('modal_cover'); + modal_box = $dom('modal_box'); } function install_modal() { @@ -1392,7 +1393,7 @@ modal_cover.parentNode.removeChild(modal_cover); modal_box.parentNode.removeChild(modal_box); - var modal_parent = $('top_parent'); + var modal_parent = $dom('top_parent'); modal_parent.parentNode.insertBefore(modal_cover, modal_parent); modal_parent.parentNode.insertBefore(modal_box, modal_parent); modal_inst = 1; @@ -1423,12 +1424,12 @@ } function getModalPrefs(section, title, tabbed) { - document.getElementById('preference_title').innerHTML = title; - var params = []; + document.getElementById('preference_title').innerHTML = title; + var params = {}; params['op'] = 'getModalPrefs'; params['section'] = section; params['reskey'] = reskey_static; - params['tabbed'] = tabbed; + params['tabbed'] = tabbed; var handlers = {onComplete:show_modal_box}; ajax_update(params, 'modal_box_content', handlers); @@ -1436,21 +1437,21 @@ } function firehose_get_media_popup(id) { - if ($('preference_title')) { - $('preference_title').innerHTML = "Media"; + if ($dom('preference_title')) { + $dom('preference_title').innerHTML = "Media"; } - var params = []; + var params = {}; params['op'] = 'firehose_get_media'; params['id'] = id; show_modal_box(); - $('modal_box_content').innerHTML = "

    Loading...

    "; + $dom('modal_box_content').innerHTML = "

    Loading...

    "; ajax_update(params, 'modal_box_content'); } function saveModalPrefs() { - var params = []; + var params = {}; params['op'] = 'saveModalPrefs'; - params['data'] = Form.serialize(document.forms['modal_prefs']); + params['data'] = jQuery("#modal_prefs").serialize(); params['reskey'] = reskey_static; var handlers = { onComplete: function() { @@ -1473,7 +1474,7 @@ sep = ","; } - var params = []; + var params = {}; params['op'] = 'page_save_user_boxes'; params['reskey'] = reskey_static; params['bids'] = all; @@ -1496,14 +1497,14 @@ } function toggle_filter_prefs() { - var fps = $('filter_play_status'); - var fp = $('filter_prefs'); + var fps = $dom('filter_play_status'); + var fp = $dom('filter_prefs'); if (fps) { if (fps.className == "") { fps.className = "hide"; if (fp) { fp.className = ""; - setTimeout("firehose_slider_init()",500); + setTimeout(firehose_slider_init,500); } } else if (fps.className == "hide") { fps.className = ""; @@ -1514,3 +1515,126 @@ } } + +function admin_signoff(stoid, type, id) { + var params = []; + params['op'] = 'admin_signoff'; + params['stoid'] = stoid; + params['reskey'] = reskey_static; + ajax_update(params, 'signoff_' + stoid); + if (type == "firehose") { + firehose_collapse_entry(id); + } +} + + +function scrollWindowToFirehose(fhid) { + var firehose_y = getOffsetTop($('firehose-' + fhid)); + console.log(firehose_y); + scroll(viewWindowLeft(), firehose_y); +} + +function viewWindowLeft() { + if (self.pageXOffset) // all except Explorer + { + return self.pageXOffset; + } + else if (document.documentElement && document.documentElement.scrollTop) + // Explorer 6 Strict + { + return document.documentElement.scrollLeft; + } + else if (document.body) // all other Explorers + { + return document.body.scrollLeft; + } +} + +function getOffsetTop (el) { + if (!el) + return false; + var ot = el.offsetTop; + while((el = el.offsetParent) != null) + ot += el.offsetTop; + return ot; +} + +function firehoseIsInWindow(fhid, just_head) { + var in_window = isInWindow($('firehose-' + fhid)); + return in_window; +} + +function isInWindow(obj) { + var y = getOffsetTop(obj); + + if (y > viewWindowTop() && y < viewWindowBottom()) { + return 1; + } + return 0; +} + +function viewWindowTop() { + if (self.pageYOffset) // all except Explorer + { + return self.pageYOffset; + } + else if (document.documentElement && document.documentElement.scrollTop) + // Explorer 6 Strict + { + return document.documentElement.scrollTop; + } + else if (document.body) // all other Explorers + { + return document.body.scrollTop; + } + return; +} + +function viewWindowBottom() { + return viewWindowTop() + (window.innerHeight || document.documentElement.clientHeight); +} + +function firehose_get_cur() { + if (!firehose_cur) { + firehose_cur = firehose_ordered[0]; + firehose_set_cur(firehose_cur); + } + return firehose_cur; +} + +function firehose_set_cur(id) { + firehose_cur = id; +} + +function firehose_get_pos_of_id(id) { + var ret; + for (var i=0; i< firehose_ordered.length; i++) { + if (firehose_ordered[i] == id) { + ret = i; + } + } + return ret; +} + +function firehose_go_next() { + var cur = firehose_get_cur(); + var pos = firehose_get_pos_of_id(cur); + if (pos < (firehose_ordered.length - 1)) { + pos++; + } + firehose_set_cur(firehose_ordered[pos]); + scrollWindowToFirehose(firehose_cur); +} + +function firehose_go_prev() { + var cur = firehose_get_cur(); + var pos = firehose_get_pos_of_id(cur); + if (pos>0) { + pos--; + } + firehose_set_cur(firehose_ordered[pos]); + scrollWindowToFirehose(firehose_cur); + +} + + Added: slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/jquery-1.2.3.js =================================================================== --- slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/jquery-1.2.3.js (rev 0) +++ slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/jquery-1.2.3.js 2008-04-01 03:35:14 UTC (rev 560) @@ -0,0 +1,11 @@ +/* + * jQuery 1.2.3 - New Wave Javascript + * + * Copyright (c) 2008 John Resig (jquery.com) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * $Date: 2008/03/14 15:48:06 $ + * $Rev: 4663 $ + */ +eval(function(p,a,c,k,e,r){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('(J(){7(1e.3N)L w=1e.3N;L E=1e.3N=J(a,b){K 1B E.2l.4T(a,b)};7(1e.$)L D=1e.$;1e.$=E;L u=/^[^<]*(<(.|\\s)+>)[^>]*$|^#(\\w+)$/;L G=/^.[^:#\\[\\.]*$/;E.1n=E.2l={4T:J(d,b){d=d||T;7(d.15){6[0]=d;6.M=1;K 6}N 7(1o d=="25"){L c=u.2O(d);7(c&&(c[1]||!b)){7(c[1])d=E.4a([c[1]],b);N{L a=T.5J(c[3]);7(a)7(a.2w!=c[3])K E().2s(d);N{6[0]=a;6.M=1;K 6}N d=[]}}N K 1B E(b).2s(d)}N 7(E.1q(d))K 1B E(T)[E.1n.21?"21":"3U"](d);K 6.6E(d.1k==1M&&d||(d.5h||d.M&&d!=1e&&!d.15&&d[0]!=10&&d[0].15)&&E.2I(d)||[d])},5h:"1.2.3",87:J(){K 6.M},M:0,22:J(a){K a==10?E.2I(6):6[a]},2F:J(b){L a=E(b);a.54=6;K a},6E:J(a){6.M=0;1M.2l.1g.1i(6,a);K 6},R:J(a,b){K E.R(6,a,b)},4X:J(b){L a=-1;6.R(J(i){7(6==b)a=i});K a},1J:J(c,a,b){L d=c;7(c.1k==4e)7(a==10)K 6.M&&E[b||"1J"](6[0],c)||10;N{d={};d[c]=a}K 6.R(J(i){Q(c 1p d)E.1J(b?6.W:6,c,E.1l(6,d[c],b,i,c))})},1j:J(b,a){7((b==\'27\'||b==\'1R\')&&2M(a)<0)a=10;K 6.1J(b,a,"2o")},1u:J(b){7(1o b!="3V"&&b!=V)K 6.4x().3t((6[0]&&6[0].2i||T).5r(b));L a="";E.R(b||6,J(){E.R(6.3p,J(){7(6.15!=8)a+=6.15!=1?6.6K:E.1n.1u([6])})});K a},5m:J(b){7(6[0])E(b,6[0].2i).5k().3o(6[0]).2c(J(){L a=6;2b(a.1C)a=a.1C;K a}).3t(6);K 6},8w:J(a){K 6.R(J(){E(6).6z().5m(a)})},8p:J(a){K 6.R(J(){E(6).5m(a)})},3t:J(){K 6.3O(18,P,S,J(a){7(6.15==1)6.38(a)})},6q:J(){K 6.3O(18,P,P,J(a){7(6.15==1)6.3o(a,6.1C)})},6o:J(){K 6.3O(18,S,S,J(a){6.1a.3o(a,6)})},5a:J(){K 6.3O(18,S,P,J(a){6.1a.3o(a,6.2B)})},3h:J(){K 6.54||E([])},2s:J(b){L c=E.2c(6,J(a){K E.2s(b,a)});K 6.2F(/[^+>] [^+>]/.17(b)||b.1f("..")>-1?E.57(c):c)},5k:J(e){L f=6.2c(J(){7(E.14.1d&&!E.3E(6)){L a=6.69(P),4Y=T.3s("1x");4Y.38(a);K E.4a([4Y.3d])[0]}N K 6.69(P)});L d=f.2s("*").4R().R(J(){7(6[F]!=10)6[F]=V});7(e===P)6.2s("*").4R().R(J(i){7(6.15==3)K;L c=E.O(6,"2R");Q(L a 1p c)Q(L b 1p c[a])E.16.1b(d[i],a,c[a][b],c[a][b].O)});K f},1E:J(b){K 6.2F(E.1q(b)&&E.3y(6,J(a,i){K b.1P(a,i)})||E.3e(b,6))},56:J(b){7(b.1k==4e)7(G.17(b))K 6.2F(E.3e(b,6,P));N b=E.3e(b,6);L a=b.M&&b[b.M-1]!==10&&!b.15;K 6.1E(J(){K a?E.33(6,b)<0:6!=b})},1b:J(a){K!a?6:6.2F(E.37(6.22(),a.1k==4e?E(a).22():a.M!=10&&(!a.12||E.12(a,"3u"))?a:[a]))},3H:J(a){K a?E.3e(a,6).M>0:S},7j:J(a){K 6.3H("."+a)},5O:J(b){7(b==10){7(6.M){L c=6[0];7(E.12(c,"2k")){L e=c.3T,5I=[],11=c.11,2X=c.U=="2k-2X";7(e<0)K V;Q(L i=2X?e:0,2f=2X?e+1:11.M;i<2f;i++){L d=11[i];7(d.2p){b=E.14.1d&&!d.9J.1A.9y?d.1u:d.1A;7(2X)K b;5I.1g(b)}}K 5I}N K(6[0].1A||"").1r(/\\r/g,"")}K 10}K 6.R(J(){7(6.15!=1)K;7(b.1k==1M&&/5u|5t/.17(6.U))6.3k=(E.33(6.1A,b)>=0||E.33(6.31,b)>=0);N 7(E.12(6,"2k")){L a=b.1k==1M?b:[b];E("98",6).R(J(){6.2p=(E.33(6.1A,a)>=0||E.33(6.1u,a)>=0)});7(!a.M)6.3T=-1}N 6.1A=b})},3q:J(a){K a==10?(6.M?6[0].3d:V):6.4x().3t(a)},6S:J(a){K 6.5a(a).1V()},6Z:J(i){K 6.2K(i,i+1)},2K:J(){K 6.2F(1M.2l.2K.1i(6,18))},2c:J(b){K 6.2F(E.2c(6,J(a,i){K b.1P(a,i,a)}))},4R:J(){K 6.1b(6.54)},O:J(d,b){L a=d.23(".");a[1]=a[1]?"."+a[1]:"";7(b==V){L c=6.5n("8P"+a[1]+"!",[a[0]]);7(c==10&&6.M)c=E.O(6[0],d);K c==V&&a[1]?6.O(a[0]):c}N K 6.1N("8K"+a[1]+"!",[a[0],b]).R(J(){E.O(6,d,b)})},35:J(a){K 6.R(J(){E.35(6,a)})},3O:J(g,f,h,d){L e=6.M>1,3n;K 6.R(J(){7(!3n){3n=E.4a(g,6.2i);7(h)3n.8D()}L b=6;7(f&&E.12(6,"1O")&&E.12(3n[0],"4v"))b=6.3S("1U")[0]||6.38(6.2i.3s("1U"));L c=E([]);E.R(3n,J(){L a=e?E(6).5k(P)[0]:6;7(E.12(a,"1m")){c=c.1b(a)}N{7(a.15==1)c=c.1b(E("1m",a).1V());d.1P(b,a)}});c.R(6A)})}};E.2l.4T.2l=E.2l;J 6A(i,a){7(a.3Q)E.3P({1c:a.3Q,3l:S,1H:"1m"});N E.5g(a.1u||a.6x||a.3d||"");7(a.1a)a.1a.34(a)}E.1s=E.1n.1s=J(){L b=18[0]||{},i=1,M=18.M,5c=S,11;7(b.1k==8d){5c=b;b=18[1]||{};i=2}7(1o b!="3V"&&1o b!="J")b={};7(M==1){b=6;i=0}Q(;i-1}},68:J(b,c,a){L e={};Q(L d 1p c){e[d]=b.W[d];b.W[d]=c[d]}a.1P(b);Q(L d 1p c)b.W[d]=e[d]},1j:J(d,e,c){7(e=="27"||e=="1R"){L b,46={43:"4W",4U:"1Z",19:"3D"},3c=e=="27"?["7O","7M"]:["7J","7I"];J 5E(){b=e=="27"?d.7H:d.7F;L a=0,2N=0;E.R(3c,J(){a+=2M(E.2o(d,"7E"+6,P))||0;2N+=2M(E.2o(d,"2N"+6+"5X",P))||0});b-=24.7C(a+2N)}7(E(d).3H(":4d"))5E();N E.68(d,46,5E);K 24.2f(0,b)}K E.2o(d,e,c)},2o:J(e,k,j){L d;J 3x(b){7(!E.14.2d)K S;L a=T.4c.4K(b,V);K!a||a.4M("3x")==""}7(k=="1w"&&E.14.1d){d=E.1J(e.W,"1w");K d==""?"1":d}7(E.14.2z&&k=="19"){L c=e.W.50;e.W.50="0 7r 7o";e.W.50=c}7(k.1D(/4g/i))k=y;7(!j&&e.W&&e.W[k])d=e.W[k];N 7(T.4c&&T.4c.4K){7(k.1D(/4g/i))k="4g";k=k.1r(/([A-Z])/g,"-$1").2h();L h=T.4c.4K(e,V);7(h&&!3x(e))d=h.4M(k);N{L f=[],2C=[];Q(L a=e;a&&3x(a);a=a.1a)2C.4J(a);Q(L i=0;i<2C.M;i++)7(3x(2C[i])){f[i]=2C[i].W.19;2C[i].W.19="3D"}d=k=="19"&&f[2C.M-1]!=V?"2H":(h&&h.4M(k))||"";Q(L i=0;i]*?)\\/>/g,J(b,a,c){K c.1D(/^(aa|a6|7e|a5|4D|7a|a0|3m|9W|9U|9S)$/i)?b:a+">"});L f=E.3g(d).2h(),1x=h.3s("1x");L e=!f.1f("<9P")&&[1,"<2k 74=\'74\'>",""]||!f.1f("<9M")&&[1,"<73>",""]||f.1D(/^<(9G|1U|9E|9B|9x)/)&&[1,"<1O>",""]||!f.1f("<4v")&&[2,"<1O><1U>",""]||(!f.1f("<9w")||!f.1f("<9v"))&&[3,"<1O><1U><4v>",""]||!f.1f("<7e")&&[2,"<1O><1U><6V>",""]||E.14.1d&&[1,"1x<1x>",""]||[0,"",""];1x.3d=e[1]+d+e[2];2b(e[0]--)1x=1x.5o;7(E.14.1d){L g=!f.1f("<1O")&&f.1f("<1U")<0?1x.1C&&1x.1C.3p:e[1]=="<1O>"&&f.1f("<1U")<0?1x.3p:[];Q(L j=g.M-1;j>=0;--j)7(E.12(g[j],"1U")&&!g[j].3p.M)g[j].1a.34(g[j]);7(/^\\s/.17(d))1x.3o(h.5r(d.1D(/^\\s*/)[0]),1x.1C)}d=E.2I(1x.3p)}7(d.M===0&&(!E.12(d,"3u")&&!E.12(d,"2k")))K;7(d[0]==10||E.12(d,"3u")||d.11)k.1g(d);N k=E.37(k,d)});K k},1J:J(d,e,c){7(!d||d.15==3||d.15==8)K 10;L f=E.3E(d)?{}:E.46;7(e=="2p"&&E.14.2d)d.1a.3T;7(f[e]){7(c!=10)d[f[e]]=c;K d[f[e]]}N 7(E.14.1d&&e=="W")K E.1J(d.W,"9u",c);N 7(c==10&&E.14.1d&&E.12(d,"3u")&&(e=="9r"||e=="9o"))K d.9m(e).6K;N 7(d.28){7(c!=10){7(e=="U"&&E.12(d,"4D")&&d.1a)6Q"U 9i 9h\'t 9g 9e";d.9b(e,""+c)}7(E.14.1d&&/6O|3Q/.17(e)&&!E.3E(d))K d.4z(e,2);K d.4z(e)}N{7(e=="1w"&&E.14.1d){7(c!=10){d.6k=1;d.1E=(d.1E||"").1r(/6M\\([^)]*\\)/,"")+(2M(c).3X()=="96"?"":"6M(1w="+c*6L+")")}K d.1E&&d.1E.1f("1w=")>=0?(2M(d.1E.1D(/1w=([^)]*)/)[1])/6L).3X():""}e=e.1r(/-([a-z])/95,J(a,b){K b.2E()});7(c!=10)d[e]=c;K d[e]}},3g:J(a){K(a||"").1r(/^\\s+|\\s+$/g,"")},2I:J(b){L a=[];7(1o b!="93")Q(L i=0,M=b.M;i*",6).1V();2b(6.1C)6.34(6.1C)}},J(a,b){E.1n[a]=J(){K 6.R(b,18)}});E.R(["8f","5X"],J(i,c){L b=c.2h();E.1n[b]=J(a){K 6[0]==1e?E.14.2z&&T.1h["5e"+c]||E.14.2d&&1e["8e"+c]||T.6F=="79"&&T.1F["5e"+c]||T.1h["5e"+c]:6[0]==T?24.2f(24.2f(T.1h["5d"+c],T.1F["5d"+c]),24.2f(T.1h["5L"+c],T.1F["5L"+c])):a==10?(6.M?E.1j(6[0],b):V):6.1j(b,a.1k==4e?a:a+"2S")}});L C=E.14.2d&&4s(E.14.5K)<8c?"(?:[\\\\w*4r-]|\\\\\\\\.)":"(?:[\\\\w\\8b-\\8a*4r-]|\\\\\\\\.)",6v=1B 4q("^>\\\\s*("+C+"+)"),6u=1B 4q("^("+C+"+)(#)("+C+"+)"),6s=1B 4q("^([#.]?)("+C+"*)");E.1s({6r:{"":J(a,i,m){K m[2]=="*"||E.12(a,m[2])},"#":J(a,i,m){K a.4z("2w")==m[2]},":":{89:J(a,i,m){K im[3]-0},2Z:J(a,i,m){K m[3]-0==i},6Z:J(a,i,m){K m[3]-0==i},3j:J(a,i){K i==0},3J:J(a,i,m,r){K i==r.M-1},6n:J(a,i){K i%2==0},6l:J(a,i){K i%2},"3j-4p":J(a){K a.1a.3S("*")[0]==a},"3J-4p":J(a){K E.2Z(a.1a.5o,1,"4t")==a},"83-4p":J(a){K!E.2Z(a.1a.5o,2,"4t")},6B:J(a){K a.1C},4x:J(a){K!a.1C},82:J(a,i,m){K(a.6x||a.81||E(a).1u()||"").1f(m[3])>=0},4d:J(a){K"1Z"!=a.U&&E.1j(a,"19")!="2H"&&E.1j(a,"4U")!="1Z"},1Z:J(a){K"1Z"==a.U||E.1j(a,"19")=="2H"||E.1j(a,"4U")=="1Z"},80:J(a){K!a.2Y},2Y:J(a){K a.2Y},3k:J(a){K a.3k},2p:J(a){K a.2p||E.1J(a,"2p")},1u:J(a){K"1u"==a.U},5u:J(a){K"5u"==a.U},5t:J(a){K"5t"==a.U},59:J(a){K"59"==a.U},3I:J(a){K"3I"==a.U},58:J(a){K"58"==a.U},6j:J(a){K"6j"==a.U},6i:J(a){K"6i"==a.U},2G:J(a){K"2G"==a.U||E.12(a,"2G")},4D:J(a){K/4D|2k|6h|2G/i.17(a.12)},3Y:J(a,i,m){K E.2s(m[3],a).M},7X:J(a){K/h\\d/i.17(a.12)},7W:J(a){K E.3y(E.3G,J(b){K a==b.Y}).M}}},6g:[/^(\\[) *@?([\\w-]+) *([!*$^~=]*) *(\'?"?)(.*?)\\4 *\\]/,/^(:)([\\w-]+)\\("?\'?(.*?(\\(.*?\\))?[^(]*?)"?\'?\\)/,1B 4q("^([:.#]*)("+C+"+)")],3e:J(a,c,b){L d,2m=[];2b(a&&a!=d){d=a;L f=E.1E(a,c,b);a=f.t.1r(/^\\s*,\\s*/,"");2m=b?c=f.r:E.37(2m,f.r)}K 2m},2s:J(t,p){7(1o t!="25")K[t];7(p&&p.15!=1&&p.15!=9)K[];p=p||T;L d=[p],2r=[],3J,12;2b(t&&3J!=t){L r=[];3J=t;t=E.3g(t);L o=S;L g=6v;L m=g.2O(t);7(m){12=m[1].2E();Q(L i=0;d[i];i++)Q(L c=d[i].1C;c;c=c.2B)7(c.15==1&&(12=="*"||c.12.2E()==12))r.1g(c);d=r;t=t.1r(g,"");7(t.1f(" ")==0)6w;o=P}N{g=/^([>+~])\\s*(\\w*)/i;7((m=g.2O(t))!=V){r=[];L l={};12=m[2].2E();m=m[1];Q(L j=0,3f=d.M;j<3f;j++){L n=m=="~"||m=="+"?d[j].2B:d[j].1C;Q(;n;n=n.2B)7(n.15==1){L h=E.O(n);7(m=="~"&&l[h])1Q;7(!12||n.12.2E()==12){7(m=="~")l[h]=P;r.1g(n)}7(m=="+")1Q}}d=r;t=E.3g(t.1r(g,""));o=P}}7(t&&!o){7(!t.1f(",")){7(p==d[0])d.4l();2r=E.37(2r,d);r=d=[p];t=" "+t.6e(1,t.M)}N{L k=6u;L m=k.2O(t);7(m){m=[0,m[2],m[3],m[1]]}N{k=6s;m=k.2O(t)}m[2]=m[2].1r(/\\\\/g,"");L f=d[d.M-1];7(m[1]=="#"&&f&&f.5J&&!E.3E(f)){L q=f.5J(m[2]);7((E.14.1d||E.14.2z)&&q&&1o q.2w=="25"&&q.2w!=m[2])q=E(\'[@2w="\'+m[2]+\'"]\',f)[0];d=r=q&&(!m[3]||E.12(q,m[3]))?[q]:[]}N{Q(L i=0;d[i];i++){L a=m[1]=="#"&&m[3]?m[3]:m[1]!=""||m[0]==""?"*":m[2];7(a=="*"&&d[i].12.2h()=="3V")a="3m";r=E.37(r,d[i].3S(a))}7(m[1]==".")r=E.55(r,m[2]);7(m[1]=="#"){L e=[];Q(L i=0;r[i];i++)7(r[i].4z("2w")==m[2]){e=[r[i]];1Q}r=e}d=r}t=t.1r(k,"")}}7(t){L b=E.1E(t,r);d=r=b.r;t=E.3g(b.t)}}7(t)d=[];7(d&&p==d[0])d.4l();2r=E.37(2r,d);K 2r},55:J(r,m,a){m=" "+m+" ";L c=[];Q(L i=0;r[i];i++){L b=(" "+r[i].1t+" ").1f(m)>=0;7(!a&&b||a&&!b)c.1g(r[i])}K c},1E:J(t,r,h){L d;2b(t&&t!=d){d=t;L p=E.6g,m;Q(L i=0;p[i];i++){m=p[i].2O(t);7(m){t=t.7V(m[0].M);m[2]=m[2].1r(/\\\\/g,"");1Q}}7(!m)1Q;7(m[1]==":"&&m[2]=="56")r=G.17(m[3])?E.1E(m[3],r,P).r:E(r).56(m[3]);N 7(m[1]==".")r=E.55(r,m[2],h);N 7(m[1]=="["){L g=[],U=m[3];Q(L i=0,3f=r.M;i<3f;i++){L a=r[i],z=a[E.46[m[2]]||m[2]];7(z==V||/6O|3Q|2p/.17(m[2]))z=E.1J(a,m[2])||\'\';7((U==""&&!!z||U=="="&&z==m[5]||U=="!="&&z!=m[5]||U=="^="&&z&&!z.1f(m[5])||U=="$="&&z.6e(z.M-m[5].M)==m[5]||(U=="*="||U=="~=")&&z.1f(m[5])>=0)^h)g.1g(a)}r=g}N 7(m[1]==":"&&m[2]=="2Z-4p"){L e={},g=[],17=/(-?)(\\d*)n((?:\\+|-)?\\d*)/.2O(m[3]=="6n"&&"2n"||m[3]=="6l"&&"2n+1"||!/\\D/.17(m[3])&&"7U+"+m[3]||m[3]),3j=(17[1]+(17[2]||1))-0,d=17[3]-0;Q(L i=0,3f=r.M;i<3f;i++){L j=r[i],1a=j.1a,2w=E.O(1a);7(!e[2w]){L c=1;Q(L n=1a.1C;n;n=n.2B)7(n.15==1)n.4k=c++;e[2w]=P}L b=S;7(3j==0){7(j.4k==d)b=P}N 7((j.4k-d)%3j==0&&(j.4k-d)/3j>=0)b=P;7(b^h)g.1g(j)}r=g}N{L f=E.6r[m[1]];7(1o f=="3V")f=f[m[2]];7(1o f=="25")f=6c("S||J(a,i){K "+f+";}");r=E.3y(r,J(a,i){K f(a,i,m,r)},h)}}K{r:r,t:t}},4u:J(b,c){L d=[];L a=b[c];2b(a&&a!=T){7(a.15==1)d.1g(a);a=a[c]}K d},2Z:J(a,e,c,b){e=e||1;L d=0;Q(;a;a=a[c])7(a.15==1&&++d==e)1Q;K a},5i:J(n,a){L r=[];Q(;n;n=n.2B){7(n.15==1&&(!a||n!=a))r.1g(n)}K r}});E.16={1b:J(f,i,g,e){7(f.15==3||f.15==8)K;7(E.14.1d&&f.53!=10)f=1e;7(!g.2D)g.2D=6.2D++;7(e!=10){L h=g;g=J(){K h.1i(6,18)};g.O=e;g.2D=h.2D}L j=E.O(f,"2R")||E.O(f,"2R",{}),1v=E.O(f,"1v")||E.O(f,"1v",J(){L a;7(1o E=="10"||E.16.5f)K a;a=E.16.1v.1i(18.3R.Y,18);K a});1v.Y=f;E.R(i.23(/\\s+/),J(c,b){L a=b.23(".");b=a[0];g.U=a[1];L d=j[b];7(!d){d=j[b]={};7(!E.16.2y[b]||E.16.2y[b].4j.1P(f)===S){7(f.3F)f.3F(b,1v,S);N 7(f.6b)f.6b("4i"+b,1v)}}d[g.2D]=g;E.16.2a[b]=P});f=V},2D:1,2a:{},1V:J(e,h,f){7(e.15==3||e.15==8)K;L i=E.O(e,"2R"),29,4X;7(i){7(h==10||(1o h=="25"&&h.7T(0)=="."))Q(L g 1p i)6.1V(e,g+(h||""));N{7(h.U){f=h.2q;h=h.U}E.R(h.23(/\\s+/),J(b,a){L c=a.23(".");a=c[0];7(i[a]){7(f)2V i[a][f.2D];N Q(f 1p i[a])7(!c[1]||i[a][f].U==c[1])2V i[a][f];Q(29 1p i[a])1Q;7(!29){7(!E.16.2y[a]||E.16.2y[a].4h.1P(e)===S){7(e.67)e.67(a,E.O(e,"1v"),S);N 7(e.66)e.66("4i"+a,E.O(e,"1v"))}29=V;2V i[a]}}})}Q(29 1p i)1Q;7(!29){L d=E.O(e,"1v");7(d)d.Y=V;E.35(e,"2R");E.35(e,"1v")}}},1N:J(g,c,d,f,h){c=E.2I(c||[]);7(g.1f("!")>=0){g=g.2K(0,-1);L a=P}7(!d){7(6.2a[g])E("*").1b([1e,T]).1N(g,c)}N{7(d.15==3||d.15==8)K 10;L b,29,1n=E.1q(d[g]||V),16=!c[0]||!c[0].36;7(16)c.4J(6.4Z({U:g,2L:d}));c[0].U=g;7(a)c[0].65=P;7(E.1q(E.O(d,"1v")))b=E.O(d,"1v").1i(d,c);7(!1n&&d["4i"+g]&&d["4i"+g].1i(d,c)===S)b=S;7(16)c.4l();7(h&&E.1q(h)){29=h.1i(d,b==V?c:c.71(b));7(29!==10)b=29}7(1n&&f!==S&&b!==S&&!(E.12(d,\'a\')&&g=="4V")){6.5f=P;1S{d[g]()}1X(e){}}6.5f=S}K b},1v:J(c){L a;c=E.16.4Z(c||1e.16||{});L b=c.U.23(".");c.U=b[0];L f=E.O(6,"2R")&&E.O(6,"2R")[c.U],42=1M.2l.2K.1P(18,1);42.4J(c);Q(L j 1p f){L d=f[j];42[0].2q=d;42[0].O=d.O;7(!b[1]&&!c.65||d.U==b[1]){L e=d.1i(6,42);7(a!==S)a=e;7(e===S){c.36();c.44()}}}7(E.14.1d)c.2L=c.36=c.44=c.2q=c.O=V;K a},4Z:J(c){L a=c;c=E.1s({},a);c.36=J(){7(a.36)a.36();a.7S=S};c.44=J(){7(a.44)a.44();a.7R=P};7(!c.2L)c.2L=c.7Q||T;7(c.2L.15==3)c.2L=a.2L.1a;7(!c.4S&&c.5w)c.4S=c.5w==c.2L?c.7P:c.5w;7(c.64==V&&c.63!=V){L b=T.1F,1h=T.1h;c.64=c.63+(b&&b.2v||1h&&1h.2v||0)-(b.62||0);c.7N=c.7L+(b&&b.2x||1h&&1h.2x||0)-(b.60||0)}7(!c.3c&&((c.4f||c.4f===0)?c.4f:c.5Z))c.3c=c.4f||c.5Z;7(!c.7b&&c.5Y)c.7b=c.5Y;7(!c.3c&&c.2G)c.3c=(c.2G&1?1:(c.2G&2?3:(c.2G&4?2:0)));K c},2y:{21:{4j:J(){5M();K},4h:J(){K}},3C:{4j:J(){7(E.14.1d)K S;E(6).2j("4P",E.16.2y.3C.2q);K P},4h:J(){7(E.14.1d)K S;E(6).3w("4P",E.16.2y.3C.2q);K P},2q:J(a){7(I(a,6))K P;18[0].U="3C";K E.16.1v.1i(6,18)}},3B:{4j:J(){7(E.14.1d)K S;E(6).2j("4O",E.16.2y.3B.2q);K P},4h:J(){7(E.14.1d)K S;E(6).3w("4O",E.16.2y.3B.2q);K P},2q:J(a){7(I(a,6))K P;18[0].U="3B";K E.16.1v.1i(6,18)}}}};E.1n.1s({2j:J(c,a,b){K c=="4H"?6.2X(c,a,b):6.R(J(){E.16.1b(6,c,b||a,b&&a)})},2X:J(d,b,c){K 6.R(J(){E.16.1b(6,d,J(a){E(6).3w(a);K(c||b).1i(6,18)},c&&b)})},3w:J(a,b){K 6.R(J(){E.16.1V(6,a,b)})},1N:J(c,a,b){K 6.R(J(){E.16.1N(c,a,6,P,b)})},5n:J(c,a,b){7(6[0])K E.16.1N(c,a,6[0],S,b);K 10},2g:J(){L b=18;K 6.4V(J(a){6.4N=0==6.4N?1:0;a.36();K b[6.4N].1i(6,18)||S})},7D:J(a,b){K 6.2j(\'3C\',a).2j(\'3B\',b)},21:J(a){5M();7(E.2Q)a.1P(T,E);N E.3A.1g(J(){K a.1P(6,E)});K 6}});E.1s({2Q:S,3A:[],21:J(){7(!E.2Q){E.2Q=P;7(E.3A){E.R(E.3A,J(){6.1i(T)});E.3A=V}E(T).5n("21")}}});L x=S;J 5M(){7(x)K;x=P;7(T.3F&&!E.14.2z)T.3F("5W",E.21,S);7(E.14.1d&&1e==3b)(J(){7(E.2Q)K;1S{T.1F.7B("26")}1X(3a){3z(18.3R,0);K}E.21()})();7(E.14.2z)T.3F("5W",J(){7(E.2Q)K;Q(L i=0;i=0){L i=g.2K(e,g.M);g=g.2K(0,e)}c=c||J(){};L f="4Q";7(d)7(E.1q(d)){c=d;d=V}N{d=E.3m(d);f="61"}L h=6;E.3P({1c:g,U:f,1H:"3q",O:d,1y:J(a,b){7(b=="1W"||b=="5U")h.3q(i?E("<1x/>").3t(a.4b.1r(/<1m(.|\\s)*?\\/1m>/g,"")).2s(i):a.4b);h.R(c,[a.4b,b,a])}});K 6},7n:J(){K E.3m(6.5T())},5T:J(){K 6.2c(J(){K E.12(6,"3u")?E.2I(6.7m):6}).1E(J(){K 6.31&&!6.2Y&&(6.3k||/2k|6h/i.17(6.12)||/1u|1Z|3I/i.17(6.U))}).2c(J(i,c){L b=E(6).5O();K b==V?V:b.1k==1M?E.2c(b,J(a,i){K{31:c.31,1A:a}}):{31:c.31,1A:b}}).22()}});E.R("5S,6d,5R,6D,5Q,6m".23(","),J(i,o){E.1n[o]=J(f){K 6.2j(o,f)}});L B=(1B 3v).3L();E.1s({22:J(d,b,a,c){7(E.1q(b)){a=b;b=V}K E.3P({U:"4Q",1c:d,O:b,1W:a,1H:c})},7l:J(b,a){K E.22(b,V,a,"1m")},7k:J(c,b,a){K E.22(c,b,a,"3i")},7i:J(d,b,a,c){7(E.1q(b)){a=b;b={}}K E.3P({U:"61",1c:d,O:b,1W:a,1H:c})},85:J(a){E.1s(E.4I,a)},4I:{2a:P,U:"4Q",2U:0,5P:"4o/x-7h-3u-7g",5N:P,3l:P,O:V,6p:V,3I:V,49:{3M:"4o/3M, 1u/3M",3q:"1u/3q",1m:"1u/4m, 4o/4m",3i:"4o/3i, 1u/4m",1u:"1u/a7",4G:"*/*"}},4F:{},3P:J(s){L f,2W=/=\\?(&|$)/g,1z,O;s=E.1s(P,s,E.1s(P,{},E.4I,s));7(s.O&&s.5N&&1o s.O!="25")s.O=E.3m(s.O);7(s.1H=="4E"){7(s.U.2h()=="22"){7(!s.1c.1D(2W))s.1c+=(s.1c.1D(/\\?/)?"&":"?")+(s.4E||"7d")+"=?"}N 7(!s.O||!s.O.1D(2W))s.O=(s.O?s.O+"&":"")+(s.4E||"7d")+"=?";s.1H="3i"}7(s.1H=="3i"&&(s.O&&s.O.1D(2W)||s.1c.1D(2W))){f="4E"+B++;7(s.O)s.O=(s.O+"").1r(2W,"="+f+"$1");s.1c=s.1c.1r(2W,"="+f+"$1");s.1H="1m";1e[f]=J(a){O=a;1W();1y();1e[f]=10;1S{2V 1e[f]}1X(e){}7(h)h.34(g)}}7(s.1H=="1m"&&s.1T==V)s.1T=S;7(s.1T===S&&s.U.2h()=="22"){L i=(1B 3v()).3L();L j=s.1c.1r(/(\\?|&)4r=.*?(&|$)/,"$a4="+i+"$2");s.1c=j+((j==s.1c)?(s.1c.1D(/\\?/)?"&":"?")+"4r="+i:"")}7(s.O&&s.U.2h()=="22"){s.1c+=(s.1c.1D(/\\?/)?"&":"?")+s.O;s.O=V}7(s.2a&&!E.5H++)E.16.1N("5S");7((!s.1c.1f("a3")||!s.1c.1f("//"))&&s.1H=="1m"&&s.U.2h()=="22"){L h=T.3S("6f")[0];L g=T.3s("1m");g.3Q=s.1c;7(s.7c)g.a2=s.7c;7(!f){L l=S;g.9Z=g.9Y=J(){7(!l&&(!6.39||6.39=="5V"||6.39=="1y")){l=P;1W();1y();h.34(g)}}}h.38(g);K 10}L m=S;L k=1e.78?1B 78("9X.9V"):1B 76();k.9T(s.U,s.1c,s.3l,s.6p,s.3I);1S{7(s.O)k.4C("9R-9Q",s.5P);7(s.5C)k.4C("9O-5A-9N",E.4F[s.1c]||"9L, 9K 9I 9H 5z:5z:5z 9F");k.4C("X-9C-9A","76");k.4C("9z",s.1H&&s.49[s.1H]?s.49[s.1H]+", */*":s.49.4G)}1X(e){}7(s.6Y)s.6Y(k);7(s.2a)E.16.1N("6m",[k,s]);L c=J(a){7(!m&&k&&(k.39==4||a=="2U")){m=P;7(d){6I(d);d=V}1z=a=="2U"&&"2U"||!E.6X(k)&&"3a"||s.5C&&E.6J(k,s.1c)&&"5U"||"1W";7(1z=="1W"){1S{O=E.6W(k,s.1H)}1X(e){1z="5x"}}7(1z=="1W"){L b;1S{b=k.5q("6U-5A")}1X(e){}7(s.5C&&b)E.4F[s.1c]=b;7(!f)1W()}N E.5v(s,k,1z);1y();7(s.3l)k=V}};7(s.3l){L d=53(c,13);7(s.2U>0)3z(J(){7(k){k.9t();7(!m)c("2U")}},s.2U)}1S{k.9s(s.O)}1X(e){E.5v(s,k,V,e)}7(!s.3l)c();J 1W(){7(s.1W)s.1W(O,1z);7(s.2a)E.16.1N("5Q",[k,s])}J 1y(){7(s.1y)s.1y(k,1z);7(s.2a)E.16.1N("5R",[k,s]);7(s.2a&&!--E.5H)E.16.1N("6d")}K k},5v:J(s,a,b,e){7(s.3a)s.3a(a,b,e);7(s.2a)E.16.1N("6D",[a,s,e])},5H:0,6X:J(r){1S{K!r.1z&&9q.9p=="59:"||(r.1z>=6T&&r.1z<9n)||r.1z==6R||r.1z==9l||E.14.2d&&r.1z==10}1X(e){}K S},6J:J(a,c){1S{L b=a.5q("6U-5A");K a.1z==6R||b==E.4F[c]||E.14.2d&&a.1z==10}1X(e){}K S},6W:J(r,b){L c=r.5q("9k-U");L d=b=="3M"||!b&&c&&c.1f("3M")>=0;L a=d?r.9j:r.4b;7(d&&a.1F.28=="5x")6Q"5x";7(b=="1m")E.5g(a);7(b=="3i")a=6c("("+a+")");K a},3m:J(a){L s=[];7(a.1k==1M||a.5h)E.R(a,J(){s.1g(3r(6.31)+"="+3r(6.1A))});N Q(L j 1p a)7(a[j]&&a[j].1k==1M)E.R(a[j],J(){s.1g(3r(j)+"="+3r(6))});N s.1g(3r(j)+"="+3r(a[j]));K s.6a("&").1r(/%20/g,"+")}});E.1n.1s({1G:J(c,b){K c?6.2e({1R:"1G",27:"1G",1w:"1G"},c,b):6.1E(":1Z").R(J(){6.W.19=6.5s||"";7(E.1j(6,"19")=="2H"){L a=E("<"+6.28+" />").6y("1h");6.W.19=a.1j("19");7(6.W.19=="2H")6.W.19="3D";a.1V()}}).3h()},1I:J(b,a){K b?6.2e({1R:"1I",27:"1I",1w:"1I"},b,a):6.1E(":4d").R(J(){6.5s=6.5s||E.1j(6,"19");6.W.19="2H"}).3h()},6N:E.1n.2g,2g:J(a,b){K E.1q(a)&&E.1q(b)?6.6N(a,b):a?6.2e({1R:"2g",27:"2g",1w:"2g"},a,b):6.R(J(){E(6)[E(6).3H(":1Z")?"1G":"1I"]()})},9f:J(b,a){K 6.2e({1R:"1G"},b,a)},9d:J(b,a){K 6.2e({1R:"1I"},b,a)},9c:J(b,a){K 6.2e({1R:"2g"},b,a)},9a:J(b,a){K 6.2e({1w:"1G"},b,a)},99:J(b,a){K 6.2e({1w:"1I"},b,a)},97:J(c,a,b){K 6.2e({1w:a},c,b)},2e:J(l,k,j,h){L i=E.6P(k,j,h);K 6[i.2P===S?"R":"2P"](J(){7(6.15!=1)K S;L g=E.1s({},i);L f=E(6).3H(":1Z"),4A=6;Q(L p 1p l){7(l[p]=="1I"&&f||l[p]=="1G"&&!f)K E.1q(g.1y)&&g.1y.1i(6);7(p=="1R"||p=="27"){g.19=E.1j(6,"19");g.32=6.W.32}}7(g.32!=V)6.W.32="1Z";g.40=E.1s({},l);E.R(l,J(c,a){L e=1B E.2t(4A,g,c);7(/2g|1G|1I/.17(a))e[a=="2g"?f?"1G":"1I":a](l);N{L b=a.3X().1D(/^([+-]=)?([\\d+-.]+)(.*)$/),1Y=e.2m(P)||0;7(b){L d=2M(b[2]),2A=b[3]||"2S";7(2A!="2S"){4A.W[c]=(d||1)+2A;1Y=((d||1)/e.2m(P))*1Y;4A.W[c]=1Y+2A}7(b[1])d=((b[1]=="-="?-1:1)*d)+1Y;e.45(1Y,d,2A)}N e.45(1Y,a,"")}});K P})},2P:J(a,b){7(E.1q(a)||(a&&a.1k==1M)){b=a;a="2t"}7(!a||(1o a=="25"&&!b))K A(6[0],a);K 6.R(J(){7(b.1k==1M)A(6,a,b);N{A(6,a).1g(b);7(A(6,a).M==1)b.1i(6)}})},94:J(b,c){L a=E.3G;7(b)6.2P([]);6.R(J(){Q(L i=a.M-1;i>=0;i--)7(a[i].Y==6){7(c)a[i](P);a.72(i,1)}});7(!c)6.5p();K 6}});L A=J(b,c,a){7(!b)K 10;c=c||"2t";L q=E.O(b,c+"2P");7(!q||a)q=E.O(b,c+"2P",a?E.2I(a):[]);K q};E.1n.5p=J(a){a=a||"2t";K 6.R(J(){L q=A(6,a);q.4l();7(q.M)q[0].1i(6)})};E.1s({6P:J(b,a,c){L d=b&&b.1k==92?b:{1y:c||!c&&a||E.1q(b)&&b,2u:b,3Z:c&&a||a&&a.1k!=91&&a};d.2u=(d.2u&&d.2u.1k==51?d.2u:{90:8Z,9D:6T}[d.2u])||8X;d.5y=d.1y;d.1y=J(){7(d.2P!==S)E(6).5p();7(E.1q(d.5y))d.5y.1i(6)};K d},3Z:{70:J(p,n,b,a){K b+a*p},5j:J(p,n,b,a){K((-24.8V(p*24.8U)/2)+0.5)*a+b}},3G:[],3W:V,2t:J(b,c,a){6.11=c;6.Y=b;6.1l=a;7(!c.47)c.47={}}});E.2t.2l={4y:J(){7(6.11.30)6.11.30.1i(6.Y,[6.2J,6]);(E.2t.30[6.1l]||E.2t.30.4G)(6);7(6.1l=="1R"||6.1l=="27")6.Y.W.19="3D"},2m:J(a){7(6.Y[6.1l]!=V&&6.Y.W[6.1l]==V)K 6.Y[6.1l];L r=2M(E.1j(6.Y,6.1l,a));K r&&r>-8Q?r:2M(E.2o(6.Y,6.1l))||0},45:J(c,b,d){6.5B=(1B 3v()).3L();6.1Y=c;6.3h=b;6.2A=d||6.2A||"2S";6.2J=6.1Y;6.4B=6.4w=0;6.4y();L e=6;J t(a){K e.30(a)}t.Y=6.Y;E.3G.1g(t);7(E.3W==V){E.3W=53(J(){L a=E.3G;Q(L i=0;i6.11.2u+6.5B){6.2J=6.3h;6.4B=6.4w=1;6.4y();6.11.40[6.1l]=P;L b=P;Q(L i 1p 6.11.40)7(6.11.40[i]!==P)b=S;7(b){7(6.11.19!=V){6.Y.W.32=6.11.32;6.Y.W.19=6.11.19;7(E.1j(6.Y,"19")=="2H")6.Y.W.19="3D"}7(6.11.1I)6.Y.W.19="2H";7(6.11.1I||6.11.1G)Q(L p 1p 6.11.40)E.1J(6.Y.W,p,6.11.47[p])}7(b&&E.1q(6.11.1y))6.11.1y.1i(6.Y);K S}N{L n=t-6.5B;6.4w=n/6.11.2u;6.4B=E.3Z[6.11.3Z||(E.3Z.5j?"5j":"70")](6.4w,n,0,1,6.11.2u);6.2J=6.1Y+((6.3h-6.1Y)*6.4B);6.4y()}K P}};E.2t.30={2v:J(a){a.Y.2v=a.2J},2x:J(a){a.Y.2x=a.2J},1w:J(a){E.1J(a.Y.W,"1w",a.2J)},4G:J(a){a.Y.W[a.1l]=a.2J+a.2A}};E.1n.5L=J(){L b=0,3b=0,Y=6[0],5l;7(Y)8M(E.14){L d=Y.1a,41=Y,1K=Y.1K,1L=Y.2i,5D=2d&&4s(5K)<8J&&!/a1/i.17(v),2T=E.1j(Y,"43")=="2T";7(Y.6G){L c=Y.6G();1b(c.26+24.2f(1L.1F.2v,1L.1h.2v),c.3b+24.2f(1L.1F.2x,1L.1h.2x));1b(-1L.1F.62,-1L.1F.60)}N{1b(Y.5G,Y.5F);2b(1K){1b(1K.5G,1K.5F);7(48&&!/^t(8H|d|h)$/i.17(1K.28)||2d&&!5D)2N(1K);7(!2T&&E.1j(1K,"43")=="2T")2T=P;41=/^1h$/i.17(1K.28)?41:1K;1K=1K.1K}2b(d&&d.28&&!/^1h|3q$/i.17(d.28)){7(!/^8G|1O.*$/i.17(E.1j(d,"19")))1b(-d.2v,-d.2x);7(48&&E.1j(d,"32")!="4d")2N(d);d=d.1a}7((5D&&(2T||E.1j(41,"43")=="4W"))||(48&&E.1j(41,"43")!="4W"))1b(-1L.1h.5G,-1L.1h.5F);7(2T)1b(24.2f(1L.1F.2v,1L.1h.2v),24.2f(1L.1F.2x,1L.1h.2x))}5l={3b:3b,26:b}}J 2N(a){1b(E.2o(a,"a8",P),E.2o(a,"a9",P))}J 1b(l,t){b+=4s(l)||0;3b+=4s(t)||0}K 5l}})();',62,631,'||||||this|if||||||||||||||||||||||||||||||||||||||function|return|var|length|else|data|true|for|each|false|document|type|null|style||elem||undefined|options|nodeName||browser|nodeType|event|test|arguments|display|parentNode|add|url|msie|window|indexOf|push|body|apply|css|constructor|prop|script|fn|typeof|in|isFunction|replace|extend|className|text|handle|opacity|div|complete|status|value|new|firstChild|match|filter|documentElement|show|dataType|hide|attr|offsetParent|doc|Array|trigger|table|call|break|height|try|cache|tbody|remove|success|catch|start|hidden||ready|get|split|Math|string|left|width|tagName|ret|global|while|map|safari|animate|max|toggle|toLowerCase|ownerDocument|bind|select|prototype|cur||curCSS|selected|handler|done|find|fx|duration|scrollLeft|id|scrollTop|special|opera|unit|nextSibling|stack|guid|toUpperCase|pushStack|button|none|makeArray|now|slice|target|parseFloat|border|exec|queue|isReady|events|px|fixed|timeout|delete|jsre|one|disabled|nth|step|name|overflow|inArray|removeChild|removeData|preventDefault|merge|appendChild|readyState|error|top|which|innerHTML|multiFilter|rl|trim|end|json|first|checked|async|param|elems|insertBefore|childNodes|html|encodeURIComponent|createElement|append|form|Date|unbind|color|grep|setTimeout|readyList|mouseleave|mouseenter|block|isXMLDoc|addEventListener|timers|is|password|last|runtimeStyle|getTime|xml|jQuery|domManip|ajax|src|callee|getElementsByTagName|selectedIndex|load|object|timerId|toString|has|easing|curAnim|offsetChild|args|position|stopPropagation|custom|props|orig|mozilla|accepts|clean|responseText|defaultView|visible|String|charCode|float|teardown|on|setup|nodeIndex|shift|javascript|currentStyle|application|child|RegExp|_|parseInt|previousSibling|dir|tr|state|empty|update|getAttribute|self|pos|setRequestHeader|input|jsonp|lastModified|_default|unload|ajaxSettings|unshift|getComputedStyle|styleSheets|getPropertyValue|lastToggle|mouseout|mouseover|GET|andSelf|relatedTarget|init|visibility|click|absolute|index|container|fix|outline|Number|removeAttribute|setInterval|prevObject|classFilter|not|unique|submit|file|after|windowData|deep|scroll|client|triggered|globalEval|jquery|sibling|swing|clone|results|wrapAll|triggerHandler|lastChild|dequeue|getResponseHeader|createTextNode|oldblock|checkbox|radio|handleError|fromElement|parsererror|old|00|Modified|startTime|ifModified|safari2|getWH|offsetTop|offsetLeft|active|values|getElementById|version|offset|bindReady|processData|val|contentType|ajaxSuccess|ajaxComplete|ajaxStart|serializeArray|notmodified|loaded|DOMContentLoaded|Width|ctrlKey|keyCode|clientTop|POST|clientLeft|clientX|pageX|exclusive|detachEvent|removeEventListener|swap|cloneNode|join|attachEvent|eval|ajaxStop|substr|head|parse|textarea|reset|image|zoom|odd|ajaxSend|even|before|username|prepend|expr|quickClass|uuid|quickID|quickChild|continue|textContent|appendTo|contents|evalScript|parent|defaultValue|ajaxError|setArray|compatMode|getBoundingClientRect|styleFloat|clearInterval|httpNotModified|nodeValue|100|alpha|_toggle|href|speed|throw|304|replaceWith|200|Last|colgroup|httpData|httpSuccess|beforeSend|eq|linear|concat|splice|fieldset|multiple|cssFloat|XMLHttpRequest|webkit|ActiveXObject|CSS1Compat|link|metaKey|scriptCharset|callback|col|pixelLeft|urlencoded|www|post|hasClass|getJSON|getScript|elements|serialize|black|keyup|keypress|solid|change|mousemove|mouseup|dblclick|resize|focus|blur|stylesheet|rel|doScroll|round|hover|padding|offsetHeight|mousedown|offsetWidth|Bottom|Top|keydown|clientY|Right|pageY|Left|toElement|srcElement|cancelBubble|returnValue|charAt|0n|substring|animated|header|noConflict|line|enabled|innerText|contains|only|weight|ajaxSetup|font|size|gt|lt|uFFFF|u0128|417|Boolean|inner|Height|toggleClass|removeClass|addClass|removeAttr|replaceAll|insertAfter|prependTo|contentWindow|contentDocument|wrap|iframe|children|siblings|prevAll|nextAll|prev|wrapInner|next|parents|maxLength|maxlength|readOnly|readonly|reverse|class|htmlFor|inline|able|boxModel|522|setData|compatible|with|1px|ie|getData|10000|ra|it|rv|PI|cos|userAgent|400|navigator|600|slow|Function|Object|array|stop|ig|NaN|fadeTo|option|fadeOut|fadeIn|setAttribute|slideToggle|slideUp|changed|slideDown|be|can|property|responseXML|content|1223|getAttributeNode|300|method|protocol|location|action|send|abort|cssText|th|td|cap|specified|Accept|With|colg|Requested|fast|tfoot|GMT|thead|1970|Jan|attributes|01|Thu|leg|Since|If|opt|Type|Content|embed|open|area|XMLHTTP|hr|Microsoft|onreadystatechange|onload|meta|adobeair|charset|http|1_|img|br|plain|borderLeftWidth|borderTopWidth|abbr'.split('|'),0,{})) Modified: slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/nodnix.js =================================================================== --- slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/nodnix.js 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/nodnix.js 2008-04-01 03:35:14 UTC (rev 560) @@ -1,5 +1,5 @@ // _*_ Mode: JavaScript; tab-width: 8; indent-tabs-mode: true _*_ -// $Id: nodnix.js,v 1.9 2008/02/20 18:43:31 scc Exp $ +// $Id: nodnix.js,v 1.17 2008/03/14 15:48:06 scc Exp $ var nod_completer = null; var nix_completer = null; @@ -100,6 +100,17 @@ firehose_up_down(g_nodnix_item_id, up_down); } +function nodnix_not_tag( old_tag ) { + var new_tag = old_tag[0]=='!' ? old_tag.slice(1) : '!'+old_tag; + createTag(new_tag, g_nodnix_item_id, "firehose"); + var tag_list = _get_nodnix('ol'); + // XXX not a good idea if the tag happens to be 'span' or 'li', etc + tag_list.innerHTML = tag_list.innerHTML.replace(old_tag, new_tag, "g"); +} + +function nodnix_del_tag( tag ) { +} + function hide_nod_menu() { get_nod_menu().style.display = 'none'; } @@ -117,7 +128,7 @@ } else { if ( g_pending_hidemenu ) clearTimeout(g_pending_hidemenu); - g_pending_hidemenu = setTimeout("hide_nodnix_menu()", delay); + g_pending_hidemenu = setTimeout(hide_nodnix_menu, delay); } } @@ -204,7 +215,21 @@ YAHOO.util.Dom.removeClass(get_nix_menu(), 'soon'); } +function refresh_tag_bar( tag_list ) { + // ajax request to fill the user tags list + var params = {}; + params['op'] = 'tags_get_user_firehose'; + params['id'] = g_nodnix_item_id; + params['nodnix'] = 1; + ajax_update(params, tag_list, {}); +} + function begin_nodnix_editing() { + if ( is_firehose_playing() ) { + firehose_pause(); + end_nodnix_editing.restore_firehose_state = firehose_play; + } + get_nodnix_listener().disable(); YAHOO.util.Dom.addClass(get_nod_menu(), 'soon'); YAHOO.util.Dom.addClass(get_nix_menu(), 'soon'); @@ -215,17 +240,22 @@ var input = _get_nodnix('input'); input.value = ""; input.focus(); - - _get_nodnix('ol').innerHTML = ""; + var tag_list = _get_nodnix('ol'); + tag_list.innerHTML = ""; + refresh_tag_bar(tag_list); + (input.getAttribute("updown")=="+" ? nod_completer : nix_completer).sendQuery(); - setTimeout("soon_is_now()", 225); + setTimeout(soon_is_now, 225); } function end_nodnix_editing() { YAHOO.util.Dom.removeClass(get_nod_menu(), 'editing'); YAHOO.util.Dom.removeClass(get_nix_menu(), 'editing'); + end_nodnix_editing.restore_firehose_state(); + end_nodnix_editing.restore_firehose_state = function(){} } +end_nodnix_editing.restore_firehose_state = function(){} function handle_nodnix_blur( type, args ) { hide_nodnix_menu(); @@ -239,13 +269,16 @@ nodnix_tag(tagname); // now 'harden' the tag var list = _get_nodnix('ol'); - list.innerHTML = '
  • ' + tagname + '
  • ' + list.innerHTML; + list.innerHTML = handle_nodnix_select.template_string.split('$').join(tagname) + list.innerHTML; _get_nodnix('input').value = ""; } if ( !stay_open ) hide_nodnix_menu(); } + // WARNING: keep this string in sync with tagsnodnixuser;misc;default +handle_nodnix_select.template_string = '
  • $! x
  • '; + function handle_completer_key( type, args ) { var key = args[0]; var event = args[1]; Deleted: slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/prototype.js =================================================================== --- slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/prototype.js 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/prototype.js 2008-04-01 03:35:14 UTC (rev 560) @@ -1,1785 +0,0 @@ -/* Prototype JavaScript framework, version 1.4.0 - * (c) 2005 Sam Stephenson - * - * THIS FILE IS AUTOMATICALLY GENERATED. When sending patches, please diff - * against the source tree, available from the Prototype darcs repository. - * - * Prototype is freely distributable under the terms of an MIT-style license. - * - * For details, see the Prototype web site: http://prototype.conio.net/ - * -/*--------------------------------------------------------------------------*/ - -var Prototype = { - Version: '1.4.0', - ScriptFragment: '(?:)((\n|\r|.)*?)(?:<\/script>)', - - emptyFunction: function() {}, - K: function(x) {return x} -} - -var Class = { - create: function() { - return function() { - this.initialize.apply(this, arguments); - } - } -} - -var Abstract = new Object(); - -Object.extend = function(destination, source) { - for (property in source) { - destination[property] = source[property]; - } - return destination; -} - -Object.inspect = function(object) { - try { - if (object == undefined) return 'undefined'; - if (object == null) return 'null'; - return object.inspect ? object.inspect() : object.toString(); - } catch (e) { - if (e instanceof RangeError) return '...'; - throw e; - } -} - -Function.prototype.bind = function() { - var __method = this, args = $A(arguments), object = args.shift(); - return function() { - return __method.apply(object, args.concat($A(arguments))); - } -} - -Function.prototype.bindAsEventListener = function(object) { - var __method = this; - return function(event) { - return __method.call(object, event || window.event); - } -} - -Object.extend(Number.prototype, { - toColorPart: function() { - var digits = this.toString(16); - if (this < 16) return '0' + digits; - return digits; - }, - - succ: function() { - return this + 1; - }, - - times: function(iterator) { - $R(0, this, true).each(iterator); - return this; - } -}); - -var Try = { - these: function() { - var returnValue; - - for (var i = 0; i < arguments.length; i++) { - var lambda = arguments[i]; - try { - returnValue = lambda(); - break; - } catch (e) {} - } - - return returnValue; - } -} - -/*--------------------------------------------------------------------------*/ - -var PeriodicalExecuter = Class.create(); -PeriodicalExecuter.prototype = { - initialize: function(callback, frequency) { - this.callback = callback; - this.frequency = frequency; - this.currentlyExecuting = false; - - this.registerCallback(); - }, - - registerCallback: function() { - setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); - }, - - onTimerEvent: function() { - if (!this.currentlyExecuting) { - try { - this.currentlyExecuting = true; - this.callback(); - } finally { - this.currentlyExecuting = false; - } - } - } -} - -/*--------------------------------------------------------------------------*/ - -function $() { - var elements = new Array(); - - for (var i = 0; i < arguments.length; i++) { - var element = arguments[i]; - if (typeof element == 'string') - element = document.getElementById(element); - - if (arguments.length == 1) - return element; - - elements.push(element); - } - - return elements; -} -Object.extend(String.prototype, { - stripTags: function() { - return this.replace(/<\/?[^>]+>/gi, ''); - }, - - stripScripts: function() { - return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); - }, - - extractScripts: function() { - var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); - var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); - return (this.match(matchAll) || []).map(function(scriptTag) { - return (scriptTag.match(matchOne) || ['', ''])[1]; - }); - }, - - evalScripts: function() { - return this.extractScripts().map(eval); - }, - - escapeHTML: function() { - var div = document.createElement('div'); - var text = document.createTextNode(this); - div.appendChild(text); - return div.innerHTML; - }, - - unescapeHTML: function() { - var div = document.createElement('div'); - div.innerHTML = this.stripTags(); - return div.childNodes[0] ? div.childNodes[0].nodeValue : ''; - }, - - toQueryParams: function() { - var pairs = this.match(/^\??(.*)$/)[1].split('&'); - return pairs.inject({}, function(params, pairString) { - var pair = pairString.split('='); - params[pair[0]] = pair[1]; - return params; - }); - }, - - toArray: function() { - return this.split(''); - }, - - camelize: function() { - var oStringList = this.split('-'); - if (oStringList.length == 1) return oStringList[0]; - - var camelizedString = this.indexOf('-') == 0 - ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1) - : oStringList[0]; - - for (var i = 1, len = oStringList.length; i < len; i++) { - var s = oStringList[i]; - camelizedString += s.charAt(0).toUpperCase() + s.substring(1); - } - - return camelizedString; - }, - - inspect: function() { - return "'" + this.replace('\\', '\\\\').replace("'", '\\\'') + "'"; - } -}); - -String.prototype.parseQuery = String.prototype.toQueryParams; - -var $break = new Object(); -var $continue = new Object(); - -var Enumerable = { - each: function(iterator) { - var index = 0; - try { - this._each(function(value) { - try { - iterator(value, index++); - } catch (e) { - if (e != $continue) throw e; - } - }); - } catch (e) { - if (e != $break) throw e; - } - }, - - all: function(iterator) { - var result = true; - this.each(function(value, index) { - result = result && !!(iterator || Prototype.K)(value, index); - if (!result) throw $break; - }); - return result; - }, - - any: function(iterator) { - var result = true; - this.each(function(value, index) { - if (result = !!(iterator || Prototype.K)(value, index)) - throw $break; - }); - return result; - }, - - collect: function(iterator) { - var results = []; - this.each(function(value, index) { - results.push(iterator(value, index)); - }); - return results; - }, - - detect: function (iterator) { - var result; - this.each(function(value, index) { - if (iterator(value, index)) { - result = value; - throw $break; - } - }); - return result; - }, - - findAll: function(iterator) { - var results = []; - this.each(function(value, index) { - if (iterator(value, index)) - results.push(value); - }); - return results; - }, - - grep: function(pattern, iterator) { - var results = []; - this.each(function(value, index) { - var stringValue = value.toString(); - if (stringValue.match(pattern)) - results.push((iterator || Prototype.K)(value, index)); - }) - return results; - }, - - include: function(object) { - var found = false; - this.each(function(value) { - if (value == object) { - found = true; - throw $break; - } - }); - return found; - }, - - inject: function(memo, iterator) { - this.each(function(value, index) { - memo = iterator(memo, value, index); - }); - return memo; - }, - - invoke: function(method) { - var args = $A(arguments).slice(1); - return this.collect(function(value) { - return value[method].apply(value, args); - }); - }, - - max: function(iterator) { - var result; - this.each(function(value, index) { - value = (iterator || Prototype.K)(value, index); - if (value >= (result || value)) - result = value; - }); - return result; - }, - - min: function(iterator) { - var result; - this.each(function(value, index) { - value = (iterator || Prototype.K)(value, index); - if (value <= (result || value)) - result = value; - }); - return result; - }, - - partition: function(iterator) { - var trues = [], falses = []; - this.each(function(value, index) { - ((iterator || Prototype.K)(value, index) ? - trues : falses).push(value); - }); - return [trues, falses]; - }, - - pluck: function(property) { - var results = []; - this.each(function(value, index) { - results.push(value[property]); - }); - return results; - }, - - reject: function(iterator) { - var results = []; - this.each(function(value, index) { - if (!iterator(value, index)) - results.push(value); - }); - return results; - }, - - sortBy: function(iterator) { - return this.collect(function(value, index) { - return {value: value, criteria: iterator(value, index)}; - }).sort(function(left, right) { - var a = left.criteria, b = right.criteria; - return a < b ? -1 : a > b ? 1 : 0; - }).pluck('value'); - }, - - toArray: function() { - return this.collect(Prototype.K); - }, - - zip: function() { - var iterator = Prototype.K, args = $A(arguments); - if (typeof args.last() == 'function') - iterator = args.pop(); - - var collections = [this].concat(args).map($A); - return this.map(function(value, index) { - iterator(value = collections.pluck(index)); - return value; - }); - }, - - inspect: function() { - return '#'; - } -} - -Object.extend(Enumerable, { - map: Enumerable.collect, - find: Enumerable.detect, - select: Enumerable.findAll, - member: Enumerable.include, - entries: Enumerable.toArray -}); -var $A = Array.from = function(iterable) { - if (!iterable) return []; - if (iterable.toArray) { - return iterable.toArray(); - } else { - var results = []; - for (var i = 0; i < iterable.length; i++) - results.push(iterable[i]); - return results; - } -} - -Object.extend(Array.prototype, Enumerable); - -Array.prototype._reverse = Array.prototype.reverse; - -Object.extend(Array.prototype, { - _each: function(iterator) { - for (var i = 0; i < this.length; i++) - iterator(this[i]); - }, - - clear: function() { - this.length = 0; - return this; - }, - - first: function() { - return this[0]; - }, - - last: function() { - return this[this.length - 1]; - }, - - compact: function() { - return this.select(function(value) { - return value != undefined || value != null; - }); - }, - - flatten: function() { - return this.inject([], function(array, value) { - return array.concat(value.constructor == Array ? - value.flatten() : [value]); - }); - }, - - without: function() { - var values = $A(arguments); - return this.select(function(value) { - return !values.include(value); - }); - }, - - indexOf: function(object) { - for (var i = 0; i < this.length; i++) - if (this[i] == object) return i; - return -1; - }, - - reverse: function(inline) { - return (inline !== false ? this : this.toArray())._reverse(); - }, - - shift: function() { - var result = this[0]; - for (var i = 0; i < this.length - 1; i++) - this[i] = this[i + 1]; - this.length--; - return result; - }, - - inspect: function() { - return '[' + this.map(Object.inspect).join(', ') + ']'; - } -}); -var Hash = { - _each: function(iterator) { - for (key in this) { - var value = this[key]; - if (typeof value == 'function') continue; - - var pair = [key, value]; - pair.key = key; - pair.value = value; - iterator(pair); - } - }, - - keys: function() { - return this.pluck('key'); - }, - - values: function() { - return this.pluck('value'); - }, - - merge: function(hash) { - return $H(hash).inject($H(this), function(mergedHash, pair) { - mergedHash[pair.key] = pair.value; - return mergedHash; - }); - }, - - toQueryString: function() { - return this.map(function(pair) { - return pair.map(encodeURIComponent).join('='); - }).join('&'); - }, - - inspect: function() { - return '#'; - } -} - -function $H(object) { - var hash = Object.extend({}, object || {}); - Object.extend(hash, Enumerable); - Object.extend(hash, Hash); - return hash; -} -ObjectRange = Class.create(); -Object.extend(ObjectRange.prototype, Enumerable); -Object.extend(ObjectRange.prototype, { - initialize: function(start, end, exclusive) { - this.start = start; - this.end = end; - this.exclusive = exclusive; - }, - - _each: function(iterator) { - var value = this.start; - do { - iterator(value); - value = value.succ(); - } while (this.include(value)); - }, - - include: function(value) { - if (value < this.start) - return false; - if (this.exclusive) - return value < this.end; - return value <= this.end; - } -}); - -var $R = function(start, end, exclusive) { - return new ObjectRange(start, end, exclusive); -} - -var Ajax = { - getTransport: function() { - return Try.these( - function() {return new ActiveXObject('Msxml2.XMLHTTP')}, - function() {return new ActiveXObject('Microsoft.XMLHTTP')}, - function() {return new XMLHttpRequest()} - ) || false; - }, - - activeRequestCount: 0 -} - -Ajax.Responders = { - responders: [], - - _each: function(iterator) { - this.responders._each(iterator); - }, - - register: function(responderToAdd) { - if (!this.include(responderToAdd)) - this.responders.push(responderToAdd); - }, - - unregister: function(responderToRemove) { - this.responders = this.responders.without(responderToRemove); - }, - - dispatch: function(callback, request, transport, json) { - this.each(function(responder) { - if (responder[callback] && typeof responder[callback] == 'function') { - try { - responder[callback].apply(responder, [request, transport, json]); - } catch (e) {} - } - }); - } -}; - -Object.extend(Ajax.Responders, Enumerable); - -Ajax.Responders.register({ - onCreate: function() { - Ajax.activeRequestCount++; - }, - - onComplete: function() { - Ajax.activeRequestCount--; - } -}); - -Ajax.Base = function() {}; -Ajax.Base.prototype = { - setOptions: function(options) { - this.options = { - method: 'post', - asynchronous: true, - parameters: '' - } - Object.extend(this.options, options || {}); - }, - - responseIsSuccess: function() { - return this.transport.status == undefined - || this.transport.status == 0 - || (this.transport.status >= 200 && this.transport.status < 300); - }, - - responseIsFailure: function() { - return !this.responseIsSuccess(); - } -} - -Ajax.Request = Class.create(); -Ajax.Request.Events = - ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; - -Ajax.Request.prototype = Object.extend(new Ajax.Base(), { - initialize: function(url, options) { - this.transport = Ajax.getTransport(); - this.setOptions(options); - this.request(url); - }, - - request: function(url) { - var parameters = this.options.parameters || ''; - if (parameters.length > 0) parameters += '&_='; - - try { - this.url = url; - if (this.options.method == 'get' && parameters.length > 0) - this.url += (this.url.match(/\?/) ? '&' : '?') + parameters; - - Ajax.Responders.dispatch('onCreate', this, this.transport); - - this.transport.open(this.options.method, this.url, - this.options.asynchronous); - - if (this.options.asynchronous) { - this.transport.onreadystatechange = this.onStateChange.bind(this); - setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10); - } - - this.setRequestHeaders(); - - var body = this.options.postBody ? this.options.postBody : parameters; - this.transport.send(this.options.method == 'post' ? body : null); - - } catch (e) { - this.dispatchException(e); - } - }, - - setRequestHeaders: function() { - var requestHeaders = - ['X-Requested-With', 'XMLHttpRequest', - 'X-Prototype-Version', Prototype.Version]; - - if (this.options.method == 'post') { - requestHeaders.push('Content-type', - 'application/x-www-form-urlencoded'); - - /* Force "Connection: close" for Mozilla browsers to work around - * a bug where XMLHttpReqeuest sends an incorrect Content-length - * header. See Mozilla Bugzilla #246651. - */ - if (this.transport.overrideMimeType) - requestHeaders.push('Connection', 'close'); - } - - if (this.options.requestHeaders) - requestHeaders.push.apply(requestHeaders, this.options.requestHeaders); - - for (var i = 0; i < requestHeaders.length; i += 2) - this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]); - }, - - onStateChange: function() { - var readyState = this.transport.readyState; - if (readyState != 1) - this.respondToReadyState(this.transport.readyState); - }, - - header: function(name) { - try { - return this.transport.getResponseHeader(name); - } catch (e) {} - }, - - evalJSON: function() { - try { - return eval(this.header('X-JSON')); - } catch (e) {} - }, - - evalResponse: function() { - try { - return eval(this.transport.responseText); - } catch (e) { - this.dispatchException(e); - } - }, - - respondToReadyState: function(readyState) { - var event = Ajax.Request.Events[readyState]; - var transport = this.transport, json = this.evalJSON(); - - if (event == 'Complete') { - try { - (this.options['on' + this.transport.status] - || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')] - || Prototype.emptyFunction)(transport, json); - } catch (e) { - this.dispatchException(e); - } - - if ((this.header('Content-type') || '').match(/^text\/javascript/i)) - this.evalResponse(); - } - - try { - (this.options['on' + event] || Prototype.emptyFunction)(transport, json); - Ajax.Responders.dispatch('on' + event, this, transport, json); - } catch (e) { - this.dispatchException(e); - } - - /* Avoid memory leak in MSIE: clean up the oncomplete event handler */ - if (event == 'Complete') - this.transport.onreadystatechange = Prototype.emptyFunction; - }, - - dispatchException: function(exception) { - (this.options.onException || Prototype.emptyFunction)(this, exception); - Ajax.Responders.dispatch('onException', this, exception); - } -}); - -Ajax.Updater = Class.create(); - -Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), { - initialize: function(container, url, options) { - this.containers = { - success: container.success ? $(container.success) : $(container), - failure: container.failure ? $(container.failure) : - (container.success ? null : $(container)) - } - - this.transport = Ajax.getTransport(); - this.setOptions(options); - - var onComplete = this.options.onComplete || Prototype.emptyFunction; - this.options.onComplete = (function(transport, object) { - this.updateContent(); - onComplete(transport, object); - }).bind(this); - - this.request(url); - }, - - updateContent: function() { - var receiver = this.responseIsSuccess() ? - this.containers.success : this.containers.failure; - var response = this.transport.responseText; - - if (!this.options.evalScripts) - response = response.stripScripts(); - - if (receiver) { - if (this.options.insertion) { - new this.options.insertion(receiver, response); - } else { - Element.update(receiver, response); - } - } - - if (this.responseIsSuccess()) { - if (this.onComplete) - setTimeout(this.onComplete.bind(this), 10); - } - } -}); - -Ajax.PeriodicalUpdater = Class.create(); -Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), { - initialize: function(container, url, options) { - this.setOptions(options); - this.onComplete = this.options.onComplete; - - this.frequency = (this.options.frequency || 2); - this.decay = (this.options.decay || 1); - - this.updater = {}; - this.container = container; - this.url = url; - - this.start(); - }, - - start: function() { - this.options.onComplete = this.updateComplete.bind(this); - this.onTimerEvent(); - }, - - stop: function() { - this.updater.onComplete = undefined; - clearTimeout(this.timer); - (this.onComplete || Prototype.emptyFunction).apply(this, arguments); - }, - - updateComplete: function(request) { - if (this.options.decay) { - this.decay = (request.responseText == this.lastText ? - this.decay * this.options.decay : 1); - - this.lastText = request.responseText; - } - this.timer = setTimeout(this.onTimerEvent.bind(this), - this.decay * this.frequency * 1000); - }, - - onTimerEvent: function() { - this.updater = new Ajax.Updater(this.container, this.url, this.options); - } -}); -document.getElementsByClassName = function(className, parentElement) { - var children = ($(parentElement) || document.body).getElementsByTagName('*'); - return $A(children).inject([], function(elements, child) { - if (child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)"))) - elements.push(child); - return elements; - }); -} - -/*--------------------------------------------------------------------------*/ - -if (!window.Element) { - var Element = new Object(); -} - -Object.extend(Element, { - visible: function(element) { - return $(element).style.display != 'none'; - }, - - toggle: function() { - for (var i = 0; i < arguments.length; i++) { - var element = $(arguments[i]); - Element[Element.visible(element) ? 'hide' : 'show'](element); - } - }, - - hide: function() { - for (var i = 0; i < arguments.length; i++) { - var element = $(arguments[i]); - element.style.display = 'none'; - } - }, - - show: function() { - for (var i = 0; i < arguments.length; i++) { - var element = $(arguments[i]); - element.style.display = ''; - } - }, - - remove: function(element) { - element = $(element); - element.parentNode.removeChild(element); - }, - - update: function(element, html) { - $(element).innerHTML = html.stripScripts(); - setTimeout(function() {html.evalScripts()}, 10); - }, - - getHeight: function(element) { - element = $(element); - return element.offsetHeight; - }, - - classNames: function(element) { - return new Element.ClassNames(element); - }, - - hasClassName: function(element, className) { - if (!(element = $(element))) return; - return Element.classNames(element).include(className); - }, - - addClassName: function(element, className) { - if (!(element = $(element))) return; - return Element.classNames(element).add(className); - }, - - removeClassName: function(element, className) { - if (!(element = $(element))) return; - return Element.classNames(element).remove(className); - }, - - // removes whitespace-only text node children - cleanWhitespace: function(element) { - element = $(element); - for (var i = 0; i < element.childNodes.length; i++) { - var node = element.childNodes[i]; - if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) - Element.remove(node); - } - }, - - empty: function(element) { - return $(element).innerHTML.match(/^\s*$/); - }, - - scrollTo: function(element) { - element = $(element); - var x = element.x ? element.x : element.offsetLeft, - y = element.y ? element.y : element.offsetTop; - window.scrollTo(x, y); - }, - - getStyle: function(element, style) { - element = $(element); - var value = element.style[style.camelize()]; - if (!value) { - if (document.defaultView && document.defaultView.getComputedStyle) { - var css = document.defaultView.getComputedStyle(element, null); - value = css ? css.getPropertyValue(style) : null; - } else if (element.currentStyle) { - value = element.currentStyle[style.camelize()]; - } - } - - if (window.opera && ['left', 'top', 'right', 'bottom'].include(style)) - if (Element.getStyle(element, 'position') == 'static') value = 'auto'; - - return value == 'auto' ? null : value; - }, - - setStyle: function(element, style) { - element = $(element); - for (name in style) - element.style[name.camelize()] = style[name]; - }, - - getDimensions: function(element) { - element = $(element); - if (Element.getStyle(element, 'display') != 'none') - return {width: element.offsetWidth, height: element.offsetHeight}; - - // All *Width and *Height properties give 0 on elements with display none, - // so enable the element temporarily - var els = element.style; - var originalVisibility = els.visibility; - var originalPosition = els.position; - els.visibility = 'hidden'; - els.position = 'absolute'; - els.display = ''; - var originalWidth = element.clientWidth; - var originalHeight = element.clientHeight; - els.display = 'none'; - els.position = originalPosition; - els.visibility = originalVisibility; - return {width: originalWidth, height: originalHeight}; - }, - - makePositioned: function(element) { - element = $(element); - var pos = Element.getStyle(element, 'position'); - if (pos == 'static' || !pos) { - element._madePositioned = true; - element.style.position = 'relative'; - // Opera returns the offset relative to the positioning context, when an - // element is position relative but top and left have not been defined - if (window.opera) { - element.style.top = 0; - element.style.left = 0; - } - } - }, - - undoPositioned: function(element) { - element = $(element); - if (element._madePositioned) { - element._madePositioned = undefined; - element.style.position = - element.style.top = - element.style.left = - element.style.bottom = - element.style.right = ''; - } - }, - - makeClipping: function(element) { - element = $(element); - if (element._overflow) return; - element._overflow = element.style.overflow; - if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden') - element.style.overflow = 'hidden'; - }, - - undoClipping: function(element) { - element = $(element); - if (element._overflow) return; - element.style.overflow = element._overflow; - element._overflow = undefined; - } -}); - -var Toggle = new Object(); -Toggle.display = Element.toggle; - -/*--------------------------------------------------------------------------*/ - -Abstract.Insertion = function(adjacency) { - this.adjacency = adjacency; -} - -Abstract.Insertion.prototype = { - initialize: function(element, content) { - this.element = $(element); - this.content = content.stripScripts(); - - if (this.adjacency && this.element.insertAdjacentHTML) { - try { - this.element.insertAdjacentHTML(this.adjacency, this.content); - } catch (e) { - if (this.element.tagName.toLowerCase() == 'tbody') { - this.insertContent(this.contentFromAnonymousTable()); - } else { - throw e; - } - } - } else { - this.range = this.element.ownerDocument.createRange(); - if (this.initializeRange) this.initializeRange(); - this.insertContent([this.range.createContextualFragment(this.content)]); - } - - setTimeout(function() {content.evalScripts()}, 10); - }, - - contentFromAnonymousTable: function() { - var div = document.createElement('div'); - div.innerHTML = '' + this.content + '
    '; - return $A(div.childNodes[0].childNodes[0].childNodes); - } -} - -var Insertion = new Object(); - -Insertion.Before = Class.create(); -Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), { - initializeRange: function() { - this.range.setStartBefore(this.element); - }, - - insertContent: function(fragments) { - fragments.each((function(fragment) { - this.element.parentNode.insertBefore(fragment, this.element); - }).bind(this)); - } -}); - -Insertion.Top = Class.create(); -Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), { - initializeRange: function() { - this.range.selectNodeContents(this.element); - this.range.collapse(true); - }, - - insertContent: function(fragments) { - fragments.reverse(false).each((function(fragment) { - this.element.insertBefore(fragment, this.element.firstChild); - }).bind(this)); - } -}); - -Insertion.Bottom = Class.create(); -Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), { - initializeRange: function() { - this.range.selectNodeContents(this.element); - this.range.collapse(this.element); - }, - - insertContent: function(fragments) { - fragments.each((function(fragment) { - this.element.appendChild(fragment); - }).bind(this)); - } -}); - -Insertion.After = Class.create(); -Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), { - initializeRange: function() { - this.range.setStartAfter(this.element); - }, - - insertContent: function(fragments) { - fragments.each((function(fragment) { - this.element.parentNode.insertBefore(fragment, - this.element.nextSibling); - }).bind(this)); - } -}); - -/*--------------------------------------------------------------------------*/ - -Element.ClassNames = Class.create(); -Element.ClassNames.prototype = { - initialize: function(element) { - this.element = $(element); - }, - - _each: function(iterator) { - this.element.className.split(/\s+/).select(function(name) { - return name.length > 0; - })._each(iterator); - }, - - set: function(className) { - this.element.className = className; - }, - - add: function(classNameToAdd) { - if (this.include(classNameToAdd)) return; - this.set(this.toArray().concat(classNameToAdd).join(' ')); - }, - - remove: function(classNameToRemove) { - if (!this.include(classNameToRemove)) return; - this.set(this.select(function(className) { - return className != classNameToRemove; - }).join(' ')); - }, - - toString: function() { - return this.toArray().join(' '); - } -} - -Object.extend(Element.ClassNames.prototype, Enumerable); -var Field = { - clear: function() { - for (var i = 0; i < arguments.length; i++) - $(arguments[i]).value = ''; - }, - - focus: function(element) { - $(element).focus(); - }, - - present: function() { - for (var i = 0; i < arguments.length; i++) - if ($(arguments[i]).value == '') return false; - return true; - }, - - select: function(element) { - $(element).select(); - }, - - activate: function(element) { - element = $(element); - element.focus(); - if (element.select) - element.select(); - } -} - -/*--------------------------------------------------------------------------*/ - -var Form = { - serialize: function(form) { - var elements = Form.getElements($(form)); - var queryComponents = new Array(); - - for (var i = 0; i < elements.length; i++) { - var queryComponent = Form.Element.serialize(elements[i]); - if (queryComponent) - queryComponents.push(queryComponent); - } - - return queryComponents.join('&'); - }, - - getElements: function(form) { - form = $(form); - var elements = new Array(); - - for (tagName in Form.Element.Serializers) { - var tagElements = form.getElementsByTagName(tagName); - for (var j = 0; j < tagElements.length; j++) - elements.push(tagElements[j]); - } - return elements; - }, - - getInputs: function(form, typeName, name) { - form = $(form); - var inputs = form.getElementsByTagName('input'); - - if (!typeName && !name) - return inputs; - - var matchingInputs = new Array(); - for (var i = 0; i < inputs.length; i++) { - var input = inputs[i]; - if ((typeName && input.type != typeName) || - (name && input.name != name)) - continue; - matchingInputs.push(input); - } - - return matchingInputs; - }, - - disable: function(form) { - var elements = Form.getElements(form); - for (var i = 0; i < elements.length; i++) { - var element = elements[i]; - element.blur(); - element.disabled = 'true'; - } - }, - - enable: function(form) { - var elements = Form.getElements(form); - for (var i = 0; i < elements.length; i++) { - var element = elements[i]; - element.disabled = ''; - } - }, - - findFirstElement: function(form) { - return Form.getElements(form).find(function(element) { - return element.type != 'hidden' && !element.disabled && - ['input', 'select', 'textarea'].include(element.tagName.toLowerCase()); - }); - }, - - focusFirstElement: function(form) { - Field.activate(Form.findFirstElement(form)); - }, - - reset: function(form) { - $(form).reset(); - } -} - -Form.Element = { - serialize: function(element) { - element = $(element); - var method = element.tagName.toLowerCase(); - var parameter = Form.Element.Serializers[method](element); - - if (parameter) { - var key = encodeURIComponent(parameter[0]); - if (key.length == 0) return; - - if (parameter[1].constructor != Array) - parameter[1] = [parameter[1]]; - - return parameter[1].map(function(value) { - return key + '=' + encodeURIComponent(value); - }).join('&'); - } - }, - - getValue: function(element) { - element = $(element); - var method = element.tagName.toLowerCase(); - var parameter = Form.Element.Serializers[method](element); - - if (parameter) - return parameter[1]; - } -} - -Form.Element.Serializers = { - input: function(element) { - switch (element.type.toLowerCase()) { - case 'submit': - case 'hidden': - case 'password': - case 'text': - return Form.Element.Serializers.textarea(element); - case 'checkbox': - case 'radio': - return Form.Element.Serializers.inputSelector(element); - } - return false; - }, - - inputSelector: function(element) { - if (element.checked) - return [element.name, element.value]; - }, - - textarea: function(element) { - return [element.name, element.value]; - }, - - select: function(element) { - return Form.Element.Serializers[element.type == 'select-one' ? - 'selectOne' : 'selectMany'](element); - }, - - selectOne: function(element) { - var value = '', opt, index = element.selectedIndex; - if (index >= 0) { - opt = element.options[index]; - value = opt.value; - if (!value && !('value' in opt)) - value = opt.text; - } - return [element.name, value]; - }, - - selectMany: function(element) { - var value = new Array(); - for (var i = 0; i < element.length; i++) { - var opt = element.options[i]; - if (opt.selected) { - var optValue = opt.value; - if (!optValue && !('value' in opt)) - optValue = opt.text; - value.push(optValue); - } - } - return [element.name, value]; - } -} - -/*--------------------------------------------------------------------------*/ - -var $F = Form.Element.getValue; - -/*--------------------------------------------------------------------------*/ - -Abstract.TimedObserver = function() {} -Abstract.TimedObserver.prototype = { - initialize: function(element, frequency, callback) { - this.frequency = frequency; - this.element = $(element); - this.callback = callback; - - this.lastValue = this.getValue(); - this.registerCallback(); - }, - - registerCallback: function() { - setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); - }, - - onTimerEvent: function() { - var value = this.getValue(); - if (this.lastValue != value) { - this.callback(this.element, value); - this.lastValue = value; - } - } -} - -Form.Element.Observer = Class.create(); -Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { - getValue: function() { - return Form.Element.getValue(this.element); - } -}); - -Form.Observer = Class.create(); -Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { - getValue: function() { - return Form.serialize(this.element); - } -}); - -/*--------------------------------------------------------------------------*/ - -Abstract.EventObserver = function() {} -Abstract.EventObserver.prototype = { - initialize: function(element, callback) { - this.element = $(element); - this.callback = callback; - - this.lastValue = this.getValue(); - if (this.element.tagName.toLowerCase() == 'form') - this.registerFormCallbacks(); - else - this.registerCallback(this.element); - }, - - onElementEvent: function() { - var value = this.getValue(); - if (this.lastValue != value) { - this.callback(this.element, value); - this.lastValue = value; - } - }, - - registerFormCallbacks: function() { - var elements = Form.getElements(this.element); - for (var i = 0; i < elements.length; i++) - this.registerCallback(elements[i]); - }, - - registerCallback: function(element) { - if (element.type) { - switch (element.type.toLowerCase()) { - case 'checkbox': - case 'radio': - Event.observe(element, 'click', this.onElementEvent.bind(this)); - break; - case 'password': - case 'text': - case 'textarea': - case 'select-one': - case 'select-multiple': - Event.observe(element, 'change', this.onElementEvent.bind(this)); - break; - } - } - } -} - -Form.Element.EventObserver = Class.create(); -Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { - getValue: function() { - return Form.Element.getValue(this.element); - } -}); - -Form.EventObserver = Class.create(); -Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { - getValue: function() { - return Form.serialize(this.element); - } -}); -if (!window.Event) { - var Event = new Object(); -} - -Object.extend(Event, { - KEY_BACKSPACE: 8, - KEY_TAB: 9, - KEY_RETURN: 13, - KEY_ESC: 27, - KEY_LEFT: 37, - KEY_UP: 38, - KEY_RIGHT: 39, - KEY_DOWN: 40, - KEY_DELETE: 46, - - element: function(event) { - return event.target || event.srcElement; - }, - - isLeftClick: function(event) { - return (((event.which) && (event.which == 1)) || - ((event.button) && (event.button == 1))); - }, - - pointerX: function(event) { - return event.pageX || (event.clientX + - (document.documentElement.scrollLeft || document.body.scrollLeft)); - }, - - pointerY: function(event) { - return event.pageY || (event.clientY + - (document.documentElement.scrollTop || document.body.scrollTop)); - }, - - stop: function(event) { - if (event.preventDefault) { - event.preventDefault(); - event.stopPropagation(); - } else { - event.returnValue = false; - event.cancelBubble = true; - } - }, - - // find the first node with the given tagName, starting from the - // node the event was triggered on; traverses the DOM upwards - findElement: function(event, tagName) { - var element = Event.element(event); - while (element.parentNode && (!element.tagName || - (element.tagName.toUpperCase() != tagName.toUpperCase()))) - element = element.parentNode; - return element; - }, - - observers: false, - - _observeAndCache: function(element, name, observer, useCapture) { - if (!this.observers) this.observers = []; - if (element.addEventListener) { - this.observers.push([element, name, observer, useCapture]); - element.addEventListener(name, observer, useCapture); - } else if (element.attachEvent) { - this.observers.push([element, name, observer, useCapture]); - element.attachEvent('on' + name, observer); - } - }, - - unloadCache: function() { - if (!Event.observers) return; - for (var i = 0; i < Event.observers.length; i++) { - Event.stopObserving.apply(this, Event.observers[i]); - Event.observers[i][0] = null; - } - Event.observers = false; - }, - - observe: function(element, name, observer, useCapture) { - var element = $(element); - useCapture = useCapture || false; - - if (name == 'keypress' && - (navigator.appVersion.match(/Konqueror|Safari|KHTML/) - || element.attachEvent)) - name = 'keydown'; - - this._observeAndCache(element, name, observer, useCapture); - }, - - stopObserving: function(element, name, observer, useCapture) { - var element = $(element); - useCapture = useCapture || false; - - if (name == 'keypress' && - (navigator.appVersion.match(/Konqueror|Safari|KHTML/) - || element.detachEvent)) - name = 'keydown'; - - if (element.removeEventListener) { - element.removeEventListener(name, observer, useCapture); - } else if (element.detachEvent) { - element.detachEvent('on' + name, observer); - } - } -}); - -/* prevent memory leaks in IE */ -Event.observe(window, 'unload', Event.unloadCache, false); -var Position = { - // set to true if needed, warning: firefox performance problems - // NOT neeeded for page scrolling, only if draggable contained in - // scrollable elements - includeScrollOffsets: false, - - // must be called before calling withinIncludingScrolloffset, every time the - // page is scrolled - prepare: function() { - this.deltaX = window.pageXOffset - || document.documentElement.scrollLeft - || document.body.scrollLeft - || 0; - this.deltaY = window.pageYOffset - || document.documentElement.scrollTop - || document.body.scrollTop - || 0; - }, - - realOffset: function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.scrollTop || 0; - valueL += element.scrollLeft || 0; - element = element.parentNode; - } while (element); - return [valueL, valueT]; - }, - - cumulativeOffset: function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - element = element.offsetParent; - } while (element); - return [valueL, valueT]; - }, - - positionedOffset: function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - element = element.offsetParent; - if (element) { - p = Element.getStyle(element, 'position'); - if (p == 'relative' || p == 'absolute') break; - } - } while (element); - return [valueL, valueT]; - }, - - offsetParent: function(element) { - if (element.offsetParent) return element.offsetParent; - if (element == document.body) return element; - - while ((element = element.parentNode) && element != document.body) - if (Element.getStyle(element, 'position') != 'static') - return element; - - return document.body; - }, - - // caches x/y coordinate pair to use with overlap - within: function(element, x, y) { - if (this.includeScrollOffsets) - return this.withinIncludingScrolloffsets(element, x, y); - this.xcomp = x; - this.ycomp = y; - this.offset = this.cumulativeOffset(element); - - return (y >= this.offset[1] && - y < this.offset[1] + element.offsetHeight && - x >= this.offset[0] && - x < this.offset[0] + element.offsetWidth); - }, - - withinIncludingScrolloffsets: function(element, x, y) { - var offsetcache = this.realOffset(element); - - this.xcomp = x + offsetcache[0] - this.deltaX; - this.ycomp = y + offsetcache[1] - this.deltaY; - this.offset = this.cumulativeOffset(element); - - return (this.ycomp >= this.offset[1] && - this.ycomp < this.offset[1] + element.offsetHeight && - this.xcomp >= this.offset[0] && - this.xcomp < this.offset[0] + element.offsetWidth); - }, - - // within must be called directly before - overlap: function(mode, element) { - if (!mode) return 0; - if (mode == 'vertical') - return ((this.offset[1] + element.offsetHeight) - this.ycomp) / - element.offsetHeight; - if (mode == 'horizontal') - return ((this.offset[0] + element.offsetWidth) - this.xcomp) / - element.offsetWidth; - }, - - clone: function(source, target) { - source = $(source); - target = $(target); - target.style.position = 'absolute'; - var offsets = this.cumulativeOffset(source); - target.style.top = offsets[1] + 'px'; - target.style.left = offsets[0] + 'px'; - target.style.width = source.offsetWidth + 'px'; - target.style.height = source.offsetHeight + 'px'; - }, - - page: function(forElement) { - var valueT = 0, valueL = 0; - - var element = forElement; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - - // Safari fix - if (element.offsetParent==document.body) - if (Element.getStyle(element,'position')=='absolute') break; - - } while (element = element.offsetParent); - - element = forElement; - do { - valueT -= element.scrollTop || 0; - valueL -= element.scrollLeft || 0; - } while (element = element.parentNode); - - return [valueL, valueT]; - }, - - clone: function(source, target) { - var options = Object.extend({ - setLeft: true, - setTop: true, - setWidth: true, - setHeight: true, - offsetTop: 0, - offsetLeft: 0 - }, arguments[2] || {}) - - // find page position of source - source = $(source); - var p = Position.page(source); - - // find coordinate system to use - target = $(target); - var delta = [0, 0]; - var parent = null; - // delta [0,0] will do fine with position: fixed elements, - // position:absolute needs offsetParent deltas - if (Element.getStyle(target,'position') == 'absolute') { - parent = Position.offsetParent(target); - delta = Position.page(parent); - } - - // correct by body offsets (fixes Safari) - if (parent == document.body) { - delta[0] -= document.body.offsetLeft; - delta[1] -= document.body.offsetTop; - } - - // set position - if(options.setLeft) target.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; - if(options.setTop) target.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; - if(options.setWidth) target.style.width = source.offsetWidth + 'px'; - if(options.setHeight) target.style.height = source.offsetHeight + 'px'; - }, - - absolutize: function(element) { - element = $(element); - if (element.style.position == 'absolute') return; - Position.prepare(); - - var offsets = Position.positionedOffset(element); - var top = offsets[1]; - var left = offsets[0]; - var width = element.clientWidth; - var height = element.clientHeight; - - element._originalLeft = left - parseFloat(element.style.left || 0); - element._originalTop = top - parseFloat(element.style.top || 0); - element._originalWidth = element.style.width; - element._originalHeight = element.style.height; - - element.style.position = 'absolute'; - element.style.top = top + 'px';; - element.style.left = left + 'px';; - element.style.width = width + 'px';; - element.style.height = height + 'px';; - }, - - relativize: function(element) { - element = $(element); - if (element.style.position == 'relative') return; - Position.prepare(); - - element.style.position = 'relative'; - var top = parseFloat(element.style.top || 0) - (element._originalTop || 0); - var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); - - element.style.top = top + 'px'; - element.style.left = left + 'px'; - element.style.height = element._originalHeight; - element.style.width = element._originalWidth; - } -} - -// Safari returns margins on body which is incorrect if the child is absolutely -// positioned. For performance reasons, redefine Position.cumulativeOffset for -// KHTML/WebKit only. -if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) { - Position.cumulativeOffset = function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - if (element.offsetParent == document.body) - if (Element.getStyle(element, 'position') == 'absolute') break; - - element = element.offsetParent; - } while (element); - - return [valueL, valueT]; - } -} \ No newline at end of file Modified: slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/sd_autocomplete.js =================================================================== --- slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/sd_autocomplete.js 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/sd_autocomplete.js 2008-04-01 03:35:14 UTC (rev 560) @@ -1,5 +1,5 @@ // _*_ Mode: JavaScript; tab-width: 8; indent-tabs-mode: true _*_ -// $Id: sd_autocomplete.js,v 1.47 2008/01/24 19:51:02 pudge Exp $ +// $Id: sd_autocomplete.js,v 1.50 2008/03/11 16:38:18 scc Exp $ YAHOO.namespace("slashdot"); @@ -79,6 +79,7 @@ "books", "bsd", "developers", +"entertainment", "features", "games", "hardware", @@ -86,12 +87,14 @@ "it", "linux", "mainpage", +"news", "politics", "polls", "radio", "science", "search", "tacohell", +"technology", "vendors", "vendor_amd", "yro" ]; @@ -126,7 +129,6 @@ "links", "movies", "money", -"news", "pilot", "starwars", "sun", @@ -201,7 +203,6 @@ "osnine", "osx", "portables", -"technology", "utilities", "wireless", "portables", @@ -380,9 +381,9 @@ this._completer.autoHighlight = false; - // widget must be visible to move + // widget must be visible to move YAHOO.util.Dom.removeClass(this._widget, "hidden"); - // move widget to be near the 'source' + // move widget to be near the 'source' var pos = YAHOO.util.Dom.getXY(this._sourceEl); pos[1] += this._sourceEl.offsetHeight; YAHOO.util.Dom.setXY(this._widget, pos); @@ -394,7 +395,7 @@ YAHOO.util.Dom.removeClass(this._spareInput, "hidden"); this._spareInput.value = ""; this._spareInput.focus(); - this._pending_hide = setTimeout("YAHOO.slashdot.gCompleterWidget._hide()", 15000); + this._pending_hide = setTimeout(YAHOO.slashdot.gCompleterWidget._hide, 15000); } else YAHOO.util.Dom.addClass(this._spareInput, "hidden"); @@ -507,9 +508,9 @@ me._hide(); break; case 13: - // I'm sorry to say we have to test first, something somehow somewhere can still leave - // leave this listener dangling; want to look deeper into this, as this would _still_ - // leave the listener dangling + // I'm sorry to say we have to test first, something somehow somewhere can still + // leave this listener dangling; want to look deeper into this, as this would _still_ + // leave the listener dangling if ( me._completer ) me._completer.unmatchedItemSelectEvent.fire(me._completer, me, me._completer._sCurQuery); break; @@ -517,6 +518,6 @@ if ( me._pending_hide ) clearTimeout(me._pending_hide); if ( me._needsSpareInput() ) - me._pending_hide = setTimeout("YAHOO.slashdot.gCompleterWidget._hide()", 15000); + me._pending_hide = setTimeout(YAHOO.slashdot.gCompleterWidget._hide, 15000); } } Modified: slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/sectionprefs.js =================================================================== --- slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/sectionprefs.js 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/sectionprefs.js 2008-04-01 03:35:14 UTC (rev 560) @@ -1,4 +1,4 @@ -// $Id: sectionprefs.js,v 1.8 2007/11/29 19:06:20 entweichen Exp $ +// $Id: sectionprefs.js,v 1.10 2008/03/14 18:45:51 scc Exp $ function configSectionPopup() { var title = "Sectional Display Prefs "; @@ -7,7 +7,7 @@ createPopup(getXYForId('links-sections-title'), title, "sectionprefs", "", "Loading..."); var url = 'ajax.pl'; - var params = []; + var params = {}; params['op'] = 'getSectionPrefsHTML'; ajax_update(params, 'sectionprefs-contents'); @@ -26,12 +26,11 @@ } function postSectionPrefChanges(el) { - var params = []; + var params = {}; params['op'] = 'setSectionNexusPrefs'; params[el.name] = el.value; - var h = $H(params); - var sec_pref_msg = $("sectionprefs-message"); + var sec_pref_msg = $dom("sectionprefs-message"); sec_pref_msg.innerHTML = "Saving..."; var url = 'ajax.pl'; ajax_update(params, 'sectionprefs-message'); Modified: slashjp/branches/upstream/current/plugins/Ajax/mysql_dump.sql =================================================================== --- slashjp/branches/upstream/current/plugins/Ajax/mysql_dump.sql 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/plugins/Ajax/mysql_dump.sql 2008-04-01 03:35:14 UTC (rev 560) @@ -1,5 +1,5 @@ # -# $Id: mysql_dump.sql,v 1.25 2007/12/12 22:35:19 tvroom Exp $ +# $Id: mysql_dump.sql,v 1.26 2008/03/18 16:26:16 tvroom Exp $ # INSERT INTO reskey_resources VALUES (100, 'ajax_base', 'no'); @@ -155,7 +155,7 @@ INSERT INTO ajax_ops VALUES (NULL, 'remarks_config_save', 'Slash::Remarks', 'ajaxConfigSave', 'ajax_admin', 'createuse'); # signoff -INSERT INTO ajax_ops VALUES (NULL, 'admin_signoff', 'Slash::Admin', 'ajax_signoff', 'ajax_admin', 'use'); +INSERT INTO ajax_ops VALUES (NULL, 'admin_signoff', 'Slash::Admin', 'ajax_signoff', 'ajax_user_static', 'createuse'); # slashboxes INSERT INTO ajax_ops VALUES (NULL, 'admin_slashdbox', 'Slash::Admin', 'ajax_slashdbox', 'ajax_admin', 'createuse'); Modified: slashjp/branches/upstream/current/plugins/Ajax/templates/edit_comment;ajax;default =================================================================== --- slashjp/branches/upstream/current/plugins/Ajax/templates/edit_comment;ajax;default 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/plugins/Ajax/templates/edit_comment;ajax;default 2008-04-01 03:35:14 UTC (rev 560) @@ -20,16 +20,16 @@ edit_comment __template__
    -[% IF pid %] - [% PROCESS titlebar title="Reply to: $reply.subject" %] -[% ELSE %] - [% PROCESS titlebar title="Reply to: XXXXX" %] -[% END %] +[% this_title = pid ? reply.subject : discussion.title; + this_title = this_title | strip_html; + PROCESS titlebar title="Reply to: $this_title" %] +

    If you have difficulty with this form, please use the old form.

    + [% IF user.is_anon %]

    [% IF constants.allow_anonymous %] You are not logged in. You can log -in now, or Create an Account/ +in now, or Create an Account. [% ELSE %] You are not logged in. You can log in now, Create an Account, @@ -43,22 +43,28 @@

    [% IF pid %][% END %] -[% IF gotmodwarning %][% END # XXXXX %] + [% reskey_label = "reskey_reply_$pid"; PROCESS reskey_tag %] -

    -[Customize Posting Preferences]

    +

    +[% UNLESS user.is_anon %][Options] +[%- IF constants.allow_anonymous && user.karma > -1 && (discussion.commentstatus == 'enabled' || discussion.commentstatus == 'logged_in') -%] + Post Anonymously +[%- END %]

    [% END %]

    -[% IF constants.allow_anonymous && user.karma > -1 && !user.is_anon && (discussion.commentstatus == 'enabled' || discussion.commentstatus == 'logged_in') %] -

    Post Anonymously

    -[% END %] -
    -
    - - - +
    + + +[%- IF pid # not for root-level reply %] +[% END %] + + +
    [% END # IF !user.is_anon || constants.allow_anonymous %] @@ -67,4 +73,4 @@ __seclev__ 1000 __version__ -$Id: edit_comment;ajax;default,v 1.1 2008/02/28 21:39:31 pudge Exp $ +$Id: edit_comment;ajax;default,v 1.5 2008/03/19 08:25:31 pudge Exp $ Modified: slashjp/branches/upstream/current/plugins/Ajax/templates/prefs_d2;ajax;default =================================================================== --- slashjp/branches/upstream/current/plugins/Ajax/templates/prefs_d2;ajax;default 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/plugins/Ajax/templates/prefs_d2;ajax;default 2008-04-01 03:35:14 UTC (rev 560) @@ -42,7 +42,6 @@
    [% IF user.discussion2 && user.discussion2 == "slashdot" %] -
    Retrieve [% comment_q_name = (user.is_subscriber || user.is_admin) ? 'd2_comment_q_all' : 'd2_comment_q'; comment_q = Slash.db.getDescriptions(comment_q_name); @@ -54,7 +53,6 @@ comment_order_def = user.d2_comment_order || 0; # score Slash.createSelect('d2_comment_order', comment_order, comment_order_def, 1) %] Comments First
    -
    [% END %] -
    +
    Never show link domains
    Show the links domain only in recommended situations
    Always show link domains -
    +
    @@ -112,4 +110,4 @@ __seclev__ 500 __version__ -$Id: prefs_d2;ajax;default,v 1.12 2008/02/28 17:03:12 entweichen Exp $ +$Id: prefs_d2;ajax;default,v 1.13 2008/03/12 14:14:59 entweichen Exp $ Modified: slashjp/branches/upstream/current/plugins/Email/templates/dispStory;email;default =================================================================== --- slashjp/branches/upstream/current/plugins/Email/templates/dispStory;email;default 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/plugins/Email/templates/dispStory;email;default 2008-04-01 03:35:14 UTC (rev 560) @@ -56,7 +56,7 @@ To opt-out of further emailings: [% thisurl %]/email.pl?op=optout_form -Copyright 1997-2005 [% constants.sitepublisher %]. All rights reserved. +Copyright 1997-2008 [% constants.sitepublisher %]. All rights reserved. __version__ -$Id: dispStory;email;default,v 1.9 2005/03/30 23:41:45 pudge Exp $ +$Id: dispStory;email;default,v 1.10 2008/03/13 14:22:37 entweichen Exp $ Modified: slashjp/branches/upstream/current/plugins/FAQSlashdot/faq/friends.shtml =================================================================== --- slashjp/branches/upstream/current/plugins/FAQSlashdot/faq/friends.shtml 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/plugins/FAQSlashdot/faq/friends.shtml 2008-04-01 03:35:14 UTC (rev 560) @@ -3,18 +3,25 @@ Slashdot FAQ - Friends and Journals - + - - -
    +
    +
    +

    Friends and Journals

    +
    +
    + +

    Where is my journal?

    Your journal can be found at http://slashdot.org/my/journal.

    Modified: slashjp/branches/upstream/current/plugins/FireHose/FireHose.pm =================================================================== --- slashjp/branches/upstream/current/plugins/FireHose/FireHose.pm 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/plugins/FireHose/FireHose.pm 2008-04-01 03:35:14 UTC (rev 560) @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. # Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: FireHose.pm,v 1.223 2008/02/27 02:37:05 tvroom Exp $ +# $Id: FireHose.pm,v 1.226 2008/03/18 16:16:02 tvroom Exp $ package Slash::FireHose; @@ -41,7 +41,7 @@ use base 'Slash::DB::MySQL'; use vars qw($VERSION); -($VERSION) = ' $Revision: 1.223 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.226 $ ' =~ /\$Revision:\s+([^\s]+)/; sub createFireHose { my($self, $data) = @_; $data->{dept} ||= ""; @@ -561,7 +561,7 @@ push @where, "popularity >= $pop_q"; } } - if ($user->{is_admin}) { + if ($user->{is_admin} || $user->{acl}{signoff_allowed}) { my $signoff_label = 'sign' . $user->{uid} . 'ed'; if ($options->{unsigned}) { @@ -1124,7 +1124,7 @@ my $newtagspreloadtext = join ' ', @newtagspreload; #print STDERR "ajaxGetUserFirehose $newtagspreloadtext\n\n"; - return slashDisplay('tagsfirehosedivuser', { + return slashDisplay($form->{nodnix} ? 'tagsnodnixuser' : 'tagsfirehosedivuser', { id => $id, newtagspreloadtext => $newtagspreloadtext, }, { Return => 1 }); @@ -1516,9 +1516,13 @@ } +# Return a positive number if data was altered, 0 if it was not, +# or undef on error. + sub setFireHose { my($self, $id, $data) = @_; - return unless $id && $data; + return undef unless $id && $data; + return 0 if !%$data; my $id_q = $self->sqlQuote($id); my $mcd = $self->getMCD(); @@ -1547,7 +1551,7 @@ $self->setGlobjAdminnote($globjid, $note); } - return if !keys %$data; + return 0 if !keys %$data; my $text_data = {}; @@ -1556,9 +1560,11 @@ $text_data->{bodytext} = delete $data->{bodytext} if exists $data->{bodytext}; $text_data->{media} = delete $data->{media} if exists $data->{media}; - $self->sqlUpdate('firehose', $data, "id=$id_q"); - $self->sqlUpdate('firehose_text', $text_data, "id=$id_q") if keys %$text_data; - + my $rows = $self->sqlUpdate('firehose', $data, "id=$id_q"); +#{ use Data::Dumper; my $dstr = Dumper($data); $dstr =~ s/\s+/ /g; print STDERR "setFireHose A rows=$rows for id=$id_q data: $dstr\n"; } + $rows += $self->sqlUpdate('firehose_text', $text_data, "id=$id_q") if keys %$text_data; +#{ use Data::Dumper; my $dstr = Dumper($text_data); $dstr =~ s/\s+/ /g; print STDERR "setFireHose B rows=$rows for id=$id_q data: $dstr\n"; } + if ($mcd) { $mcd->delete("$mcdkey:$id", 3); } @@ -1570,6 +1576,8 @@ # $status = 'deleted' if $data->{accepted} eq 'yes' || $data->{rejected} eq 'yes'; $searchtoo->storeRecords(firehose => $id, { $status => 1 }); } + + return $rows; } sub dispFireHose { @@ -1595,6 +1603,9 @@ return [] unless $item && $user->{is_admin}; my $subnotes_ref = []; my $sub_memory = $self->getSubmissionMemory(); + my $url = ""; + $url = $self->getUrl($item->{url_id}) if $item->{url_id}; + foreach my $memory (@$sub_memory) { my $match = $memory->{submatch}; @@ -1602,7 +1613,8 @@ $item->{name} =~ m/$match/i || $item->{title} =~ m/$match/i || $item->{ipid} =~ m/$match/i || - $item->{introtext} =~ m/$match/i) { + $item->{introtext} =~ m/$match/i || + $url =~ m/$match/i) { push @$subnotes_ref, $memory; } } @@ -2625,4 +2637,4 @@ =head1 VERSION -$Id: FireHose.pm,v 1.223 2008/02/27 02:37:05 tvroom Exp $ +$Id: FireHose.pm,v 1.226 2008/03/18 16:16:02 tvroom Exp $ Modified: slashjp/branches/upstream/current/plugins/FireHose/PLUGIN =================================================================== --- slashjp/branches/upstream/current/plugins/FireHose/PLUGIN 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/plugins/FireHose/PLUGIN 2008-04-01 03:35:14 UTC (rev 560) @@ -1,4 +1,4 @@ -# $Id: PLUGIN,v 1.29 2008/02/19 14:45:30 scc Exp $ +# $Id: PLUGIN,v 1.30 2008/03/03 14:11:11 scc Exp $ name=FireHose description="FireHose" css=firehose.css @@ -32,6 +32,7 @@ template=templates/tagsfirehosedivadmin;misc;default template=templates/tagsfirehosedivtagbox;misc;default template=templates/tagsfirehosedivuser;misc;default +template=templates/tagsnodnixuser;misc;default task=firehose_reject_old.pl task=firehose_backend.pl task=firehose_get_thumbnails.pl Modified: slashjp/branches/upstream/current/plugins/FireHose/firehose.css =================================================================== --- slashjp/branches/upstream/current/plugins/FireHose/firehose.css 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/plugins/FireHose/firehose.css 2008-04-01 03:35:14 UTC (rev 560) @@ -449,9 +449,15 @@ .embed #nod-user-tags, #console #nod-input {left: 63px !important;} .embed #nix-user-tags, #console #nix-input {left: 68px !important;} .embed #nodmenu ul, #console #nodmenu ul {margin: 0 0 0 43px; background: #222; opacity: .9; border: 1px solid #111;} -ol#nod-hardened, ol#nix-hardened, ol#nod-hardened li, ol#nix-hardened li {background: black !important;} -ol#nod-hardened, ol#nix-hardened {margin-left: 0 !important; padding-left: 0 !important;} +ol#nod-hardened, ol#nix-hardened, ol#nod-hardened li, ol#nix-hardened li {position: relative; background: black !important;} +ol#nod-hardened, ol#nix-hardened {margin-left: 0 !important; padding-left: 0 !important; cursor: pointer;} +.tag-actions {display: none; position: absolute; opacity: 0.6; top: -0.75em; right: 0; width: 1.5em; font-size: 120%; text-align: center; color: black; background-color: white; -moz-border-radius: 0.1em; -webkit-border-radius: 0.1em;} +a.not-tag, a.del-tag {text-decoration: none;} +li:hover .tag-actions {display: inline;} +li .tag-actions:hover {opacity: 0.9;} +li .tag-actions .not-tag:hover, li .tag-actions .del-tag:hover {color: red;} + .article .title, .article h3, .article .generaltitle {border: none !important} .article .generaltitle, #firehoselist .article .title, .article h3 {line-height: 170% !important;} .briefarticle .generaltitle, .briefarticle .title, .briefarticle h3 {line-height: 160% !important;} Modified: slashjp/branches/upstream/current/plugins/FireHose/templates/firehose_tags_top;misc;default =================================================================== --- slashjp/branches/upstream/current/plugins/FireHose/templates/firehose_tags_top;misc;default 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/plugins/FireHose/templates/firehose_tags_top;misc;default 2008-04-01 03:35:14 UTC (rev 560) @@ -26,7 +26,7 @@ [%- END -%] [%- tags_seen.${parts.0} = 1 -%] [%- END -%] - [%- IF item.type == "story" -%][% IF user.is_admin %][% PROCESS signoff stoid=item.srcid fhid = item.id %][% END %][% END %] + [%- IF item.type == "story" -%][% IF user.is_admin || user.acl.signoff_allowed %][% PROCESS signoff stoid=item.srcid fhid = item.id %][% END %][% END %] [% IF item.type == "feed" && user.is_admin %] [% feed_user = Slash.db.getUser(item.uid, "nickname"); %] [% feed_user | strip_literal %] @@ -35,4 +35,4 @@ __seclev__ 10000 __version__ -$Id: firehose_tags_top;misc;default,v 1.22 2007/08/22 20:26:14 scc Exp $ +$Id: firehose_tags_top;misc;default,v 1.23 2008/03/18 16:16:02 tvroom Exp $ Added: slashjp/branches/upstream/current/plugins/FireHose/templates/tagsnodnixuser;misc;default =================================================================== --- slashjp/branches/upstream/current/plugins/FireHose/templates/tagsnodnixuser;misc;default (rev 0) +++ slashjp/branches/upstream/current/plugins/FireHose/templates/tagsnodnixuser;misc;default 2008-04-01 03:35:14 UTC (rev 560) @@ -0,0 +1,23 @@ +__section__ +default +__description__ +id = id +newtagspreloadtext = text to preload the newtags-# field with + +WARNING: keep the related string in nodnix.js in sync with the

  • expansion, below +__title__ + +__page__ +misc +__lang__ +en_US +__name__ +tagsnodnixuser +__template__ +[% FOREACH tag = newtagspreloadtext.split(' ') %] +
  • [% tag %]! x
  • +[% END %] +__seclev__ +10000 +__version__ +$Id: tagsnodnixuser;misc;default,v 1.4 2008/03/03 20:54:00 scc Exp $ Modified: slashjp/branches/upstream/current/plugins/Messages/templates/dailyheadlines;messages;default =================================================================== --- slashjp/branches/upstream/current/plugins/Messages/templates/dailyheadlines;messages;default 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/plugins/Messages/templates/dailyheadlines;messages;default 2008-04-01 03:35:14 UTC (rev 560) @@ -25,9 +25,9 @@ [% END %] -Copyright 1997-2007 [% constants.sitepublisher %]. All rights reserved. +Copyright 1997-2008 [% constants.sitepublisher %]. All rights reserved. __seclev__ 500 __version__ -$Id: dailyheadlines;messages;default,v 1.13 2007/01/02 18:35:59 cowboyneal Exp $ +$Id: dailyheadlines;messages;default,v 1.14 2008/03/13 14:13:18 entweichen Exp $ Modified: slashjp/branches/upstream/current/plugins/Messages/templates/dailynews;messages;default =================================================================== --- slashjp/branches/upstream/current/plugins/Messages/templates/dailynews;messages;default 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/plugins/Messages/templates/dailynews;messages;default 2008-04-01 03:35:14 UTC (rev 560) @@ -52,9 +52,9 @@ [% END %] -Copyright 1997-2006 [% constants.sitepublisher %]. All rights reserved. +Copyright 1997-2008 [% constants.sitepublisher %]. All rights reserved. __seclev__ 500 __version__ -$Id: dailynews;messages;default,v 1.14 2006/01/25 16:11:42 cowboyneal Exp $ +$Id: dailynews;messages;default,v 1.15 2008/03/13 14:14:08 entweichen Exp $ Modified: slashjp/branches/upstream/current/plugins/Moderation/Moderation.pm =================================================================== --- slashjp/branches/upstream/current/plugins/Moderation/Moderation.pm 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/plugins/Moderation/Moderation.pm 2008-04-01 03:35:14 UTC (rev 560) @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. # Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Moderation.pm,v 1.4 2008/02/21 01:01:52 pudge Exp $ +# $Id: Moderation.pm,v 1.9 2008/03/19 08:25:31 pudge Exp $ package Slash::Moderation; @@ -17,7 +17,7 @@ use base 'Slash::DB::Utility'; use base 'Slash::DB::MySQL'; -($VERSION) = ' $Revision: 1.4 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.9 $ ' =~ /\$Revision:\s+([^\s]+)/; sub new { my($class, $user) = @_; @@ -91,10 +91,12 @@ $self->countUsers({ max => 1 }), $self->getReasons ); - $html->{$score} = "(Score:$points"; + $html->{$score} = "Score:$points"; + $html->{$score} = qq[$html->{$score}] + if $constants->{modal_prefs_active} && !$user->{is_anon}; $html->{$score} .= ", $reasons->{$comment->{reason}}{name}" if $comment->{reason} && $reasons->{$comment->{reason}}; - $html->{$score} .= ")"; + $html->{$score} = "($html->{$score})"; my $ptstr = $user->{points} == 1 ? 'point' : 'points'; $html->{$select} = "Moderated '$reasons->{$reason}{name}.' $user->{points} $ptstr left."; Modified: slashjp/branches/upstream/current/plugins/Rating/Rating.pm =================================================================== --- slashjp/branches/upstream/current/plugins/Rating/Rating.pm 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/plugins/Rating/Rating.pm 2008-04-01 03:35:14 UTC (rev 560) @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. # Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Rating.pm,v 1.7 2005/03/11 19:58:12 pudge Exp $ +# $Id: Rating.pm,v 1.8 2008/03/19 08:25:31 pudge Exp $ package Slash::Rating; @@ -16,7 +16,7 @@ use base 'Slash::DB::Utility'; use base 'Slash::DB::MySQL'; -($VERSION) = ' $Revision: 1.7 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.8 $ ' =~ /\$Revision:\s+([^\s]+)/; #Right, this is not needed at the moment but will be in the near future sub new { @@ -52,13 +52,13 @@ my $extras; $extras = $slashdb->getNexusExtrasForChosen({$disc_skin->{nexus} => 1}, {content_type => "comment"}) if $disc_skin && $disc_skin->{nexus}; - return unless $extras; + return 0 unless $extras; foreach my $extra(@$extras) { $can_create_vote=1 if $extra->[1] eq "comment_vote"; } - return unless $can_create_vote; + return 0 unless $can_create_vote; my $active = "yes"; my $val = 0; Modified: slashjp/branches/upstream/current/plugins/ResKey/mysql_dump.sql =================================================================== --- slashjp/branches/upstream/current/plugins/ResKey/mysql_dump.sql 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/plugins/ResKey/mysql_dump.sql 2008-04-01 03:35:14 UTC (rev 560) @@ -1,5 +1,5 @@ # -# $Id: mysql_dump.sql,v 1.20 2007/11/01 20:35:19 jamiemccarthy Exp $ +# $Id: mysql_dump.sql,v 1.21 2008/03/19 21:09:47 pudge Exp $ # ### NOTE: reserved reskey IDs: @@ -54,7 +54,7 @@ INSERT INTO reskey_resource_checks VALUES (NULL, 1, 'all', 'Slash::ResKey::Checks::AL2::NoPost', 501); INSERT INTO reskey_resource_checks VALUES (NULL, 1, 'all', 'Slash::ResKey::Checks::AL2::Spammer', 531); INSERT INTO reskey_resource_checks VALUES (NULL, 1, 'all', 'Slash::ResKey::Checks::Duration', 601); -INSERT INTO reskey_resource_checks VALUES (NULL, 1, 'use', 'Slash::ResKey::Checks::ProxyScan', 1001); +#INSERT INTO reskey_resource_checks VALUES (NULL, 1, 'use', 'Slash::ResKey::Checks::ProxyScan', 1001); # dummy example of how to disable the Slash::ResKey::Checks::User check for "touch" # (maybe, for example, because the check isn't needed) @@ -66,8 +66,8 @@ INSERT INTO reskey_vars VALUES (1, 'user_seclev', 0, 'Minimum seclev to use resource'); INSERT INTO reskey_vars VALUES (1, 'duration_max-uses', 30, 'how many uses per timeframe'); INSERT INTO reskey_vars VALUES (1, 'duration_max-failures', 10, 'how many failures per reskey'); -INSERT INTO reskey_vars VALUES (1, 'duration_uses', 120, 'min duration (in seconds) between uses'); -INSERT INTO reskey_vars VALUES (1, 'duration_creation-use', 5, 'min duration between (in seconds) creation and use'); +INSERT INTO reskey_vars VALUES (1, 'duration_uses', 60, 'min duration (in seconds) between uses'); +INSERT INTO reskey_vars VALUES (1, 'duration_creation-use', 10, 'min duration between (in seconds) creation and use'); Modified: slashjp/branches/upstream/current/plugins/Submit/submit.pl =================================================================== --- slashjp/branches/upstream/current/plugins/Submit/submit.pl 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/plugins/Submit/submit.pl 2008-04-01 03:35:14 UTC (rev 560) @@ -2,7 +2,7 @@ # This code is a part of Slash, and is released under the GPL. # Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: submit.pl,v 1.144 2007/10/23 20:56:46 tvroom Exp $ +# $Id: submit.pl,v 1.145 2008/03/18 16:45:13 tvroom Exp $ use strict; use Slash 2.003; # require Slash 2.3.x @@ -265,6 +265,9 @@ } } + my $url = ""; + $url = $slashdb->getUrl($sub->{url_id}) if $sub->{url_id}; + foreach my $memory (@$sub_memory) { my $match = $memory->{submatch}; @@ -272,7 +275,8 @@ $sub->{name} =~ m/$match/i || $sub->{subj} =~ m/$match/i || $sub->{ipid} =~ m/$match/i || - $sub->{story} =~ m/$match/i) { + $sub->{story} =~ m/$match/i || + $url =~ m/$match/i ) { push @$subnotes_ref, $memory; } } Modified: slashjp/branches/upstream/current/plugins/TagModeration/TagModeration.pm =================================================================== --- slashjp/branches/upstream/current/plugins/TagModeration/TagModeration.pm 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/plugins/TagModeration/TagModeration.pm 2008-04-01 03:35:14 UTC (rev 560) @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. # Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: TagModeration.pm,v 1.5 2008/02/21 01:01:52 pudge Exp $ +# $Id: TagModeration.pm,v 1.10 2008/03/19 08:25:31 pudge Exp $ package Slash::TagModeration; @@ -17,7 +17,7 @@ use base 'Slash::DB::Utility'; use base 'Slash::DB::MySQL'; -($VERSION) = ' $Revision: 1.5 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.10 $ ' =~ /\$Revision:\s+([^\s]+)/; sub new { my($class, $user) = @_; @@ -91,10 +91,12 @@ $self->countUsers({ max => 1 }), $self->getReasons ); - $html->{$score} = "(Score:$points"; + $html->{$score} = "Score:$points"; + $html->{$score} = qq[$html->{$score}] + if $constants->{modal_prefs_active} && !$user->{is_anon}; $html->{$score} .= ", $reasons->{$comment->{reason}}{name}" if $comment->{reason} && $reasons->{$comment->{reason}}; - $html->{$score} .= ")"; + $html->{$score} = "($html->{$score})"; my $ptstr = $user->{points} == 1 ? 'point' : 'points'; $html->{$select} = "Moderated '$reasons->{$reason}{name}.' $user->{points} $ptstr left."; Modified: slashjp/branches/upstream/current/plugins/Tags/PLUGIN =================================================================== --- slashjp/branches/upstream/current/plugins/Tags/PLUGIN 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/plugins/Tags/PLUGIN 2008-04-01 03:35:14 UTC (rev 560) @@ -1,4 +1,4 @@ -# $Id: PLUGIN,v 1.14 2007/12/06 02:49:31 jamiemccarthy Exp $ +# $Id: PLUGIN,v 1.15 2008/03/19 14:49:35 jamiemccarthy Exp $ name=Tags description="Tags" htdoc=tags.pl @@ -6,6 +6,7 @@ mysql_schema=mysql_schema.sql requiresplugin=Ajax task=tagbox.pl +task=tags_tagnamecache.pl task=tags_udc.pl task=tags_updateclouts.pl template=templates/data;tags;default Modified: slashjp/branches/upstream/current/plugins/Tags/Tags.pm =================================================================== --- slashjp/branches/upstream/current/plugins/Tags/Tags.pm 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/plugins/Tags/Tags.pm 2008-04-01 03:35:14 UTC (rev 560) @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. # Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Tags.pm,v 1.101 2008/02/28 19:51:01 jamiemccarthy Exp $ +# $Id: Tags.pm,v 1.107 2008/03/19 14:49:35 jamiemccarthy Exp $ package Slash::Tags; @@ -17,7 +17,7 @@ use base 'Slash::DB::Utility'; use base 'Slash::DB::MySQL'; -($VERSION) = ' $Revision: 1.101 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.107 $ ' =~ /\$Revision:\s+([^\s]+)/; # FRY: And where would a giant nerd be? THE LIBRARY! @@ -603,6 +603,9 @@ } # Is it descriptive? + # XXX this should be optimized by retrieving the list of _all_ + # descriptive tagnames in memcached or the local closure and + # doing a lookup on that. if ($types->{describe} && !$clid) { $tn_data = $self->getTagnameDataFromId($tagnameid); $clid = $types->{describe} if $tn_data->{descriptive}; @@ -685,7 +688,8 @@ for my $uid (keys %uid) { # XXX getUser($foo, 'clout') does not work at the moment, # so getUser($foo)->{clout} is used instead - $user_clout_hr->{$uid} = $self->getUser($uid)->{clout}; + my $user = $self->getUser($uid); + $user_clout_hr->{$uid} = $self->getUser($uid)->{clout} if $user; } @@ -704,7 +708,9 @@ $tagname_clid = $default_clout_clid; } my $tagname_clout_name = $clout_types->{ $tagname_clid }; - $tag_hr->{user_clout} = $mult * $user_clout_hr ->{$tag_hr->{uid}}{$tagname_clout_name}; + my $clout = $user_clout_hr->{$tag_hr->{uid}}; + my $clout_specific = $clout ? $clout->{$tagname_clout_name} : 0; + $tag_hr->{user_clout} = $mult * $clout_specific; $tag_hr->{total_clout} = $tag_hr->{tag_clout} * $tag_hr->{tagname_clout} * $tag_hr->{user_clout}; } } @@ -849,7 +855,7 @@ # my $value = $mcd->get("$mcdkey$name"); # return $value if defined $value; # } - my $private_clause = $options->{include_private} ? '' : " AND private='no'"; + my $private_clause = ref($options) && $options->{include_private} ? '' : " AND private='no'"; my $id = $self->getTagnameidFromNameIfExists($name); return [ ] if !$id; my $hr_ar = $self->sqlSelectAllHashrefArray( @@ -965,7 +971,7 @@ my($self, $constants, $user, $form) = @_; my $sidenc = $form->{sidenc}; - my $sid = $sidenc; $sid =~ tr{:}{/}; + my $sid = $sidenc; $sid =~ tr{-}{/}; my $stoid = $self->getStoidFromSid($sid); my $tags_reader = getObject('Slash::Tags', { db_type => 'reader' }); #print STDERR scalar(localtime) . " ajaxGetUserStory for stoid=$stoid sidenc=$sidenc tr=$tags_reader\n"; @@ -1023,7 +1029,7 @@ sub ajaxGetAdminStory { my($slashdb, $constants, $user, $form) = @_; my $sidenc = $form->{sidenc}; - my $sid = $sidenc; $sid =~ tr{:}{/}; + my $sid = $sidenc; $sid =~ tr{-}{/}; if (!$sid || $sid !~ regexSid() || !$user->{is_admin}) { return getData('error', {}, 'tags'); @@ -1155,7 +1161,7 @@ sub ajaxCreateForStory { my($slashdb, $constants, $user, $form) = @_; my $sidenc = $form->{sidenc}; - my $sid = $sidenc; $sid =~ tr{:}{/}; + my $sid = $sidenc; $sid =~ tr{-}{/}; my $tags = getObject('Slash::Tags'); my $tagsstring = $form->{tags}; if (!$sid || $sid !~ regexSid() || $user->{is_anon} || !$tags) { @@ -1189,6 +1195,30 @@ return $retval; } +sub ajaxDeactivateTag { + my($self, $constants, $user, $form) = @_; + my $type = $form->{type} || "stories"; + my $tags = getObject('Slash::Tags'); # XXX isn't this the same as $self? -Jamie + + my ($table, $id); + + if ($type eq "firehose") { + my $firehose = getObject("Slash::FireHose"); + my $item = $firehose->getFireHose($form->{id}); + ($table, $id) = $tags->getGlobjTarget($item->{globjid}); + } else { + # XXX doesn't work yet for stories or urls + return; + } + + $tags->deactivateTag({ + uid => $user->{uid}, + name => $form->{tag}, + table => $table, + id => $id, + }); +} + sub ajaxProcessAdminTags { my($slashdb, $constants, $user, $form) = @_; #print STDERR "ajaxProcessAdminTags\n"; @@ -1197,7 +1227,7 @@ my($id, $table, $sid, $sidenc, $itemid); if ($type eq "stories") { $sidenc = $form->{sidenc}; - $sid = $sidenc; $sid =~ tr{:}{/}; + $sid = $sidenc; $sid =~ tr{-}{/}; $id = $slashdb->getStoidFromSid($sid); $table = "stories"; } elsif ($type eq "urls") { @@ -1293,7 +1323,7 @@ my $table; if ($form->{type} eq "stories") { my $sidenc = $form->{sidenc}; - my $sid = $sidenc; $sid =~ tr{:}{/}; + my $sid = $sidenc; $sid =~ tr{-}{/}; $id = $slashdb->getStoidFromSid($sid); $table = "stories" } elsif ($form->{type} eq "urls") { @@ -1380,6 +1410,13 @@ my $len = length($prefix); my $notize = $form->{prefix} =~ /^([-!])/ ? $1 : ''; + my $minlen = $constants->{tags_prefixlist_minlen} || 3; + if ($len < $minlen) { + # Too short to give a meaningful suggestion, and the + # shorter the prefix the longer the DB query takes. + return ''; + } + my $tnhr = $tags_reader->listTagnamesByPrefix($prefix); my @priority = @@ -1683,10 +1720,10 @@ sub listTagnamesActive { my($self, $options) = @_; my $constants = getCurrentStatic(); - my $max_num = $options->{max_num} || 100; - my $seconds = $options->{seconds} || (3600*6); - my $include_private = $options->{include_private} || 0; - my $min_slice = $options->{min_slice} || 0; + my $max_num = ref($options) && $options->{max_num} || 100; + my $seconds = ref($options) && $options->{seconds} || (3600*6); + my $include_private = ref($options) && $options->{include_private} || 0; + my $min_slice = ref($options) && $options->{min_slice} || 0; $min_slice = 0 if !$constants->{plugin}{FireHose}; # This seems like a horrendous query, but I _think_ it will run @@ -1791,8 +1828,8 @@ sub listTagnamesRecent { my($self, $options) = @_; my $constants = getCurrentStatic(); - my $seconds = $options->{seconds} || (3600*6); - my $include_private = $options->{include_private} || 0; + my $seconds = ref($options) && $options->{seconds} || (3600*6); + my $include_private = ref($options) && $options->{include_private} || 0; my $private_clause = $include_private ? '' : " AND private='no'"; my $recent_ar = $self->sqlSelectColArrayref( 'DISTINCT tagnames.tagname', @@ -1820,24 +1857,65 @@ $a2 cmp $b2 || $a1 cmp $b1; } +{ # closure +my $tagname_cache_lastcheck = 1; sub listTagnamesByPrefix { my($self, $prefix_str, $options) = @_; my $constants = getCurrentStatic(); my $reader = getObject('Slash::DB', { db_type => 'reader' }); - my $like_str = $self->sqlQuote("$prefix_str%"); - my $minc = $self->sqlQuote($options->{minc} || $constants->{tags_prefixlist_minc} || 4); - my $mins = $self->sqlQuote($options->{mins} || $constants->{tags_prefixlist_mins} || 3); - my $num = $options->{num} || $constants->{tags_prefixlist_num}; - $num = 10 if !$num || $num !~ /^(\d+)$/ || $num < 1; + my $ret_hr; my $mcd = undef; $mcd = $self->getMCD() unless $options; my $mcdkey = "$self->{_mcd_keyprefix}:tag_prefx:"; if ($mcd) { - my $ret_str = $mcd->get("$mcdkey$prefix_str"); - return $ret_str if $ret_str; + $ret_hr = $mcd->get("$mcdkey$prefix_str"); + return $ret_hr if $ret_hr; } + # If the tagname_cache table has been filled, use it. + # Otherwise, perform an expensive query directly. + # The logic is that $tagname_cache_lastcheck stays a + # large positive number (a timestamp) until we determine + # that the table _does_ have rows, at which point that + # number drops to 0. Once its value hits 0, it is never + # checked again. + if ($tagname_cache_lastcheck > 0 && $tagname_cache_lastcheck < time()-3600) { + my $rows = $reader->sqlCount('tagname_cache'); + $tagname_cache_lastcheck = $rows ? 0 : time; + } + my $use_cache_table = $tagname_cache_lastcheck ? 0 : 1; + if ($use_cache_table) { + $ret_hr = $self->listTagnamesByPrefix_cache($prefix_str, $options); + } else { + $ret_hr = $self->listTagnamesByPrefix_direct($prefix_str, $options); + } + + if ($mcd) { + # The expiration we use is much longer than the tags_cache_expire + # var since the cache data changes only once a day. + $mcd->set("$mcdkey$prefix_str", $ret_hr, 3600); + } + + return $ret_hr; +} +} + +# This is a quick-and-dirty (and not very accurate) estimate which +# is only performed for a site which has not built its tagname_cache +# table yet. Hopefully most sites will use this the first day the +# Tags plugin is installed and then never again. + +sub listTagnamesByPrefix_direct { + my($self, $prefix_str, $options) = @_; + my $constants = getCurrentStatic(); + my $like_str = $self->sqlQuote("$prefix_str%"); + my $minc = $self->sqlQuote($options->{minc} || $constants->{tags_prefixlist_minc} || 4); + my $mins = $self->sqlQuote($options->{mins} || $constants->{tags_prefixlist_mins} || 3); + my $num = $options->{num} || $constants->{tags_prefixlist_num}; + $num = 10 if !$num || $num !~ /^(\d+)$/ || $num < 1; + + my $reader = getObject('Slash::DB', { db_type => 'reader' }); my $ar = $reader->sqlSelectAllHashrefArray( 'tagname, COUNT(DISTINCT tags.uid) AS c, @@ -1856,13 +1934,25 @@ for my $hr (@$ar) { $ret_hr->{ $hr->{tagname} } = $hr->{sc}; } - if ($mcd) { - my $mcdexp = $constants->{tags_cache_expire} || 180; - $mcd->set("$mcdkey$prefix_str", $ret_hr, $mcdexp) - } return $ret_hr; } +sub listTagnamesByPrefix_cache { + my($self, $prefix_str, $options) = @_; + my $constants = getCurrentStatic(); + my $like_str = $self->sqlQuote("$prefix_str%"); + my $num = $options->{num} || $constants->{tags_prefixlist_num}; + $num = 10 if !$num || $num !~ /^(\d+)$/ || $num < 1; + + my $reader = getObject('Slash::DB', { db_type => 'reader' }); + my $ret_hr = $reader->sqlSelectAllKeyValue( + 'tagname, weight', + 'tagname_cache', + "tagname LIKE $like_str", + "ORDER BY weight DESC LIMIT $num"); + return $ret_hr; +} + sub getPrivateTagnames { my ($self) = @_; my $user = getCurrentUser; Modified: slashjp/branches/upstream/current/plugins/Tags/mysql_dump.sql =================================================================== --- slashjp/branches/upstream/current/plugins/Tags/mysql_dump.sql 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/plugins/Tags/mysql_dump.sql 2008-04-01 03:35:14 UTC (rev 560) @@ -1,5 +1,5 @@ # -# $Id: mysql_dump.sql,v 1.34 2008/02/28 19:51:01 jamiemccarthy Exp $ +# $Id: mysql_dump.sql,v 1.36 2008/03/11 19:57:26 jamiemccarthy Exp $ # INSERT INTO vars (name, value, description) VALUES ('memcached_exptime_tags', '3600', 'Seconds to cache tag data in memcached'); @@ -10,6 +10,7 @@ INSERT INTO vars (name, value, description) VALUES ('tags_cache_expire', '180', 'Local data cache expiration for tags'); INSERT INTO vars (name, value, description) VALUES ('tags_list_mintc', '4', 'Minimum value of total_clout for tagged items shown at /tags/foo'); INSERT INTO vars (name, value, description) VALUES ('tags_prefixlist_minc', '4', 'Minimum value of c (count) for tagnames returned by listTagnamesByPrefix'); +INSERT INTO vars (name, value, description) VALUES ('tags_prefixlist_minlen', '3', 'Minimum length of a tag prefix to bother looking up suggestions for'); INSERT INTO vars (name, value, description) VALUES ('tags_prefixlist_mins', '3', 'Minimum value of s (clout sum) for tagnames returned by listTagnamesByPrefix'); INSERT INTO vars (name, value, description) VALUES ('tags_prefixlist_num', '10', 'Number of tagnames returned by listTagnamesByPrefix'); INSERT INTO vars (name, value, description) VALUES ('tags_prefixlist_priority', 'back bookmark feed hold journal none quik submission story', 'Tagnames to give priority to on autocomplete'); @@ -48,6 +49,7 @@ INSERT INTO ajax_ops VALUES (NULL, 'tags_admin_commands', 'Slash::Tags', 'ajaxProcessAdminTags', 'ajax_admin', 'use'); INSERT INTO ajax_ops VALUES (NULL, 'tags_history', 'Slash::Tags', 'ajaxTagHistory', 'ajax_admin', 'createuse'); INSERT INTO ajax_ops VALUES (NULL, 'tags_list_tagnames', 'Slash::Tags', 'ajaxListTagnames', 'ajax_tags_read', 'createuse'); +INSERT INTO ajax_ops VALUES (NULL, 'tags_deactivate', 'Slash::Tags', 'ajaxDeactivateTag', 'ajax_tags_write', 'use'); INSERT INTO menus VALUES (NULL, 'tagszg', 'Active', 'active', '[% gSkin.rootdir %]/tags', 1, 1, 1); INSERT INTO menus VALUES (NULL, 'tagszg', 'Recent', 'recent', '[% gSkin.rootdir %]/tags/recent', 1, 1, 2); Modified: slashjp/branches/upstream/current/plugins/Tags/mysql_schema.sql =================================================================== --- slashjp/branches/upstream/current/plugins/Tags/mysql_schema.sql 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/plugins/Tags/mysql_schema.sql 2008-04-01 03:35:14 UTC (rev 560) @@ -1,5 +1,5 @@ # -# $Id: mysql_schema.sql,v 1.17 2007/09/26 21:25:51 jamiemccarthy Exp $ +# $Id: mysql_schema.sql,v 1.18 2008/03/19 14:49:36 jamiemccarthy Exp $ # DROP TABLE IF EXISTS tags; @@ -33,7 +33,19 @@ PRIMARY KEY tagnameid (tagnameid), UNIQUE tagname (tagname) ) TYPE=InnoDB; - + +# tagname_cache is not normalized because it's intended to be used +# for quick lookups. + +DROP TABLE IF EXISTS tagname_cache; +CREATE TABLE tagname_cache ( + tagnameid int UNSIGNED NOT NULL, + tagname VARCHAR(64) NOT NULL, + weight FLOAT UNSIGNED DEFAULT 0.0 NOT NULL, + PRIMARY KEY tagnameid (tagnameid), + UNIQUE tagname (tagname), +) TYPE=InnoDB; + DROP TABLE IF EXISTS tagname_params; CREATE TABLE tagname_params ( tagnameid int UNSIGNED NOT NULL, Modified: slashjp/branches/upstream/current/plugins/Tags/tagbox.pl =================================================================== --- slashjp/branches/upstream/current/plugins/Tags/tagbox.pl 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/plugins/Tags/tagbox.pl 2008-04-01 03:35:14 UTC (rev 560) @@ -2,7 +2,7 @@ # This code is a part of Slash, and is released under the GPL. # Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: tagbox.pl,v 1.18 2008/01/30 22:42:38 jamiemccarthy Exp $ +# $Id: tagbox.pl,v 1.19 2008/03/10 20:39:02 jamiemccarthy Exp $ use strict; @@ -282,7 +282,7 @@ sub insert_feederlog { my($tagbox, $feeder_ar) = @_; for my $feeder_hr (@$feeder_ar) { -main::tagboxLog("addFeederInfo: tbid=$tagbox->{tbid} tagid=$feeder_hr->{tagid} affected_id=$feeder_hr->{affected_id} imp=$feeder_hr->{importance}"); +{ my $fstr = Dumper($feeder_hr); $fstr =~ s/\s+/ /g; main::tagboxLog("addFeederInfo: tbid=$tagbox->{tbid} f: $fstr"); } $tagboxdb->addFeederInfo($tagbox->{tbid}, $feeder_hr); } } @@ -300,6 +300,10 @@ for my $affected_hr (@$affected_ar) { my $tagbox = $tagboxdb->getTagboxes($affected_hr->{tbid}, [qw( object )]); #my $ad = Dumper($affected_hr); $ad =~ s/\s+/ /g; my $tb = Dumper($tagbox); $tb =~ s/\s+/ /g; print STDERR "r_t_u affected_hr: $ad tagbox: $tb\n"; +if ($affected_hr->{tbid} == 17) { +my $feeder_ar = $tagboxdb->sqlSelectAllHashrefArray('*', 'tagboxlog_feeder', "tbid=17 AND affected_id=$affected_hr->{affected_id}", 'ORDER BY tfid'); +print STDERR "r_t_u rows for tbid=17 id=$affected_hr->{affected_id}: " . Dumper($feeder_ar) +} $tagbox->{object}->run($affected_hr->{affected_id}); $tagboxdb->markTagboxRunComplete($affected_hr); last if time() >= $run_until || $task_exit_flag; Added: slashjp/branches/upstream/current/plugins/Tags/tags_tagnamecache.pl =================================================================== --- slashjp/branches/upstream/current/plugins/Tags/tags_tagnamecache.pl (rev 0) +++ slashjp/branches/upstream/current/plugins/Tags/tags_tagnamecache.pl 2008-04-01 03:35:14 UTC (rev 560) @@ -0,0 +1,144 @@ +#!/usr/bin/perl -w +# This code is a part of Slash, and is released under the GPL. +# Copyright 1997-2005 by Open Source Technology Group. See README +# and COPYING for more information, or see http://slashcode.com/. +# $Id: tags_tagnamecache.pl,v 1.1 2008/03/21 04:10:35 jamiemccarthy Exp $ + +# Once a day, rewrite the tags_tagnamecache table, used for finding +# tagname suggestions based on prefixes. + +use strict; +use vars qw( %task $me $task_exit_flag ); +use Slash::DB; +use Slash::Display; +use Slash::Utility; +use Slash::Constants ':slashd'; + +(my $VERSION) = ' $Revision: 1.1 $ ' =~ /\$Revision:\s+([^\s]+)/; + +$task{$me}{timespec} = "30 6 * * *"; +$task{$me}{timespec_panic_1} = ''; # not that important +$task{$me}{fork} = SLASHD_NOWAIT; + +$task{$me}{code} = sub { + my($virtual_user, $constants, $slashdb, $user) = @_; + my $tagsdb = getObject('Slash::Tags'); + my $tagsdb_reader = getObject('Slash::Tags', { db_type => 'reader' }); + my $daysback = $constants->{tags_tagnamecache_daysback} || 180; + my $min_tagid = getMinimumTagid($tagsdb, $daysback); + my $ar = getTagnameList($tagsdb_reader, $min_tagid); + my $rows_replaced = replaceTagnames($tagsdb, $ar); + my $rows_deleted = deleteTagnamesNotIn($tagsdb, $ar); + my $total_rows = $tagsdb->sqlCount('tagname_cache'); + return "replaced $rows_replaced, deleted $rows_deleted, total $total_rows"; +}; + +sub getMinimumTagid { + my($tagsdb, $daysback) = @_; + my $min = $tagsdb->sqlSelectNumericKeyAssumingMonotonic( + 'tags', 'min', 'tagid', + "created_at >= DATE_SUB(NOW(), INTERVAL $daysback DAY)"); + return $min; +} + +# For now, let's include private tagnames in this list. It's not +# revealing private information since it's completely aggregated, +# and while suggesting tagnames like 'nod' and 'nix' may not be +# helpful, suggesting 'troll' and 'interesting' seems OK. + +sub getTagnameList { + my($tagsdb_reader, $min_tagid) = @_; + $min_tagid ||= 1; + + my $constants = getCurrentStatic(); + my $minc = $tagsdb_reader->sqlQuote($constants->{tags_prefixlist_minc} || 4); + my $mins = $tagsdb_reader->sqlQuote($constants->{tags_prefixlist_mins} || 3); + # $maxnum is to prevent $tagnameid_str from exceeding MySQL limits. + # Default max_allowed_packet should be 16 MB, so an ~80K query + # should be perfectly fine. + my $maxnum = 10000; + + # Get the list of tagnameids sorted in a very rough order of + # "importance." + # Note that the query uses multiple columns to sort the data, + # but we skim off only the tagnameid on the client side since + # that's all we care about. + + my $tagnameid_ar = $tagsdb_reader->sqlSelectColArrayref( + 'tags.tagnameid, + COUNT(DISTINCT tags.uid) AS c, + SUM(tag_clout * IF(value IS NULL, 1, value)) AS s, + COUNT(DISTINCT tags.uid)/3 + SUM(tag_clout * IF(value IS NULL, 1, value)) AS sc', + 'tags, users_info, tagnames + LEFT JOIN tagname_params USING (tagnameid)', + "tagnames.tagnameid=tags.tagnameid + AND tags.uid=users_info.uid + AND tags.inactivated IS NULL + AND tagid >= $min_tagid", + "GROUP BY tags.tagnameid + HAVING c >= $minc AND s >= $mins + ORDER BY sc DESC, tagname ASC + LIMIT $maxnum"); + return [ ] if !$tagnameid_ar || !@$tagnameid_ar; + my $tagnameid_str = join(',', sort { $a <=> $b } @$tagnameid_ar); + + # Now get the total list of tags (which will be very large, + # so this is a slow query) + + my $tag_ar = $tagsdb_reader->sqlSelectAllHashrefArray( + '*, UNIX_TIMESTAMP(created_at) AS created_at_ut', + 'tags', + "tagnameid IN ($tagnameid_str) + AND tagid >= $min_tagid + AND tags.inactivated IS NULL"); + + # This will call getUser() for every uid in the above list and + # getTagnameidClid() for every tagnameid (up to 10,000). So + # this will be a very slow operation. + + $tagsdb_reader->addCloutsToTagArrayref($tag_ar); + + my $tagnameid_sum = { }; + for my $hr (@$tag_ar) { + $tagnameid_sum->{ $hr->{tagnameid} } ||= 0; + $tagnameid_sum->{ $hr->{tagnameid} } += $hr->{total_clout}; + } + my $ret_ar = [ ]; + for my $tagnameid (@$tagnameid_ar) { + my $sum = $tagnameid_sum->{$tagnameid}; + next unless $sum > 0; + my $tagname = $tagsdb_reader->getTagnameDataFromId($tagnameid)->{tagname}; + push @$ret_ar, { + tagnameid => $tagnameid, + tagname => $tagname, + weight => $sum, + }; + } + + return $ret_ar; +} + +sub replaceTagnames { + my($tagsdb, $ar) = @_; + my $rows = 0; + for my $hr (@$ar) { + $rows += $tagsdb->sqlReplace('tagname_cache', $hr); + Time::HiRes::sleep(0.01); + } + return $rows; +} + +sub deleteTagnamesNotIn { + my($tagsdb, $ar) = @_; + my $tagnameid_str = join(',', + sort { $a <=> $b } + map { $_->{tagnameid} } + @$ar + ); + my $rows = $tagsdb->sqlDelete('tagname_cache', + "tagnameid NOT IN ($tagnameid_str)"); + return $rows; +} + +1; + Modified: slashjp/branches/upstream/current/plugins/Tags/templates/tagsstorydivtagbox;misc;default =================================================================== --- slashjp/branches/upstream/current/plugins/Tags/templates/tagsstorydivtagbox;misc;default 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/plugins/Tags/templates/tagsstorydivtagbox;misc;default 2008-04-01 03:35:14 UTC (rev 560) @@ -13,7 +13,7 @@ __name__ tagsstorydivtagbox __template__ -[% sidenc = story.sid.replace("/",":") %] +[% sidenc = story.sid.replace("/","-") # no '/'s in html ids (see: http://www.w3.org/TR/html401/types.html) %] [% IF user.tags_canread_stories %]
    @@ -54,4 +54,4 @@ __seclev__ 10000 __version__ -$Id: tagsstorydivtagbox;misc;default,v 1.10 2007/10/24 00:30:08 scc Exp $ +$Id: tagsstorydivtagbox;misc;default,v 1.11 2008/03/13 17:15:30 scc Exp $ Modified: slashjp/branches/upstream/current/sql/mysql/defaults.sql =================================================================== --- slashjp/branches/upstream/current/sql/mysql/defaults.sql 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/sql/mysql/defaults.sql 2008-04-01 03:35:14 UTC (rev 560) @@ -3,7 +3,7 @@ #-------------------------------------------------------- # Server version 3.23.26-beta-log # -# $Id: defaults.sql,v 1.393 2008/02/28 20:44:48 pudge Exp $ +# $Id: defaults.sql,v 1.394 2008/03/12 16:48:57 pudge Exp $ # # @@ -832,7 +832,7 @@ INSERT INTO vars (name, value, description) VALUES ('cur_performance_stats_lastid', '0', 'accesslogid to start searching at'); INSERT INTO vars (name, value, description) VALUES ('cur_performance_stats_weeks', '8', 'number of weeks back to compare current stats to'); INSERT INTO vars (name, value, description) VALUES ('currentqid',1,'The Current Question on the homepage pollbooth'); -INSERT INTO vars (name, value, description) VALUES ('cvs_tag_currentcode','T_2_5_0_196','The current cvs tag that the code was updated to - this does not affect site behavior but may be useful for your records'); +INSERT INTO vars (name, value, description) VALUES ('cvs_tag_currentcode','T_2_5_0_197','The current cvs tag that the code was updated to - this does not affect site behavior but may be useful for your records'); INSERT INTO vars (name, value, description) VALUES ('datadir','/usr/local/slash/www.example.com','What is the root of the install for Slash'); INSERT INTO vars (name, value, description) VALUES ('db_auto_increment_increment','1','If your master DB uses auto_increment_increment, i.e. multiple master replication, echo its value into this var'); INSERT INTO vars (name, value, description) VALUES ('dbsparklines_disp','0','Display dbsparklines in the currentAdminUsers box?'); Modified: slashjp/branches/upstream/current/sql/mysql/upgrades =================================================================== --- slashjp/branches/upstream/current/sql/mysql/upgrades 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/sql/mysql/upgrades 2008-04-01 03:35:14 UTC (rev 560) @@ -10,7 +10,7 @@ # after X started at the same time that X was tagged. # -# $Id: upgrades,v 1.1318 2008/02/28 20:44:48 pudge Exp $ +# $Id: upgrades,v 1.1328 2008/03/21 02:44:47 pudge Exp $ # # BEGIN tf23's additions @@ -5049,8 +5049,6 @@ # not for slashdot UPDATE vars SET value = 'yes no binspam dupe notthebest offtopic stupid slownewsday interesting funny insightful' WHERE name = 'tagbox_top_excludetagnames'; -# PUDGE LAST UPDATED HERE - # 2007-12-05 UPDATE vars SET value = 'T_2_5_0_185' WHERE name = 'cvs_tag_currentcode'; @@ -5136,8 +5134,6 @@ # 2008-02-13 UPDATE vars SET value = 'T_2_5_0_194' WHERE name = 'cvs_tag_currentcode'; -# SLASHDOT LAST UPDATED HERE - # For sites *without* plugins/Tags DELETE FROM clout_types; @@ -5147,8 +5143,6 @@ # 2008-02-20 UPDATE vars SET value = 'T_2_5_0_195' WHERE name = 'cvs_tag_currentcode'; -# SLASHCODE/USEPERL LAST UPDATED HERE - # for plugins/Tags INSERT INTO vars (name, value, description) VALUES ('tags_unknowntype_default_clid', '1', 'For tags of unknown type, which clout id do we pretend they are?'); INSERT INTO vars (name, value, description) VALUES ('tags_unknowntype_default_mult', '0.3', 'For tags of unknown type, what multiplier do we give to the tagging user clout or type tags_unknowntype_default_clid?'); @@ -5156,3 +5150,50 @@ # 2008-02-28 UPDATE vars SET value = 'T_2_5_0_196' WHERE name = 'cvs_tag_currentcode'; +# for plugins/Tags +INSERT INTO ajax_ops VALUES (NULL, 'tags_deactivate', 'Slash::Tags', 'ajaxDeactivateTag', 'ajax_tags_write', 'use'); +INSERT INTO vars (name, value, description) VALUES ('tags_prefixlist_minlen', '3', 'Minimum length of a tag prefix to bother looking up suggestions for'); + +# 2008-03-12 +UPDATE vars SET value = 'T_2_5_0_197' WHERE name = 'cvs_tag_currentcode'; + +# SLASHDOT LAST UPDATED HERE + +# for plugins/Ajax +UPDATE ajax_ops set reskey_name = 'ajax_user_static', reskey_type='createuse' WHERE op='admin_signoff'; + +# comments +DELETE FROM reskey_resource_checks WHERE rkrid = 1; +INSERT INTO reskey_resource_checks VALUES (NULL, 1, 'all', 'Slash::ResKey::Checks::User', 101); +INSERT INTO reskey_resource_checks VALUES (NULL, 1, 'all', 'Slash::ResKey::Checks::ACL', 201); +INSERT INTO reskey_resource_checks VALUES (NULL, 1, 'all', 'Slash::ResKey::Checks::AL2::AnonNoPost', 301); +INSERT INTO reskey_resource_checks VALUES (NULL, 1, 'all', 'Slash::ResKey::Checks::AL2::NoPostAnon', 401); +INSERT INTO reskey_resource_checks VALUES (NULL, 1, 'all', 'Slash::ResKey::Checks::AL2::NoPost', 501); +INSERT INTO reskey_resource_checks VALUES (NULL, 1, 'all', 'Slash::ResKey::Checks::AL2::Spammer', 531); +INSERT INTO reskey_resource_checks VALUES (NULL, 1, 'all', 'Slash::ResKey::Checks::Duration', 601); + +DELETE FROM reskey_vars WHERE rkrid = 1; +INSERT INTO reskey_vars VALUES (1, 'adminbypass', 1, 'If admin, bypass checks for duration, proxy, and user'); +INSERT INTO reskey_vars VALUES (1, 'acl_no', 'reskey_no_comments', 'If this ACL present, can\'t use resource'); +INSERT INTO reskey_vars VALUES (1, 'user_seclev', 0, 'Minimum seclev to use resource'); +INSERT INTO reskey_vars VALUES (1, 'duration_max-uses', 30, 'how many uses per timeframe'); +INSERT INTO reskey_vars VALUES (1, 'duration_max-failures', 10, 'how many failures per reskey'); +INSERT INTO reskey_vars VALUES (1, 'duration_uses', 60, 'min duration (in seconds) between uses'); +INSERT INTO reskey_vars VALUES (1, 'duration_creation-use', 10, 'min duration between (in seconds) creation and use'); + +# for plugins/Tags +CREATE TABLE tagname_cache ( + tagnameid int UNSIGNED NOT NULL, + tagname VARCHAR(64) NOT NULL, + weight FLOAT UNSIGNED DEFAULT 0.0 NOT NULL, + PRIMARY KEY tagnameid (tagnameid), + UNIQUE tagname (tagname) +) TYPE=InnoDB; + + +# 2008-03-19 +UPDATE vars SET value = 'T_2_5_0_198' WHERE name = 'cvs_tag_currentcode'; + +# SLASHCODE/USEPERL LAST UPDATED HERE + +# PUDGE LAST UPDATED HERE Modified: slashjp/branches/upstream/current/tagboxes/Despam/Despam.pm =================================================================== --- slashjp/branches/upstream/current/tagboxes/Despam/Despam.pm 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/tagboxes/Despam/Despam.pm 2008-04-01 03:35:14 UTC (rev 560) @@ -2,7 +2,7 @@ # This code is a part of Slash, and is released under the GPL. # Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Despam.pm,v 1.7 2008/01/24 18:27:41 jamiemccarthy Exp $ +# $Id: Despam.pm,v 1.9 2008/03/12 14:27:28 jamiemccarthy Exp $ package Slash::Tagbox::Despam; @@ -28,7 +28,7 @@ use Data::Dumper; use vars qw( $VERSION ); -$VERSION = ' $Revision: 1.7 $ ' =~ /\$Revision:\s+([^\s]+)/; +$VERSION = ' $Revision: 1.9 $ ' =~ /\$Revision:\s+([^\s]+)/; use base 'Slash::DB::Utility'; # first for object init stuff, but really # needs to be second! figure it out. -- pudge @@ -53,9 +53,10 @@ my $constants = getCurrentStatic(); my $tagsdb = getObject('Slash::Tags'); - $self->{spamid} = $tagsdb->getTagnameidCreate('binspam'); - $self->{upvoteid} = $tagsdb->getTagnameidCreate($constants->{tags_upvote_tagname} || 'nod'); + $self->{spamid} = $tagsdb->getTagnameidCreate('binspam'); return undef unless $self->{spamid}; + $self->{upvoteid} = $tagsdb->getTagnameidCreate($constants->{tags_upvote_tagname} || 'nod'); + $self->{recalc_tbids} = undef; return $self; } @@ -91,6 +92,7 @@ }; push @$ret_ar, $ret_hr; } + main::tagboxLog("Despam->feed_newtags A " . scalar(@$ret_ar) . ": '@$ret_ar'"); return [ ] if !@$ret_ar; # Tags applied to globjs that have a firehose entry associated @@ -101,6 +103,7 @@ 'globjid', 'firehose', "globjid IN ($globjs_str)"); + main::tagboxLog("Despam->feed_newtags B " . scalar(@$fh_globjs_ar) . ": '@$fh_globjs_ar'"); return [ ] if !@$fh_globjs_ar; # if no affected globjs have firehose entries, short-circuit out my %fh_globjs = ( map { $_, 1 } @$fh_globjs_ar ); $ret_ar = [ grep { $fh_globjs{ $_->{affected_id} } } @$ret_ar ]; @@ -111,13 +114,10 @@ sub feed_deactivatedtags { my($self, $tags_ar) = @_; - # XXX This need not do anything, I don't think -- not even call - # feed_newtags. - # The way Despam is set up, 2 admin binspam tags will mark a globjid, - # and even if 1 of them is deactivated a moment later, we have no way - # to undo the process. - main::tagboxLog("Despam->feed_deactivatedtags called: tags_ar='" . join(' ', map { $_->{tagid} } @$tags_ar) . "', returning nothing"); - return [ ]; + main::tagboxLog("Despam->feed_deactivatedtags called: tags_ar='" . join(' ', map { $_->{tagid} } @$tags_ar) . "', calling feed_newtags"); + my $ret_ar = $self->feed_newtags($tags_ar); + main::tagboxLog("Despam->feed_deactivatedtags returning " . scalar(@$ret_ar)); + return $ret_ar; } sub feed_userchanges { @@ -134,6 +134,7 @@ my $firehose_db = getObject('Slash::FireHose'); my $slashdb = getCurrentDB(); + # Get the list of admin uids. my $admins = $tagsdb->getAdmins(); my $admin_in_str = join(',', sort { $a <=> $b } @@ -141,170 +142,281 @@ keys %$admins); return unless $admin_in_str; + # Get info about the firehose item that may have been tagged. my $affected_id_q = $self->sqlQuote($affected_id); - my $fhid = $self->sqlSelect('id', 'firehose', "globjid = $affected_id_q"); - warn "Slash::Tagbox::Despam->run bad data, fhid='$fhid' db='$firehose_db'" if !$fhid || !$firehose_db; + my $fhid = $self->sqlSelect('DISTINCT id', 'firehose', "globjid = $affected_id_q"); + if (!$fhid || !$firehose_db) { + main::tagboxLog("Slash::Tagbox::Despam->run bad data, fhid='$fhid' db='$firehose_db'"); + return ; + } my $fhitem = $firehose_db->getFireHose($fhid); + + # Get info about the uid and ipid that submitted the firehose item. + # We only track ipid for actual submissions, not journals/bookmarks. my $submitter_uid = $fhitem->{uid}; - my $submitter_srcid = $fhitem->{srcid_32}; + my $submitter_ipid = ''; + my $types = $slashdb->getGlobjTypes(); + my $submission_gtid = $types->{submissions}; + if ($submission_gtid) { + $submitter_ipid = $slashdb->sqlSelect( + 'ipid', + 'globjs, submissions', + "globjid=$affected_id + AND gtid=$submission_gtid + AND target_id=subid" + ) || ''; + } - my $binspam_count = $slashdb->sqlCount( - 'tags, firehose', - "tags.uid IN ($admin_in_str) - AND tags.inactivated IS NULL - AND tags.tagnameid = $self->{spamid} - AND tags.globjid = firehose.globjid - AND firehose.uid = $submitter_uid"); - my $binspam_tagids = $slashdb->sqlSelectColArrayref( - 'tagid', - 'tags, firehose', - "tags.uid IN ($admin_in_str) - AND tags.inactivated IS NULL - AND tags.tagnameid = $self->{spamid} - AND tags.globjid = firehose.globjid - AND firehose.uid = $submitter_uid"); - main::tagboxLog(sprintf("%s->run marking fhid %d (%d) as is_spam (for count %d on uid %d: '%s')", - ref($self), $fhid, $affected_id, $binspam_count, $submitter_uid, join(' ', @$binspam_tagids))); - $firehose_db->setFireHose($fhid, { is_spam => 'yes' }); + # First figure out how many times the globjid was tagged binspam by + # an admin. It may be zero (if forceFeederRecalc was called, or if + # an old binspam tag was deactivated). Even one admin binspam tag + # is enough to mark the individual item as binspam. + my $binspam_count_globjid = $slashdb->sqlCount( + 'tags', + "globjid=$affected_id + AND tagnameid=$self->{spamid} + AND uid IN ($admin_in_str) + AND inactivated IS NULL"); + my $is_spam = $binspam_count_globjid > 0 ? 1 : 0; - if (isAnon($submitter_uid)) { - # Non-logged-in user, check by IP (srcid_32) - if ($submitter_srcid && - $binspam_count > $constants->{tagbox_despam_binspamsallowed_ip} - ) { - main::tagboxLog(sprintf("%s->run marking srcid %s for %d admin binspam tags, based on %d (%d)", - ref($self), $submitter_srcid, $binspam_count, $fhid, $affected_id)); - $self->despam_srcid($submitter_srcid, $binspam_count); - } - } else { - # Logged-in user, check by uid - if ($binspam_count > $constants->{tagbox_despam_binspamsallowed}) { - main::tagboxLog(sprintf("%s->run marking uid %d for %d admin binspam tags, based on %d (%d)", - ref($self), $submitter_uid, $binspam_count, $fhid, $affected_id)); - $self->despam_uid($submitter_uid, $binspam_count); - } + # Now see how many times this globjid's uid (or, if anonymous, ipid) + # was tagged binspam by an admin. If greater than a certain + # threshold, that srcid (uid/ipid) will be given the 'spammer' al2. + my($check_type, $srcid, $table_clause, $where_clause) = (undef, undef); + if (!isAnon($submitter_uid)) { + # Logged-in user, check by uid. + $check_type = 'uid'; + $srcid = $submitter_uid; + $table_clause = ''; + $where_clause = "firehose.uid = $submitter_uid"; + } elsif ($submitter_ipid) { + # Non-logged-in user, check by IP (submissions.ipid) + $check_type = 'ipid'; + $srcid = convert_srcid('ipid', $submitter_ipid); + $table_clause = ', globjs, submissions'; + $where_clause = "firehose.type='submission' + AND firehose.globjid=globjs.globjid + AND globjs.target_id=submissions.subid + AND submissions.ipid='$submitter_ipid'"; } -} + # If neither of the above, it's an anonymous non-submission, so + # (at present) there's nothing we will do to block its "fellow" + # firehose items. -sub despam_srcid { - my($self, $srcid, $count) = @_; - my $slashdb = getCurrentDB(); - my $constants = getCurrentStatic(); + # Find out which and how many other 'binspam' tags this contributor + # has amassed in total (where "contributor" can be an ipid or uid). + my $binspam_tagid_globj_hr = { }; + if ($check_type) { + $binspam_tagid_globj_hr = $slashdb->sqlSelectAllKeyValue( + 'tags.tagid, tags.globjid', + "tags, firehose$table_clause", + "tags.globjid = firehose.globjid + AND tags.tagnameid = $self->{spamid} + AND tags.uid IN ($admin_in_str) + AND tags.inactivated IS NULL + AND $where_clause"); + } - my $al2_hr = $slashdb->getAL2($srcid); - if ($count > $constants->{tagbox_despam_binspamsallowed_ip}) { - main::tagboxLog("marking $srcid as spammer for $count"); - if (!$al2_hr->{spammer}) { - $slashdb->setAL2($srcid, { spammer => 1, comment => "Despam $count" }); - } + # This array contains the list of admin tags applied to + # firehose items from this srcid. If there are too many + # of them, mark the srcid. + my $binspam_count = scalar(keys %$binspam_tagid_globj_hr); + my $mark_srcid = 0; + if ($binspam_count > + ( $check_type eq 'uid' + ? $constants->{tagbox_despam_binspamsallowed} + : $constants->{tagbox_despam_binspamsallowed_ip} ) + ) { + $is_spam = $mark_srcid = 1; } -} -sub despam_uid { - my($self, $uid, $count) = @_; - my $constants = getCurrentStatic(); - my $slashdb = getCurrentDB(); - my $reader = getObject('Slash::DB', { db_type => 'reader' }); - my $tagboxdb = getObject('Slash::Tagbox'); + main::tagboxLog(sprintf("%s->run uid=%d ipid=%s check_type=%s affected_id=%d srcid=%s count=%d is_spam=%d mark_srcid=%d tagids: '%s'", + ref($self), ($submitter_uid || '0'), ($submitter_ipid || 'none'), + (defined($check_type) ? $check_type : 'undef'), + $affected_id, $srcid, $binspam_count, $is_spam, $mark_srcid, + join(' ', sort { $a <=> $b } keys %$binspam_tagid_globj_hr))); - # First, set the user's 'spammer' AL2. - my $adminuid = $constants->{tagbox_despam_al2adminuid}; - my $al2_hr = $slashdb->getAL2($uid); - if (!$al2_hr->{spammer}) { - $slashdb->setAL2($uid, { spammer => 1, comment => "Despam $count" }, - { adminuid => $adminuid }); + # is_spam=0 is_spam=1 mark_srcid=1 + # + # check_type undef clear 1 globj set 1 globjid set 1 globjid + # check_type=uid clear 1 globj set 1 globjid set all globjids, setAL2 + # check_type=ipid clear 1 globj set 1 globjid set all globjids, setAL2 + + # Always set/clear at least the one globjid affected. + my %globjids = ( $affected_id, 1 ); + if ($mark_srcid && $check_type) { + # Set/clear both the individual globjid and all its + # fellow submitted globjids, if known. + for my $tagid (keys %$binspam_tagid_globj_hr) { + $globjids{ $binspam_tagid_globj_hr->{$tagid} } = 1; + } } + # Convert that list of globjids to firehose ids. + my $globjid_in_str = join(',', sort { $a <=> $b } keys %globjids); + my $fhid_hr = $slashdb->sqlSelectAllKeyValue( + 'id, globjid', + 'firehose', + "globjid IN ($globjid_in_str)"); + main::tagboxLog(sprintf("%s->run globjids '%s' -> fhids '%s'", + ref($self), + join(' ', sort { $a <=> $b } keys %globjids), + join(' ', sort { $a <=> $b } keys %$fhid_hr))); - # Next, set the user's clout manually to 0. - $slashdb->setUser($uid, { tag_clout => 0 }); - - # Next, mark as spam everything the user's submitted. - $slashdb->sqlUpdate('firehose', { is_spam => 'yes' }, - "accepted != 'no' AND uid=$uid"); - - # Next, if $count is high enough, set the 'spammer' AL2 for all - # the IPID's the user has submitted from. - if ($count > $constants->{tagbox_despam_binspamsallowed_ip}) { - my $days = defined($constants->{tagbox_despam_ipdayslookback}) - ? $constants->{tagbox_despam_ipdayslookback} : 60; - my %srcid_used = ( ); - if ($days) { - my $sub_ipid_ar = $reader->sqlSelectColArrayref( - 'DISTINCT ipid', - 'submissions', - "uid=$uid AND time >= DATE_SUB(NOW(), INTERVAL $days DAY) AND ipid != ''"); - my $journal_srcid_ar = $reader->sqlSelectColArrayref( - 'DISTINCT ' . get_srcid_sql_out('srcid_32'), - 'journals', - "uid=$uid AND date >= DATE_SUB(NOW(), INTERVAL $days DAY) AND srcid_32 != 0"); - my $book_srcid_ar = $reader->sqlSelectColArrayref( - 'DISTINCT ' . get_srcid_sql_out('srcid_32'), - 'bookmarks', - "uid=$uid AND createdtime >= DATE_SUB(NOW(), INTERVAL $days DAY) AND srcid_32 != 0"); - for my $ipid (@$sub_ipid_ar) { - my $srcid = convert_srcid(ipid => $ipid); - $srcid_used{$srcid} = 1; + # Loop on all the fhids required to be changed, setting or + # clearing them as appropriate. + for my $fhid (sort { $a <=> $b } keys %$fhid_hr) { + my $globjid = $fhid_hr->{$fhid}; + my $rows = $firehose_db->setFireHose($fhid, { is_spam => ($is_spam ? 'yes' : 'no') }); + main::tagboxLog(sprintf("%s->run marked fhid %d (%d) as is_spam=%d rows=%s", + ref($self), $fhid, $globjid, $is_spam, $rows)); + if ($rows > 0) { + # If this firehose item's spam status changed, either way, its + # scores now need to be recalculated immediately. + # Get the list of tbids we need to force a recalc for. + if (!defined $self->{recalc_tbids}) { + my $tagboxes = $tagboxdb->getTagboxes(); + for my $tagbox_hr (@$tagboxes) { + push @{$self->{recalc_tbids}}, $tagbox_hr->{tbid} + if $tagbox_hr->{name} =~ /^(FHEditorPop|FireHoseScores)$/; + } } - for my $srcid (@$journal_srcid_ar) { - $srcid_used{$srcid} = 1; + # Force the recalculations of their scores. + for my $tbid (@{$self->{recalc_tbids}}) { + $tagboxdb->forceFeederRecalc($tbid, $globjid); + main::tagboxLog(sprintf("%s->run force recalc tbid=%d globjid=%d", + ref($self), $tbid, $globjid)); } - for my $srcid (@$book_srcid_ar) { - $srcid_used{$srcid} = 1; - } - my @srcids = sort grep { $_ } keys %srcid_used; - for my $srcid (@srcids) { - $al2_hr = $slashdb->getAL2($srcid); - if (!$al2_hr->{spammer}) { - $slashdb->setAL2($srcid, { spammer => 1, comment => "Despam $count for $uid" }); - } - } } } - # Next, declout everyone who's upvoted any of the user's - # recent submissions (except bookmarks, because those are - # generic enough). - my $daysback = $constants->{tagbox_despam_decloutdaysback} || 7; - my $upvoter_ar = $slashdb->sqlSelectColArrayref( - 'DISTINCT tags.uid', - 'tags, firehose', - "tags.globjid = firehose.globjid - AND firehose.uid = $uid - AND type IN ('submission', 'journal') - AND createtime >= DATE_SUB(NOW(), INTERVAL $daysback DAY) - AND tagnameid = $self->{upvoteid} - AND inactivated IS NULL"); - my $max_clout = defined($constants->{tagbox_despam_upvotermaxclout}) - ? $constants->{tagbox_despam_upvotermaxclout} : '0.85'; - for my $upvoter (@$upvoter_ar) { - main::tagboxLog("setting user $upvoter clout to max $max_clout for upvoting user $uid"); - $slashdb->setUser($upvoter, { - -tag_clout => "MAX(tag_clout, $max_clout)" - }); + # If appropriate, mark the submitter's uid or ipid as a spammer + # and mark _all_ their submissions as binspam. + if ($mark_srcid && $check_type) { + main::tagboxLog(sprintf("%s->run marking spammer AL2 srcid=%s", + ref($self), $srcid)); + $slashdb->setAL2($srcid, { spammer => 1 }, { adminuid => 1183959 }); } - - # Next, insert tagboxlog_feeder entries to tell the relevant - # tagboxes to recalculate those scores. - my $tagboxes = $tagboxdb->getTagboxes(); - my @tagboxids = map { $_->{tbid} } grep { $_->{name} =~ /^(FHEditorPop|FireHoseScores)$/ } @$tagboxes; - my $globjid_tagid = $slashdb->sqlSelectAllKeyValue( - 'firehose.globjid, tagid', - 'firehose, tags', - "firehose.uid=$uid - AND firehose.globjid=tags.globjid - AND tags.uid=$uid - AND tagnameid=$self->{upvoteid}", - 'GROUP BY firehose.globjid'); - for my $globjid (sort keys %$globjid_tagid) { - for my $tbid (@tagboxids) { - $tagboxdb->addFeederInfo($tbid, { - affected_id => $globjid, - importance => 1, - tagid => $globjid_tagid->{ $globjid }, - }); - } - } } +#sub despam_srcid { +# my($self, $srcid, $count) = @_; +# my $slashdb = getCurrentDB(); +# my $constants = getCurrentStatic(); +# +# my $al2_hr = $slashdb->getAL2($srcid); +# if ($count > $constants->{tagbox_despam_binspamsallowed_ip}) { +# main::tagboxLog("marking $srcid as spammer for $count"); +# if (!$al2_hr->{spammer}) { +# $slashdb->setAL2($srcid, { spammer => 1, comment => "Despam $count" }); +# } +# } +#} +# +#sub despam_uid { +# my($self, $uid, $count) = @_; +# my $constants = getCurrentStatic(); +# my $slashdb = getCurrentDB(); +# my $reader = getObject('Slash::DB', { db_type => 'reader' }); +# my $tagboxdb = getObject('Slash::Tagbox'); +# +# # First, set the user's 'spammer' AL2. +# my $adminuid = $constants->{tagbox_despam_al2adminuid}; +# my $al2_hr = $slashdb->getAL2($uid); +# if (!$al2_hr->{spammer}) { +# $slashdb->setAL2($uid, { spammer => 1, comment => "Despam $count" }, +# { adminuid => $adminuid }); +# } +# +# # Next, set the user's clout manually to 0. +# $slashdb->setUser($uid, { tag_clout => 0 }); +# +# # Next, mark as spam everything the user's submitted. +# $slashdb->sqlUpdate('firehose', { is_spam => 'yes' }, +# "accepted != 'no' AND uid=$uid"); +# +# # Next, if $count is high enough, set the 'spammer' AL2 for all +# # the IPID's the user has submitted from. +# if ($count > $constants->{tagbox_despam_binspamsallowed_ip}) { +# my $days = defined($constants->{tagbox_despam_ipdayslookback}) +# ? $constants->{tagbox_despam_ipdayslookback} : 60; +# my %srcid_used = ( ); +# if ($days) { +# my $sub_ipid_ar = $reader->sqlSelectColArrayref( +# 'DISTINCT ipid', +# 'submissions', +# "uid=$uid AND time >= DATE_SUB(NOW(), INTERVAL $days DAY) AND ipid != ''"); +# my $journal_srcid_ar = $reader->sqlSelectColArrayref( +# 'DISTINCT ' . get_srcid_sql_out('srcid_32'), +# 'journals', +# "uid=$uid AND date >= DATE_SUB(NOW(), INTERVAL $days DAY) AND srcid_32 != 0"); +# my $book_srcid_ar = $reader->sqlSelectColArrayref( +# 'DISTINCT ' . get_srcid_sql_out('srcid_32'), +# 'bookmarks', +# "uid=$uid AND createdtime >= DATE_SUB(NOW(), INTERVAL $days DAY) AND srcid_32 != 0"); +# for my $ipid (@$sub_ipid_ar) { +# my $srcid = convert_srcid(ipid => $ipid); +# $srcid_used{$srcid} = 1; +# } +# for my $srcid (@$journal_srcid_ar) { +# $srcid_used{$srcid} = 1; +# } +# for my $srcid (@$book_srcid_ar) { +# $srcid_used{$srcid} = 1; +# } +# my @srcids = sort grep { $_ } keys %srcid_used; +# for my $srcid (@srcids) { +# $al2_hr = $slashdb->getAL2($srcid); +# if (!$al2_hr->{spammer}) { +# $slashdb->setAL2($srcid, { spammer => 1, comment => "Despam $count for $uid" }); +# } +# } +# } +# } +# +# # Next, declout everyone who's upvoted any of the user's +# # recent submissions (except bookmarks, because those are +# # generic enough). +# my $daysback = $constants->{tagbox_despam_decloutdaysback} || 7; +# my $upvoter_ar = $slashdb->sqlSelectColArrayref( +# 'DISTINCT tags.uid', +# 'tags, firehose', +# "tags.globjid = firehose.globjid +# AND firehose.uid = $uid +# AND type IN ('submission', 'journal') +# AND createtime >= DATE_SUB(NOW(), INTERVAL $daysback DAY) +# AND tagnameid = $self->{upvoteid} +# AND inactivated IS NULL"); +# my $max_clout = defined($constants->{tagbox_despam_upvotermaxclout}) +# ? $constants->{tagbox_despam_upvotermaxclout} : '0.85'; +# for my $upvoter (@$upvoter_ar) { +# main::tagboxLog("setting user $upvoter clout to max $max_clout for upvoting user $uid"); +# $slashdb->setUser($upvoter, { +# -tag_clout => "MAX(tag_clout, $max_clout)" +# }); +# } +# +# # Next, insert tagboxlog_feeder entries to tell the relevant +# # tagboxes to recalculate those scores. +# my $tagboxes = $tagboxdb->getTagboxes(); +# my @tagboxids = map { $_->{tbid} } grep { $_->{name} =~ /^(FHEditorPop|FireHoseScores)$/ } @$tagboxes; +# my $globjid_tagid = $slashdb->sqlSelectAllKeyValue( +# 'firehose.globjid, tagid', +# 'firehose, tags', +# "firehose.uid=$uid +# AND firehose.globjid=tags.globjid +# AND tags.uid=$uid +# AND tagnameid=$self->{upvoteid}", +# 'GROUP BY firehose.globjid'); +# for my $globjid (sort keys %$globjid_tagid) { +# for my $tbid (@tagboxids) { +# $tagboxdb->addFeederInfo($tbid, { +# affected_id => $globjid, +# importance => 1, +# tagid => $globjid_tagid->{ $globjid }, +# }); +# } +# } +#} + 1; Modified: slashjp/branches/upstream/current/themes/slashcode/THEME =================================================================== --- slashjp/branches/upstream/current/themes/slashcode/THEME 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/themes/slashcode/THEME 2008-04-01 03:35:14 UTC (rev 560) @@ -1,4 +1,4 @@ -# $Id: THEME,v 1.129 2008/02/21 01:01:52 pudge Exp $ +# $Id: THEME,v 1.131 2008/03/14 17:57:33 scc Exp $ name=slashcode description="Slashcode.com theme" topic=htdocs/images/topics/topicbug.jpg @@ -127,7 +127,6 @@ htdoc=htdocs/topics.pl htdoc=htdocs/users.pl htdoc=htdocs/images/comments.js -htdoc=htdocs/images/comments2.js htdoc=htdocs/images/dumper.js htdoc=htdocs/badge.pl htdoc=htdocs/help.pl @@ -340,6 +339,7 @@ plugin=Login plugin=Hof plugin=Messages +plugin=Moderation plugin=PollBooth plugin=Print plugin=PubKey Modified: slashjp/branches/upstream/current/themes/slashcode/htdocs/comments.pl =================================================================== --- slashjp/branches/upstream/current/themes/slashcode/htdocs/comments.pl 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/themes/slashcode/htdocs/comments.pl 2008-04-01 03:35:14 UTC (rev 560) @@ -2,7 +2,7 @@ # This code is a part of Slash, and is released under the GPL. # Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: comments.pl,v 1.270 2008/02/28 19:26:58 pudge Exp $ +# $Id: comments.pl,v 1.272 2008/03/20 07:30:29 pudge Exp $ use strict; use Slash 2.003; # require Slash 2.3.x @@ -203,7 +203,7 @@ header($title, $section) or return; $header_emitted = 1; } - print getError('login error'); + print Slash::Utility::Comments::getError('login error'); $op = 'preview'; } $op = 'default' if @@ -217,7 +217,7 @@ header($title, $section) or return; $header_emitted = 1; } - print getError("nosubscription"); + print Slash::Utility::Comments::getError("nosubscription"); } #print STDERR scalar(localtime) . " $$ B op=$op header_emitted=$header_emitted\n"; @@ -369,18 +369,6 @@ return fixurl($uri); } -################################################################# -# this groups all the errors together in -# one template, called "errors;comments;default" -# Why not just getData??? -Brian -sub getError { - my($value, $hashref, $nocomm) = @_; - $hashref ||= {}; - $hashref->{value} = $value; - return slashDisplay('errors', $hashref, - { Return => 1, Nocomm => $nocomm }); -} - ################################################################## sub delete { my($form, $slashdb, $user, $constants) = @_; @@ -449,7 +437,7 @@ if ($sid) { $sid =~ /(\d+)/; $sid = $1 } if (!$sid) { # Need a discussion ID to reply to, or there's no point. - print getError('no sid'); + print Slash::Utility::Comments::getError('no sid'); return; } @@ -461,7 +449,7 @@ # An attempt to reply to a comment that doesn't exist is an error. if ($pid && !%$reply) { - print getError('no such parent'); + print Slash::Utility::Comments::getError('no such parent'); return; } elsif ($pid) { $pid_reply = prepareQuoteReply($reply); @@ -485,12 +473,12 @@ # just in case the user fudged it. if (($user->{is_anon} || $form->{postanon}) && !$slashdb->checkAllowAnonymousPosting($user->{uid})) { - print getError('anonymous disallowed'); + print Slash::Utility::Comments::getError('anonymous disallowed'); return; } if ($discussion->{type} eq 'archived') { - print getError('archive_error'); + print Slash::Utility::Comments::getError('archive_error'); return; } @@ -498,12 +486,7 @@ $preview = previewForm(\$error_message, $discussion) or $error_flag++; } - if (%$reply && !$form->{postersubj}) { - $form->{postersubj} = decode_entities($reply->{subject}); - $form->{postersubj} =~ s/^Re://i; - $form->{postersubj} =~ s/\s\s/ /g; - $form->{postersubj} = "Re:$form->{postersubj}"; - } + preProcessReplyForm($form, $reply); my $extras = []; my $disc_skin = $slashdb->getSkin($discussion->{primaryskid}); @@ -514,8 +497,10 @@ if $disc_skin && $disc_skin->{nexus}; my $gotmodwarning; - $gotmodwarning = 1 if $form->{gotmodwarning} - || $error_message && $error_message eq getError("moderations to be lost"); + $gotmodwarning = 1 if $form->{gotmodwarning} || + ($error_message && $error_message eq + Slash::Utility::Comments::getError("moderations to be lost") + ); slashDisplay('edit_comment', { pid_reply => $pid_reply, @@ -542,7 +527,7 @@ my $comment = preProcessComment($form, $user, $discussion, $error_message) or return; return $$error_message if $comment eq '-1'; - my $preview = postProcessComment({ %$comment, %$user }, 0, $discussion); + my $preview = postProcessComment({ %$user, %$form, %$comment }, 0, $discussion); if ($constants->{plugin}{Subscribe}) { $preview->{subscriber_bonus} = @@ -685,9 +670,9 @@ # went wrong. if ($ret_val < 0) { if ($ret_val == -1) { - print getError('no points'); + print Slash::Utility::Comments::getError('no points'); } elsif ($ret_val == -2){ - print getError('not enough points'); + print Slash::Utility::Comments::getError('not enough points'); } } else { $was_touched += $ret_val; Modified: slashjp/branches/upstream/current/themes/slashcode/htdocs/images/comments.js =================================================================== (Binary files differ) Deleted: slashjp/branches/upstream/current/themes/slashcode/htdocs/images/comments2.js =================================================================== (Binary files differ) Modified: slashjp/branches/upstream/current/themes/slashcode/htdocs/images/dumper.js =================================================================== (Binary files differ) Modified: slashjp/branches/upstream/current/themes/slashcode/templates/dispComment;misc;default =================================================================== --- slashjp/branches/upstream/current/themes/slashcode/templates/dispComment;misc;default 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/themes/slashcode/templates/dispComment;misc;default 2008-04-01 03:35:14 UTC (rev 560) @@ -34,7 +34,7 @@ [% ELSE %]

    [% subject %] [%- END %] - [% UNLESS user.noscores %](Score:[% IF points.length; points; ELSE; "?"; END %][% IF reasons && reason %], [% reasons.$reason.name %][% END %])[% END %]

    + [% UNLESS user.noscores %]([% IF constants.modal_prefs_active && !user.is_anon %][% END %]Score:[% points.length ? points : "?" %][% IF constants.modal_prefs_active && !user.is_anon %][% END %][% IF reasons && reason %], [% reasons.$reason.name %][% END %])[% END %]
    by @@ -81,4 +81,4 @@ __seclev__ 10000 __version__ -$Id: dispComment;misc;default,v 1.64 2007/10/25 02:12:17 pudge Exp $ +$Id: dispComment;misc;default,v 1.66 2008/03/19 08:25:31 pudge Exp $ Modified: slashjp/branches/upstream/current/themes/slashcode/templates/dispLinkComment;misc;default =================================================================== --- slashjp/branches/upstream/current/themes/slashcode/templates/dispLinkComment;misc;default 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/themes/slashcode/templates/dispLinkComment;misc;default 2008-04-01 03:35:14 UTC (rev 560) @@ -22,14 +22,14 @@ [ [% IF !user.state.discussion_archived && !user.state.discussion_future_nopost %] - [% Slash.linkComment({ + [% Slash.linkComment({ sid => sid, pid => cid, op => 'Reply', subject => 'Reply to This', subject_only => 1, - onclick => ((discussion2 && user.test_code) ? "replyTo($cid); return false;" : '') - }) %] + onclick => ((discussion2 && (!constants.subscribe || user.is_subscriber)) ? "replyTo($cid); return false;" : '') + }) %] [% END %] [% IF !(user.state.discussion_archived) && ( do_parent || can_mod || can_del ) %] | [% END %] @@ -68,4 +68,4 @@ __seclev__ 10000 __version__ -$Id: dispLinkComment;misc;default,v 1.40 2008/02/28 19:26:58 pudge Exp $ +$Id: dispLinkComment;misc;default,v 1.43 2008/03/19 21:09:47 pudge Exp $ Modified: slashjp/branches/upstream/current/themes/slashcode/templates/dispStory;misc;default =================================================================== --- slashjp/branches/upstream/current/themes/slashcode/templates/dispStory;misc;default 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/themes/slashcode/templates/dispStory;misc;default 2008-04-01 03:35:14 UTC (rev 560) @@ -71,7 +71,7 @@ [% mypagemenu = PROCESS pagemenu; IF mypagemenu %]
    [% mypagemenu %][% END %]
    [% seen_topics.${topic.tid} = 1 %] - [% IF user.noicons || user.simpledesign || user.lowbandwidth %] + [% IF user.noicons || user.simpledesign || user.lowbandwidth || user.pda %] [ [% topic.textname %] ] [% ELSIF topic.image %] @@ -95,7 +95,17 @@ [% story.introtext %]
    -[% IF full && user.is_admin && !preview && env.script_name != '/admin.pl' %]
    [ Edit ] [% IF constants.plugin.Ajax %][% PROCESS signoff stoid = story.stoid %] [% PROCESS neverdisplay stoid = stoid %][% END %][% END %] +[% IF full && user.is_admin && !preview && env.script_name != '/admin.pl' %]
    [ Edit ] [% END %] +[% IF full && !preview && env.script_name != '/admin.pl' %] + [% IF constants.plugin.Ajax %] + [% IF user.is_admin || user.acl.signoff_allowed %] + [% PROCESS signoff stoid = story.stoid %] + [% END %] + [% IF user.is_admin %] + [% PROCESS neverdisplay stoid = stoid %] + [% END %] + [% END %] +[% END %] [% IF story.is_future && !user.is_admin %]

    See any serious problems with this story? [% IF constants.ircslash_remarks %] @@ -164,4 +174,4 @@ __seclev__ 10000 __version__ -$Id: dispStory;misc;default,v 1.67 2007/10/24 00:30:08 scc Exp $ +$Id: dispStory;misc;default,v 1.69 2008/03/18 20:33:39 tvroom Exp $ Modified: slashjp/branches/upstream/current/themes/slashcode/templates/errors;comments;default =================================================================== --- slashjp/branches/upstream/current/themes/slashcode/templates/errors;comments;default 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/themes/slashcode/templates/errors;comments;default 2008-04-01 03:35:14 UTC (rev 560) @@ -34,7 +34,7 @@ to do so, because open proxies are used to spam web boards like this one. [% IF constants.comments_portscan!=2 %]If you really can't close it and still want to post, you'll have to register and log in.[% END %] -

    If you have questions, mention that your proxy is at +If you have questions, mention that your proxy is at [% unencoded_ip %] on port [% port %]. [% # COMMENT TABLE NOT AVAILABLE FOR WRITING @@ -69,133 +69,128 @@ [% # NO POINTS. CASE "no points" %] -You don't have any moderator points.
    +You don't have any moderator points. [% # NO POINTS. CASE "not enough points" %] -You don't have enough moderator points.
    +You don't have enough moderator points. [% # COMMENTS MAX POSTS. CASE "comments max posts" %] -

    You've reached your maximum number of comments you can post: [% max_posts %] comments over [% timeframe %]. -

    +You've reached your maximum number of comments you can post: [% max_posts %] comments over [% timeframe %]. [% # COMMENTS MAX POSTS. CASE "discussions max posts" %] -

    You've reached your maximum number of discussions you can submit: [% max_posts %] discussions over [% timeframe %]. -

    +You've reached your maximum number of discussions you can submit: [% max_posts %] discussions over [% timeframe %]. [% # INVALID FORMKEY CASE "invalid formkey" %] -[% PROCESS titlebar width="100%" title="Invalid form key!" %] -

    form key: [% formkey %] !

    +[% PROCESS titlebar width="100%" title="Invalid form key!" UNLESS no_titlebar %] +Invalid form key: [% formkey %]! [% # RESPONSE LIMIT CASE "comments response limit" %] -[% PROCESS titlebar width="100%" title="Slow Down Cowboy!" %] -

    [% constants.sitename %] requires you to wait [% limit %] between -hitting 'reply' and submitting a comment.

    -

    It's been [% response %] since you hit 'reply'!

    +[% PROCESS titlebar width="100%" title="Slow Down Cowboy!" UNLESS no_titlebar %] +[% constants.sitename %] requires you to wait [% limit %] between hitting 'Reply' +and submitting a comment. It's been [% response %] since you hit 'Reply.' [% # POST LIMIT CASE "comments post limit" %] -[% PROCESS titlebar width="100%" title="Slow Down Cowboy!" %] -

    [% constants.sitename %] requires you to wait between -each successful posting of a comment to allow everyone a fair chance -at posting a comment.

    -

    It's been [% interval %] since you last successfully posted a comment.

    +[% PROCESS titlebar width="100%" title="Slow Down Cowboy!" UNLESS no_titlebar %] +[% constants.sitename %] requires you to wait between each successful posting of +a comment to allow everyone a fair chance at posting a comment. It's been +[% interval %] since you last successfully posted a comment. [% # POST LIMIT CASE "discussions post limit" %] -[% PROCESS titlebar width="100%" title="Slow Down Cowboy!" %] -

    [% constants.sitename %] requires you to wait between -each successful creation of a discussion .

    -

    It's been [% interval %] since you last successfully created a discussion.

    +[% PROCESS titlebar width="100%" title="Slow Down Cowboy!" UNLESS no_titlebar %] +[% constants.sitename %] requires you to wait between each successful creation +of a discussion. It's been [% interval %] since you last successfully created a discussion. + [% # USED FORM CASE "used form" %] -[% PROCESS titlebar width="100%" title="Form Error!" %] +[% PROCESS titlebar width="100%" title="Form Error!" UNLESS no_titlebar %] This form has been used already to submit a comment [% interval %] ago. You can not use a form and hit the back button to use it again. [% # READ ONLY CASE "readonly" %] -
    You can't post to this page.
    +You can't post to this page. [% # TOO MANY POSTS CASE "comments post limit daily" %] -[% PROCESS titlebar width="100%" title="Call It A Night, Cowboy!" %] -

    [% constants.sitename %] only allows -[% IF user.is_anon; "anonymous users"; -ELSE; "a user with your karma"; END %] -to post [% limit %] times per day (more or less, depending on -moderation). -[% IF user.is_anon; "A user from your IP has already shared his or her thoughts"; -ELSE; "You've already shared your thoughts"; END %] +[% PROCESS titlebar width="100%" title="Call It A Night, Cowboy!" UNLESS no_titlebar %] +[% constants.sitename %] only allows +[% IF user.is_anon; + "anonymous users"; +ELSE; + "a user with your karma"; END %] +to post [% limit %] times per day (more or less, depending on moderation). + +[% IF user.is_anon; + "A user from your IP has already shared his or her thoughts"; +ELSE; + "You've already shared your thoughts"; END %] with us that many times. Take a breather, and come back and see us in 24 hours or so. -

    If you think this is unfair, please email -[% IF constants.adminmail_post; constants.adminmail_post; -ELSE; constants.adminmail; END %] -with your + +If you think this is unfair, please email +[% constants.adminmail_post || constants.adminmail %] with your [% IF user.is_anon %] -MD5'd IPID, which is [% user.ipid %][% -ELSE %] -username "[% user.nickname | strip_literal %]"[% -END %]. Let us know how many comments you think you've -posted in the last 24 hours. + MD5'd IPID, which is [% user.ipid %][% ELSE %] + username "[% user.nickname | strip_literal %]"[% END %]. +Let us know how many comments you think you've posted in the last 24 hours. + + [% # TROLL MESSAGE. CASE "troll message" %] Due to excessive bad posting from this IP or Subnet, [% IF logged_in_allowed -%]anonymous [% END %]comment posting -has temporarily been disabled. +%]anonymous [% END %]comment posting has temporarily been disabled. + [% IF logged_in_allowed %] You can still login to post. However, if bad posting continues from your IP or Subnet that privilege could be revoked as well. [% END %] -If it's you, consider this a chance to -sit in the timeout corner[% IF logged_in_allowed %] or login and improve your posting[% END %] -. If it's someone else, this is a chance to hunt them down. -If you think this is unfair, please email -[% IF constants.adminmail_mod; constants.adminmail_mod; -ELSE; constants.adminmail; END %] -with your MD5'd IPID and SubnetID, which are -"[% user.ipid %]" and "[% user.subnetid %]"[% -IF !user.is_anon %] -and (optionally, but preferably) your IP number -"[% unencoded_ip %]" and your username "[% user.nickname | strip_literal %]"[% -END %]. +If it's you, consider this a chance to sit in the timeout +corner[% IF logged_in_allowed %] or login and improve your posting[% END %]. +If it's someone else, this is a chance to hunt them down. If you think this is +unfair, please email [% constants.adminmail_mod || constants.adminmail %] +with your MD5'd IPID and SubnetID, which are "[% user.ipid %]" and +"[% user.subnetid %]"[% IF !user.is_anon %] + and (optionally, but preferably) your IP number + "[% unencoded_ip %]" and your username + "[% user.nickname | strip_literal %]"[% END %]. + [% CASE "broken html" %] Your comment could not be processed. Please try again. [% # LOW CHARS-PER-LINE CASE "low chars-per-line" %] -Your comment has too few characters per line (currently [% ratio %]).
    +Your comment has too few characters per line (currently [% ratio %]). [% # FILTER MESSAGE. CASE "filter message" %] -[% PROCESS titlebar width="100%" title="Lameness filter encountered. Post aborted!" %] +[% PROCESS titlebar width="100%" title="Lameness filter encountered. Post aborted!" UNLESS no_titlebar %] [% IF err_message %] -Reason: [% err_message %]
    +Filter error: [% err_message %] [% END %] [% # COMPRESS FILTER. CASE "compress filter" %] -[% PROCESS titlebar width="100%" title="Lameness filter encountered." %] -Your comment violated the "[% ratio %]" compression filter. Try less -whitespace and/or less repetition[% -IF ratio == 'postersubj' %] in the subject line[% END %]. -Comment aborted. +[% PROCESS titlebar width="100%" title="Lameness filter encountered." UNLESS no_titlebar %] +Your comment violated the "[% ratio %]" compression filter. Try less whitespace +and/or less repetition[% IF ratio == 'postersubj' %] in the subject line[% END %]. [% # SUBMISSION ERROR. CASE "submission error" %] -

    There was an unknown error in the submission.
    +There was an unknown error in the submission. [% # MAXCID EXCEEDED. CASE "maxcid exceeded" %] -Don't you have anything better to do with your life?
    +Don't you have anything better to do with your life? [% # DUPLICATION ERROR. CASE "duplication error" %] @@ -214,31 +209,30 @@ form [% formname %] [% formkey %] already submitted [% CASE "seclevtoolow" %] -[% PROCESS titlebar width="100%" title="No permissions" %] +[% PROCESS titlebar width="100%" title="No permissions" UNLESS no_titlebar %] You do not have appropriate permissions to perform that action. [% CASE "nosubscription" %] -[% PROCESS titlebar width="100%" title="Not subscriber, or not subscribed page" %] -You can't see this discussion because it's scheduled in the future, -where only subscribers can see it.

    -Either you are not a subscriber to [% constants.sitename %], or you -have indicated you don't want comments pages ad-free, or you have -set your daily limit of ad-free pages to lower than -the default [% constants.subscribe_hits_btmd %]. -Any of these three possible issues can be resolved at -your subscription page.

    +[% PROCESS titlebar width="100%" title="Not subscriber, or not subscribed page" UNLESS no_titlebar %] +You can't see this discussion because it's scheduled in the future, where only +subscribers can see it. Either you are not a subscriber to +[% constants.sitename %], or you have indicated you don't want comments pages +ad-free, or you have set your daily limit of ad-free pages to lower than the +default [% constants.subscribe_hits_btmd %]. Any of these three possible +issues can be resolved at your +subscription page. [% CASE "moderations to be lost" %] -[% PROCESS titlebar width="100%" title="You've Already Moderated this Discussion" %] +[% PROCESS titlebar width="100%" title="You've Already Moderated this Discussion" UNLESS no_titlebar %] If you continue to post this comment, all moderations done to this discussion will be undone! Are you sure you want to post? [% # NO DISCUSSION ID SPECIFIED CASE "no sid" %] -[% PROCESS titlebar width="100%" title="No Discussion Specified" %] -You did not specify a discussion ID. If you clicked on a link internal -to [% constants.sitename %], this is a bug. If not, someone sent you -to a silly invalid URL. +[% PROCESS titlebar width="100%" title="No Discussion Specified" UNLESS no_titlebar %] +You did not specify a discussion ID. If you clicked on a link internal to +[% constants.sitename %], this is a bug. If not, someone sent you to a silly +invalid URL. [% CASE 'no_moderation' %] The moderation system is currently down. @@ -248,10 +242,10 @@ [% CASE %] -An unexpected error has occurred.
    [% value %]
    +An unexpected error has occurred: [% value %] [% END %] __seclev__ 1000 __version__ -$Id: errors;comments;default,v 1.39 2006/09/12 04:44:07 pudge Exp $ +$Id: errors;comments;default,v 1.42 2008/03/12 06:25:50 pudge Exp $ Modified: slashjp/branches/upstream/current/themes/slashcode/templates/html-header;misc;default =================================================================== --- slashjp/branches/upstream/current/themes/slashcode/templates/html-header;misc;default 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/themes/slashcode/templates/html-header;misc;default 2008-04-01 03:35:14 UTC (rev 560) @@ -28,7 +28,7 @@ [% IF file.ie_cond %][% END %] [% END -%] [%- IF constants.plugin.Ajax %] - + @@ -56,4 +56,4 @@ __seclev__ 10000 __version__ -$Id: html-header;misc;default,v 1.38 2008/02/04 14:50:17 scc Exp $ +$Id: html-header;misc;default,v 1.39 2008/03/14 15:48:07 scc Exp $ Modified: slashjp/branches/upstream/current/themes/slashcode/templates/modCommentLog;misc;default =================================================================== --- slashjp/branches/upstream/current/themes/slashcode/templates/modCommentLog;misc;default 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/themes/slashcode/templates/modCommentLog;misc;default 2008-04-01 03:35:14 UTC (rev 560) @@ -36,15 +36,17 @@ __template__ [% IF mod_admin %] [% +hr_shown = 0; mod_index = 0; down=0; cnt=0; m2_down=0; m2_count=0; m2_offside=0; +a_up=0; a_sum=0; a_count=0; up=0; sum=0; count=0; a_m2_count=0; a_down=0; a_cnt=0; a_m2_down=0; a_m2_up=0; m2_count=0; a_m2_offside=0; a_m2_unfair_votes=0; unanimous = 0; unresolved=0; show_uid_totals = (type == "uid" && (this_user.totalmods || this_user.downmods || this_user.upmods || this_user.m2unfair || this_user.m2unfairpercent || this_user.stirred)); bg_toggle = 0; %] [% IF mods.size > 0 || show_uid_totals %] - [% IF user.is_admin and need_m2_form %] -

    + [% IF user.is_admin && need_m2_form %] +
    [% END %] [% IF meta_mod_only %] @@ -53,7 +55,7 @@ [% total_cols = 6 %] [% IF title; extra = ""; - IF constants.m2; + IF constants.m2 && !constants.modal_prefs_active; show_m2s_op = show_m2s ? 0 : 1; self_url = PROCESS base_url_mod; url_tail = PROCESS state_url_mod override = { show_m2s => show_m2s_op}; @@ -84,8 +86,6 @@ Moderatee [% IF constants.m2 %]/ Metamoderator[% END %] [% END %] - [% hr_shown = 0; - mod_index = 0; %] [% FOREACH moderation = mods %] [% IF constants.m2 && type == "cid" && constants.show_m2s_with_mods && show_m2s && constants.m2_multicount; prev_index = mod_index - 1; @@ -203,7 +203,13 @@ [% IF need_m2_button %] - [%# XXX really? %] + [%- IF constants.modal_prefs_active %] + + + + [%- ELSE %] + + [%- END %] [% END %] [% END %] @@ -367,4 +373,4 @@ __seclev__ 10000 __version__ -$Id: modCommentLog;misc;default,v 1.49 2006/10/26 17:33:09 jamiemccarthy Exp $ +$Id: modCommentLog;misc;default,v 1.52 2008/03/19 08:25:31 pudge Exp $ Modified: slashjp/branches/upstream/current/themes/slashcode/templates/printCommComments;misc;default =================================================================== --- slashjp/branches/upstream/current/themes/slashcode/templates/printCommComments;misc;default 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/themes/slashcode/templates/printCommComments;misc;default 2008-04-01 03:35:14 UTC (rev 560) @@ -71,7 +71,8 @@ [% Slash.linkComment(next, 1) %]>> [% END %]
    - [% m1_classname = "Slash::" _ constants.m1_pluginname; + [% UNLESS constants.modal_prefs_active; + m1_classname = "Slash::" _ constants.m1_pluginname; moddb = Slash.getObject(m1_classname); IF moddb; moddb.dispModCommentLog('cid', cid, { @@ -82,6 +83,7 @@ need_m2_button => constants.m2, title => " " }); END; + END; # constants.modal_prefs_active %] [% END %] @@ -101,6 +103,7 @@ [% lcp %] [% IF discussion2 && !cid %] +
    Check for more [% UNLESS user.state.discussion_archived || user.state.discussion_future_nopost %] | [% Slash.linkComment({ @@ -108,7 +111,8 @@ cid => cid, op => 'reply', subject => 'Reply', - subject_only => 1 + subject_only => 1, + onclick => ((discussion2 && (!constants.subscribe || user.is_subscriber)) ? "replyTo(0); return false;" : '') }); END %]
    @@ -155,4 +159,4 @@ __seclev__ 10000 __version__ -$Id: printCommComments;misc;default,v 1.64 2008/01/18 22:36:51 pudge Exp $ +$Id: printCommComments;misc;default,v 1.68 2008/03/19 21:09:47 pudge Exp $ Modified: slashjp/branches/upstream/current/themes/slashcode/templates/printCommentsMain;misc;default =================================================================== --- slashjp/branches/upstream/current/themes/slashcode/templates/printCommentsMain;misc;default 2008-03-31 12:09:17 UTC (rev 559) +++ slashjp/branches/upstream/current/themes/slashcode/templates/printCommentsMain;misc;default 2008-04-01 03:35:14 UTC (rev 560) @@ -201,7 +201,8 @@ cid => cid, op => 'reply', subject => 'Reply', - subject_only => 1 + subject_only => 1, + onclick => ((discussion2 && (!constants.subscribe || user.is_subscriber)) ? "replyTo(0); return false;" : '') }) %] [% END %] @@ -285,7 +286,8 @@ cid => cid, op => 'reply', subject => 'Reply', - subject_only => 1 + subject_only => 1, + onclick => ((discussion2 && (!constants.subscribe || user.is_subscriber)) ? "replyTo(0); return false;" : '') }) %] [% END %]
    Keybindings Beta
    @@ -308,4 +310,4 @@ __seclev__ 10000 __version__ -$Id: printCommentsMain;misc;default,v 1.103 2008/01/31 19:24:59 pudge Exp $ +$Id: printCommentsMain;misc;default,v 1.106 2008/03/19 21:09:47 pudge Exp $ From svnnotify ¡÷ sourceforge.jp Tue Apr 1 13:03:21 2008 From: svnnotify ¡÷ sourceforge.jp (svnnotify ¡÷ sourceforge.jp) Date: Tue, 01 Apr 2008 13:03:21 +0900 Subject: [Slashdotjp-dev 1036] [563] merged from upstream/2.5.0.198 branch Message-ID: <1207022601.872601.16040.nullmailer@users.sourceforge.jp> Revision: 563 http://svn.sourceforge.jp/cgi-bin/viewcvs.cgi?root=slashdotjp&view=rev&rev=563 Author: tach Date: 2008-04-01 13:03:21 +0900 (Tue, 01 Apr 2008) Log Message: ----------- merged from upstream/2.5.0.198 branch Modified Paths: -------------- slashjp/trunk/AUTHORS slashjp/trunk/INSTALL slashjp/trunk/Slash/DB/MySQL/MySQL.pm slashjp/trunk/Slash/Hook/Hook.pm slashjp/trunk/Slash/Slash.pm slashjp/trunk/Slash/Utility/Comments/Comments.pm slashjp/trunk/Slash/Utility/Environment/Environment.pm slashjp/trunk/bin/install-slashsite slashjp/trunk/debian/changelog slashjp/trunk/docs/INSTALL.pod slashjp/trunk/plugins/Admin/Admin.pm slashjp/trunk/plugins/Admin/admin.pl slashjp/trunk/plugins/Admin/templates/editStory;admin;default slashjp/trunk/plugins/Admin/templates/signoff;misc;default slashjp/trunk/plugins/Admin/templates/signoff_stats;misc;default slashjp/trunk/plugins/Ajax/PLUGIN slashjp/trunk/plugins/Ajax/htdocs/ajax.pl slashjp/trunk/plugins/Ajax/htdocs/images/admin.js slashjp/trunk/plugins/Ajax/htdocs/images/common.js slashjp/trunk/plugins/Ajax/htdocs/images/nodnix.js slashjp/trunk/plugins/Ajax/htdocs/images/sd_autocomplete.js slashjp/trunk/plugins/Ajax/htdocs/images/sectionprefs.js slashjp/trunk/plugins/Ajax/mysql_dump.sql slashjp/trunk/plugins/Ajax/templates/edit_comment;ajax;default slashjp/trunk/plugins/Ajax/templates/prefs_d2;ajax;default slashjp/trunk/plugins/Email/templates/dispStory;email;default slashjp/trunk/plugins/FAQSlashdot/faq/friends.shtml slashjp/trunk/plugins/FireHose/FireHose.pm slashjp/trunk/plugins/FireHose/PLUGIN slashjp/trunk/plugins/FireHose/firehose.css slashjp/trunk/plugins/FireHose/templates/firehose_tags_top;misc;default slashjp/trunk/plugins/Messages/templates/dailyheadlines;messages;default slashjp/trunk/plugins/Messages/templates/dailynews;messages;default slashjp/trunk/plugins/Moderation/Moderation.pm slashjp/trunk/plugins/Rating/Rating.pm slashjp/trunk/plugins/ResKey/mysql_dump.sql slashjp/trunk/plugins/Submit/submit.pl slashjp/trunk/plugins/TagModeration/TagModeration.pm slashjp/trunk/plugins/Tags/PLUGIN slashjp/trunk/plugins/Tags/Tags.pm slashjp/trunk/plugins/Tags/mysql_dump.sql slashjp/trunk/plugins/Tags/mysql_schema.sql slashjp/trunk/plugins/Tags/tagbox.pl slashjp/trunk/plugins/Tags/templates/tagsstorydivtagbox;misc;default slashjp/trunk/sql/mysql/defaults.sql slashjp/trunk/sql/mysql/upgrades slashjp/trunk/tagboxes/Despam/Despam.pm slashjp/trunk/themes/slashcode/THEME slashjp/trunk/themes/slashcode/htdocs/comments.pl slashjp/trunk/themes/slashcode/htdocs/images/comments.js slashjp/trunk/themes/slashcode/htdocs/images/dumper.js slashjp/trunk/themes/slashcode/templates/dispComment;misc;default slashjp/trunk/themes/slashcode/templates/dispLinkComment;misc;default slashjp/trunk/themes/slashcode/templates/dispStory;misc;default slashjp/trunk/themes/slashcode/templates/errors;comments;default slashjp/trunk/themes/slashcode/templates/html-header;misc;default slashjp/trunk/themes/slashcode/templates/modCommentLog;misc;default slashjp/trunk/themes/slashcode/templates/printCommComments;misc;default slashjp/trunk/themes/slashcode/templates/printCommentsMain;misc;default Added Paths: ----------- slashjp/trunk/plugins/Ajax/htdocs/images/jquery-1.2.3.js slashjp/trunk/plugins/FireHose/templates/tagsnodnixuser;misc;default slashjp/trunk/plugins/Tags/tags_tagnamecache.pl Removed Paths: ------------- slashjp/trunk/plugins/Ajax/htdocs/images/prototype.js slashjp/trunk/themes/slashcode/htdocs/images/comments2.js -------------- next part -------------- Modified: slashjp/trunk/AUTHORS =================================================================== --- slashjp/trunk/AUTHORS 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/AUTHORS 2008-04-01 04:03:21 UTC (rev 563) @@ -8,6 +8,7 @@ Cliff Wood cliff ¡÷ slashdot.org Jamie McCarthy jamie ¡÷ mccarthy.vg Tim Vroom vroom ¡÷ slashdot.org + Scott Collins scc ¡÷ slashdot.org Special thanks to some of the outstanding contributors to Slash, who have helped with various kinds of feedback, all of it invaluable. Modified: slashjp/trunk/INSTALL =================================================================== --- slashjp/trunk/INSTALL 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/INSTALL 2008-04-01 04:03:21 UTC (rev 563) @@ -261,6 +261,14 @@ cpan> o conf prerequisites_policy follow cpan> o conf commit + Data::JavaScript::Anon + There are bugs in versions earlier than 1.00 that break our + JS. Unfortunately, CPAN seems to prefer version 0.9 even + though 1.00 is available. You may have to install a better + version in CPAN by hand: + + cpan> install A/AD/ADAMK/Data-JavaScript-Anon-1.00.tar.gz + Additional Libraries You must have certain libraries existing on your system before building, for Compress::Zlib, XML::Parser, DBI and Modified: slashjp/trunk/Slash/DB/MySQL/MySQL.pm =================================================================== --- slashjp/trunk/Slash/DB/MySQL/MySQL.pm 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/Slash/DB/MySQL/MySQL.pm 2008-04-01 04:03:21 UTC (rev 563) @@ -538,7 +538,7 @@ my $page = $user->{currentPage}; my $skin = getCurrentSkin('name'); my $admin = $user->{is_admin}; - my $theme = $user->{simpledesign} ? "light" : $user->{css_theme}; + my $theme = ($user->{simpledesign} || $user->{pda}) ? "light" : $user->{css_theme}; my $constants = getCurrentStatic(); my $expire_time = $constants->{css_expire} || 3600; @@ -557,7 +557,7 @@ $css_skins_ref = $self->getCSSValuesHashForCol('skin') if !$css_skins_ref; $css_themes_ref= $self->getCSSValuesHashForCol('theme') if !$css_themes_ref; - my $lowbandwidth = $user->{lowbandwidth} ? "yes" : "no"; + my $lowbandwidth = ($user->{lowbandwidth} || $user->{pda}) ? "yes" : "no"; $page = '' if !$css_pages_ref->{$page}; $skin = '' if !$css_skins_ref->{$skin}; @@ -7966,15 +7966,16 @@ } sub getSignoffCountHashForStoids { - my($self, $stoids) = @_; + my($self, $stoids, $adminsonly) = @_; return {} if !@$stoids; my $stoid_list = join ',', @$stoids; + my $user_limit_clause = $adminsonly ? ' AND seclev >= 100' : ''; my $signoff_hash = $self->sqlSelectAllHashref( "stoid", - "stoid, COUNT(DISTINCT uid) AS cnt", - "signoff", - "stoid in ($stoid_list)", + "stoid, COUNT(DISTINCT signoff.uid) AS cnt", + "signoff, users", + "users.uid = signoff.uid AND stoid IN ($stoid_list) $user_limit_clause", "GROUP BY stoid" ); Modified: slashjp/trunk/Slash/Hook/Hook.pm =================================================================== --- slashjp/trunk/Slash/Hook/Hook.pm 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/Slash/Hook/Hook.pm 2008-04-01 04:03:21 UTC (rev 563) @@ -5,9 +5,6 @@ package Slash::Hook; use strict; -use DBIx::Password; -use Slash; -use Slash::DB; use Slash::Utility::Environment; # avoid cross-caller issues use vars qw($VERSION); Modified: slashjp/trunk/Slash/Slash.pm =================================================================== --- slashjp/trunk/Slash/Slash.pm 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/Slash/Slash.pm 2008-04-01 04:03:21 UTC (rev 563) @@ -217,6 +217,7 @@ && $story->{rendered} && !$options->{force_cache_freshen} && !$form->{simpledesign} && !$user->{simpledesign} && !$form->{lowbandwidth} && !$user->{lowbandwidth} + && !$form->{pda} && !$user->{pda} && (!$form->{ssi} || $form->{ssi} ne 'yes') && !$user->{noicons} && !$form->{issue} Modified: slashjp/trunk/Slash/Utility/Comments/Comments.pm =================================================================== --- slashjp/trunk/Slash/Utility/Comments/Comments.pm 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/Slash/Utility/Comments/Comments.pm 2008-04-01 04:03:21 UTC (rev 563) @@ -38,7 +38,7 @@ @EXPORT = qw( constrain_score dispComment displayThread printComments jsSelectComments commentCountThreshold commentThresholds discussion2 - tempUofmLinkGenerate tempUofmCipherObj selectComments + tempUofmLinkGenerate tempUofmCipherObj selectComments preProcessReplyForm getPoints preProcessComment postProcessComment prevComment saveComment ); @@ -405,8 +405,9 @@ my $anon_thresh = Data::JavaScript::Anon->anon_dump($thresh_totals || {}); s/\s+//g for ($anon_thresh, $anon_roots, $anon_rootsh); - $user->{is_anon} ||= 0; - $user->{is_admin} ||= 0; + $user->{is_anon} ||= 0; + $user->{is_admin} ||= 0; + $user->{is_subscriber} ||= 0; my $extra = ''; if ($d2_seen_0) { @@ -442,6 +443,7 @@ user_uid = $user->{uid}; user_is_anon = $user->{is_anon}; user_is_admin = $user->{is_admin}; +user_is_subscriber = $user->{is_subscriber}; user_threshold = $threshold; user_highlightthresh = $highlightthresh; @@ -534,6 +536,17 @@ my($value, $hashref, $nocomm) = @_; $hashref ||= {}; $hashref->{value} = $value; + + # this is a cheap hack to NOT print titlebar in getError if we + # are calling from ajax.pl ... easier than reorganizing the code + # for now -- pudge 2008/03/04 + for (0..9) { + if ((caller($_))[1] =~ /\bajax\.pl$/) { + $hashref->{no_titlebar} = 1; + last; + } + } + return slashDisplay('errors', $hashref, { Return => 1, Nocomm => $nocomm, Page => 'comments' }); } @@ -587,7 +600,7 @@ # Adjust reasons. Do we need a reason? # Are you threatening me? - if ($reasons) { + if ($reasons && $C->{reason}) { my $reason_id = $reasons->{$C->{reason}}{id}; if ($reason_id && $user->{"reason_alter_$reason_id"}) { $hr->{reason_bonus} = @@ -599,7 +612,7 @@ # Keep your friends close but your enemies closer. # Or ignore them, we don't care. - if ($user->{uid} != $C->{uid}) { + if ($user->{people} && $user->{uid} != $C->{uid}) { if ($user->{people}{FRIEND()}{$C->{uid}}) { $hr->{people_bonus_friend} = $user->{people_bonus_friend}; @@ -1325,6 +1338,18 @@ #======================================================================== +sub preProcessReplyForm { + my($form, $reply) = @_; + return if !$form->{pid} || !$reply->{subject} || $form->{postersubj}; + + $form->{postersubj} = decode_entities($reply->{subject}); + $form->{postersubj} =~ s/^Re://i; + $form->{postersubj} =~ s/\s\s/ /g; + $form->{postersubj} = "Re:$form->{postersubj}"; +} + +#======================================================================== + sub preProcessComment { my($comm, $user, $discussion, $error_message) = @_; # probably $comm = $form my $constants = getCurrentStatic(); @@ -1339,7 +1364,7 @@ my $tempSubject = strip_notags($comm->{postersubj}); my $tempComment = $comm->{postercomment}; - $comm->{anon} = 0; + $comm->{anon} = $user->{is_anon}; if ($comm->{postanon} && $reader->checkAllowAnonymousPosting && $user->{karma} > -1 @@ -1424,22 +1449,23 @@ $comm->{comment} = parseDomainTags($comm->{comment}, !$comm->{anon} && $comm->{fakeemail}); -# my $discussion = $slashdb->getDiscussion($comm->{sid}) || 0; my $extras = []; my $disc_skin = $slashdb->getSkin($discussion->{primaryskid}); $extras = $slashdb->getNexusExtrasForChosen( { $disc_skin->{nexus} => 1 }, { content_type => "comment" }) if $disc_skin && $disc_skin->{nexus}; - + my $preview = { - nickname => $comm->{postanon} + nickname => $comm->{anon} ? getCurrentAnonymousCoward('nickname') : $comm->{nickname}, + uid => $comm->{anon} + ? getCurrentAnonymousCoward('uid') + : $comm->{uid}, pid => $comm->{pid}, - uid => $comm->{postanon} ? '' : $comm->{uid}, - homepage => $comm->{postanon} ? '' : $comm->{homepage}, - fakeemail => $comm->{postanon} ? '' : $comm->{fakeemail}, + homepage => $comm->{anon} ? '' : $comm->{homepage}, + fakeemail => $comm->{anon} ? '' : $comm->{fakeemail}, journal_last_entry_date => $comm->{journal_last_entry_date} || '', 'time' => $slashdb->getTime, subject => $comm->{subject}, @@ -1584,7 +1610,7 @@ my $moddb = getObject("Slash::$constants->{m1_pluginname}"); if ($moddb) { my $text = $moddb->checkDiscussionForUndoModeration($comm->{sid}); - # XXX + # XXX doesn't work for D2 print $text if $text; } @@ -1617,13 +1643,16 @@ my $users = $messages->checkMessageCodes(MSG_CODE_COMMENT_REPLY, [$parent->{uid}]); if (_send_comment_msg($users->[0], \%users, $pts, $clean_comment)) { my $data = { - template_name => 'reply_msg', - subject => { template_name => 'reply_msg_subj' }, - reply => $reply, - parent => $parent, - discussion => $discussion, + template_name => 'reply_msg', + template_page => 'comments', + subject => { + template_name => 'reply_msg_subj', + template_page => 'comments', + }, + reply => $reply, + parent => $parent, + discussion => $discussion, }; - $messages->create($users->[0], MSG_CODE_COMMENT_REPLY, $data); $users{$users->[0]}++; } @@ -1634,10 +1663,14 @@ my $users = $messages->checkMessageCodes(MSG_CODE_JOURNAL_REPLY, [$discussion->{uid}]); if (_send_comment_msg($users->[0], \%users, $pts, $clean_comment)) { my $data = { - template_name => 'journrep', - subject => { template_name => 'journrep_subj' }, - reply => $reply, - discussion => $discussion, + template_name => 'journrep', + template_page => 'comments', + subject => { + template_name => 'journrep_subj', + template_page => 'comments', + }, + reply => $reply, + discussion => $discussion, }; $messages->create($users->[0], MSG_CODE_JOURNAL_REPLY, $data); @@ -1650,10 +1683,14 @@ my $users = $messages->getMessageUsers(MSG_CODE_NEW_COMMENT); my $data = { - template_name => 'commnew', - subject => { template_name => 'commnew_subj' }, - reply => $reply, - discussion => $discussion, + template_name => 'commnew', + template_page => 'comments', + subject => { + template_name => 'commnew_subj', + template_page => 'comments', + }, + reply => $reply, + discussion => $discussion, }; my @users_send; @@ -1862,12 +1899,18 @@ $time_to_display = timeCalc($comment->{date}); unless ($user->{noscores}) { - $score_to_display .= " (Score:"; - $score_to_display .= length($comment->{points}) ? $comment->{points} : "?"; + $score_to_display .= "Score:"; + if (length $comment->{points}) { + $score_to_display .= $comment->{points}; + $score_to_display = qq[$score_to_display] + if $constants->{modal_prefs_active} && !$user->{is_anon}; + } else { + $score_to_display .= '?'; + } if ($reasons && $comment->{reason}) { $score_to_display .= ", $reasons->{$comment->{reason}}{name}"; } - $score_to_display .= ")"; + $score_to_display = " ($score_to_display)"; } if ($comment->{sid} && $comment->{cid}) { @@ -1948,14 +1991,14 @@ && $comment->{nickname} ne "-") { # this last test probably useless my @link = ( ); - push @link, linkComment({ + push @link, (qq'' . linkComment({ sid => $comment->{sid}, pid => $comment->{cid}, op => 'Reply', subject => 'Reply to This', subject_only => 1, - onclick => (($discussion2 && $user->{test_code}) ? "replyTo($comment->{cid}); return false;" : '') - }) unless $user->{state}{discussion_archived}; + onclick => (($discussion2 && (!$constants->{subscribe} || $user->{is_subscriber})) ? "replyTo($comment->{cid}); return false;" : '') + }) . '') unless $user->{state}{discussion_archived}; push @link, linkComment({ sid => $comment->{sid}, @@ -2155,6 +2198,7 @@ # some commonly-used proxy ports to access our own site. # If we can, they're coming from an open HTTP proxy, which # we don't want to allow to post. + # XXX : this can become a reskey check -- pudge 2008-03 if ($constants->{comments_portscan} && ( $constants->{comments_portscan} == 2 || $constants->{comments_portscan} == 1 && $user->{is_anon} ) Modified: slashjp/trunk/Slash/Utility/Environment/Environment.pm =================================================================== --- slashjp/trunk/Slash/Utility/Environment/Environment.pm 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/Slash/Utility/Environment/Environment.pm 2008-04-01 04:03:21 UTC (rev 563) @@ -1556,7 +1556,7 @@ my @defaults = ( ['mode', 'thread'], qw[ savechanges commentsort threshold - posttype noboxes lowbandwidth simpledesign + posttype noboxes lowbandwidth simpledesign pda ]); for my $param (@defaults) { Modified: slashjp/trunk/bin/install-slashsite =================================================================== --- slashjp/trunk/bin/install-slashsite 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/bin/install-slashsite 2008-04-01 04:03:21 UTC (rev 563) @@ -26,7 +26,7 @@ my %opts; # Remember to doublecheck these match usage()! -usage('Options used incorrectly') unless getopts('hvu:H:n:xRL:i:T:P:a:e:p:o:g:', \%opts); +usage('Options used incorrectly') unless getopts('hvfu:H:n:xRL:i:T:P:a:e:p:o:g:', \%opts); usage() if !$opts{'u'} and ($opts{'h'} or !keys %opts); # if invoked with both -u and -h, call usage() later, after we load Slash::Install version() if $opts{'v'}; Modified: slashjp/trunk/debian/changelog =================================================================== --- slashjp/trunk/debian/changelog 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/debian/changelog 2008-04-01 04:03:21 UTC (rev 563) @@ -1,3 +1,9 @@ +slash (2.5.0.198-1) unstable; urgency=low + + * New upstream CVS release + + -- Taku YASUI Tue, 01 Apr 2008 13:02:56 +0900 + slash (2.5.0.196-1) unstable; urgency=low * New upstream CVS release Modified: slashjp/trunk/docs/INSTALL.pod =================================================================== --- slashjp/trunk/docs/INSTALL.pod 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/docs/INSTALL.pod 2008-04-01 04:03:21 UTC (rev 563) @@ -311,6 +311,14 @@ cpan> o conf prerequisites_policy follow cpan> o conf commit +=item B + +There are bugs in versions earlier than 1.00 that break our JS. Unfortunately, +CPAN seems to prefer version 0.9 even though 1.00 is available. You may +have to install a better version in CPAN by hand: + + cpan> install A/AD/ADAMK/Data-JavaScript-Anon-1.00.tar.gz + =item B You must have certain libraries existing on your system before building, Modified: slashjp/trunk/plugins/Admin/Admin.pm =================================================================== --- slashjp/trunk/plugins/Admin/Admin.pm 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/plugins/Admin/Admin.pm 2008-04-01 04:03:21 UTC (rev 563) @@ -222,7 +222,7 @@ my $slashdb = getCurrentDB(); my $form = getCurrentForm(); my $user = getCurrentUser(); - return unless $user->{is_admin}; + return unless $user->{is_admin} || $user->{acl}{signoff_allowed}; my $stoid = $form->{stoid}; my $uid = $user->{uid}; @@ -327,11 +327,11 @@ my($self, $days) = @_; my $days_q = $self->sqlQuote($days); my $signoff_info = $self->sqlSelectAllHashrefArray( - "stories.stoid, users.uid, (unix_timestamp(min(signoff_time)) - unix_timestamp(stories.time)) / 60 AS min_to_sign, users.nickname", + "stories.stoid, users.uid, (unix_timestamp(min(signoff_time)) - unix_timestamp(stories.time)) / 60 AS min_to_sign, users.nickname, users.seclev", "stories, story_topics_rendered, signoff, users", "stories.stoid = story_topics_rendered.stoid AND signoff.stoid=stories.stoid AND users.uid = signoff.uid AND stories.time <= NOW() AND stories.time > DATE_SUB(NOW(), INTERVAL $days_q DAY)", - "GROUP BY signoff.uid, signoff.stoid" + "GROUP BY signoff.uid, signoff.stoid ORDER BY users.seclev DESC" ); return $signoff_info; Modified: slashjp/trunk/plugins/Admin/admin.pl =================================================================== --- slashjp/trunk/plugins/Admin/admin.pl 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/plugins/Admin/admin.pl 2008-04-01 04:03:21 UTC (rev 563) @@ -1888,7 +1888,7 @@ } my $usersignoffs = $slashdb->getUserSignoffHashForStoids($user->{uid}, $stoid_list); - my $storysignoffcnt = $slashdb->getSignoffCountHashForStoids($stoid_list); + my $storysignoffcnt = $slashdb->getSignoffCountHashForStoids($stoid_list, 1); my $needed_signoffs = $slashdb->getActiveAdminCount; @@ -2607,15 +2607,22 @@ my $signoff_info = $admin->getSignoffData($days); foreach (@$signoff_info) { $author_info->{$_->{uid}}{nickname} = $_->{nickname}; + $author_info->{$_->{uid}}{uid} = $_->{uid}; $author_info->{$_->{uid}}{$days}{cnt}++; $author_info->{$_->{uid}}{$days}{tot_time} += $_->{min_to_sign}; + $author_info->{$_->{uid}}{seclev} = $_->{seclev}; $stoids_for_days{$days}{$_->{stoid}}++; push @{$author_info->{$_->{uid}}{$days}{mins}}, $_->{min_to_sign}; } } + my @author_array = values %$author_info; + + @author_array = sort { $b->{seclev} <=> $a->{seclev} } @author_array; + slashDisplay("signoff_stats", { author_info => $author_info, + author_array => \@author_array, stoids_for_days => \%stoids_for_days, num_days => $num_days }); Modified: slashjp/trunk/plugins/Admin/templates/editStory;admin;default =================================================================== --- slashjp/trunk/plugins/Admin/templates/editStory;admin;default 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/plugins/Admin/templates/editStory;admin;default 2008-04-01 04:03:21 UTC (rev 563) @@ -248,7 +248,7 @@ Media Files associated with this story - + [% FOREACH mfile = story_static_files %] [% bigfile = mfile.name %] [% IF mfile.filetype != "image" || (mfile.filetype == "image" && bigfile.match('-thumb\.')) %] @@ -269,11 +269,18 @@ [% height = height.int %] [% END %] [% bigfile = bigfile.replace('-thumb') %] - + [% ELSE %] Add [% filename %] [% END %] + [% END %] [% END %] @@ -293,6 +300,7 @@ +
    [% ispell_comments.bodytext %]
    [% PROCESS editbuttons %] Modified: slashjp/trunk/plugins/Admin/templates/signoff;misc;default =================================================================== --- slashjp/trunk/plugins/Admin/templates/signoff;misc;default 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/plugins/Admin/templates/signoff;misc;default 2008-04-01 04:03:21 UTC (rev 563) @@ -18,7 +18,6 @@ [% IF storylink %]
  • [% END %] , [% UNLESS signed %]unsigned[% END %] -[% PROCESS ajax_reskey_signoff reskey_label => 'signoff-reskey-' _ stoid, reskey_name => 'ajax_admin' %] [% IF storylink %]
  • [% END %] [% END %] __seclev__ Modified: slashjp/trunk/plugins/Admin/templates/signoff_stats;misc;default =================================================================== --- slashjp/trunk/plugins/Admin/templates/signoff_stats;misc;default 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/plugins/Admin/templates/signoff_stats;misc;default 2008-04-01 04:03:21 UTC (rev 563) @@ -23,16 +23,22 @@ [% END %] - -[% FOREACH author = author_info.keys %] - +[% seen_admin = 0 %] +[% separator = 0 %] +[% FOREACH author = author_array %] + [% IF author.seclev >= 100; seen_admin = 1; END %] + [% IF seen_admin && author.seclev < 100 && !separator %] + + [% separator = 1; %] + [% END %] + [% FOREACH days = num_days %] [% num_stories = stoids_for_days.$days.keys.size || 0 %] - [% cnt = author_info.$author.$days.cnt || 0 %] + [% cnt = author.$days.cnt || 0 %] Modified: slashjp/trunk/plugins/Email/templates/dispStory;email;default =================================================================== --- slashjp/trunk/plugins/Email/templates/dispStory;email;default 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/plugins/Email/templates/dispStory;email;default 2008-04-01 04:03:21 UTC (rev 563) @@ -56,7 +56,7 @@ To opt-out of further emailings: [% thisurl %]/email.pl?op=optout_form -Copyright 1997-2005 [% constants.sitepublisher %]. All rights reserved. +Copyright 1997-2008 [% constants.sitepublisher %]. All rights reserved. __version__ $Id$ Modified: slashjp/trunk/plugins/FAQSlashdot/faq/friends.shtml =================================================================== --- slashjp/trunk/plugins/FAQSlashdot/faq/friends.shtml 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/plugins/FAQSlashdot/faq/friends.shtml 2008-04-01 04:03:21 UTC (rev 563) @@ -7,14 +7,21 @@ - - -
    +
    +
    +

    Friends and Journals

    +
    +
    + +

    Where is my journal?

    Your journal can be found at http://slashdot.org/my/journal.

    Modified: slashjp/trunk/plugins/FireHose/FireHose.pm =================================================================== --- slashjp/trunk/plugins/FireHose/FireHose.pm 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/plugins/FireHose/FireHose.pm 2008-04-01 04:03:21 UTC (rev 563) @@ -563,7 +563,7 @@ push @where, "popularity >= $pop_q"; } } - if ($user->{is_admin}) { + if ($user->{is_admin} || $user->{acl}{signoff_allowed}) { my $signoff_label = 'sign' . $user->{uid} . 'ed'; if ($options->{unsigned}) { @@ -1126,7 +1126,7 @@ my $newtagspreloadtext = join ' ', @newtagspreload; #print STDERR "ajaxGetUserFirehose $newtagspreloadtext\n\n"; - return slashDisplay('tagsfirehosedivuser', { + return slashDisplay($form->{nodnix} ? 'tagsnodnixuser' : 'tagsfirehosedivuser', { id => $id, newtagspreloadtext => $newtagspreloadtext, }, { Return => 1 }); @@ -1518,9 +1518,13 @@ } +# Return a positive number if data was altered, 0 if it was not, +# or undef on error. + sub setFireHose { my($self, $id, $data) = @_; - return unless $id && $data; + return undef unless $id && $data; + return 0 if !%$data; my $id_q = $self->sqlQuote($id); my $mcd = $self->getMCD(); @@ -1549,7 +1553,7 @@ $self->setGlobjAdminnote($globjid, $note); } - return if !keys %$data; + return 0 if !keys %$data; my $text_data = {}; @@ -1558,9 +1562,11 @@ $text_data->{bodytext} = delete $data->{bodytext} if exists $data->{bodytext}; $text_data->{media} = delete $data->{media} if exists $data->{media}; - $self->sqlUpdate('firehose', $data, "id=$id_q"); - $self->sqlUpdate('firehose_text', $text_data, "id=$id_q") if keys %$text_data; - + my $rows = $self->sqlUpdate('firehose', $data, "id=$id_q"); +#{ use Data::Dumper; my $dstr = Dumper($data); $dstr =~ s/\s+/ /g; print STDERR "setFireHose A rows=$rows for id=$id_q data: $dstr\n"; } + $rows += $self->sqlUpdate('firehose_text', $text_data, "id=$id_q") if keys %$text_data; +#{ use Data::Dumper; my $dstr = Dumper($text_data); $dstr =~ s/\s+/ /g; print STDERR "setFireHose B rows=$rows for id=$id_q data: $dstr\n"; } + if ($mcd) { $mcd->delete("$mcdkey:$id", 3); } @@ -1572,6 +1578,8 @@ # $status = 'deleted' if $data->{accepted} eq 'yes' || $data->{rejected} eq 'yes'; $searchtoo->storeRecords(firehose => $id, { $status => 1 }); } + + return $rows; } sub dispFireHose { @@ -1597,6 +1605,9 @@ return [] unless $item && $user->{is_admin}; my $subnotes_ref = []; my $sub_memory = $self->getSubmissionMemory(); + my $url = ""; + $url = $self->getUrl($item->{url_id}) if $item->{url_id}; + foreach my $memory (@$sub_memory) { my $match = $memory->{submatch}; @@ -1604,7 +1615,8 @@ $item->{name} =~ m/$match/i || $item->{title} =~ m/$match/i || $item->{ipid} =~ m/$match/i || - $item->{introtext} =~ m/$match/i) { + $item->{introtext} =~ m/$match/i || + $url =~ m/$match/i) { push @$subnotes_ref, $memory; } } Modified: slashjp/trunk/plugins/FireHose/PLUGIN =================================================================== --- slashjp/trunk/plugins/FireHose/PLUGIN 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/plugins/FireHose/PLUGIN 2008-04-01 04:03:21 UTC (rev 563) @@ -32,6 +32,7 @@ template=templates/tagsfirehosedivadmin;misc;default template=templates/tagsfirehosedivtagbox;misc;default template=templates/tagsfirehosedivuser;misc;default +template=templates/tagsnodnixuser;misc;default task=firehose_reject_old.pl task=firehose_backend.pl task=firehose_get_thumbnails.pl Modified: slashjp/trunk/plugins/FireHose/firehose.css =================================================================== --- slashjp/trunk/plugins/FireHose/firehose.css 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/plugins/FireHose/firehose.css 2008-04-01 04:03:21 UTC (rev 563) @@ -449,9 +449,15 @@ .embed #nod-user-tags, #console #nod-input {left: 63px !important;} .embed #nix-user-tags, #console #nix-input {left: 68px !important;} .embed #nodmenu ul, #console #nodmenu ul {margin: 0 0 0 43px; background: #222; opacity: .9; border: 1px solid #111;} -ol#nod-hardened, ol#nix-hardened, ol#nod-hardened li, ol#nix-hardened li {background: black !important;} -ol#nod-hardened, ol#nix-hardened {margin-left: 0 !important; padding-left: 0 !important;} +ol#nod-hardened, ol#nix-hardened, ol#nod-hardened li, ol#nix-hardened li {position: relative; background: black !important;} +ol#nod-hardened, ol#nix-hardened {margin-left: 0 !important; padding-left: 0 !important; cursor: pointer;} +.tag-actions {display: none; position: absolute; opacity: 0.6; top: -0.75em; right: 0; width: 1.5em; font-size: 120%; text-align: center; color: black; background-color: white; -moz-border-radius: 0.1em; -webkit-border-radius: 0.1em;} +a.not-tag, a.del-tag {text-decoration: none;} +li:hover .tag-actions {display: inline;} +li .tag-actions:hover {opacity: 0.9;} +li .tag-actions .not-tag:hover, li .tag-actions .del-tag:hover {color: red;} + .article .title, .article h3, .article .generaltitle {border: none !important} .article .generaltitle, #firehoselist .article .title, .article h3 {line-height: 170% !important;} .briefarticle .generaltitle, .briefarticle .title, .briefarticle h3 {line-height: 160% !important;} Modified: slashjp/trunk/plugins/FireHose/templates/firehose_tags_top;misc;default =================================================================== --- slashjp/trunk/plugins/FireHose/templates/firehose_tags_top;misc;default 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/plugins/FireHose/templates/firehose_tags_top;misc;default 2008-04-01 04:03:21 UTC (rev 563) @@ -26,7 +26,7 @@ [%- END -%] [%- tags_seen.${parts.0} = 1 -%] [%- END -%] - [%- IF item.type == "story" -%][% IF user.is_admin %][% PROCESS signoff stoid=item.srcid fhid = item.id %][% END %][% END %] + [%- IF item.type == "story" -%][% IF user.is_admin || user.acl.signoff_allowed %][% PROCESS signoff stoid=item.srcid fhid = item.id %][% END %][% END %] [% IF item.type == "feed" && user.is_admin %] [% feed_user = Slash.db.getUser(item.uid, "nickname"); %] [% feed_user | strip_literal %] Copied: slashjp/trunk/plugins/FireHose/templates/tagsnodnixuser;misc;default (from rev 561, slashjp/branches/upstream/current/plugins/FireHose/templates/tagsnodnixuser;misc;default) =================================================================== --- slashjp/trunk/plugins/FireHose/templates/tagsnodnixuser;misc;default (rev 0) +++ slashjp/trunk/plugins/FireHose/templates/tagsnodnixuser;misc;default 2008-04-01 04:03:21 UTC (rev 563) @@ -0,0 +1,23 @@ +__section__ +default +__description__ +id = id +newtagspreloadtext = text to preload the newtags-# field with + +WARNING: keep the related string in nodnix.js in sync with the

  • expansion, below +__title__ + +__page__ +misc +__lang__ +en_US +__name__ +tagsnodnixuser +__template__ +[% FOREACH tag = newtagspreloadtext.split(' ') %] +
  • [% tag %]! x
  • +[% END %] +__seclev__ +10000 +__version__ +$Id: tagsnodnixuser;misc;default,v 1.4 2008/03/03 20:54:00 scc Exp $ Modified: slashjp/trunk/plugins/Messages/templates/dailyheadlines;messages;default =================================================================== --- slashjp/trunk/plugins/Messages/templates/dailyheadlines;messages;default 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/plugins/Messages/templates/dailyheadlines;messages;default 2008-04-01 04:03:21 UTC (rev 563) @@ -25,7 +25,7 @@ [% END %] -Copyright 1997-2007 [% constants.sitepublisher %]. All rights reserved. +Copyright 1997-2008 [% constants.sitepublisher %]. All rights reserved. __seclev__ 500 Modified: slashjp/trunk/plugins/Messages/templates/dailynews;messages;default =================================================================== --- slashjp/trunk/plugins/Messages/templates/dailynews;messages;default 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/plugins/Messages/templates/dailynews;messages;default 2008-04-01 04:03:21 UTC (rev 563) @@ -52,7 +52,7 @@ [% END %] -Copyright 1997-2006 [% constants.sitepublisher %]. All rights reserved. +Copyright 1997-2008 [% constants.sitepublisher %]. All rights reserved. __seclev__ 500 Modified: slashjp/trunk/plugins/Moderation/Moderation.pm =================================================================== --- slashjp/trunk/plugins/Moderation/Moderation.pm 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/plugins/Moderation/Moderation.pm 2008-04-01 04:03:21 UTC (rev 563) @@ -91,10 +91,12 @@ $self->countUsers({ max => 1 }), $self->getReasons ); - $html->{$score} = "(Score:$points"; + $html->{$score} = "Score:$points"; + $html->{$score} = qq[$html->{$score}] + if $constants->{modal_prefs_active} && !$user->{is_anon}; $html->{$score} .= ", $reasons->{$comment->{reason}}{name}" if $comment->{reason} && $reasons->{$comment->{reason}}; - $html->{$score} .= ")"; + $html->{$score} = "($html->{$score})"; my $ptstr = $user->{points} == 1 ? 'point' : 'points'; $html->{$select} = "Moderated '$reasons->{$reason}{name}.' $user->{points} $ptstr left."; Modified: slashjp/trunk/plugins/Rating/Rating.pm =================================================================== --- slashjp/trunk/plugins/Rating/Rating.pm 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/plugins/Rating/Rating.pm 2008-04-01 04:03:21 UTC (rev 563) @@ -52,13 +52,13 @@ my $extras; $extras = $slashdb->getNexusExtrasForChosen({$disc_skin->{nexus} => 1}, {content_type => "comment"}) if $disc_skin && $disc_skin->{nexus}; - return unless $extras; + return 0 unless $extras; foreach my $extra(@$extras) { $can_create_vote=1 if $extra->[1] eq "comment_vote"; } - return unless $can_create_vote; + return 0 unless $can_create_vote; my $active = "yes"; my $val = 0; Modified: slashjp/trunk/plugins/ResKey/mysql_dump.sql =================================================================== --- slashjp/trunk/plugins/ResKey/mysql_dump.sql 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/plugins/ResKey/mysql_dump.sql 2008-04-01 04:03:21 UTC (rev 563) @@ -54,7 +54,7 @@ INSERT INTO reskey_resource_checks VALUES (NULL, 1, 'all', 'Slash::ResKey::Checks::AL2::NoPost', 501); INSERT INTO reskey_resource_checks VALUES (NULL, 1, 'all', 'Slash::ResKey::Checks::AL2::Spammer', 531); INSERT INTO reskey_resource_checks VALUES (NULL, 1, 'all', 'Slash::ResKey::Checks::Duration', 601); -INSERT INTO reskey_resource_checks VALUES (NULL, 1, 'use', 'Slash::ResKey::Checks::ProxyScan', 1001); +#INSERT INTO reskey_resource_checks VALUES (NULL, 1, 'use', 'Slash::ResKey::Checks::ProxyScan', 1001); # dummy example of how to disable the Slash::ResKey::Checks::User check for "touch" # (maybe, for example, because the check isn't needed) @@ -66,8 +66,8 @@ INSERT INTO reskey_vars VALUES (1, 'user_seclev', 0, 'Minimum seclev to use resource'); INSERT INTO reskey_vars VALUES (1, 'duration_max-uses', 30, 'how many uses per timeframe'); INSERT INTO reskey_vars VALUES (1, 'duration_max-failures', 10, 'how many failures per reskey'); -INSERT INTO reskey_vars VALUES (1, 'duration_uses', 120, 'min duration (in seconds) between uses'); -INSERT INTO reskey_vars VALUES (1, 'duration_creation-use', 5, 'min duration between (in seconds) creation and use'); +INSERT INTO reskey_vars VALUES (1, 'duration_uses', 60, 'min duration (in seconds) between uses'); +INSERT INTO reskey_vars VALUES (1, 'duration_creation-use', 10, 'min duration between (in seconds) creation and use'); Modified: slashjp/trunk/plugins/Submit/submit.pl =================================================================== --- slashjp/trunk/plugins/Submit/submit.pl 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/plugins/Submit/submit.pl 2008-04-01 04:03:21 UTC (rev 563) @@ -265,6 +265,9 @@ } } + my $url = ""; + $url = $slashdb->getUrl($sub->{url_id}) if $sub->{url_id}; + foreach my $memory (@$sub_memory) { my $match = $memory->{submatch}; @@ -272,7 +275,8 @@ $sub->{name} =~ m/$match/i || $sub->{subj} =~ m/$match/i || $sub->{ipid} =~ m/$match/i || - $sub->{story} =~ m/$match/i) { + $sub->{story} =~ m/$match/i || + $url =~ m/$match/i ) { push @$subnotes_ref, $memory; } } Modified: slashjp/trunk/plugins/TagModeration/TagModeration.pm =================================================================== --- slashjp/trunk/plugins/TagModeration/TagModeration.pm 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/plugins/TagModeration/TagModeration.pm 2008-04-01 04:03:21 UTC (rev 563) @@ -91,10 +91,12 @@ $self->countUsers({ max => 1 }), $self->getReasons ); - $html->{$score} = "(Score:$points"; + $html->{$score} = "Score:$points"; + $html->{$score} = qq[$html->{$score}] + if $constants->{modal_prefs_active} && !$user->{is_anon}; $html->{$score} .= ", $reasons->{$comment->{reason}}{name}" if $comment->{reason} && $reasons->{$comment->{reason}}; - $html->{$score} .= ")"; + $html->{$score} = "($html->{$score})"; my $ptstr = $user->{points} == 1 ? 'point' : 'points'; $html->{$select} = "Moderated '$reasons->{$reason}{name}.' $user->{points} $ptstr left."; Modified: slashjp/trunk/plugins/Tags/PLUGIN =================================================================== --- slashjp/trunk/plugins/Tags/PLUGIN 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/plugins/Tags/PLUGIN 2008-04-01 04:03:21 UTC (rev 563) @@ -6,6 +6,7 @@ mysql_schema=mysql_schema.sql requiresplugin=Ajax task=tagbox.pl +task=tags_tagnamecache.pl task=tags_udc.pl task=tags_updateclouts.pl template=templates/data;tags;default Modified: slashjp/trunk/plugins/Tags/Tags.pm =================================================================== --- slashjp/trunk/plugins/Tags/Tags.pm 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/plugins/Tags/Tags.pm 2008-04-01 04:03:21 UTC (rev 563) @@ -603,6 +603,9 @@ } # Is it descriptive? + # XXX this should be optimized by retrieving the list of _all_ + # descriptive tagnames in memcached or the local closure and + # doing a lookup on that. if ($types->{describe} && !$clid) { $tn_data = $self->getTagnameDataFromId($tagnameid); $clid = $types->{describe} if $tn_data->{descriptive}; @@ -685,7 +688,8 @@ for my $uid (keys %uid) { # XXX getUser($foo, 'clout') does not work at the moment, # so getUser($foo)->{clout} is used instead - $user_clout_hr->{$uid} = $self->getUser($uid)->{clout}; + my $user = $self->getUser($uid); + $user_clout_hr->{$uid} = $self->getUser($uid)->{clout} if $user; } @@ -704,7 +708,9 @@ $tagname_clid = $default_clout_clid; } my $tagname_clout_name = $clout_types->{ $tagname_clid }; - $tag_hr->{user_clout} = $mult * $user_clout_hr ->{$tag_hr->{uid}}{$tagname_clout_name}; + my $clout = $user_clout_hr->{$tag_hr->{uid}}; + my $clout_specific = $clout ? $clout->{$tagname_clout_name} : 0; + $tag_hr->{user_clout} = $mult * $clout_specific; $tag_hr->{total_clout} = $tag_hr->{tag_clout} * $tag_hr->{tagname_clout} * $tag_hr->{user_clout}; } } @@ -849,7 +855,7 @@ # my $value = $mcd->get("$mcdkey$name"); # return $value if defined $value; # } - my $private_clause = $options->{include_private} ? '' : " AND private='no'"; + my $private_clause = ref($options) && $options->{include_private} ? '' : " AND private='no'"; my $id = $self->getTagnameidFromNameIfExists($name); return [ ] if !$id; my $hr_ar = $self->sqlSelectAllHashrefArray( @@ -965,7 +971,7 @@ my($self, $constants, $user, $form) = @_; my $sidenc = $form->{sidenc}; - my $sid = $sidenc; $sid =~ tr{:}{/}; + my $sid = $sidenc; $sid =~ tr{-}{/}; my $stoid = $self->getStoidFromSid($sid); my $tags_reader = getObject('Slash::Tags', { db_type => 'reader' }); #print STDERR scalar(localtime) . " ajaxGetUserStory for stoid=$stoid sidenc=$sidenc tr=$tags_reader\n"; @@ -1023,7 +1029,7 @@ sub ajaxGetAdminStory { my($slashdb, $constants, $user, $form) = @_; my $sidenc = $form->{sidenc}; - my $sid = $sidenc; $sid =~ tr{:}{/}; + my $sid = $sidenc; $sid =~ tr{-}{/}; if (!$sid || $sid !~ regexSid() || !$user->{is_admin}) { return getData('error', {}, 'tags'); @@ -1155,7 +1161,7 @@ sub ajaxCreateForStory { my($slashdb, $constants, $user, $form) = @_; my $sidenc = $form->{sidenc}; - my $sid = $sidenc; $sid =~ tr{:}{/}; + my $sid = $sidenc; $sid =~ tr{-}{/}; my $tags = getObject('Slash::Tags'); my $tagsstring = $form->{tags}; if (!$sid || $sid !~ regexSid() || $user->{is_anon} || !$tags) { @@ -1189,6 +1195,30 @@ return $retval; } +sub ajaxDeactivateTag { + my($self, $constants, $user, $form) = @_; + my $type = $form->{type} || "stories"; + my $tags = getObject('Slash::Tags'); # XXX isn't this the same as $self? -Jamie + + my ($table, $id); + + if ($type eq "firehose") { + my $firehose = getObject("Slash::FireHose"); + my $item = $firehose->getFireHose($form->{id}); + ($table, $id) = $tags->getGlobjTarget($item->{globjid}); + } else { + # XXX doesn't work yet for stories or urls + return; + } + + $tags->deactivateTag({ + uid => $user->{uid}, + name => $form->{tag}, + table => $table, + id => $id, + }); +} + sub ajaxProcessAdminTags { my($slashdb, $constants, $user, $form) = @_; #print STDERR "ajaxProcessAdminTags\n"; @@ -1197,7 +1227,7 @@ my($id, $table, $sid, $sidenc, $itemid); if ($type eq "stories") { $sidenc = $form->{sidenc}; - $sid = $sidenc; $sid =~ tr{:}{/}; + $sid = $sidenc; $sid =~ tr{-}{/}; $id = $slashdb->getStoidFromSid($sid); $table = "stories"; } elsif ($type eq "urls") { @@ -1293,7 +1323,7 @@ my $table; if ($form->{type} eq "stories") { my $sidenc = $form->{sidenc}; - my $sid = $sidenc; $sid =~ tr{:}{/}; + my $sid = $sidenc; $sid =~ tr{-}{/}; $id = $slashdb->getStoidFromSid($sid); $table = "stories" } elsif ($form->{type} eq "urls") { @@ -1380,6 +1410,13 @@ my $len = length($prefix); my $notize = $form->{prefix} =~ /^([-!])/ ? $1 : ''; + my $minlen = $constants->{tags_prefixlist_minlen} || 3; + if ($len < $minlen) { + # Too short to give a meaningful suggestion, and the + # shorter the prefix the longer the DB query takes. + return ''; + } + my $tnhr = $tags_reader->listTagnamesByPrefix($prefix); my @priority = @@ -1683,10 +1720,10 @@ sub listTagnamesActive { my($self, $options) = @_; my $constants = getCurrentStatic(); - my $max_num = $options->{max_num} || 100; - my $seconds = $options->{seconds} || (3600*6); - my $include_private = $options->{include_private} || 0; - my $min_slice = $options->{min_slice} || 0; + my $max_num = ref($options) && $options->{max_num} || 100; + my $seconds = ref($options) && $options->{seconds} || (3600*6); + my $include_private = ref($options) && $options->{include_private} || 0; + my $min_slice = ref($options) && $options->{min_slice} || 0; $min_slice = 0 if !$constants->{plugin}{FireHose}; # This seems like a horrendous query, but I _think_ it will run @@ -1791,8 +1828,8 @@ sub listTagnamesRecent { my($self, $options) = @_; my $constants = getCurrentStatic(); - my $seconds = $options->{seconds} || (3600*6); - my $include_private = $options->{include_private} || 0; + my $seconds = ref($options) && $options->{seconds} || (3600*6); + my $include_private = ref($options) && $options->{include_private} || 0; my $private_clause = $include_private ? '' : " AND private='no'"; my $recent_ar = $self->sqlSelectColArrayref( 'DISTINCT tagnames.tagname', @@ -1824,24 +1861,65 @@ $a2 cmp $b2 || $a1 cmp $b1; } +{ # closure +my $tagname_cache_lastcheck = 1; sub listTagnamesByPrefix { my($self, $prefix_str, $options) = @_; my $constants = getCurrentStatic(); my $reader = getObject('Slash::DB', { db_type => 'reader' }); - my $like_str = $self->sqlQuote("$prefix_str%"); - my $minc = $self->sqlQuote($options->{minc} || $constants->{tags_prefixlist_minc} || 4); - my $mins = $self->sqlQuote($options->{mins} || $constants->{tags_prefixlist_mins} || 3); - my $num = $options->{num} || $constants->{tags_prefixlist_num}; - $num = 10 if !$num || $num !~ /^(\d+)$/ || $num < 1; + my $ret_hr; my $mcd = undef; $mcd = $self->getMCD() unless $options; my $mcdkey = "$self->{_mcd_keyprefix}:tag_prefx:"; if ($mcd) { - my $ret_str = $mcd->get("$mcdkey$prefix_str"); - return $ret_str if $ret_str; + $ret_hr = $mcd->get("$mcdkey$prefix_str"); + return $ret_hr if $ret_hr; } + # If the tagname_cache table has been filled, use it. + # Otherwise, perform an expensive query directly. + # The logic is that $tagname_cache_lastcheck stays a + # large positive number (a timestamp) until we determine + # that the table _does_ have rows, at which point that + # number drops to 0. Once its value hits 0, it is never + # checked again. + if ($tagname_cache_lastcheck > 0 && $tagname_cache_lastcheck < time()-3600) { + my $rows = $reader->sqlCount('tagname_cache'); + $tagname_cache_lastcheck = $rows ? 0 : time; + } + my $use_cache_table = $tagname_cache_lastcheck ? 0 : 1; + if ($use_cache_table) { + $ret_hr = $self->listTagnamesByPrefix_cache($prefix_str, $options); + } else { + $ret_hr = $self->listTagnamesByPrefix_direct($prefix_str, $options); + } + + if ($mcd) { + # The expiration we use is much longer than the tags_cache_expire + # var since the cache data changes only once a day. + $mcd->set("$mcdkey$prefix_str", $ret_hr, 3600); + } + + return $ret_hr; +} +} + +# This is a quick-and-dirty (and not very accurate) estimate which +# is only performed for a site which has not built its tagname_cache +# table yet. Hopefully most sites will use this the first day the +# Tags plugin is installed and then never again. + +sub listTagnamesByPrefix_direct { + my($self, $prefix_str, $options) = @_; + my $constants = getCurrentStatic(); + my $like_str = $self->sqlQuote("$prefix_str%"); + my $minc = $self->sqlQuote($options->{minc} || $constants->{tags_prefixlist_minc} || 4); + my $mins = $self->sqlQuote($options->{mins} || $constants->{tags_prefixlist_mins} || 3); + my $num = $options->{num} || $constants->{tags_prefixlist_num}; + $num = 10 if !$num || $num !~ /^(\d+)$/ || $num < 1; + + my $reader = getObject('Slash::DB', { db_type => 'reader' }); my $ar = $reader->sqlSelectAllHashrefArray( 'tagname, COUNT(DISTINCT tags.uid) AS c, @@ -1860,13 +1938,25 @@ for my $hr (@$ar) { $ret_hr->{ $hr->{tagname} } = $hr->{sc}; } - if ($mcd) { - my $mcdexp = $constants->{tags_cache_expire} || 180; - $mcd->set("$mcdkey$prefix_str", $ret_hr, $mcdexp) - } return $ret_hr; } +sub listTagnamesByPrefix_cache { + my($self, $prefix_str, $options) = @_; + my $constants = getCurrentStatic(); + my $like_str = $self->sqlQuote("$prefix_str%"); + my $num = $options->{num} || $constants->{tags_prefixlist_num}; + $num = 10 if !$num || $num !~ /^(\d+)$/ || $num < 1; + + my $reader = getObject('Slash::DB', { db_type => 'reader' }); + my $ret_hr = $reader->sqlSelectAllKeyValue( + 'tagname, weight', + 'tagname_cache', + "tagname LIKE $like_str", + "ORDER BY weight DESC LIMIT $num"); + return $ret_hr; +} + sub getPrivateTagnames { my ($self) = @_; my $user = getCurrentUser; Modified: slashjp/trunk/plugins/Tags/mysql_dump.sql =================================================================== --- slashjp/trunk/plugins/Tags/mysql_dump.sql 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/plugins/Tags/mysql_dump.sql 2008-04-01 04:03:21 UTC (rev 563) @@ -10,6 +10,7 @@ INSERT INTO vars (name, value, description) VALUES ('tags_cache_expire', '180', 'Local data cache expiration for tags'); INSERT INTO vars (name, value, description) VALUES ('tags_list_mintc', '4', 'Minimum value of total_clout for tagged items shown at /tags/foo'); INSERT INTO vars (name, value, description) VALUES ('tags_prefixlist_minc', '4', 'Minimum value of c (count) for tagnames returned by listTagnamesByPrefix'); +INSERT INTO vars (name, value, description) VALUES ('tags_prefixlist_minlen', '3', 'Minimum length of a tag prefix to bother looking up suggestions for'); INSERT INTO vars (name, value, description) VALUES ('tags_prefixlist_mins', '3', 'Minimum value of s (clout sum) for tagnames returned by listTagnamesByPrefix'); INSERT INTO vars (name, value, description) VALUES ('tags_prefixlist_num', '10', 'Number of tagnames returned by listTagnamesByPrefix'); INSERT INTO vars (name, value, description) VALUES ('tags_prefixlist_priority', 'back bookmark feed hold journal none quik submission story', 'Tagnames to give priority to on autocomplete'); @@ -48,6 +49,7 @@ INSERT INTO ajax_ops VALUES (NULL, 'tags_admin_commands', 'Slash::Tags', 'ajaxProcessAdminTags', 'ajax_admin', 'use'); INSERT INTO ajax_ops VALUES (NULL, 'tags_history', 'Slash::Tags', 'ajaxTagHistory', 'ajax_admin', 'createuse'); INSERT INTO ajax_ops VALUES (NULL, 'tags_list_tagnames', 'Slash::Tags', 'ajaxListTagnames', 'ajax_tags_read', 'createuse'); +INSERT INTO ajax_ops VALUES (NULL, 'tags_deactivate', 'Slash::Tags', 'ajaxDeactivateTag', 'ajax_tags_write', 'use'); INSERT INTO menus VALUES (NULL, 'tagszg', 'Active', 'active', '[% gSkin.rootdir %]/tags', 1, 1, 1); INSERT INTO menus VALUES (NULL, 'tagszg', 'Recent', 'recent', '[% gSkin.rootdir %]/tags/recent', 1, 1, 2); Modified: slashjp/trunk/plugins/Tags/mysql_schema.sql =================================================================== --- slashjp/trunk/plugins/Tags/mysql_schema.sql 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/plugins/Tags/mysql_schema.sql 2008-04-01 04:03:21 UTC (rev 563) @@ -33,7 +33,19 @@ PRIMARY KEY tagnameid (tagnameid), UNIQUE tagname (tagname) ) TYPE=InnoDB; - + +# tagname_cache is not normalized because it's intended to be used +# for quick lookups. + +DROP TABLE IF EXISTS tagname_cache; +CREATE TABLE tagname_cache ( + tagnameid int UNSIGNED NOT NULL, + tagname VARCHAR(64) NOT NULL, + weight FLOAT UNSIGNED DEFAULT 0.0 NOT NULL, + PRIMARY KEY tagnameid (tagnameid), + UNIQUE tagname (tagname), +) TYPE=InnoDB; + DROP TABLE IF EXISTS tagname_params; CREATE TABLE tagname_params ( tagnameid int UNSIGNED NOT NULL, Modified: slashjp/trunk/plugins/Tags/tagbox.pl =================================================================== --- slashjp/trunk/plugins/Tags/tagbox.pl 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/plugins/Tags/tagbox.pl 2008-04-01 04:03:21 UTC (rev 563) @@ -282,7 +282,7 @@ sub insert_feederlog { my($tagbox, $feeder_ar) = @_; for my $feeder_hr (@$feeder_ar) { -main::tagboxLog("addFeederInfo: tbid=$tagbox->{tbid} tagid=$feeder_hr->{tagid} affected_id=$feeder_hr->{affected_id} imp=$feeder_hr->{importance}") +{ my $fstr = Dumper($feeder_hr); $fstr =~ s/\s+/ /g; main::tagboxLog("addFeederInfo: tbid=$tagbox->{tbid} f: $fstr"); } if (defined($feeder_hr->{tagid})); $tagboxdb->addFeederInfo($tagbox->{tbid}, $feeder_hr); } @@ -301,6 +301,10 @@ for my $affected_hr (@$affected_ar) { my $tagbox = $tagboxdb->getTagboxes($affected_hr->{tbid}, [qw( object )]); #my $ad = Dumper($affected_hr); $ad =~ s/\s+/ /g; my $tb = Dumper($tagbox); $tb =~ s/\s+/ /g; print STDERR "r_t_u affected_hr: $ad tagbox: $tb\n"; +if ($affected_hr->{tbid} == 17) { +my $feeder_ar = $tagboxdb->sqlSelectAllHashrefArray('*', 'tagboxlog_feeder', "tbid=17 AND affected_id=$affected_hr->{affected_id}", 'ORDER BY tfid'); +print STDERR "r_t_u rows for tbid=17 id=$affected_hr->{affected_id}: " . Dumper($feeder_ar) +} $tagbox->{object}->run($affected_hr->{affected_id}); $tagboxdb->markTagboxRunComplete($affected_hr); last if time() >= $run_until || $task_exit_flag; Copied: slashjp/trunk/plugins/Tags/tags_tagnamecache.pl (from rev 561, slashjp/branches/upstream/current/plugins/Tags/tags_tagnamecache.pl) =================================================================== --- slashjp/trunk/plugins/Tags/tags_tagnamecache.pl (rev 0) +++ slashjp/trunk/plugins/Tags/tags_tagnamecache.pl 2008-04-01 04:03:21 UTC (rev 563) @@ -0,0 +1,144 @@ +#!/usr/bin/perl -w +# This code is a part of Slash, and is released under the GPL. +# Copyright 1997-2005 by Open Source Technology Group. See README +# and COPYING for more information, or see http://slashcode.com/. +# $Id: tags_tagnamecache.pl,v 1.1 2008/03/21 04:10:35 jamiemccarthy Exp $ + +# Once a day, rewrite the tags_tagnamecache table, used for finding +# tagname suggestions based on prefixes. + +use strict; +use vars qw( %task $me $task_exit_flag ); +use Slash::DB; +use Slash::Display; +use Slash::Utility; +use Slash::Constants ':slashd'; + +(my $VERSION) = ' $Revision: 1.1 $ ' =~ /\$Revision:\s+([^\s]+)/; + +$task{$me}{timespec} = "30 6 * * *"; +$task{$me}{timespec_panic_1} = ''; # not that important +$task{$me}{fork} = SLASHD_NOWAIT; + +$task{$me}{code} = sub { + my($virtual_user, $constants, $slashdb, $user) = @_; + my $tagsdb = getObject('Slash::Tags'); + my $tagsdb_reader = getObject('Slash::Tags', { db_type => 'reader' }); + my $daysback = $constants->{tags_tagnamecache_daysback} || 180; + my $min_tagid = getMinimumTagid($tagsdb, $daysback); + my $ar = getTagnameList($tagsdb_reader, $min_tagid); + my $rows_replaced = replaceTagnames($tagsdb, $ar); + my $rows_deleted = deleteTagnamesNotIn($tagsdb, $ar); + my $total_rows = $tagsdb->sqlCount('tagname_cache'); + return "replaced $rows_replaced, deleted $rows_deleted, total $total_rows"; +}; + +sub getMinimumTagid { + my($tagsdb, $daysback) = @_; + my $min = $tagsdb->sqlSelectNumericKeyAssumingMonotonic( + 'tags', 'min', 'tagid', + "created_at >= DATE_SUB(NOW(), INTERVAL $daysback DAY)"); + return $min; +} + +# For now, let's include private tagnames in this list. It's not +# revealing private information since it's completely aggregated, +# and while suggesting tagnames like 'nod' and 'nix' may not be +# helpful, suggesting 'troll' and 'interesting' seems OK. + +sub getTagnameList { + my($tagsdb_reader, $min_tagid) = @_; + $min_tagid ||= 1; + + my $constants = getCurrentStatic(); + my $minc = $tagsdb_reader->sqlQuote($constants->{tags_prefixlist_minc} || 4); + my $mins = $tagsdb_reader->sqlQuote($constants->{tags_prefixlist_mins} || 3); + # $maxnum is to prevent $tagnameid_str from exceeding MySQL limits. + # Default max_allowed_packet should be 16 MB, so an ~80K query + # should be perfectly fine. + my $maxnum = 10000; + + # Get the list of tagnameids sorted in a very rough order of + # "importance." + # Note that the query uses multiple columns to sort the data, + # but we skim off only the tagnameid on the client side since + # that's all we care about. + + my $tagnameid_ar = $tagsdb_reader->sqlSelectColArrayref( + 'tags.tagnameid, + COUNT(DISTINCT tags.uid) AS c, + SUM(tag_clout * IF(value IS NULL, 1, value)) AS s, + COUNT(DISTINCT tags.uid)/3 + SUM(tag_clout * IF(value IS NULL, 1, value)) AS sc', + 'tags, users_info, tagnames + LEFT JOIN tagname_params USING (tagnameid)', + "tagnames.tagnameid=tags.tagnameid + AND tags.uid=users_info.uid + AND tags.inactivated IS NULL + AND tagid >= $min_tagid", + "GROUP BY tags.tagnameid + HAVING c >= $minc AND s >= $mins + ORDER BY sc DESC, tagname ASC + LIMIT $maxnum"); + return [ ] if !$tagnameid_ar || !@$tagnameid_ar; + my $tagnameid_str = join(',', sort { $a <=> $b } @$tagnameid_ar); + + # Now get the total list of tags (which will be very large, + # so this is a slow query) + + my $tag_ar = $tagsdb_reader->sqlSelectAllHashrefArray( + '*, UNIX_TIMESTAMP(created_at) AS created_at_ut', + 'tags', + "tagnameid IN ($tagnameid_str) + AND tagid >= $min_tagid + AND tags.inactivated IS NULL"); + + # This will call getUser() for every uid in the above list and + # getTagnameidClid() for every tagnameid (up to 10,000). So + # this will be a very slow operation. + + $tagsdb_reader->addCloutsToTagArrayref($tag_ar); + + my $tagnameid_sum = { }; + for my $hr (@$tag_ar) { + $tagnameid_sum->{ $hr->{tagnameid} } ||= 0; + $tagnameid_sum->{ $hr->{tagnameid} } += $hr->{total_clout}; + } + my $ret_ar = [ ]; + for my $tagnameid (@$tagnameid_ar) { + my $sum = $tagnameid_sum->{$tagnameid}; + next unless $sum > 0; + my $tagname = $tagsdb_reader->getTagnameDataFromId($tagnameid)->{tagname}; + push @$ret_ar, { + tagnameid => $tagnameid, + tagname => $tagname, + weight => $sum, + }; + } + + return $ret_ar; +} + +sub replaceTagnames { + my($tagsdb, $ar) = @_; + my $rows = 0; + for my $hr (@$ar) { + $rows += $tagsdb->sqlReplace('tagname_cache', $hr); + Time::HiRes::sleep(0.01); + } + return $rows; +} + +sub deleteTagnamesNotIn { + my($tagsdb, $ar) = @_; + my $tagnameid_str = join(',', + sort { $a <=> $b } + map { $_->{tagnameid} } + @$ar + ); + my $rows = $tagsdb->sqlDelete('tagname_cache', + "tagnameid NOT IN ($tagnameid_str)"); + return $rows; +} + +1; + Modified: slashjp/trunk/plugins/Tags/templates/tagsstorydivtagbox;misc;default =================================================================== --- slashjp/trunk/plugins/Tags/templates/tagsstorydivtagbox;misc;default 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/plugins/Tags/templates/tagsstorydivtagbox;misc;default 2008-04-01 04:03:21 UTC (rev 563) @@ -13,7 +13,7 @@ __name__ tagsstorydivtagbox __template__ -[% sidenc = story.sid.replace("/",":") %] +[% sidenc = story.sid.replace("/","-") # no '/'s in html ids (see: http://www.w3.org/TR/html401/types.html) %] [% IF user.tags_canread_stories %]
    Modified: slashjp/trunk/sql/mysql/defaults.sql =================================================================== --- slashjp/trunk/sql/mysql/defaults.sql 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/sql/mysql/defaults.sql 2008-04-01 04:03:21 UTC (rev 563) @@ -833,7 +833,7 @@ INSERT INTO vars (name, value, description) VALUES ('cur_performance_stats_lastid', '0', 'accesslogid to start searching at'); INSERT INTO vars (name, value, description) VALUES ('cur_performance_stats_weeks', '8', 'number of weeks back to compare current stats to'); INSERT INTO vars (name, value, description) VALUES ('currentqid',1,'The Current Question on the homepage pollbooth'); -INSERT INTO vars (name, value, description) VALUES ('cvs_tag_currentcode','T_2_5_0_196','The current cvs tag that the code was updated to - this does not affect site behavior but may be useful for your records'); +INSERT INTO vars (name, value, description) VALUES ('cvs_tag_currentcode','T_2_5_0_197','The current cvs tag that the code was updated to - this does not affect site behavior but may be useful for your records'); INSERT INTO vars (name, value, description) VALUES ('datadir','/usr/local/slash/www.example.com','What is the root of the install for Slash'); INSERT INTO vars (name, value, description) VALUES ('db_auto_increment_increment','1','If your master DB uses auto_increment_increment, i.e. multiple master replication, echo its value into this var'); INSERT INTO vars (name, value, description) VALUES ('dbsparklines_disp','0','Display dbsparklines in the currentAdminUsers box?'); Modified: slashjp/trunk/sql/mysql/upgrades =================================================================== --- slashjp/trunk/sql/mysql/upgrades 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/sql/mysql/upgrades 2008-04-01 04:03:21 UTC (rev 563) @@ -5049,8 +5049,6 @@ # not for slashdot UPDATE vars SET value = 'yes no binspam dupe notthebest offtopic stupid slownewsday interesting funny insightful' WHERE name = 'tagbox_top_excludetagnames'; -# PUDGE LAST UPDATED HERE - # 2007-12-05 UPDATE vars SET value = 'T_2_5_0_185' WHERE name = 'cvs_tag_currentcode'; @@ -5136,8 +5134,6 @@ # 2008-02-13 UPDATE vars SET value = 'T_2_5_0_194' WHERE name = 'cvs_tag_currentcode'; -# SLASHDOT LAST UPDATED HERE - # For sites *without* plugins/Tags DELETE FROM clout_types; @@ -5147,8 +5143,6 @@ # 2008-02-20 UPDATE vars SET value = 'T_2_5_0_195' WHERE name = 'cvs_tag_currentcode'; -# SLASHCODE/USEPERL LAST UPDATED HERE - # for plugins/Tags INSERT INTO vars (name, value, description) VALUES ('tags_unknowntype_default_clid', '1', 'For tags of unknown type, which clout id do we pretend they are?'); INSERT INTO vars (name, value, description) VALUES ('tags_unknowntype_default_mult', '0.3', 'For tags of unknown type, what multiplier do we give to the tagging user clout or type tags_unknowntype_default_clid?'); @@ -5156,3 +5150,50 @@ # 2008-02-28 UPDATE vars SET value = 'T_2_5_0_196' WHERE name = 'cvs_tag_currentcode'; +# for plugins/Tags +INSERT INTO ajax_ops VALUES (NULL, 'tags_deactivate', 'Slash::Tags', 'ajaxDeactivateTag', 'ajax_tags_write', 'use'); +INSERT INTO vars (name, value, description) VALUES ('tags_prefixlist_minlen', '3', 'Minimum length of a tag prefix to bother looking up suggestions for'); + +# 2008-03-12 +UPDATE vars SET value = 'T_2_5_0_197' WHERE name = 'cvs_tag_currentcode'; + +# SLASHDOT LAST UPDATED HERE + +# for plugins/Ajax +UPDATE ajax_ops set reskey_name = 'ajax_user_static', reskey_type='createuse' WHERE op='admin_signoff'; + +# comments +DELETE FROM reskey_resource_checks WHERE rkrid = 1; +INSERT INTO reskey_resource_checks VALUES (NULL, 1, 'all', 'Slash::ResKey::Checks::User', 101); +INSERT INTO reskey_resource_checks VALUES (NULL, 1, 'all', 'Slash::ResKey::Checks::ACL', 201); +INSERT INTO reskey_resource_checks VALUES (NULL, 1, 'all', 'Slash::ResKey::Checks::AL2::AnonNoPost', 301); +INSERT INTO reskey_resource_checks VALUES (NULL, 1, 'all', 'Slash::ResKey::Checks::AL2::NoPostAnon', 401); +INSERT INTO reskey_resource_checks VALUES (NULL, 1, 'all', 'Slash::ResKey::Checks::AL2::NoPost', 501); +INSERT INTO reskey_resource_checks VALUES (NULL, 1, 'all', 'Slash::ResKey::Checks::AL2::Spammer', 531); +INSERT INTO reskey_resource_checks VALUES (NULL, 1, 'all', 'Slash::ResKey::Checks::Duration', 601); + +DELETE FROM reskey_vars WHERE rkrid = 1; +INSERT INTO reskey_vars VALUES (1, 'adminbypass', 1, 'If admin, bypass checks for duration, proxy, and user'); +INSERT INTO reskey_vars VALUES (1, 'acl_no', 'reskey_no_comments', 'If this ACL present, can\'t use resource'); +INSERT INTO reskey_vars VALUES (1, 'user_seclev', 0, 'Minimum seclev to use resource'); +INSERT INTO reskey_vars VALUES (1, 'duration_max-uses', 30, 'how many uses per timeframe'); +INSERT INTO reskey_vars VALUES (1, 'duration_max-failures', 10, 'how many failures per reskey'); +INSERT INTO reskey_vars VALUES (1, 'duration_uses', 60, 'min duration (in seconds) between uses'); +INSERT INTO reskey_vars VALUES (1, 'duration_creation-use', 10, 'min duration between (in seconds) creation and use'); + +# for plugins/Tags +CREATE TABLE tagname_cache ( + tagnameid int UNSIGNED NOT NULL, + tagname VARCHAR(64) NOT NULL, + weight FLOAT UNSIGNED DEFAULT 0.0 NOT NULL, + PRIMARY KEY tagnameid (tagnameid), + UNIQUE tagname (tagname) +) TYPE=InnoDB; + + +# 2008-03-19 +UPDATE vars SET value = 'T_2_5_0_198' WHERE name = 'cvs_tag_currentcode'; + +# SLASHCODE/USEPERL LAST UPDATED HERE + +# PUDGE LAST UPDATED HERE Modified: slashjp/trunk/tagboxes/Despam/Despam.pm =================================================================== --- slashjp/trunk/tagboxes/Despam/Despam.pm 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/tagboxes/Despam/Despam.pm 2008-04-01 04:03:21 UTC (rev 563) @@ -53,9 +53,10 @@ my $constants = getCurrentStatic(); my $tagsdb = getObject('Slash::Tags'); - $self->{spamid} = $tagsdb->getTagnameidCreate('binspam'); - $self->{upvoteid} = $tagsdb->getTagnameidCreate($constants->{tags_upvote_tagname} || 'nod'); + $self->{spamid} = $tagsdb->getTagnameidCreate('binspam'); return undef unless $self->{spamid}; + $self->{upvoteid} = $tagsdb->getTagnameidCreate($constants->{tags_upvote_tagname} || 'nod'); + $self->{recalc_tbids} = undef; return $self; } @@ -91,6 +92,7 @@ }; push @$ret_ar, $ret_hr; } + main::tagboxLog("Despam->feed_newtags A " . scalar(@$ret_ar) . ": '@$ret_ar'"); return [ ] if !@$ret_ar; # Tags applied to globjs that have a firehose entry associated @@ -101,6 +103,7 @@ 'globjid', 'firehose', "globjid IN ($globjs_str)"); + main::tagboxLog("Despam->feed_newtags B " . scalar(@$fh_globjs_ar) . ": '@$fh_globjs_ar'"); return [ ] if !@$fh_globjs_ar; # if no affected globjs have firehose entries, short-circuit out my %fh_globjs = ( map { $_, 1 } @$fh_globjs_ar ); $ret_ar = [ grep { $fh_globjs{ $_->{affected_id} } } @$ret_ar ]; @@ -111,13 +114,10 @@ sub feed_deactivatedtags { my($self, $tags_ar) = @_; - # XXX This need not do anything, I don't think -- not even call - # feed_newtags. - # The way Despam is set up, 2 admin binspam tags will mark a globjid, - # and even if 1 of them is deactivated a moment later, we have no way - # to undo the process. - main::tagboxLog("Despam->feed_deactivatedtags called: tags_ar='" . join(' ', map { $_->{tagid} } @$tags_ar) . "', returning nothing"); - return [ ]; + main::tagboxLog("Despam->feed_deactivatedtags called: tags_ar='" . join(' ', map { $_->{tagid} } @$tags_ar) . "', calling feed_newtags"); + my $ret_ar = $self->feed_newtags($tags_ar); + main::tagboxLog("Despam->feed_deactivatedtags returning " . scalar(@$ret_ar)); + return $ret_ar; } sub feed_userchanges { @@ -134,6 +134,7 @@ my $firehose_db = getObject('Slash::FireHose'); my $slashdb = getCurrentDB(); + # Get the list of admin uids. my $admins = $tagsdb->getAdmins(); my $admin_in_str = join(',', sort { $a <=> $b } @@ -141,170 +142,281 @@ keys %$admins); return unless $admin_in_str; + # Get info about the firehose item that may have been tagged. my $affected_id_q = $self->sqlQuote($affected_id); - my $fhid = $self->sqlSelect('id', 'firehose', "globjid = $affected_id_q"); - warn "Slash::Tagbox::Despam->run bad data, fhid='$fhid' db='$firehose_db'" if !$fhid || !$firehose_db; + my $fhid = $self->sqlSelect('DISTINCT id', 'firehose', "globjid = $affected_id_q"); + if (!$fhid || !$firehose_db) { + main::tagboxLog("Slash::Tagbox::Despam->run bad data, fhid='$fhid' db='$firehose_db'"); + return ; + } my $fhitem = $firehose_db->getFireHose($fhid); + + # Get info about the uid and ipid that submitted the firehose item. + # We only track ipid for actual submissions, not journals/bookmarks. my $submitter_uid = $fhitem->{uid}; - my $submitter_srcid = $fhitem->{srcid_32}; + my $submitter_ipid = ''; + my $types = $slashdb->getGlobjTypes(); + my $submission_gtid = $types->{submissions}; + if ($submission_gtid) { + $submitter_ipid = $slashdb->sqlSelect( + 'ipid', + 'globjs, submissions', + "globjid=$affected_id + AND gtid=$submission_gtid + AND target_id=subid" + ) || ''; + } - my $binspam_count = $slashdb->sqlCount( - 'tags, firehose', - "tags.uid IN ($admin_in_str) - AND tags.inactivated IS NULL - AND tags.tagnameid = $self->{spamid} - AND tags.globjid = firehose.globjid - AND firehose.uid = $submitter_uid"); - my $binspam_tagids = $slashdb->sqlSelectColArrayref( - 'tagid', - 'tags, firehose', - "tags.uid IN ($admin_in_str) - AND tags.inactivated IS NULL - AND tags.tagnameid = $self->{spamid} - AND tags.globjid = firehose.globjid - AND firehose.uid = $submitter_uid"); - main::tagboxLog(sprintf("%s->run marking fhid %d (%d) as is_spam (for count %d on uid %d: '%s')", - ref($self), $fhid, $affected_id, $binspam_count, $submitter_uid, join(' ', @$binspam_tagids))); - $firehose_db->setFireHose($fhid, { is_spam => 'yes' }); + # First figure out how many times the globjid was tagged binspam by + # an admin. It may be zero (if forceFeederRecalc was called, or if + # an old binspam tag was deactivated). Even one admin binspam tag + # is enough to mark the individual item as binspam. + my $binspam_count_globjid = $slashdb->sqlCount( + 'tags', + "globjid=$affected_id + AND tagnameid=$self->{spamid} + AND uid IN ($admin_in_str) + AND inactivated IS NULL"); + my $is_spam = $binspam_count_globjid > 0 ? 1 : 0; - if (isAnon($submitter_uid)) { - # Non-logged-in user, check by IP (srcid_32) - if ($submitter_srcid && - $binspam_count > $constants->{tagbox_despam_binspamsallowed_ip} - ) { - main::tagboxLog(sprintf("%s->run marking srcid %s for %d admin binspam tags, based on %d (%d)", - ref($self), $submitter_srcid, $binspam_count, $fhid, $affected_id)); - $self->despam_srcid($submitter_srcid, $binspam_count); - } - } else { - # Logged-in user, check by uid - if ($binspam_count > $constants->{tagbox_despam_binspamsallowed}) { - main::tagboxLog(sprintf("%s->run marking uid %d for %d admin binspam tags, based on %d (%d)", - ref($self), $submitter_uid, $binspam_count, $fhid, $affected_id)); - $self->despam_uid($submitter_uid, $binspam_count); - } + # Now see how many times this globjid's uid (or, if anonymous, ipid) + # was tagged binspam by an admin. If greater than a certain + # threshold, that srcid (uid/ipid) will be given the 'spammer' al2. + my($check_type, $srcid, $table_clause, $where_clause) = (undef, undef); + if (!isAnon($submitter_uid)) { + # Logged-in user, check by uid. + $check_type = 'uid'; + $srcid = $submitter_uid; + $table_clause = ''; + $where_clause = "firehose.uid = $submitter_uid"; + } elsif ($submitter_ipid) { + # Non-logged-in user, check by IP (submissions.ipid) + $check_type = 'ipid'; + $srcid = convert_srcid('ipid', $submitter_ipid); + $table_clause = ', globjs, submissions'; + $where_clause = "firehose.type='submission' + AND firehose.globjid=globjs.globjid + AND globjs.target_id=submissions.subid + AND submissions.ipid='$submitter_ipid'"; } -} + # If neither of the above, it's an anonymous non-submission, so + # (at present) there's nothing we will do to block its "fellow" + # firehose items. -sub despam_srcid { - my($self, $srcid, $count) = @_; - my $slashdb = getCurrentDB(); - my $constants = getCurrentStatic(); + # Find out which and how many other 'binspam' tags this contributor + # has amassed in total (where "contributor" can be an ipid or uid). + my $binspam_tagid_globj_hr = { }; + if ($check_type) { + $binspam_tagid_globj_hr = $slashdb->sqlSelectAllKeyValue( + 'tags.tagid, tags.globjid', + "tags, firehose$table_clause", + "tags.globjid = firehose.globjid + AND tags.tagnameid = $self->{spamid} + AND tags.uid IN ($admin_in_str) + AND tags.inactivated IS NULL + AND $where_clause"); + } - my $al2_hr = $slashdb->getAL2($srcid); - if ($count > $constants->{tagbox_despam_binspamsallowed_ip}) { - main::tagboxLog("marking $srcid as spammer for $count"); - if (!$al2_hr->{spammer}) { - $slashdb->setAL2($srcid, { spammer => 1, comment => "Despam $count" }); - } + # This array contains the list of admin tags applied to + # firehose items from this srcid. If there are too many + # of them, mark the srcid. + my $binspam_count = scalar(keys %$binspam_tagid_globj_hr); + my $mark_srcid = 0; + if ($binspam_count > + ( $check_type eq 'uid' + ? $constants->{tagbox_despam_binspamsallowed} + : $constants->{tagbox_despam_binspamsallowed_ip} ) + ) { + $is_spam = $mark_srcid = 1; } -} -sub despam_uid { - my($self, $uid, $count) = @_; - my $constants = getCurrentStatic(); - my $slashdb = getCurrentDB(); - my $reader = getObject('Slash::DB', { db_type => 'reader' }); - my $tagboxdb = getObject('Slash::Tagbox'); + main::tagboxLog(sprintf("%s->run uid=%d ipid=%s check_type=%s affected_id=%d srcid=%s count=%d is_spam=%d mark_srcid=%d tagids: '%s'", + ref($self), ($submitter_uid || '0'), ($submitter_ipid || 'none'), + (defined($check_type) ? $check_type : 'undef'), + $affected_id, $srcid, $binspam_count, $is_spam, $mark_srcid, + join(' ', sort { $a <=> $b } keys %$binspam_tagid_globj_hr))); - # First, set the user's 'spammer' AL2. - my $adminuid = $constants->{tagbox_despam_al2adminuid}; - my $al2_hr = $slashdb->getAL2($uid); - if (!$al2_hr->{spammer}) { - $slashdb->setAL2($uid, { spammer => 1, comment => "Despam $count" }, - { adminuid => $adminuid }); + # is_spam=0 is_spam=1 mark_srcid=1 + # + # check_type undef clear 1 globj set 1 globjid set 1 globjid + # check_type=uid clear 1 globj set 1 globjid set all globjids, setAL2 + # check_type=ipid clear 1 globj set 1 globjid set all globjids, setAL2 + + # Always set/clear at least the one globjid affected. + my %globjids = ( $affected_id, 1 ); + if ($mark_srcid && $check_type) { + # Set/clear both the individual globjid and all its + # fellow submitted globjids, if known. + for my $tagid (keys %$binspam_tagid_globj_hr) { + $globjids{ $binspam_tagid_globj_hr->{$tagid} } = 1; + } } + # Convert that list of globjids to firehose ids. + my $globjid_in_str = join(',', sort { $a <=> $b } keys %globjids); + my $fhid_hr = $slashdb->sqlSelectAllKeyValue( + 'id, globjid', + 'firehose', + "globjid IN ($globjid_in_str)"); + main::tagboxLog(sprintf("%s->run globjids '%s' -> fhids '%s'", + ref($self), + join(' ', sort { $a <=> $b } keys %globjids), + join(' ', sort { $a <=> $b } keys %$fhid_hr))); - # Next, set the user's clout manually to 0. - $slashdb->setUser($uid, { tag_clout => 0 }); - - # Next, mark as spam everything the user's submitted. - $slashdb->sqlUpdate('firehose', { is_spam => 'yes' }, - "accepted != 'no' AND uid=$uid"); - - # Next, if $count is high enough, set the 'spammer' AL2 for all - # the IPID's the user has submitted from. - if ($count > $constants->{tagbox_despam_binspamsallowed_ip}) { - my $days = defined($constants->{tagbox_despam_ipdayslookback}) - ? $constants->{tagbox_despam_ipdayslookback} : 60; - my %srcid_used = ( ); - if ($days) { - my $sub_ipid_ar = $reader->sqlSelectColArrayref( - 'DISTINCT ipid', - 'submissions', - "uid=$uid AND time >= DATE_SUB(NOW(), INTERVAL $days DAY) AND ipid != ''"); - my $journal_srcid_ar = $reader->sqlSelectColArrayref( - 'DISTINCT ' . get_srcid_sql_out('srcid_32'), - 'journals', - "uid=$uid AND date >= DATE_SUB(NOW(), INTERVAL $days DAY) AND srcid_32 != 0"); - my $book_srcid_ar = $reader->sqlSelectColArrayref( - 'DISTINCT ' . get_srcid_sql_out('srcid_32'), - 'bookmarks', - "uid=$uid AND createdtime >= DATE_SUB(NOW(), INTERVAL $days DAY) AND srcid_32 != 0"); - for my $ipid (@$sub_ipid_ar) { - my $srcid = convert_srcid(ipid => $ipid); - $srcid_used{$srcid} = 1; + # Loop on all the fhids required to be changed, setting or + # clearing them as appropriate. + for my $fhid (sort { $a <=> $b } keys %$fhid_hr) { + my $globjid = $fhid_hr->{$fhid}; + my $rows = $firehose_db->setFireHose($fhid, { is_spam => ($is_spam ? 'yes' : 'no') }); + main::tagboxLog(sprintf("%s->run marked fhid %d (%d) as is_spam=%d rows=%s", + ref($self), $fhid, $globjid, $is_spam, $rows)); + if ($rows > 0) { + # If this firehose item's spam status changed, either way, its + # scores now need to be recalculated immediately. + # Get the list of tbids we need to force a recalc for. + if (!defined $self->{recalc_tbids}) { + my $tagboxes = $tagboxdb->getTagboxes(); + for my $tagbox_hr (@$tagboxes) { + push @{$self->{recalc_tbids}}, $tagbox_hr->{tbid} + if $tagbox_hr->{name} =~ /^(FHEditorPop|FireHoseScores)$/; + } } - for my $srcid (@$journal_srcid_ar) { - $srcid_used{$srcid} = 1; + # Force the recalculations of their scores. + for my $tbid (@{$self->{recalc_tbids}}) { + $tagboxdb->forceFeederRecalc($tbid, $globjid); + main::tagboxLog(sprintf("%s->run force recalc tbid=%d globjid=%d", + ref($self), $tbid, $globjid)); } - for my $srcid (@$book_srcid_ar) { - $srcid_used{$srcid} = 1; - } - my @srcids = sort grep { $_ } keys %srcid_used; - for my $srcid (@srcids) { - $al2_hr = $slashdb->getAL2($srcid); - if (!$al2_hr->{spammer}) { - $slashdb->setAL2($srcid, { spammer => 1, comment => "Despam $count for $uid" }); - } - } } } - # Next, declout everyone who's upvoted any of the user's - # recent submissions (except bookmarks, because those are - # generic enough). - my $daysback = $constants->{tagbox_despam_decloutdaysback} || 7; - my $upvoter_ar = $slashdb->sqlSelectColArrayref( - 'DISTINCT tags.uid', - 'tags, firehose', - "tags.globjid = firehose.globjid - AND firehose.uid = $uid - AND type IN ('submission', 'journal') - AND createtime >= DATE_SUB(NOW(), INTERVAL $daysback DAY) - AND tagnameid = $self->{upvoteid} - AND inactivated IS NULL"); - my $max_clout = defined($constants->{tagbox_despam_upvotermaxclout}) - ? $constants->{tagbox_despam_upvotermaxclout} : '0.85'; - for my $upvoter (@$upvoter_ar) { - main::tagboxLog("setting user $upvoter clout to max $max_clout for upvoting user $uid"); - $slashdb->setUser($upvoter, { - -tag_clout => "MAX(tag_clout, $max_clout)" - }); + # If appropriate, mark the submitter's uid or ipid as a spammer + # and mark _all_ their submissions as binspam. + if ($mark_srcid && $check_type) { + main::tagboxLog(sprintf("%s->run marking spammer AL2 srcid=%s", + ref($self), $srcid)); + $slashdb->setAL2($srcid, { spammer => 1 }, { adminuid => 1183959 }); } - - # Next, insert tagboxlog_feeder entries to tell the relevant - # tagboxes to recalculate those scores. - my $tagboxes = $tagboxdb->getTagboxes(); - my @tagboxids = map { $_->{tbid} } grep { $_->{name} =~ /^(FHEditorPop|FireHoseScores)$/ } @$tagboxes; - my $globjid_tagid = $slashdb->sqlSelectAllKeyValue( - 'firehose.globjid, tagid', - 'firehose, tags', - "firehose.uid=$uid - AND firehose.globjid=tags.globjid - AND tags.uid=$uid - AND tagnameid=$self->{upvoteid}", - 'GROUP BY firehose.globjid'); - for my $globjid (sort keys %$globjid_tagid) { - for my $tbid (@tagboxids) { - $tagboxdb->addFeederInfo($tbid, { - affected_id => $globjid, - importance => 1, - tagid => $globjid_tagid->{ $globjid }, - }); - } - } } +#sub despam_srcid { +# my($self, $srcid, $count) = @_; +# my $slashdb = getCurrentDB(); +# my $constants = getCurrentStatic(); +# +# my $al2_hr = $slashdb->getAL2($srcid); +# if ($count > $constants->{tagbox_despam_binspamsallowed_ip}) { +# main::tagboxLog("marking $srcid as spammer for $count"); +# if (!$al2_hr->{spammer}) { +# $slashdb->setAL2($srcid, { spammer => 1, comment => "Despam $count" }); +# } +# } +#} +# +#sub despam_uid { +# my($self, $uid, $count) = @_; +# my $constants = getCurrentStatic(); +# my $slashdb = getCurrentDB(); +# my $reader = getObject('Slash::DB', { db_type => 'reader' }); +# my $tagboxdb = getObject('Slash::Tagbox'); +# +# # First, set the user's 'spammer' AL2. +# my $adminuid = $constants->{tagbox_despam_al2adminuid}; +# my $al2_hr = $slashdb->getAL2($uid); +# if (!$al2_hr->{spammer}) { +# $slashdb->setAL2($uid, { spammer => 1, comment => "Despam $count" }, +# { adminuid => $adminuid }); +# } +# +# # Next, set the user's clout manually to 0. +# $slashdb->setUser($uid, { tag_clout => 0 }); +# +# # Next, mark as spam everything the user's submitted. +# $slashdb->sqlUpdate('firehose', { is_spam => 'yes' }, +# "accepted != 'no' AND uid=$uid"); +# +# # Next, if $count is high enough, set the 'spammer' AL2 for all +# # the IPID's the user has submitted from. +# if ($count > $constants->{tagbox_despam_binspamsallowed_ip}) { +# my $days = defined($constants->{tagbox_despam_ipdayslookback}) +# ? $constants->{tagbox_despam_ipdayslookback} : 60; +# my %srcid_used = ( ); +# if ($days) { +# my $sub_ipid_ar = $reader->sqlSelectColArrayref( +# 'DISTINCT ipid', +# 'submissions', +# "uid=$uid AND time >= DATE_SUB(NOW(), INTERVAL $days DAY) AND ipid != ''"); +# my $journal_srcid_ar = $reader->sqlSelectColArrayref( +# 'DISTINCT ' . get_srcid_sql_out('srcid_32'), +# 'journals', +# "uid=$uid AND date >= DATE_SUB(NOW(), INTERVAL $days DAY) AND srcid_32 != 0"); +# my $book_srcid_ar = $reader->sqlSelectColArrayref( +# 'DISTINCT ' . get_srcid_sql_out('srcid_32'), +# 'bookmarks', +# "uid=$uid AND createdtime >= DATE_SUB(NOW(), INTERVAL $days DAY) AND srcid_32 != 0"); +# for my $ipid (@$sub_ipid_ar) { +# my $srcid = convert_srcid(ipid => $ipid); +# $srcid_used{$srcid} = 1; +# } +# for my $srcid (@$journal_srcid_ar) { +# $srcid_used{$srcid} = 1; +# } +# for my $srcid (@$book_srcid_ar) { +# $srcid_used{$srcid} = 1; +# } +# my @srcids = sort grep { $_ } keys %srcid_used; +# for my $srcid (@srcids) { +# $al2_hr = $slashdb->getAL2($srcid); +# if (!$al2_hr->{spammer}) { +# $slashdb->setAL2($srcid, { spammer => 1, comment => "Despam $count for $uid" }); +# } +# } +# } +# } +# +# # Next, declout everyone who's upvoted any of the user's +# # recent submissions (except bookmarks, because those are +# # generic enough). +# my $daysback = $constants->{tagbox_despam_decloutdaysback} || 7; +# my $upvoter_ar = $slashdb->sqlSelectColArrayref( +# 'DISTINCT tags.uid', +# 'tags, firehose', +# "tags.globjid = firehose.globjid +# AND firehose.uid = $uid +# AND type IN ('submission', 'journal') +# AND createtime >= DATE_SUB(NOW(), INTERVAL $daysback DAY) +# AND tagnameid = $self->{upvoteid} +# AND inactivated IS NULL"); +# my $max_clout = defined($constants->{tagbox_despam_upvotermaxclout}) +# ? $constants->{tagbox_despam_upvotermaxclout} : '0.85'; +# for my $upvoter (@$upvoter_ar) { +# main::tagboxLog("setting user $upvoter clout to max $max_clout for upvoting user $uid"); +# $slashdb->setUser($upvoter, { +# -tag_clout => "MAX(tag_clout, $max_clout)" +# }); +# } +# +# # Next, insert tagboxlog_feeder entries to tell the relevant +# # tagboxes to recalculate those scores. +# my $tagboxes = $tagboxdb->getTagboxes(); +# my @tagboxids = map { $_->{tbid} } grep { $_->{name} =~ /^(FHEditorPop|FireHoseScores)$/ } @$tagboxes; +# my $globjid_tagid = $slashdb->sqlSelectAllKeyValue( +# 'firehose.globjid, tagid', +# 'firehose, tags', +# "firehose.uid=$uid +# AND firehose.globjid=tags.globjid +# AND tags.uid=$uid +# AND tagnameid=$self->{upvoteid}", +# 'GROUP BY firehose.globjid'); +# for my $globjid (sort keys %$globjid_tagid) { +# for my $tbid (@tagboxids) { +# $tagboxdb->addFeederInfo($tbid, { +# affected_id => $globjid, +# importance => 1, +# tagid => $globjid_tagid->{ $globjid }, +# }); +# } +# } +#} + 1; Modified: slashjp/trunk/themes/slashcode/THEME =================================================================== --- slashjp/trunk/themes/slashcode/THEME 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/themes/slashcode/THEME 2008-04-01 04:03:21 UTC (rev 563) @@ -127,7 +127,6 @@ htdoc=htdocs/topics.pl htdoc=htdocs/users.pl htdoc=htdocs/images/comments.js -htdoc=htdocs/images/comments2.js htdoc=htdocs/images/dumper.js htdoc=htdocs/badge.pl htdoc=htdocs/help.pl @@ -340,6 +339,7 @@ plugin=Login plugin=Hof plugin=Messages +plugin=Moderation plugin=PollBooth plugin=Print plugin=PubKey Modified: slashjp/trunk/themes/slashcode/htdocs/comments.pl =================================================================== --- slashjp/trunk/themes/slashcode/htdocs/comments.pl 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/themes/slashcode/htdocs/comments.pl 2008-04-01 04:03:21 UTC (rev 563) @@ -203,7 +203,7 @@ header($title, $section) or return; $header_emitted = 1; } - print getError('login error'); + print Slash::Utility::Comments::getError('login error'); $op = 'preview'; } $op = 'default' if @@ -217,7 +217,7 @@ header($title, $section) or return; $header_emitted = 1; } - print getError("nosubscription"); + print Slash::Utility::Comments::getError("nosubscription"); } #print STDERR scalar(localtime) . " $$ B op=$op header_emitted=$header_emitted\n"; @@ -369,18 +369,6 @@ return fixurl($uri); } -################################################################# -# this groups all the errors together in -# one template, called "errors;comments;default" -# Why not just getData??? -Brian -sub getError { - my($value, $hashref, $nocomm) = @_; - $hashref ||= {}; - $hashref->{value} = $value; - return slashDisplay('errors', $hashref, - { Return => 1, Nocomm => $nocomm }); -} - ################################################################## sub delete { my($form, $slashdb, $user, $constants) = @_; @@ -449,7 +437,7 @@ if ($sid) { $sid =~ /(\d+)/; $sid = $1 } if (!$sid) { # Need a discussion ID to reply to, or there's no point. - print getError('no sid'); + print Slash::Utility::Comments::getError('no sid'); return; } @@ -461,7 +449,7 @@ # An attempt to reply to a comment that doesn't exist is an error. if ($pid && !%$reply) { - print getError('no such parent'); + print Slash::Utility::Comments::getError('no such parent'); return; } elsif ($pid) { $pid_reply = prepareQuoteReply($reply); @@ -485,12 +473,12 @@ # just in case the user fudged it. if (($user->{is_anon} || $form->{postanon}) && !$slashdb->checkAllowAnonymousPosting($user->{uid})) { - print getError('anonymous disallowed'); + print Slash::Utility::Comments::getError('anonymous disallowed'); return; } if ($discussion->{type} eq 'archived') { - print getError('archive_error'); + print Slash::Utility::Comments::getError('archive_error'); return; } @@ -498,12 +486,7 @@ $preview = previewForm(\$error_message, $discussion) or $error_flag++; } - if (%$reply && !$form->{postersubj}) { - $form->{postersubj} = decode_entities($reply->{subject}); - $form->{postersubj} =~ s/^Re://i; - $form->{postersubj} =~ s/\s\s/ /g; - $form->{postersubj} = "Re:$form->{postersubj}"; - } + preProcessReplyForm($form, $reply); my $extras = []; my $disc_skin = $slashdb->getSkin($discussion->{primaryskid}); @@ -514,8 +497,10 @@ if $disc_skin && $disc_skin->{nexus}; my $gotmodwarning; - $gotmodwarning = 1 if $form->{gotmodwarning} - || $error_message && $error_message eq getError("moderations to be lost"); + $gotmodwarning = 1 if $form->{gotmodwarning} || + ($error_message && $error_message eq + Slash::Utility::Comments::getError("moderations to be lost") + ); slashDisplay('edit_comment', { pid_reply => $pid_reply, @@ -542,7 +527,7 @@ my $comment = preProcessComment($form, $user, $discussion, $error_message) or return; return $$error_message if $comment eq '-1'; - my $preview = postProcessComment({ %$comment, %$user }, 0, $discussion); + my $preview = postProcessComment({ %$user, %$form, %$comment }, 0, $discussion); if ($constants->{plugin}{Subscribe}) { $preview->{subscriber_bonus} = @@ -685,9 +670,9 @@ # went wrong. if ($ret_val < 0) { if ($ret_val == -1) { - print getError('no points'); + print Slash::Utility::Comments::getError('no points'); } elsif ($ret_val == -2){ - print getError('not enough points'); + print Slash::Utility::Comments::getError('not enough points'); } } else { $was_touched += $ret_val; Modified: slashjp/trunk/themes/slashcode/htdocs/images/comments.js =================================================================== --- slashjp/trunk/themes/slashcode/htdocs/images/comments.js 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/themes/slashcode/htdocs/images/comments.js 2008-04-01 04:03:21 UTC (rev 563) @@ -14,6 +14,7 @@ var root_comments_hash = {}; var last_updated_comments = []; var last_updated_comments_index = 0; +var reply_link_html = {}; var comments_started = 0; var current_cid = 0; var more_comments_num; @@ -35,6 +36,7 @@ var comment_body_reply = []; var root_comment = 0; var discussion_id = 0; +var user_is_subscriber = 0; var user_is_admin = 0; var user_is_anon = 0; var user_uid = 0; @@ -179,7 +181,7 @@ // this doesn't work -// var statusdiv = $('comment_status_' + abscid); +// var statusdiv = $dom('comment_status_' + abscid); // statusdiv.innerHTML = 'Working ...'; // doModifiers(); @@ -219,7 +221,7 @@ // statusdiv.innerHTML = ''; - if (!commentIsInWindow(abscid)) + if (!commentIsInWindow(abscid, (cid != abscid))) scrollWindowTo(abscid); if (was_hidden) @@ -415,7 +417,7 @@ // Firefox (see ajaxFetchComments) ... we may make that into a separate // call later, as it has to be properly called AFTER addComment calls are // all done -- pudge -function addComment(cid, comment, html) { +function addComment(cid, comment, html, front) { if (!loaded || !cid || !comment) return false; @@ -432,7 +434,7 @@ } var pid = comment['pid']; - if ($('tree_' + cid)) { + if ($dom('tree_' + cid)) { if (pid) { var parent = comments[pid]; var seen = 0; @@ -460,22 +462,28 @@ html = html || dummyComment(cid); if (pid) { - var tree = $('tree_' + pid); + var tree = $dom('tree_' + pid); if (tree) { setDefaultDisplayMode(pid); var parent = comments[pid]; - parent['kids'].push(cid); + if (front) + parent['kids'].unshift(cid); + else + parent['kids'].push(cid); - var commtree = $('commtree_' + pid); + var commtree = $dom('commtree_' + pid); if (commtree) { - commtree.innerHTML = commtree.innerHTML + html; + if (front) + commtree.innerHTML = html + commtree.innerHTML; + else + commtree.innerHTML = commtree.innerHTML + html; } else { tree.innerHTML = tree.innerHTML + '
      ' + html + '
    '; } } } else { - var commlist = $('commentlisting'); + var commlist = $dom('commentlisting'); if (commlist) { root_comments.push(cid); root_comments_hash[cid] = 1; @@ -655,10 +663,10 @@ finishCommentUpdates(); if (roothiddens) { - $('roothiddens').innerHTML = roothiddens + ' comments are beneath your threshhold'; - $('roothiddens').className = 'show'; + $dom('roothiddens').innerHTML = roothiddens + ' comments are beneath your threshhold'; + $dom('roothiddens').className = 'show'; } else { - $('roothiddens').className = 'hide'; + $dom('roothiddens').className = 'hide'; } /* NOTE need to display note for hidden root comments */ return void(0); @@ -669,9 +677,17 @@ /*******************/ function numsort (a, b) { return (a - b) } +function map_hash( hash, f ) { + var result = []; + jQuery.each(hash, function(k, v) { + result.push(f([k, v])); + }); + return result; +} + function toHash(thisobject) { - return thisobject.map(function (pair) { - return pair.map(encodeURIComponent).join(','); + return map_hash(thisobject, function (pair) { + return jQuery.map(pair, encodeURIComponent).join(','); }).join(';'); } @@ -685,7 +701,7 @@ if (option) thresh = 1; - var params = []; + var params = {}; params['op'] = 'comments_fetch'; var newoldstuff = cids ? 0 : 1; @@ -713,11 +729,9 @@ if (abbrev_comments[cids[i]] >= 0) abbrev[cids[i]] = abbrev_comments[cids[i]]; } - params['abbreviated'] = $H(abbrev); - params['abbreviated'] = toHash(params['abbreviated']); + params['abbreviated'] = toHash(abbrev); - params['pieces'] = $H(cids ? fetch_comments_pieces : pieces_comments); - params['pieces'] = toHash(params['pieces']); + params['pieces'] = toHash(cids ? fetch_comments_pieces : pieces_comments); if (placeholder_comments.length) { params['placeholders'] = placeholder_comments; @@ -813,30 +827,29 @@ } } } - $('titlecountnum').innerHTML = thresh_totals[6][6][1]; // total + $dom('titlecountnum').innerHTML = thresh_totals[6][6][1]; // total updateTotals(); } updateHiddens(cids); if (do_update && highlight && last_updated_comments.length) { - for (var i = last_updated_comments_index + 1; i < last_updated_comments.length; i++) { - last_updated_comments_index = i; - if (highlight > 1 && last_updated_comments.length > i && !isUnread(last_updated_comments[i])) - continue; - setFocusComment(last_updated_comments[i], 1); - break; + var next_cid = commTreeNextComm(0, 0, 1); + if (next_cid) { + if (highlight > 1) + setFocusComment('-' + current_cid, 1); + setCurrentComment(next_cid); + setFocusComment(next_cid, 1); } - } ajaxCommentsStatus(0); if (adTimerInsert) { - var tree = $('tree_' + adTimerInsert); + var tree = $dom('tree_' + adTimerInsert); if (tree) { var adcall = ''; var html = '
  • ' + adcall +'
  • '; - var commtree = $('commtree_' + adTimerInsert); + var commtree = $dom('commtree_' + adTimerInsert); if (commtree) { commtree.innerHTML = html + commtree.innerHTML; } else { @@ -888,7 +901,7 @@ || (user_highlightthresh_orig != user_highlightthresh)) ) { - var params = []; + var params = {}; params['op'] = 'comments_set_prefs'; params['threshold'] = user_threshold; params['highlightthresh'] = user_highlightthresh; @@ -907,7 +920,7 @@ if (!shrunkdiv) return false; // seems we shouldn't be here ... - var params = []; + var params = {}; params['op'] = 'comments_read_rest'; params['cid'] = cid; params['sid'] = discussion_id; @@ -940,7 +953,7 @@ return true; el.disabled = 'true'; - var params = []; + var params = {}; params['op'] = 'comments_moderate_cid'; params['cid'] = cid; params['sid'] = discussion_id; @@ -957,64 +970,110 @@ return false; } +function cancelReply(pid) { + var replydiv = $dom('replyto_' + pid); + replydiv.innerHTML = ''; + if (pid) { // XXX + var reply_link = $dom('reply_link_' + pid); + reply_link.innerHTML = reply_link_html[pid]; + reply_link_html[pid] = ''; + } +} + function editReply(pid) { - var replydiv = fetchEl('replyto_' + pid); - var reply = fetchEl('replyto_reply_' + pid); - var preview = fetchEl('replyto_preview_' + pid); + var replydiv = $dom('replyto_' + pid); + var reply = $dom('replyto_reply_' + pid); + var preview = $dom('replyto_preview_' + pid); if (!replydiv || !reply || !preview) return false; preview.style.display = 'none'; reply.style.display = 'block'; - fetchEl('submit_' + pid).style.display = 'none'; - fetchEl('preview_' + pid).style.display = 'inline'; + + $dom('replyto_buttons_2_' + pid).style.display = 'none'; + $dom('replyto_buttons_1_' + pid).style.display = 'inline'; } -function previewReply(pid) { - var replydiv = fetchEl('replyto_' + pid); - var reply = fetchEl('replyto_reply_' + pid); - var preview = fetchEl('replyto_preview_' + pid); - var msg = fetchEl('replyto_msg_' + pid); - var this_reskey = fetchEl('reskey_reply_' + pid); - var postercomment = fetchEl('postercomment_' + pid); - var postersubj = fetchEl('postersubj_' + pid); +function replyPreviewOrSubmit (pid, op, handlers) { + var replydiv = $dom('replyto_' + pid); + var reply = $dom('replyto_reply_' + pid); + var preview = $dom('replyto_preview_' + pid); + var this_reskey = $dom('reskey_reply_' + pid); + var msgdiv = 'replyto_msg_' + pid; + var msg = $dom(msgdiv); - if (!replydiv || !reply || !preview || !msg || !this_reskey) + if (!replydiv || !reply || !preview || !this_reskey || !msg) return false; - var params = []; - params['op'] = 'comments_preview_reply'; + var params = {}; + params['op'] = op; params['pid'] = pid; params['sid'] = discussion_id; - params['postersubj'] = postersubj.value; - params['postercomment'] = postercomment.value; params['reskey'] = this_reskey.value; + params['msgdiv'] = msgdiv; + params['gotmodwarning'] = $dom('gotmodwarning_' + pid).value; + params['postersubj'] = $dom('postersubj_' + pid).value; + params['postercomment'] = $dom('postercomment_' + pid).value; - // XXX disable Reply to This link + var postanon = $dom('postanon_' + pid); + if (postanon && postanon.checked) + params['postanon'] = postanon.value; + msg.innerHTML = 'Loading...'; + ajax_update(params, '', handlers); +} - var handlers = { +function submitReply(pid) { + return replyPreviewOrSubmit(pid, 'comments_submit_reply', { onComplete: function(transport) { + var msg = $dom('replyto_msg_' + pid); msg.innerHTML = ''; - json_handler(transport); - reply.style.display = 'none'; - preview.style.display = 'block'; - // depends on error result - fetchEl('submit_' + pid).style.display = 'inline'; - fetchEl('preview_' + pid).style.display = 'none'; + var response = json_handler(transport); + + var cid = response.cid; + if (response.error) + msg.innerHTML = response.error; + else if (cid) { + cancelReply(pid); + addComment(cid, { pid: pid, kids: [] }, '', 1); + setFocusComment(cid, 1); + } } - }; + }); - ajax_update(params, '', handlers); +} +function previewReply(pid) { + return replyPreviewOrSubmit(pid, 'comments_preview_reply', { + onComplete: function(transport) { + var msg = $dom('replyto_msg_' + pid); + msg.innerHTML = ''; + var response = json_handler(transport); + + if (response.error) + msg.innerHTML = response.error; + if (response.html) { + $dom('replyto_reply_' + pid).style.display = 'none'; + $dom('replyto_preview_' + pid).style.display = 'block'; + $dom('replyto_buttons_1_' + pid).style.display = 'none'; + $dom('replyto_buttons_2_' + pid).style.display = 'inline'; + } + } + }); } function replyTo(pid) { - var replydiv = fetchEl('replyto_' + pid); + var replydiv = $dom('replyto_' + pid); if (!replydiv) return false; // seems we shouldn't be here ... - var params = []; + var postercomment = $dom('postercomment_' + pid); + if (postercomment) { + postercomment.focus(); // already have one, bail + return false; + } + + var params = {}; params['op'] = 'comments_reply_form'; params['pid'] = pid; params['sid'] = discussion_id; @@ -1022,7 +1081,15 @@ replydiv.innerHTML = 'Loading...'; var handlers = { - onComplete: json_handler + onComplete: function(transport) { + json_handler(transport); + if (pid) { // XXX + var reply_link = $dom('reply_link_' + pid); + reply_link_html[pid] = reply_link.innerHTML; + reply_link.innerHTML = 'Cancel Reply'; + } + $dom('postercomment_' + pid).focus(); + } }; ajax_update(params, '', handlers); @@ -1032,7 +1099,7 @@ function quoteReply(pid) { var this_reply = getQuotedText(comment_body_reply[pid]); - var postercomment = $('postercomment_' + pid) || $('postercomment'); + var postercomment = $dom('postercomment_' + pid) || $dom('postercomment'); if (postercomment) postercomment.value = this_reply + postercomment.value; return false; @@ -1040,7 +1107,7 @@ function getQuotedText(this_reply) { // tailor whitespace to postmode - if (!$('posttype') || $('posttype').value != 2) { + if (!$dom('posttype') || $dom('posttype').value != 2) { this_reply = this_reply.replace(/
    /g, "\n"); } else { this_reply = this_reply.replace(/
    \n*/g, "
    \n"); @@ -1075,7 +1142,7 @@ function reloadForFirefox(obj_name) { if (is_firefox) { - var obj = $(obj_name); + var obj = $dom(obj_name); loadAllElements('span', obj); loadAllElements('div', obj); loadAllElements('li', obj); @@ -1095,7 +1162,7 @@ } function loadNamedElement(name) { - commentelements[name] = $(name); + commentelements[name] = $dom(name); return; } @@ -1107,9 +1174,9 @@ // any other special cases to ignore? -- pudge if (!str.match(/^hidestring_/)) if (!obj || !grepCommentNode(obj, str)) - obj = commentelements[str] = $(str); + obj = commentelements[str] = $dom(str); } else { - obj = $(str); + obj = $dom(str); } return obj; @@ -1255,7 +1322,7 @@ } function boxStatus(bool) { - var box = $('commentControlBoxStatus'); + var box = $dom('commentControlBoxStatus'); if (bool) { boxStatusQueue.push(1); box.className = ''; @@ -1268,7 +1335,7 @@ function enableControls() { boxStatus(0); - var morelink = $('more_comments_num_a'); + var morelink = $dom('more_comments_num_a'); if (morelink) morelink.className = 'show'; @@ -1277,11 +1344,11 @@ } function floatButtons () { - $('gods').className='thor'; + $dom('gods').className='thor'; } function d2act () { - var gd = $('d2act'); + var gd = $dom('d2act'); if (gd) { var targetTop = YAHOO.util.Dom.getY('commentwrap'); var vOffset = 0; @@ -1294,7 +1361,7 @@ var oldpos = gd.style.position; - var mode = $('d2out').className; + var mode = $dom('d2out').className; if (mode=='horizontal rooted' || targetTop>vOffset) { gd.style.position = 'absolute'; gd.className = 'rooted'; @@ -1308,15 +1375,15 @@ // for Safari and maybe others, force redraw on change if ( oldpos != gd.style.position ) { gd.style.display = 'none'; - setTimeout("$('d2act').style.display = 'inline'", 1); + setTimeout("$dom('d2act').style.display = 'inline'", 1); // gd.style.display = 'inline'; } } } function toggleDisplayOptions() { - var gods = $('gods'); - var d2out = $('d2out'); + var gods = $dom('gods'); + var d2out = $dom('d2out'); // update user prefs var newMode = ''; @@ -1345,7 +1412,7 @@ gods.style.display = 'block'; if (!user_is_anon) { - var params = []; + var params = {}; params['comments_control'] = newMode; params['op'] = 'comments_set_prefs'; params['reskey'] = reskey_static; @@ -1357,9 +1424,9 @@ function updateTotals() { - $('currentHidden' ).innerHTML = currents['hidden']; - $('currentFull' ).innerHTML = currents['full']; - $('currentOneline').innerHTML = currents['oneline']; + $dom('currentHidden' ).innerHTML = currents['hidden']; + $dom('currentFull' ).innerHTML = currents['full']; + $dom('currentOneline').innerHTML = currents['oneline']; } function updateMoreNum(num) { // should be an integer, or empty string @@ -1376,9 +1443,9 @@ num_a = 'Retrieve more of the ' + num + ' remaining comments'; } - var a = $('more_comments_num_a'); - var b = $('more_comments_num_b'); - var c = $('more_comments_num_c'); + var a = $dom('more_comments_num_a'); + var b = $dom('more_comments_num_b'); + var c = $dom('more_comments_num_c'); if (a) a.innerHTML = num_a; @@ -1391,7 +1458,7 @@ function scrollWindowTo(cid) { var comment_y = getOffsetTop(fetchEl('comment_' + cid)); - if ($('d2out').className == 'horizontal') + if ($dom('d2out').className == 'horizontal') comment_y -= 60; scroll(viewWindowLeft(), comment_y); } @@ -1405,73 +1472,18 @@ return ol; } -function getOffsetTop (el) { - if (!el) - return false; - var ot = el.offsetTop; - while((el = el.offsetParent) != null) - ot += el.offsetTop; - return ot; -} - -function viewWindowLeft() { - if (self.pageXOffset) // all except Explorer - { - return self.pageXOffset; - } - else if (document.documentElement && document.documentElement.scrollTop) - // Explorer 6 Strict - { - return document.documentElement.scrollLeft; - } - else if (document.body) // all other Explorers - { - return document.body.scrollLeft; - } -} - -function viewWindowTop() { - if (self.pageYOffset) // all except Explorer - { - return self.pageYOffset; - } - else if (document.documentElement && document.documentElement.scrollTop) - // Explorer 6 Strict - { - return document.documentElement.scrollTop; - } - else if (document.body) // all other Explorers - { - return document.body.scrollTop; - } - return; -} - function viewWindowRight() { return viewWindowLeft() + (window.innerWidth || document.documentElement.clientWidth); } -function viewWindowBottom() { - return viewWindowTop() + (window.innerHeight || document.documentElement.clientHeight); -} - -function commentIsInWindow(cid) { +function commentIsInWindow(cid, just_head) { var in_window = isInWindow(fetchEl('comment_' + cid)); - if (in_window && fetchEl('comment_sub_' + cid)) + if (in_window && !just_head && fetchEl('comment_sub_' + cid)) in_window = isInWindow(fetchEl('comment_sub_' + cid)); return in_window; } -function isInWindow(obj) { - var y = getOffsetTop(obj); - if (y > viewWindowTop() && y < viewWindowBottom()) { - return 1; - } - return 0; -} - - /* code for the draggable threshold widget */ function showPrefs( category ) { @@ -1820,6 +1832,9 @@ function setCurrentComment (cid) { + if (!cid) + return false; + var this_id; if (current_cid) { if (cid == current_cid) @@ -1851,6 +1866,7 @@ prev comm chrono: Q next comm chrono: E next unread comm: F +reply: R */ var validkeys = { @@ -1861,6 +1877,7 @@ Q: { chrono : 1, prev: 1, comment: 1 }, E: { chrono : 1, next: 1, comment: 1 }, F: { thread : 1, next: 1, comment: 1, unread: 1 }, + R: { reply : 1 }, }; validkeys['H'] = validkeys['A']; @@ -1897,8 +1914,11 @@ var next_cid = 0; var key = k || String.fromCharCode(c); var keyo = validkeys[key]; + if (keyo && keyo['reply'] && user_is_subscriber && current_cid) { // XXX + replyTo(current_cid); + // forward and back between comments, in order of how they were loaded - if (keyo && keyo['chrono']) { + } else if (keyo && keyo['chrono']) { var i = last_updated_comments_index; var l = last_updated_comments.length - 1; update = 1; @@ -1940,11 +1960,11 @@ getNextUnread = 1; if (keyo['comment']) { next_cid = commTreeNextComm(current_cid, 0, getNextUnread); - if (!next_cid) { + if (!next_cid) { // && getNextUnread) { if (ajaxCommentsWait()) return; update = 2; - var highlight = 1 + getNextUnread; + var highlight = 1 + collapseCurrent; ajaxFetchComments(0, 1, '', highlight); } } else @@ -1988,12 +2008,15 @@ else kids = rootSort(); + var seen = 0; for (var i = 0; i < kids.length; i++) { var this_cid; - if (!old_cid) + if (!old_cid) { this_cid = kids[i]; - else if (kids[i] >= old_cid) + } else if ((kids[i] == old_cid) || seen) { this_cid = kids[i+1]; + seen = 1; + } if (this_cid) { if (!getNextUnread || (this_cid = getNextUnreadCid(this_cid))) Deleted: slashjp/trunk/themes/slashcode/htdocs/images/comments2.js =================================================================== --- slashjp/trunk/themes/slashcode/htdocs/images/comments2.js 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/themes/slashcode/htdocs/images/comments2.js 2008-04-01 04:03:21 UTC (rev 563) @@ -1,524 +0,0 @@ -var comments; -var root_comments; -var authorcomments; -var threshhold = 4; -var fullthreshhold = 4; -var promotedepth = 1; -var behaviors = { - 'default': { ancestors: 'none', parent: 'none', children: 'none', descendants: 'none', siblings: 'none', sameauthor: 'none' }, - 'focus': { ancestors: 'none', parent: 'none', children: 'none', descendants: 'none', siblings: 'none', sameauthor: 'none' }, - 'collapse': { ancestors: 'none', parent: 'none', siblings: 'none', sameauthor: 'none', currentmessage: 'oneline', children: 'hidden', descendants: 'hidden'} }; -var behaviorrange = ['none', 'full', 'oneline', 'hidden']; -var authorcids = {}; -var displaymode = { 0: 1}; -var futuredisplaymode = { 0: 1}; -var focalcids = []; -var currentdepth = 1; -var pointsums = []; - -var remainingroots = []; -var allroothiddens = 0; -var rootpe; - -function togglevis(nr) -{ - var vista = (document.getElementById(nr).style.display == 'none') ? 'block' : 'none'; - document.getElementById(nr).style.display = vista; -} - -function blocking(nr) -{ - togglevis(nr + "_oneline"); - togglevis(nr + "_full"); -} - -function divit(id, content) { - return '
    '+content+'
    '; -} - -/* hocked from javascript.internet.com */ -function stripHTML(Word) { - a = Word.indexOf("<"); - b = Word.indexOf(">"); - len = Word.length; - c = Word.substring(0, a); - if(b == -1) b = a; - d = Word.substring((b + 1), len); - Word = c + d; - tagCheck = Word.indexOf("<"); - if(tagCheck != -1) Word = stripHTML(Word); - return Word; -} - -function wordbreak(content, maxlen) { - content = stripHTML(content); - var words = content.split(' '); - var retval = ""; - for (var w = 0; w < words.length; w++) { - var newretval = retval +' '+ words[w]; - if (newretval.length < maxlen) { - retval = newretval; - } else { - return retval + '...'; - } - } - return retval + '...'; -} - -function replyTo() { - return '[ Reply to This ]'; -} - -function flipLink(cid, mode) { - var newmode = mode=='full'?'oneline':'full'; - var classa = newmode=='full'?'dwns':'ups'; - var polarity = newmode=='full'?'':'-'; - - - return ' '; -} - - -function renderCommentOneLine(cid) { - var comment = comments[cid]; - var retval = flipLink(cid, 'oneline') + ''; - - retval = retval + comment['subject']+' by '+comment['nickname']; - - retval = retval +' (Score:'+comment['points']+') '; - - return retval + wordbreak(comment['comment'], 45); -} - -function renderCommentFull(cid) { - var comment = comments[cid]; - return '
    '+flipLink(cid,'full')+'

    '+comment['subject']+'

    (Score: '+comment['points']+', XXXXX)
    by '+comment['nickname']+ ' on '+comment['date']+' ('+cid+')
    '+comment['comment']+'
    '+ replyTo(cid); -} - -function renderComment(cid, mode) { - if (mode == 'oneline') { - displaymode[cid] = 'oneline'; - return renderCommentOneLine(cid); - } else if (mode == 'full') { - displaymode[cid] = 'full'; - return renderCommentFull(cid); - } - displaymode['cid'] = 'hidden'; - return ""; /*this is when it's hidden*/ -} - -function updateComment(cid, mode) { - var existingdiv = $(cid + '_comment'); - if (existingdiv) { - existingdiv.innerHTML = renderComment(cid, mode); - /* if (displaymode['cid'] == 'hidden') { - $(cid + "_tree").className = "hide"; - } else { - $(cid + "_tree").className = "comment"; - } */ - } - displaymode[cid] = mode; - return void(0); -} - - -function decideMode(cid) { - var comment = comments[cid]; - if (comment['points'] < threshhold) { - return 'hidden'; - } - if (comment['points'] >= fullthreshhold) { return 'full'; } - if (promotedepth && comment['depth'] == currentdepth) { return 'full'; } - return 'oneline'; -} - -function renderCommentTree(cid) { - var comment = comments[cid]; - var retval; - /* if (futuredisplaymode[cid] == 'hidden') { - retval = '
  • '; - } else { */ - retval = '
  • '; - /* } */ - retval = retval + divit(cid + '_comment', renderComment(cid, futuredisplaymode[cid])); - retval = retval + '
      '; - var hiddens = 0; - if (comment['kids'].length) { - for (var kiddie = 0; kiddie < comment['kids'].length; kiddie++) { - var kidrets = renderCommentTree(comment['kids'][kiddie]); - retval = retval + kidrets[0]; - hiddens += kidrets[1]; - if (futuredisplaymode[comment['kids'][kiddie]] == 'hidden') { - hiddens++; - } - } - } - - if (futuredisplaymode[cid] == 'hidden') { - retval = retval + '
    • '; - hiddens += 1; - } else if (hiddens) { - retval = retval + '
    • '+hiddens+" reply beneath your current threshhold.
    • "; - } else { - retval = retval + '
    • '; - } - - retval = retval + '
    '; - retval = retval + '
  • '; - - return [retval, hiddens]; -} - -function updateCommentTree(cid) { - var comment = comments[cid]; - if (futuredisplaymode[cid] != displaymode[cid]) - updateComment(cid, futuredisplaymode[cid]); - - var kidhiddens = 0; - if (comment['kids'].length) { - for (var kiddie = 0; kiddie < comment['kids'].length; kiddie++) { - kidhiddens += updateCommentTree(comment['kids'][kiddie]); - } - } - - if (displaymode[cid] == 'hidden') { - $(cid+"_hiddens").className = "hide"; - return kidhiddens + 1 ; - - } else if (kidhiddens) { - $(cid+"_hiddens").innerHTML = kidhiddens+" reply are hidden."; - $(cid+"_hiddens").className = "show"; - } else { - $(cid+"_hiddens").className = "hide"; - } - return 0; -} - -function renderRootsAsync() { - if (!remainingroots.length) { return void(0); } - var step = 2; - var i = 0; - var root; - var element = 'commentlisting'; - - while (remainingroots.length && i < step) { - root = remainingroots.shift(); - rootret = renderCommentTree(root); - $(element).innerHTML = $(element).innerHTML + rootret[0]; - allroothiddens += rootret[1]; - i++; - } - - if (remainingroots.length) { return void(0); } - if (allroothiddens) { - $(element).innerHTML = $(element).innerHTML + '
  • '+allroothiddens+' comments are beneath your threshhold
  • ' - } else { - $(element).innerHTML = $(element).innerHTML + '
  • ' - } - - rootpe.currentlyExecuting = true; -} - -function renderRoots(element) { - - threshhold = Math.floor(Math.random() * 7)-1; - fullthreshhold = threshhold + Math.floor(Math.random() * (6-threshhold)); - - renderThreshholdWidget(); - /*randomizeBehaviors('default');*/ - renderBehaviorWidget('default', 'defaultbehaviors'); - /*randomizeBehaviors('focus');*/ - renderBehaviorWidget('focus', 'focusbehaviors'); - refreshDisplayModes(); - - remainingroots = root_comments.concat([]); - rootpe = new PeriodicalExecuter(renderRootsAsync, .5); -} - -function getComments(sid, element) { - var params = []; - params['op'] = 'get_comments'; - params['sid'] = sid; - ajax_update(params, '', { evalScripts: 1 }, 'http://use.perl.org/ajax.pl'); -} - -function randomizeBehaviors(ctype) { - for (var relation in behaviors[ctype]) { - ind = Math.floor(Math.random() * behaviorrange.length); - behaviors[ctype][relation]=behaviorrange[ind]; - } -} - -function renderBehaviorWidget(ctype, elementname) { - var newhtml = ""; - - for (var relation in behaviors[ctype]) { - newhtml = newhtml + '
  • "; - } - - $(elementname).innerHTML = newhtml; - - return void(0); -} - -function renderThreshholdWidget() { - if (pointsums.length) { - return void(0); - } else { - pointsums[0] = 0; - pointsums[1] = 0; - pointsums[2] = 0; - pointsums[3] = 0; - pointsums[4] = 0; - pointsums[5] = 0; - pointsums[6] = 0; - /* there's a better way to do this i hope? */ - } - - for (var cid in comments) { - pointsums[comments[cid]['points']+1]++; - } - - var sum = 0; - for (var i=6; i >= 0; i--) { - pointsums[i] = pointsums[i] + sum; - sum = pointsums[i] + sum; - } - - $('threshholdselect').length = 0; - $('fullthreshholdselect').length = 0; - var retval = ""; - for (var i = 0; i <= 6; i++) { - $('threshholdselect').options[i] = new Option((i-1)+": "+pointsums[i]+" comments", i-1); - $('fullthreshholdselect').options[i] = new Option((i-1)+": "+pointsums[i]+" comments", i-1); - } - - $('threshholdselect').value = threshhold; - $('fullthreshholdselect').value = fullthreshhold; - - return void(0); -} - -function faGetSetting(ctype, relation, prevview, canbelower) { - var newview = behaviors[ctype][relation]; - - if ((viewmodevalue[newview] > newmodevalue[preview]) || canbelower) { - return newview; - } - - return prevview; -} - -function getDescendants(cids) { - var descs = cids; - for (var i = 0; i < cids.length; i++) { - var cid = cids[i]; - var kids = comments[cid]['kids']; - if (kids.length) { - descs = descs.concat(getDescendants(kids)); - } - } - return descs; -} - -function findAffected(type, cid, override) { - if (!cid) { return; } - var comment = comments[cid]; - - var pid = comment['pid']; - if (pid) { - if (faGetSetting(type, 'parent') != 'none') { - if (override || futuredisplaymode[pid] != 'full') { - futuredisplaymode[pid] = faGetSetting(type, 'parent', futuredisplaymode[pid], override); - } - } - if (faGetSetting(type, 'ancestors') != 'none') { - var parent = 0; - while (pid) { - parent = comments[pid]; - pid = parent['pid']; - if (pid && (override || futuredisplaymode[pid] != 'full')) { - futuredisplaymode[pid] = faGetSetting(type, 'ancestors'); - } - } - } - pid = comment['pid']; - if (faGetSetting(type, 'siblings') != 'none') { - var sibs = comments[pid]['kids']; - for(var i = 0; i < sibs.length; i++) { - var sib = sibs[i]; - if (override || futuredisplaymode[sib] != 'full') { - futuredisplaymode[sib] = faGetSetting(type, 'siblings'); - } - } - } - } - - var kids = comment['kids']; - if (kids.length) { - if (faGetSetting(type, 'children') != 'none') { - for (var i = 0; i < kids.length; i++) { - var kid = kids[i]; - if (override || futuredisplaymode[kid] != 'full') { - futuredisplaymode[kid] = faGetSetting(type, 'children'); - } - } - } - - if (faGetSetting(type, 'descendants') != 'none') { - var descendants = getDescendants(kids); - for (var i = 0; i < descendants.length; i++) { - var desc = descendants[i]; - if (override || futuredisplaymode[desc] != 'full') { - futuredisplaymode[desc] = faGetSetting(type, 'descendants'); - } - } - } - } - - var uid = comment['uid']; - if (faGetSetting(type, 'sameauthor') != 'none') { - var sameauthor = authorcids[uid]; - for (var i = 0; i < sameauthor.length; i++) { - var sacid = sameauthor[i]; - if (override || futuredisplaymode[sacid] != 'full') { - futuredisplaymode[sacid] = faGetSetting(type, 'sameauthor'); - } - } - } - -} - -function refreshDisplayModes() { - var fulls = Array(); - authorcids = {}; - for (var mykey in comments) { - uid = comments[mykey]['uid']; - if (!authorcids[uid]) { - authorcids[uid] = new Array(mykey); - } else { - authorcids[uid].push(mykey); - } - futuredisplaymode[mykey] = decideMode(mykey); - if (futuredisplaymode[mykey] == 'full') { - fulls.push(mykey); - } - } - /* decide mode based on basic functions */ - - for (var i = 0; i < fulls.length; i++) { - findAffected('default', fulls[i], 0); - } - - if (focalcids.length) { - for (var i = 0; i < focalcids.length; i++) { - var focalcid = focalcids[i]; - if (focalcid > 0) { - futuredisplaymode[focalcid] = 'full'; - findAffected('focus', focalcid, 0); - } else { - focalcid = -1 * focalcid; - futuredisplaymode[focalcid] = behaviors['collapse']['currentmessage']; - findAffected('collapse', focalcid, 1); - } - } - } - return void(0); -} - -function refreshCommentDisplays() { - refreshDisplayModes(); - - var roothiddens = 0; - for (var root = 0; root < root_comments.length; root++) { - roothiddens += updateCommentTree(root_comments[root]); - } - if (roothiddens) { - $('roothiddens').innerHTML = roothiddens + " comments are beneath your threshhold"; - $('roothiddens').className = "show"; - } else { - $('roothiddens').className = "hide"; - } - /* NOTE need to display note for hidden root comments */ - return void(0); -} - - -function refreshSettings() { - var changed = 0; - /* one of the threshholds have changed, rerender */ - - if (threshhold != $('threshholdselect').value) { - threshhold = $('threshholdselect').value; - changed = 1; - } - - if (fullthreshhold != $('fullthreshholdselect').value) { - fullthreshhold = $('fullthreshholdselect').value; - changed = 1; - } - /* not sure if these are right is it value?*/ - - if (threshhold > fullthreshhold) { - threshhold = fullthreshhold; - $('threshholdselect').value = $('fullthreshholdselect').value; - changed = 1; - } - - var pd; - if ($('promotedepth').checked) { - pd = 1; - } else { - pd = 0; - } - - if (promotedepth != pd) { - promotedepth = pd; - changed = 1; - } - - prefbehaviors = ['default', 'focus']; - for (var ctype in prefbehaviors) { - for (var relation in behaviors[ctype]) { - if (behaviors[ctype][relation] != $(ctype+'_'+relation).value) { - behaviors[ctype][relation] = $(ctype+'_'+relation).value; - changed = 1; - } - } - } - - if (changed) { - refreshCommentDisplays(); - } - return void(0); -} - -function setFocusComment(cid) { - var alreadyfocused = -1; - for (var i = 0; i < focalcids.length; i++) { - if (focalcids[i] == cid || focalcids[i] == (-1 * cid)) { - alreadyfocused = i; - } - } - - if (alreadyfocused != -1) { - focalcids.splice(alreadyfocused, 1); - } else { - focalcids.push(cid); - } - refreshCommentDisplays(); - return void(0); -} - - - - Modified: slashjp/trunk/themes/slashcode/htdocs/images/dumper.js =================================================================== --- slashjp/trunk/themes/slashcode/htdocs/images/dumper.js 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/themes/slashcode/htdocs/images/dumper.js 2008-04-01 04:03:21 UTC (rev 563) @@ -1,6 +1,6 @@ // $Id: dumper.js,v 1.2 2006/05/26 22:51:36 pudge Exp $ -// javascript:$('commentControlBox').innerHTML = Dumper(displaymode) +// javascript:$dom('commentControlBox').innerHTML = Dumper(displaymode) // =================================================================== // Author: Matt Kruse Modified: slashjp/trunk/themes/slashcode/templates/dispComment;misc;default =================================================================== --- slashjp/trunk/themes/slashcode/templates/dispComment;misc;default 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/themes/slashcode/templates/dispComment;misc;default 2008-04-01 04:03:21 UTC (rev 563) @@ -34,7 +34,7 @@ [% ELSE %]

    [% subject %] [%- END %] - [% UNLESS user.noscores %](Score:[% IF points.length; points; ELSE; "?"; END %][% IF reasons && reason %], [% reasons.$reason.name %][% END %])[% END %]

    + [% UNLESS user.noscores %]([% IF constants.modal_prefs_active && !user.is_anon %][% END %]Score:[% points.length ? points : "?" %][% IF constants.modal_prefs_active && !user.is_anon %][% END %][% IF reasons && reason %], [% reasons.$reason.name %][% END %])[% END %]
    by Modified: slashjp/trunk/themes/slashcode/templates/dispLinkComment;misc;default =================================================================== --- slashjp/trunk/themes/slashcode/templates/dispLinkComment;misc;default 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/themes/slashcode/templates/dispLinkComment;misc;default 2008-04-01 04:03:21 UTC (rev 563) @@ -22,14 +22,14 @@ [ [% IF !user.state.discussion_archived && !user.state.discussion_future_nopost %] - [% Slash.linkComment({ + [% Slash.linkComment({ sid => sid, pid => cid, op => 'Reply', subject => 'Reply to This', subject_only => 1, - onclick => ((discussion2 && user.test_code) ? "replyTo($cid); return false;" : '') - }) %] + onclick => ((discussion2 && (!constants.subscribe || user.is_subscriber)) ? "replyTo($cid); return false;" : '') + }) %] [% END %] [% IF !(user.state.discussion_archived) && ( do_parent || can_mod || can_del ) %] | [% END %] Modified: slashjp/trunk/themes/slashcode/templates/dispStory;misc;default =================================================================== --- slashjp/trunk/themes/slashcode/templates/dispStory;misc;default 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/themes/slashcode/templates/dispStory;misc;default 2008-04-01 04:03:21 UTC (rev 563) @@ -71,7 +71,7 @@ [% mypagemenu = PROCESS pagemenu; IF mypagemenu %]
    [% mypagemenu %][% END %]
    [% seen_topics.${topic.tid} = 1 %] - [% IF user.noicons || user.simpledesign || user.lowbandwidth %] + [% IF user.noicons || user.simpledesign || user.lowbandwidth || user.pda %] [ [% topic.textname %] ] [% ELSIF topic.image %] @@ -95,7 +95,17 @@ [% story.introtext %]
    -[% IF full && user.is_admin && !preview && env.script_name != '/admin.pl' %]
    [ Edit ] [% IF constants.plugin.Ajax %][% PROCESS signoff stoid = story.stoid %] [% PROCESS neverdisplay stoid = stoid %][% END %][% END %] +[% IF full && user.is_admin && !preview && env.script_name != '/admin.pl' %]
    [ Edit ] [% END %] +[% IF full && !preview && env.script_name != '/admin.pl' %] + [% IF constants.plugin.Ajax %] + [% IF user.is_admin || user.acl.signoff_allowed %] + [% PROCESS signoff stoid = story.stoid %] + [% END %] + [% IF user.is_admin %] + [% PROCESS neverdisplay stoid = stoid %] + [% END %] + [% END %] +[% END %] [% IF story.is_future && !user.is_admin %]

    See any serious problems with this story? [% IF constants.ircslash_remarks %] Modified: slashjp/trunk/themes/slashcode/templates/errors;comments;default =================================================================== --- slashjp/trunk/themes/slashcode/templates/errors;comments;default 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/themes/slashcode/templates/errors;comments;default 2008-04-01 04:03:21 UTC (rev 563) @@ -34,7 +34,7 @@ to do so, because open proxies are used to spam web boards like this one. [% IF constants.comments_portscan!=2 %]If you really can't close it and still want to post, you'll have to register and log in.[% END %] -

    If you have questions, mention that your proxy is at +If you have questions, mention that your proxy is at [% unencoded_ip %] on port [% port %]. [% # COMMENT TABLE NOT AVAILABLE FOR WRITING @@ -69,133 +69,128 @@ [% # NO POINTS. CASE "no points" %] -You don't have any moderator points.
    +You don't have any moderator points. [% # NO POINTS. CASE "not enough points" %] -You don't have enough moderator points.
    +You don't have enough moderator points. [% # COMMENTS MAX POSTS. CASE "comments max posts" %] -

    You've reached your maximum number of comments you can post: [% max_posts %] comments over [% timeframe %]. -

    +You've reached your maximum number of comments you can post: [% max_posts %] comments over [% timeframe %]. [% # COMMENTS MAX POSTS. CASE "discussions max posts" %] -

    You've reached your maximum number of discussions you can submit: [% max_posts %] discussions over [% timeframe %]. -

    +You've reached your maximum number of discussions you can submit: [% max_posts %] discussions over [% timeframe %]. [% # INVALID FORMKEY CASE "invalid formkey" %] -[% PROCESS titlebar width="100%" title="Invalid form key!" %] -

    form key: [% formkey %] !

    +[% PROCESS titlebar width="100%" title="Invalid form key!" UNLESS no_titlebar %] +Invalid form key: [% formkey %]! [% # RESPONSE LIMIT CASE "comments response limit" %] -[% PROCESS titlebar width="100%" title="Slow Down Cowboy!" %] -

    [% constants.sitename %] requires you to wait [% limit %] between -hitting 'reply' and submitting a comment.

    -

    It's been [% response %] since you hit 'reply'!

    +[% PROCESS titlebar width="100%" title="Slow Down Cowboy!" UNLESS no_titlebar %] +[% constants.sitename %] requires you to wait [% limit %] between hitting 'Reply' +and submitting a comment. It's been [% response %] since you hit 'Reply.' [% # POST LIMIT CASE "comments post limit" %] -[% PROCESS titlebar width="100%" title="Slow Down Cowboy!" %] -

    [% constants.sitename %] requires you to wait between -each successful posting of a comment to allow everyone a fair chance -at posting a comment.

    -

    It's been [% interval %] since you last successfully posted a comment.

    +[% PROCESS titlebar width="100%" title="Slow Down Cowboy!" UNLESS no_titlebar %] +[% constants.sitename %] requires you to wait between each successful posting of +a comment to allow everyone a fair chance at posting a comment. It's been +[% interval %] since you last successfully posted a comment. [% # POST LIMIT CASE "discussions post limit" %] -[% PROCESS titlebar width="100%" title="Slow Down Cowboy!" %] -

    [% constants.sitename %] requires you to wait between -each successful creation of a discussion .

    -

    It's been [% interval %] since you last successfully created a discussion.

    +[% PROCESS titlebar width="100%" title="Slow Down Cowboy!" UNLESS no_titlebar %] +[% constants.sitename %] requires you to wait between each successful creation +of a discussion. It's been [% interval %] since you last successfully created a discussion. + [% # USED FORM CASE "used form" %] -[% PROCESS titlebar width="100%" title="Form Error!" %] +[% PROCESS titlebar width="100%" title="Form Error!" UNLESS no_titlebar %] This form has been used already to submit a comment [% interval %] ago. You can not use a form and hit the back button to use it again. [% # READ ONLY CASE "readonly" %] -
    You can't post to this page.
    +You can't post to this page. [% # TOO MANY POSTS CASE "comments post limit daily" %] -[% PROCESS titlebar width="100%" title="Call It A Night, Cowboy!" %] -

    [% constants.sitename %] only allows -[% IF user.is_anon; "anonymous users"; -ELSE; "a user with your karma"; END %] -to post [% limit %] times per day (more or less, depending on -moderation). -[% IF user.is_anon; "A user from your IP has already shared his or her thoughts"; -ELSE; "You've already shared your thoughts"; END %] +[% PROCESS titlebar width="100%" title="Call It A Night, Cowboy!" UNLESS no_titlebar %] +[% constants.sitename %] only allows +[% IF user.is_anon; + "anonymous users"; +ELSE; + "a user with your karma"; END %] +to post [% limit %] times per day (more or less, depending on moderation). + +[% IF user.is_anon; + "A user from your IP has already shared his or her thoughts"; +ELSE; + "You've already shared your thoughts"; END %] with us that many times. Take a breather, and come back and see us in 24 hours or so. -

    If you think this is unfair, please email -[% IF constants.adminmail_post; constants.adminmail_post; -ELSE; constants.adminmail; END %] -with your + +If you think this is unfair, please email +[% constants.adminmail_post || constants.adminmail %] with your [% IF user.is_anon %] -MD5'd IPID, which is [% user.ipid %][% -ELSE %] -username "[% user.nickname | strip_literal %]"[% -END %]. Let us know how many comments you think you've -posted in the last 24 hours. + MD5'd IPID, which is [% user.ipid %][% ELSE %] + username "[% user.nickname | strip_literal %]"[% END %]. +Let us know how many comments you think you've posted in the last 24 hours. + + [% # TROLL MESSAGE. CASE "troll message" %] Due to excessive bad posting from this IP or Subnet, [% IF logged_in_allowed -%]anonymous [% END %]comment posting -has temporarily been disabled. +%]anonymous [% END %]comment posting has temporarily been disabled. + [% IF logged_in_allowed %] You can still login to post. However, if bad posting continues from your IP or Subnet that privilege could be revoked as well. [% END %] -If it's you, consider this a chance to -sit in the timeout corner[% IF logged_in_allowed %] or login and improve your posting[% END %] -. If it's someone else, this is a chance to hunt them down. -If you think this is unfair, please email -[% IF constants.adminmail_mod; constants.adminmail_mod; -ELSE; constants.adminmail; END %] -with your MD5'd IPID and SubnetID, which are -"[% user.ipid %]" and "[% user.subnetid %]"[% -IF !user.is_anon %] -and (optionally, but preferably) your IP number -"[% unencoded_ip %]" and your username "[% user.nickname | strip_literal %]"[% -END %]. +If it's you, consider this a chance to sit in the timeout +corner[% IF logged_in_allowed %] or login and improve your posting[% END %]. +If it's someone else, this is a chance to hunt them down. If you think this is +unfair, please email [% constants.adminmail_mod || constants.adminmail %] +with your MD5'd IPID and SubnetID, which are "[% user.ipid %]" and +"[% user.subnetid %]"[% IF !user.is_anon %] + and (optionally, but preferably) your IP number + "[% unencoded_ip %]" and your username + "[% user.nickname | strip_literal %]"[% END %]. + [% CASE "broken html" %] Your comment could not be processed. Please try again. [% # LOW CHARS-PER-LINE CASE "low chars-per-line" %] -Your comment has too few characters per line (currently [% ratio %]).
    +Your comment has too few characters per line (currently [% ratio %]). [% # FILTER MESSAGE. CASE "filter message" %] -[% PROCESS titlebar width="100%" title="Lameness filter encountered. Post aborted!" %] +[% PROCESS titlebar width="100%" title="Lameness filter encountered. Post aborted!" UNLESS no_titlebar %] [% IF err_message %] -Reason: [% err_message %]
    +Filter error: [% err_message %] [% END %] [% # COMPRESS FILTER. CASE "compress filter" %] -[% PROCESS titlebar width="100%" title="Lameness filter encountered." %] -Your comment violated the "[% ratio %]" compression filter. Try less -whitespace and/or less repetition[% -IF ratio == 'postersubj' %] in the subject line[% END %]. -Comment aborted. +[% PROCESS titlebar width="100%" title="Lameness filter encountered." UNLESS no_titlebar %] +Your comment violated the "[% ratio %]" compression filter. Try less whitespace +and/or less repetition[% IF ratio == 'postersubj' %] in the subject line[% END %]. [% # SUBMISSION ERROR. CASE "submission error" %] -

    There was an unknown error in the submission.
    +There was an unknown error in the submission. [% # MAXCID EXCEEDED. CASE "maxcid exceeded" %] -Don't you have anything better to do with your life?
    +Don't you have anything better to do with your life? [% # DUPLICATION ERROR. CASE "duplication error" %] @@ -214,31 +209,30 @@ form [% formname %] [% formkey %] already submitted [% CASE "seclevtoolow" %] -[% PROCESS titlebar width="100%" title="No permissions" %] +[% PROCESS titlebar width="100%" title="No permissions" UNLESS no_titlebar %] You do not have appropriate permissions to perform that action. [% CASE "nosubscription" %] -[% PROCESS titlebar width="100%" title="Not subscriber, or not subscribed page" %] -You can't see this discussion because it's scheduled in the future, -where only subscribers can see it.

    -Either you are not a subscriber to [% constants.sitename %], or you -have indicated you don't want comments pages ad-free, or you have -set your daily limit of ad-free pages to lower than -the default [% constants.subscribe_hits_btmd %]. -Any of these three possible issues can be resolved at -your subscription page.

    +[% PROCESS titlebar width="100%" title="Not subscriber, or not subscribed page" UNLESS no_titlebar %] +You can't see this discussion because it's scheduled in the future, where only +subscribers can see it. Either you are not a subscriber to +[% constants.sitename %], or you have indicated you don't want comments pages +ad-free, or you have set your daily limit of ad-free pages to lower than the +default [% constants.subscribe_hits_btmd %]. Any of these three possible +issues can be resolved at your +subscription page. [% CASE "moderations to be lost" %] -[% PROCESS titlebar width="100%" title="You've Already Moderated this Discussion" %] +[% PROCESS titlebar width="100%" title="You've Already Moderated this Discussion" UNLESS no_titlebar %] If you continue to post this comment, all moderations done to this discussion will be undone! Are you sure you want to post? [% # NO DISCUSSION ID SPECIFIED CASE "no sid" %] -[% PROCESS titlebar width="100%" title="No Discussion Specified" %] -You did not specify a discussion ID. If you clicked on a link internal -to [% constants.sitename %], this is a bug. If not, someone sent you -to a silly invalid URL. +[% PROCESS titlebar width="100%" title="No Discussion Specified" UNLESS no_titlebar %] +You did not specify a discussion ID. If you clicked on a link internal to +[% constants.sitename %], this is a bug. If not, someone sent you to a silly +invalid URL. [% CASE 'no_moderation' %] The moderation system is currently down. @@ -248,7 +242,7 @@ [% CASE %] -An unexpected error has occurred.
    [% value %]
    +An unexpected error has occurred: [% value %] [% END %] __seclev__ Modified: slashjp/trunk/themes/slashcode/templates/html-header;misc;default =================================================================== --- slashjp/trunk/themes/slashcode/templates/html-header;misc;default 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/themes/slashcode/templates/html-header;misc;default 2008-04-01 04:03:21 UTC (rev 563) @@ -28,7 +28,7 @@ [% IF file.ie_cond %][% END %] [% END -%] [%- IF constants.plugin.Ajax %] - + Modified: slashjp/trunk/themes/slashcode/templates/modCommentLog;misc;default =================================================================== --- slashjp/trunk/themes/slashcode/templates/modCommentLog;misc;default 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/themes/slashcode/templates/modCommentLog;misc;default 2008-04-01 04:03:21 UTC (rev 563) @@ -36,15 +36,17 @@ __template__ [% IF mod_admin %] [% +hr_shown = 0; mod_index = 0; down=0; cnt=0; m2_down=0; m2_count=0; m2_offside=0; +a_up=0; a_sum=0; a_count=0; up=0; sum=0; count=0; a_m2_count=0; a_down=0; a_cnt=0; a_m2_down=0; a_m2_up=0; m2_count=0; a_m2_offside=0; a_m2_unfair_votes=0; unanimous = 0; unresolved=0; show_uid_totals = (type == "uid" && (this_user.totalmods || this_user.downmods || this_user.upmods || this_user.m2unfair || this_user.m2unfairpercent || this_user.stirred)); bg_toggle = 0; %] [% IF mods.size > 0 || show_uid_totals %] - [% IF user.is_admin and need_m2_form %] -
    + [% IF user.is_admin && need_m2_form %] +

    [% END %] [% IF meta_mod_only %] @@ -53,7 +55,7 @@ [% total_cols = 6 %] [% IF title; extra = ""; - IF constants.m2; + IF constants.m2 && !constants.modal_prefs_active; show_m2s_op = show_m2s ? 0 : 1; self_url = PROCESS base_url_mod; url_tail = PROCESS state_url_mod override = { show_m2s => show_m2s_op}; @@ -84,8 +86,6 @@
    [% END %] - [% hr_shown = 0; - mod_index = 0; %] [% FOREACH moderation = mods %] [% IF constants.m2 && type == "cid" && constants.show_m2s_with_mods && show_m2s && constants.m2_multicount; prev_index = mod_index - 1; @@ -203,7 +203,13 @@ [% IF need_m2_button %] [% END %] [% END %] Modified: slashjp/trunk/themes/slashcode/templates/printCommComments;misc;default =================================================================== --- slashjp/trunk/themes/slashcode/templates/printCommComments;misc;default 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/themes/slashcode/templates/printCommComments;misc;default 2008-04-01 04:03:21 UTC (rev 563) @@ -71,7 +71,8 @@ [% Slash.linkComment(next, 1) %]>> [% END %] - [% m1_classname = "Slash::" _ constants.m1_pluginname; + [% UNLESS constants.modal_prefs_active; + m1_classname = "Slash::" _ constants.m1_pluginname; moddb = Slash.getObject(m1_classname); IF moddb; moddb.dispModCommentLog('cid', cid, { @@ -82,6 +83,7 @@ need_m2_button => constants.m2, title => " " }); END; + END; # constants.modal_prefs_active %] [% END %] @@ -101,6 +103,7 @@ [% lcp %] [% IF discussion2 && !cid %] +
    Check for more [% UNLESS user.state.discussion_archived || user.state.discussion_future_nopost %] | [% Slash.linkComment({ @@ -108,7 +111,8 @@ cid => cid, op => 'reply', subject => 'Reply', - subject_only => 1 + subject_only => 1, + onclick => ((discussion2 && (!constants.subscribe || user.is_subscriber)) ? "replyTo(0); return false;" : '') }); END %]
    Modified: slashjp/trunk/themes/slashcode/templates/printCommentsMain;misc;default =================================================================== --- slashjp/trunk/themes/slashcode/templates/printCommentsMain;misc;default 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/themes/slashcode/templates/printCommentsMain;misc;default 2008-04-01 04:03:21 UTC (rev 563) @@ -201,7 +201,8 @@ cid => cid, op => 'reply', subject => 'Reply', - subject_only => 1 + subject_only => 1, + onclick => ((discussion2 && (!constants.subscribe || user.is_subscriber)) ? "replyTo(0); return false;" : '') }) %] [% END %] @@ -285,7 +286,8 @@ cid => cid, op => 'reply', subject => 'Reply', - subject_only => 1 + subject_only => 1, + onclick => ((discussion2 && (!constants.subscribe || user.is_subscriber)) ? "replyTo(0); return false;" : '') }) %] [% END %]
    Keybindings Beta
    From svnnotify ¡÷ sourceforge.jp Thu Apr 3 16:25:31 2008 From: svnnotify ¡÷ sourceforge.jp (svnnotify ¡÷ sourceforge.jp) Date: Thu, 03 Apr 2008 16:25:31 +0900 Subject: [Slashdotjp-dev 1037] [564] add slash_2.5.0.198.orig.tar.gz Message-ID: <1207207531.813311.30656.nullmailer@users.sourceforge.jp> Revision: 564 http://svn.sourceforge.jp/cgi-bin/viewcvs.cgi?root=slashdotjp&view=rev&rev=564 Author: tach Date: 2008-04-03 16:25:31 +0900 (Thu, 03 Apr 2008) Log Message: ----------- add slash_2.5.0.198.orig.tar.gz Added Paths: ----------- slashjp/tarballs/slash_2.5.0.198.orig.tar.gz -------------- next part -------------- Added: slashjp/tarballs/slash_2.5.0.198.orig.tar.gz =================================================================== (Binary files differ) Property changes on: slashjp/tarballs/slash_2.5.0.198.orig.tar.gz ___________________________________________________________________ Name: svn:mime-type + application/octet-stream From svnnotify ¡÷ sourceforge.jp Thu Apr 3 20:59:13 2008 From: svnnotify ¡÷ sourceforge.jp (svnnotify ¡÷ sourceforge.jp) Date: Thu, 03 Apr 2008 20:59:13 +0900 Subject: [Slashdotjp-dev 1038] [565] Fix variable name for new Comments.pm Message-ID: <1207223953.201025.26917.nullmailer@users.sourceforge.jp> Revision: 565 http://svn.sourceforge.jp/cgi-bin/viewcvs.cgi?root=slashdotjp&view=rev&rev=565 Author: tach Date: 2008-04-03 20:59:12 +0900 (Thu, 03 Apr 2008) Log Message: ----------- Fix variable name for new Comments.pm Modified Paths: -------------- slashjp/trunk/Slash/Utility/Comments/Comments.pm slashjp/trunk/debian/changelog -------------- next part -------------- Modified: slashjp/trunk/Slash/Utility/Comments/Comments.pm =================================================================== --- slashjp/trunk/Slash/Utility/Comments/Comments.pm 2008-04-03 07:25:31 UTC (rev 564) +++ slashjp/trunk/Slash/Utility/Comments/Comments.pm 2008-04-03 11:59:12 UTC (rev 565) @@ -1397,10 +1397,10 @@ $comm->{posttype} || PLAINTEXT ); - if ($constants->{anonymous_comment_interval} && ($user->{is_anon} || $form->{postanon})) { + if ($constants->{anonymous_comment_interval} && ($user->{is_anon} || $comm->{postanon})) { my $ipid = getCurrentUser('ipid'); - my $ipid_count = $slashdb->sqlSelect('count(*)', 'comments', - "sid='$form->{sid}' + my $ipid_count = $reader->sqlSelect('count(*)', 'comments', + "sid='$comm->{sid}' AND uid=1 AND date > SUBDATE(NOW(), INTERVAL $constants->{anonymous_comment_interval} MINUTE) AND ipid='$ipid'"); Modified: slashjp/trunk/debian/changelog =================================================================== --- slashjp/trunk/debian/changelog 2008-04-03 07:25:31 UTC (rev 564) +++ slashjp/trunk/debian/changelog 2008-04-03 11:59:12 UTC (rev 565) @@ -1,8 +1,9 @@ slash (2.5.0.198-1) unstable; urgency=low * New upstream CVS release + * Fix variable name for new Slash/Utility/Comments/Comments.pm - -- Taku YASUI Tue, 01 Apr 2008 13:02:56 +0900 + -- Taku YASUI Thu, 03 Apr 2008 20:58:51 +0900 slash (2.5.0.196-1) unstable; urgency=low From svnnotify ¡÷ sourceforge.jp Fri Apr 4 14:10:55 2008 From: svnnotify ¡÷ sourceforge.jp (svnnotify ¡÷ sourceforge.jp) Date: Fri, 04 Apr 2008 14:10:55 +0900 Subject: [Slashdotjp-dev 1039] [566] * Add imagemagick to Depends: for slash-backend package Message-ID: <1207285855.366687.21813.nullmailer@users.sourceforge.jp> Revision: 566 http://svn.sourceforge.jp/cgi-bin/viewcvs.cgi?root=slashdotjp&view=rev&rev=566 Author: tach Date: 2008-04-04 14:10:55 +0900 (Fri, 04 Apr 2008) Log Message: ----------- * Add imagemagick to Depends: for slash-backend package - task process_file_queue.pl uses /usr/bin/convert command Modified Paths: -------------- slashjp/trunk/debian/changelog slashjp/trunk/debian/control -------------- next part -------------- Modified: slashjp/trunk/debian/changelog =================================================================== --- slashjp/trunk/debian/changelog 2008-04-03 11:59:12 UTC (rev 565) +++ slashjp/trunk/debian/changelog 2008-04-04 05:10:55 UTC (rev 566) @@ -2,8 +2,10 @@ * New upstream CVS release * Fix variable name for new Slash/Utility/Comments/Comments.pm + * Add imagemagick to Depends: for slash-backend package + - task process_file_queue.pl uses /usr/bin/convert command - -- Taku YASUI Thu, 03 Apr 2008 20:58:51 +0900 + -- Taku YASUI Fri, 04 Apr 2008 14:09:27 +0900 slash (2.5.0.196-1) unstable; urgency=low Modified: slashjp/trunk/debian/control =================================================================== --- slashjp/trunk/debian/control 2008-04-03 11:59:12 UTC (rev 565) +++ slashjp/trunk/debian/control 2008-04-04 05:10:55 UTC (rev 566) @@ -18,7 +18,7 @@ Package: slash-backend Architecture: all -Depends: slash-common, adduser, mysql-server-5.0 | mysql-server-4.1, libschedule-cron-perl, ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends} +Depends: slash-common, adduser, mysql-server-5.0 | mysql-server-4.1, libschedule-cron-perl, imagemagick, ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends} Description: The code that runs Slashdot - Backend server Slash -- Slashdot Like Automated Storytelling Homepage -- is an architecture to put together web sites. It comes with functionality for posting articles, From svnnotify ¡÷ sourceforge.jp Fri Apr 4 14:37:13 2008 From: svnnotify ¡÷ sourceforge.jp (svnnotify ¡÷ sourceforge.jp) Date: Fri, 04 Apr 2008 14:37:13 +0900 Subject: [Slashdotjp-dev 1040] [567] fix syntax error of tagbox.pl Message-ID: <1207287433.599443.10751.nullmailer@users.sourceforge.jp> Revision: 567 http://svn.sourceforge.jp/cgi-bin/viewcvs.cgi?root=slashdotjp&view=rev&rev=567 Author: tach Date: 2008-04-04 14:37:13 +0900 (Fri, 04 Apr 2008) Log Message: ----------- fix syntax error of tagbox.pl Modified Paths: -------------- slashjp/trunk/plugins/Tags/tagbox.pl -------------- next part -------------- Modified: slashjp/trunk/plugins/Tags/tagbox.pl =================================================================== --- slashjp/trunk/plugins/Tags/tagbox.pl 2008-04-04 05:10:55 UTC (rev 566) +++ slashjp/trunk/plugins/Tags/tagbox.pl 2008-04-04 05:37:13 UTC (rev 567) @@ -283,7 +283,6 @@ my($tagbox, $feeder_ar) = @_; for my $feeder_hr (@$feeder_ar) { { my $fstr = Dumper($feeder_hr); $fstr =~ s/\s+/ /g; main::tagboxLog("addFeederInfo: tbid=$tagbox->{tbid} f: $fstr"); } - if (defined($feeder_hr->{tagid})); $tagboxdb->addFeederInfo($tagbox->{tbid}, $feeder_hr); } } From svnnotify ¡÷ sourceforge.jp Fri Apr 4 15:46:16 2008 From: svnnotify ¡÷ sourceforge.jp (svnnotify ¡÷ sourceforge.jp) Date: Fri, 04 Apr 2008 15:46:16 +0900 Subject: [Slashdotjp-dev 1041] [568] * Change from Apache::PerlRun to Apache::Registry in Message-ID: <1207291576.392369.7412.nullmailer@users.sourceforge.jp> Revision: 568 http://svn.sourceforge.jp/cgi-bin/viewcvs.cgi?root=slashdotjp&view=rev&rev=568 Author: tach Date: 2008-04-04 15:46:16 +0900 (Fri, 04 Apr 2008) Log Message: ----------- * Change from Apache::PerlRun to Apache::Registry in Slash/Apache/User/PasswordSalt/PasswordSalt.pm Modified Paths: -------------- slashjp/trunk/Slash/Apache/User/PasswordSalt/PasswordSalt.pm slashjp/trunk/debian/changelog -------------- next part -------------- Modified: slashjp/trunk/Slash/Apache/User/PasswordSalt/PasswordSalt.pm =================================================================== --- slashjp/trunk/Slash/Apache/User/PasswordSalt/PasswordSalt.pm 2008-04-04 05:37:13 UTC (rev 567) +++ slashjp/trunk/Slash/Apache/User/PasswordSalt/PasswordSalt.pm 2008-04-04 06:46:16 UTC (rev 568) @@ -106,7 +106,7 @@ my($package, $filename, $line, $subroutine) = @c; # If we go back up the call chain to a package we know we can # trust, then we can stop looking. - last if $package =~ /^(main|Apache::PerlRun|Apache::ROOT::.*)$/; + last if $package =~ /^(main|Apache::Registry|Apache::ROOT::.*)$/; if ($package =~ /^Template/ || $subroutine eq '(eval)') { # This exits the entire script immediately. confess(scalar(gmtime) . " $$ SuspiciousCaller for salt at package '$package'"); Modified: slashjp/trunk/debian/changelog =================================================================== --- slashjp/trunk/debian/changelog 2008-04-04 05:37:13 UTC (rev 567) +++ slashjp/trunk/debian/changelog 2008-04-04 06:46:16 UTC (rev 568) @@ -4,8 +4,10 @@ * Fix variable name for new Slash/Utility/Comments/Comments.pm * Add imagemagick to Depends: for slash-backend package - task process_file_queue.pl uses /usr/bin/convert command + * Change from Apache::PerlRun to Apache::Registry in + Slash/Apache/User/PasswordSalt/PasswordSalt.pm - -- Taku YASUI Fri, 04 Apr 2008 14:09:27 +0900 + -- Taku YASUI Fri, 04 Apr 2008 15:45:45 +0900 slash (2.5.0.196-1) unstable; urgency=low From svnnotify ¡÷ sourceforge.jp Mon Apr 7 08:11:15 2008 From: svnnotify ¡÷ sourceforge.jp (svnnotify ¡÷ sourceforge.jp) Date: Mon, 07 Apr 2008 08:11:15 +0900 Subject: [Slashdotjp-dev 1042] [569] merged from upstream T_2_5_0_198 Message-ID: <1207523475.185030.12826.nullmailer@users.sourceforge.jp> Revision: 569 http://svn.sourceforge.jp/cgi-bin/viewcvs.cgi?root=slashdotjp&view=rev&rev=569 Author: tach Date: 2008-04-07 08:11:14 +0900 (Mon, 07 Apr 2008) Log Message: ----------- merged from upstream T_2_5_0_198 Modified Paths: -------------- slashjp/branches/upstream/current/Slash/Apache/User/User.pm slashjp/branches/upstream/current/Slash/DB/MySQL/MySQL.pm slashjp/branches/upstream/current/Slash/Utility/Comments/Comments.pm slashjp/branches/upstream/current/Slash/Utility/Environment/Environment.pm slashjp/branches/upstream/current/plugins/Ajax/PLUGIN slashjp/branches/upstream/current/plugins/Ajax/htdocs/ajax.pl slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/admin.js slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/common.js slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/nodnix.js slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/sd_autocomplete.js slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/sd_calendar.js slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/slashbox.js slashjp/branches/upstream/current/plugins/Ajax/templates/data;ajax;default slashjp/branches/upstream/current/plugins/Ajax/templates/edit_comment;ajax;default slashjp/branches/upstream/current/plugins/Console/console.pl slashjp/branches/upstream/current/plugins/FireHose/FireHose.pm slashjp/branches/upstream/current/plugins/FireHose/templates/data;firehose;default slashjp/branches/upstream/current/plugins/FireHose/templates/dispTopicFireHose;misc;default slashjp/branches/upstream/current/plugins/FireHose/templates/fireHoseForm;misc;default slashjp/branches/upstream/current/plugins/FireHose/templates/firehose_pages;misc;default slashjp/branches/upstream/current/plugins/FireHose/templates/list;firehose;default slashjp/branches/upstream/current/plugins/HumanConf/HumanConf.pm slashjp/branches/upstream/current/plugins/Journal/journal.pl slashjp/branches/upstream/current/plugins/Moderation/Moderation.pm slashjp/branches/upstream/current/plugins/ResKey/MANIFEST slashjp/branches/upstream/current/plugins/ResKey/ResKey/Checks/Duration.pm slashjp/branches/upstream/current/plugins/ResKey/ResKey/Key.pm slashjp/branches/upstream/current/plugins/ResKey/example.plx slashjp/branches/upstream/current/plugins/ResKey/mysql_dump.sql slashjp/branches/upstream/current/plugins/ResKey/templates/data;reskey;default slashjp/branches/upstream/current/plugins/TagDataView/TagDataView.pm slashjp/branches/upstream/current/plugins/TagModeration/TagModeration.pm slashjp/branches/upstream/current/plugins/Tags/Clout/Describe.pm slashjp/branches/upstream/current/plugins/Tags/Clout/Vote.pm slashjp/branches/upstream/current/plugins/Tags/PLUGIN slashjp/branches/upstream/current/plugins/Tags/Tags.pm slashjp/branches/upstream/current/plugins/Tags/mysql_dump.sql slashjp/branches/upstream/current/plugins/Tags/tags.pl slashjp/branches/upstream/current/plugins/Tags/templates/usertaghistory;users;default slashjp/branches/upstream/current/plugins/Tags/templates/usertags;users;default slashjp/branches/upstream/current/sql/mysql/defaults.sql slashjp/branches/upstream/current/sql/mysql/upgrades slashjp/branches/upstream/current/tagboxes/FHEditorPop/FHEditorPop.pm slashjp/branches/upstream/current/tagboxes/FHEditorPop/mysql_dump.sql slashjp/branches/upstream/current/tagboxes/Top/Top.pm slashjp/branches/upstream/current/themes/slashcode/THEME slashjp/branches/upstream/current/themes/slashcode/htdocs/comments.css slashjp/branches/upstream/current/themes/slashcode/htdocs/comments.pl slashjp/branches/upstream/current/themes/slashcode/htdocs/images/comments.js slashjp/branches/upstream/current/themes/slashcode/htdocs/slashcode_lite.css slashjp/branches/upstream/current/themes/slashcode/htdocs/users.pl slashjp/branches/upstream/current/themes/slashcode/templates/dispComment;misc;default slashjp/branches/upstream/current/themes/slashcode/templates/dispLinkComment;misc;default slashjp/branches/upstream/current/themes/slashcode/templates/editComm;users;default slashjp/branches/upstream/current/themes/slashcode/templates/printCommComments;misc;default slashjp/branches/upstream/current/themes/slashcode/templates/printCommentsMain;misc;default slashjp/branches/upstream/current/utils/createTestTags Added Paths: ----------- slashjp/branches/upstream/current/plugins/Ajax/templates/hc_comment;ajax;default slashjp/branches/upstream/current/plugins/ResKey/ResKey/Checks/HumanConf.pm slashjp/branches/upstream/current/plugins/Tags/templates/usertagnames;users;default slashjp/branches/upstream/current/plugins/Tags/templates/usertagsforname;users;default slashjp/branches/upstream/current/tagboxes/RecentTags/ slashjp/branches/upstream/current/tagboxes/RecentTags/Makefile.PL slashjp/branches/upstream/current/tagboxes/RecentTags/RecentTags.pm slashjp/branches/upstream/current/tagboxes/RecentTags/TAGBOX slashjp/branches/upstream/current/tagboxes/RecentTags/mysql_dump.sql slashjp/branches/upstream/current/themes/slashcode/htdocs/users2.pl slashjp/branches/upstream/current/themes/slashcode/templates/userInfo2;users;default slashjp/branches/upstream/current/themes/slashcode/templates/userboxes2;misc;default -------------- next part -------------- Modified: slashjp/branches/upstream/current/Slash/Apache/User/User.pm =================================================================== --- slashjp/branches/upstream/current/Slash/Apache/User/User.pm 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/Slash/Apache/User/User.pm 2008-04-06 23:11:14 UTC (rev 569) @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. # Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: User.pm,v 1.173 2008/02/13 16:37:18 pudge Exp $ +# $Id: User.pm,v 1.175 2008/04/02 14:25:56 entweichen Exp $ package Slash::Apache::User; @@ -24,7 +24,7 @@ @ISA = qw(DynaLoader); $VERSION = '2.003000'; # v2.3.0 -($REVISION) = ' $Revision: 1.173 $ ' =~ /\$Revision:\s+([^\s]+)/; +($REVISION) = ' $Revision: 1.175 $ ' =~ /\$Revision:\s+([^\s]+)/; bootstrap Slash::Apache::User $VERSION; @@ -597,7 +597,14 @@ $r->filename($constants->{basedir} . '/help.pl'); return OK; } - + + # This is a temporary addition! + if ($uri =~ m[^/(?:%5[eE]|\^)]) { + $r->uri('/users2.pl'); + $r->filename($constants->{basedir} . '/users2.pl'); + return OK; + } + # for self-references (/~/ and /my/) if (($saveuri =~ m[^/(?:%7[eE]|~)] && $uri =~ m[^/~ (?: /(.*) | /? ) $]x) # /my/ or /my can match, but not /mything @@ -612,6 +619,7 @@ } my($op, $extra) = split /\//, $string, 2; + $extra ||= ''; my $logged_in = $r->header_in('Cookie') =~ $USER_MATCH; my $try_login = !$logged_in && $logtoken; @@ -634,9 +642,9 @@ $found_the_op = 1; if ($op eq 'journal') { my $args; - if ($extra && $extra =~ /^\d+$/) { + if ($extra =~ /^\d+$/) { $args = "id=$extra&op=edit"; - } elsif ($extra && $extra eq 'friends') { + } elsif ($extra eq 'friends') { $args = "op=friendview"; } else { $args = "op=list"; @@ -703,7 +711,10 @@ $r->filename($constants->{basedir} . '/journal.pl'); } elsif ($op eq 'tags') { - $r->args("op=showtags"); + my $args = 'op=showtags'; + # XXX "!" is a 'reserved' char in URI, escape it here? + $args .= "&tagname=$extra" if $extra; + $r->args($args); $r->uri('/users.pl'); $r->filename($constants->{basedir} . '/users.pl'); @@ -846,7 +857,10 @@ $r->filename($constants->{basedir} . '/journal.pl'); } elsif ($op eq 'tags') { - $r->args("op=showtags&nick=$nick&uid=$uid"); + my $args = "op=showtags&nick=$nick&uid=$uid"; + # XXX "!" is a 'reserved' char in URI, escape it here? + $args .= "&tagname=$extra" if $extra; + $r->args($args); $r->uri('/users.pl'); $r->filename($constants->{basedir} . '/users.pl'); Modified: slashjp/branches/upstream/current/Slash/DB/MySQL/MySQL.pm =================================================================== --- slashjp/branches/upstream/current/Slash/DB/MySQL/MySQL.pm 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/Slash/DB/MySQL/MySQL.pm 2008-04-06 23:11:14 UTC (rev 569) @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. # Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: MySQL.pm,v 1.1010 2008/03/21 03:05:35 pudge Exp $ +# $Id: MySQL.pm,v 1.1012 2008/03/27 16:56:27 tvroom Exp $ package Slash::DB::MySQL; use strict; @@ -20,7 +20,7 @@ use base 'Slash::DB::Utility'; use Slash::Constants ':messages'; -($VERSION) = ' $Revision: 1.1010 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.1012 $ ' =~ /\$Revision:\s+([^\s]+)/; # Fry: How can I live my life if I can't tell good from evil? @@ -3455,6 +3455,7 @@ # Of course, markStoryClean and -Dirty work too my($dirty_change, $dirty_newval); + if ($change_hr->{writestatus}) { $dirty_change = 1; $dirty_newval = $change_hr->{writestatus} eq 'dirty' ? 1 : 0; @@ -3468,6 +3469,11 @@ delete $change_hr->{is_dirty} } + if ($change_hr->{introtext} && $change_hr->{introtext} =~ /href=\"SELF\"/) { + my $link_url = $self->_getStorySelfLink($stoid, $change_hr); + $change_hr->{introtext} =~ s/href=\"SELF\"/href="$link_url"/; + } + $change_hr->{is_archived} = $change_hr->{is_archived} ? 'yes' : 'no' if defined $change_hr->{is_archived}; $change_hr->{in_trash} = $change_hr->{in_trash} ? 'yes' : 'no' @@ -7871,6 +7877,7 @@ $signoff_type ||= ''; $self->sqlInsert("signoff", { stoid => $stoid, uid => $uid, signoff_type => $signoff_type }); + $self->setStory($stoid, { thumb_signoff_needed => 0 }); if ($constants->{plugin}{FireHose}) { my $firehose = getObject("Slash::FireHose"); @@ -7941,6 +7948,19 @@ ); } +sub deleteSignoffsForStory { + my($self, $stoid) = @_; + my $constants = getCurrentStatic(); + my $stoid_q = $self->sqlQuote($stoid); + $self->sqlDelete("signoff", "stoid=$stoid_q"); + if ($constants->{plugin}{FireHose}) { + my $firehose = getObject("Slash::FireHose"); + my ($id) = $self->sqlSelect("id", "firehose", "type='story' and srcid=$stoid_q"); + $firehose->setFireHose($id, { signoffs => '' }); + + } +} + sub getSignoffsInLastMinutes { my ($self, $mins) = @_; $mins ||= getCurrentStatic("admin_timeout"); @@ -12569,6 +12589,23 @@ return $answer; } +sub _getStorySelfLink { + my($self, $stoid, $change_hr) = @_; + my $story = $self->getStory($stoid); + my $data = {}; + my $link = $change_hr->{title} || $story->{title}; + my $tid = $change_hr->{tid} || $story->{tid}; + my $skin = $change_hr->{primaryskid} || $story->{primary_skid}; + + my $story_link_ar = linkStory({ + sid => $story->{sid}, + link => $link, + tid => $tid, + skin => $skin + }); + return $story_link_ar->[0]; +} + ######################################################## sub DESTROY { my($self) = @_; Modified: slashjp/branches/upstream/current/Slash/Utility/Comments/Comments.pm =================================================================== --- slashjp/branches/upstream/current/Slash/Utility/Comments/Comments.pm 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/Slash/Utility/Comments/Comments.pm 2008-04-06 23:11:14 UTC (rev 569) @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. # Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Comments.pm,v 1.9 2008/03/20 07:30:29 pudge Exp $ +# $Id: Comments.pm,v 1.19 2008/04/03 00:38:32 pudge Exp $ package Slash::Utility::Comments; @@ -34,11 +34,11 @@ use base 'Exporter'; use vars qw($VERSION @EXPORT); -($VERSION) = ' $Revision: 1.9 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.19 $ ' =~ /\$Revision:\s+([^\s]+)/; @EXPORT = qw( constrain_score dispComment displayThread printComments jsSelectComments commentCountThreshold commentThresholds discussion2 - tempUofmLinkGenerate tempUofmCipherObj selectComments preProcessReplyForm + selectComments preProcessReplyForm getPoints preProcessComment postProcessComment prevComment saveComment ); @@ -156,8 +156,7 @@ #slashProf("sC main sort", "sC setup"); my($oldComment, %old_comments); - # XXXd2 disable for sub-threads for now ($cid) - if ($discussion2 && !$cid && !$options->{no_d2}) { + if ($discussion2 && !$options->{no_d2}) { my $limits = $slashdb->getDescriptions('d2_comment_limits'); my $max = $d2_comment_q ? $limits->{ $d2_comment_q } : 0; $max = int($max/2) if $shtml; @@ -165,6 +164,19 @@ $options->{existing} ||= {}; @$thisComment = sort { $a->{cid} <=> $b->{cid} } @$thisComment; + # we need to filter which comments are descendants of $cid + my %cid_seen; + if ($cid) { + # for display later + $user->{state}{d2_defaultclass}{$cid} = 'full'; + # this only works because we are already in cid order + for my $C (@$thisComment) { + if ($cid == $C->{cid} || $cid_seen{$C->{pid}}) { + $cid_seen{$C->{cid}} = 1; + } + } + } + my $sort_comments; if (!$user->{d2_comment_order}) { # score $sort_comments = [ sort { @@ -176,16 +188,21 @@ $sort_comments = $thisComment; } + for my $C (@$sort_comments) { next if $options->{existing}{$C->{cid}}; if ($max && @new_comments >= $max) { if ($cid) { + # still include $cid even if it would + # otherwise be excluded (should only + # matter if not sorting by date push @new_comments, $C if $cid == $C->{cid}; } else { last; } } else { + next if $cid && !$cid_seen{$C->{cid}}; push @new_comments, $C; } } @@ -193,9 +210,9 @@ my @seen; my $lastcid = 0; my %check = (%{$options->{existing}}, map { $_->{cid} => 1 } @new_comments); - for my $cid (sort { $a <=> $b } keys(%check)) { - push @seen, $lastcid ? $cid - $lastcid : $cid; - $lastcid = $cid; + for my $this_cid (sort { $a <=> $b } keys(%check)) { + push @seen, $lastcid ? $this_cid - $lastcid : $this_cid; + $lastcid = $this_cid; } $comments->{0}{d2_seen} = join ',', @seen; @@ -285,32 +302,38 @@ } # get the total visible kids for each comment --Pater - countTotalVisibleKids($comments); + countTotalVisibleKids($comments) unless $discussion2; - _print_cchp($discussion, $count, $comments->{0}{totals}); - -##slashProf("sC reparenting", "sC counting"); -#slashProf("sC reparenting"); - reparentComments($comments, $reader, $options); - -##slashProf("sC d2 fudging", "sC reparenting"); -#slashProf("", "sC reparenting"); +##slashProf("sC d2 fudging", "sC counting"); if ($oldComment) { - for my $cid (sort { $a <=> $b } keys %$comments) { - my $C = $comments->{$cid}; + my @new_seen; + for my $this_cid (sort { $a <=> $b } keys %$comments) { + next unless $this_cid; + my $C = $comments->{$this_cid}; # && !$options->{existing}{ $C->{pid} } while ($C->{pid}) { my $parent = $comments->{ $C->{pid} } || {}; + if (!$parent || !$parent->{kids} || !$parent->{cid} || !defined($parent->{pid}) || !defined($parent->{points})) { - $parent = $comments->{ $C->{pid} } = { - cid => $C->{pid}, - pid => ($old_comments{ $C->{pid} } && $old_comments{ $C->{pid} }{ pid }) || 0, - kids => [ ], - points => -2, - dummy => 1, - %$parent, - }; + # parents of our main cid, so spend time + # finding it ... + if ($cid && $C->{pid} < $cid) { + $user->{state}{d2_defaultclass}{$C->{pid}} = 'oneline'; + $parent = $old_comments{ $C->{pid} }; + push @new_seen, $C->{pid}; + $count++; + } else { + $parent = { + cid => $C->{pid}, + pid => ($old_comments{ $C->{pid} } && $old_comments{ $C->{pid} }{ pid }) || 0, + kids => [ ], + points => -2, + dummy => 1, + %$parent, + }; + } + $comments->{ $C->{pid} } = $parent; } unless (grep { $_ == $C->{cid} } @{$parent->{kids}}) { @@ -325,10 +348,29 @@ $C = $parent; } } + + # fix d2_seen + my @seen; + my $lastcid = 0; + for my $this_cid (sort { $a <=> $b } @new_seen) { + push @seen, $lastcid ? $this_cid - $lastcid : $this_cid; + $lastcid = $this_cid; + } + my @old_seen = split /,/, $comments->{0}{d2_seen}; + if (@seen && @old_seen) { + $old_seen[0] = $old_seen[0] - $lastcid; + } + $comments->{0}{d2_seen} = join ',', @seen, @old_seen; } ##slashProf("", "sC d2 fudging"); + _print_cchp($discussion, $count, $comments->{0}{totals}); + +#slashProf("sC reparenting"); + reparentComments($comments, $reader, $options); +#slashProf("", "sC reparenting"); + return($comments, $count); } @@ -344,7 +386,6 @@ $gSkin ||= getCurrentSkin(); my $id = $form->{sid}; - my $pid = $form->{cid} || 0; return unless $id; my $threshold = defined $user->{d2_threshold} ? $user->{d2_threshold} : $user->{threshold}; @@ -360,12 +401,8 @@ my($comments) = $user->{state}{selectComments}{comments}; my $d2_seen_0 = $comments->{0}{d2_seen} || ''; - #delete $comments->{0}; # non-comment data - if ($pid && exists $comments->{$pid}) { - $comments = _get_thread($comments, $pid); - } - my @roots = $pid ? $pid : @{$comments->{$pid}{kids}}; + my @roots = @{$comments->{0}{kids} || []}; my %roots_hash = ( map { $_ => 1 } @roots ); my $thresh_totals; @@ -392,7 +429,7 @@ } } - $thresh_totals = commentCountThreshold($comments, $pid, \%roots_hash); + $thresh_totals = commentCountThreshold($comments, 0, \%roots_hash); $comments = $comments_new; } @@ -408,6 +445,7 @@ $user->{is_anon} ||= 0; $user->{is_admin} ||= 0; $user->{is_subscriber} ||= 0; + my $root_comment = $user->{state}{selectComments}{cidorpid} || 0; my $extra = ''; if ($d2_seen_0) { @@ -435,7 +473,7 @@ thresh_totals = $anon_thresh; -root_comment = $pid; +root_comment = $root_comment; root_comments = $anon_roots; root_comments_hash = $anon_rootsh; max_cid = $max_cid; @@ -722,6 +760,7 @@ my $max_depth_allowed = $user->{state}{max_depth} || $constants->{max_depth} || 7; + # even if !reparent, we still want to be here so we can set comments at max depth return if $user->{state}{noreparent} || (!$max_depth_allowed && !$user->{reparent}); # Adjust the max_depth_allowed for the root pid or cid. @@ -730,7 +769,7 @@ # when $form->{cid|pid} is set. And besides, max depth we # display is for display, so it should be based on how much # we're displaying, not on absolute depth of this thread. - my $root_cid_or_pid = $form->{cid} || $form->{pid} || 0; + my $root_cid_or_pid = discussion2($user) ? 0 : ($form->{cid} || $form->{pid} || 0); if ($root_cid_or_pid) { my $tmpcid = $root_cid_or_pid; while ($tmpcid) { @@ -964,8 +1003,9 @@ #slashProf("", "selectComments"); if ($discussion2) { $user->{state}{selectComments} = { - comments => $comments, - count => $count + cidorpid => $cidorpid, + comments => $comments, + count => $count }; } @@ -1023,7 +1063,7 @@ return if $user->{state}{nocomment} || $user->{mode} eq 'nocomment'; my($comment, $next, $previous); - if ($cid) { + if ($cid && !$discussion2) { my($next, $previous); $comment = $comments->{$cid}; if (my $sibs = $comments->{$comment->{pid}}{kids}) { @@ -1238,6 +1278,9 @@ my $highlight = ($comment->{points} >= $highlightthresh && $class ne 'hidden') ? 1 : 0; $class = 'full' if $highlight; + if ($discussion2 && $user->{state}{d2_defaultclass}{$cid}) { + $class = $user->{state}{d2_defaultclass}{$cid}; + } $comment->{class} = $class; $user->{state}{comments}{totals}{$class}++ unless $comment->{dummy}; @@ -1885,8 +1928,10 @@ $score_to_display .= "Score:"; if (length $comment->{points}) { $score_to_display .= $comment->{points}; - $score_to_display = qq[$score_to_display] - if $constants->{modal_prefs_active} && !$user->{is_anon}; + if ($constants->{modal_prefs_active}) { + my $func = "getModalPrefs('modcommentlog', 'Moderation Comment Log', $comment->{cid})"; + $score_to_display = qq[$score_to_display]; + } } else { $score_to_display .= '?'; } @@ -1974,25 +2019,23 @@ && $comment->{nickname} ne "-") { # this last test probably useless my @link = ( ); - push @link, (qq'' . linkComment({ + push @link, (qq'

    ' . linkComment({ sid => $comment->{sid}, pid => $comment->{cid}, op => 'Reply', subject => 'Reply to This', subject_only => 1, - onclick => (($discussion2 && (!$constants->{subscribe} || $user->{is_subscriber})) ? "replyTo($comment->{cid}); return false;" : '') - }) . '') unless $user->{state}{discussion_archived}; + onclick => (($discussion2 && !$user->{is_anon}) ? "replyTo($comment->{cid}); return false;" : '') + }) . '

    ') unless $user->{state}{discussion_archived}; - push @link, linkComment({ + push @link, (qq'

    ' . linkComment({ sid => $comment->{sid}, cid => $comment->{original_pid}, pid => $comment->{original_pid}, subject => 'Parent', subject_only => 1, onclick => ($discussion2 ? "return selectParent($comment->{original_pid})" : '') - }, 1) if $comment->{original_pid};# && !($discussion2 && -# (!$form->{cid} || $form->{cid} != $comment->{cid}) -# ); + }, 1) . '

    ') if $comment->{original_pid}; #use Data::Dumper; print STDERR "_hard_dispComment createSelect can_mod='$can_mod' disc_arch='$user->{state}{discussion_archived}' modd_arch='$constants->{comments_moddable_archived}' cid='$comment->{cid}' reasons: " . Dumper($reasons); @@ -2008,10 +2051,10 @@ push @link, qq|| if $user->{is_admin}; - my $link = join(" | ", @link); + my $link = join(" ", @link); if (@link) { - $commentsub = "[ $link ]"; + $commentsub = $link; } } @@ -2067,6 +2110,7 @@ my $class = $comment->{class}; my $classattr = $discussion2 ? qq[ class="$class"] : ''; + my $contain = $class eq 'full' ? ' contain' : ''; my $head = $discussion2 ? <$comment->{subject} @@ -2076,7 +2120,7 @@ my $return = ''; $return = <{noshow_show}; -
  • +
  • EOT @@ -2486,43 +2530,11 @@ # is discussion2 active? sub discussion2 { my $user = $_[0] || getCurrentUser(); - return $user->{discussion2} =~ /^(?:slashdot|uofm)$/ + return $user->{discussion2} eq 'slashdot' ? $user->{discussion2} : 0; } -sub tempUofmLinkGenerate { - require URI::Escape; - - my $constants = getCurrentStatic(); - my $user = getCurrentUser(); - - my $cipher = tempUofmCipherObj() or return; - - my $encrypted = $cipher->encrypt($user->{uid} . '|' . $user->{nickname}); - return sprintf($constants->{uofm_address}, URI::Escape::uri_escape($encrypted)); -} - -sub tempUofmCipherObj { - my $constants = getCurrentStatic(); - return unless $constants->{uofm_key} && $constants->{uofm_iv}; - - require Crypt::CBC; - - my $cipher = Crypt::CBC->new({ - key => $constants->{uofm_key}, - iv => $constants->{uofm_iv}, - cipher => 'Blowfish', - regenerate_key => 0, - padding => 'null', - prepend_iv => 0 - }); - - return $cipher; -} - - - 1; __END__ @@ -2534,4 +2546,4 @@ =head1 VERSION -$Id: Comments.pm,v 1.9 2008/03/20 07:30:29 pudge Exp $ +$Id: Comments.pm,v 1.19 2008/04/03 00:38:32 pudge Exp $ Modified: slashjp/branches/upstream/current/Slash/Utility/Environment/Environment.pm =================================================================== --- slashjp/branches/upstream/current/Slash/Utility/Environment/Environment.pm 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/Slash/Utility/Environment/Environment.pm 2008-04-06 23:11:14 UTC (rev 569) @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. # Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Environment.pm,v 1.235 2008/03/18 20:39:17 tvroom Exp $ +# $Id: Environment.pm,v 1.236 2008/03/24 20:18:00 jamiemccarthy Exp $ package Slash::Utility::Environment; @@ -33,7 +33,7 @@ use base 'Exporter'; use vars qw($VERSION @EXPORT); -($VERSION) = ' $Revision: 1.235 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.236 $ ' =~ /\$Revision:\s+([^\s]+)/; @EXPORT = qw( dbAvailable @@ -1879,10 +1879,12 @@ colorblock => sub { $_[0] =~ s|[^\w#,]+||g }, # What I actually want to do for userfield is allow it to match # [\w.]+, or pass emailValid(), or be changed to the return value -# from nickFix(). For technical reasons I'm putting that off -# until probably next week. Until then this breaks some very -# minor functionality. - Jamie 2008-01-09 +# from nickFix(). But nickFix() uses constants, which might not +# be set up at this point. - Jamie 2008-01-09 userfield => sub { $_[0] =~ s|[^\w.@ -]||g }, +# Ditto here, really - Jamie 2008-03-24 + tagname => sub { $_[0] = '' unless + $_[0] =~ /^\!?[a-z][a-z0-9]{0,62}$/ }, ); @@ -3526,4 +3528,4 @@ =head1 VERSION -$Id: Environment.pm,v 1.235 2008/03/18 20:39:17 tvroom Exp $ +$Id: Environment.pm,v 1.236 2008/03/24 20:18:00 jamiemccarthy Exp $ Modified: slashjp/branches/upstream/current/plugins/Ajax/PLUGIN =================================================================== --- slashjp/branches/upstream/current/plugins/Ajax/PLUGIN 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/plugins/Ajax/PLUGIN 2008-04-06 23:11:14 UTC (rev 569) @@ -1,4 +1,4 @@ -# $Id: PLUGIN,v 1.41 2008/03/14 15:48:06 scc Exp $ +# $Id: PLUGIN,v 1.42 2008/03/25 18:46:24 pudge Exp $ name=Ajax description="Ajax (Asynchronous Javascript and XML)" mysql_dump=mysql_dump.sql @@ -36,6 +36,7 @@ template=templates/data;ajax;default template=templates/datewidget;misc;default template=templates/edit_comment;ajax;default +template=templates/hc_comment;ajax;default template=templates/modal_footer;misc;default template=templates/prefs_d2;ajax;default template=templates/prefs_d2_posting;ajax;default Modified: slashjp/branches/upstream/current/plugins/Ajax/htdocs/ajax.pl =================================================================== --- slashjp/branches/upstream/current/plugins/Ajax/htdocs/ajax.pl 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/plugins/Ajax/htdocs/ajax.pl 2008-04-06 23:11:14 UTC (rev 569) @@ -2,7 +2,7 @@ # This code is a part of Slash, and is released under the GPL. # Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: ajax.pl,v 1.77 2008/03/19 08:25:31 pudge Exp $ +# $Id: ajax.pl,v 1.84 2008/03/31 21:43:56 pudge Exp $ use strict; use warnings; @@ -14,7 +14,7 @@ use Slash::Utility; use vars qw($VERSION); -($VERSION) = ' $Revision: 1.77 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.84 $ ' =~ /\$Revision:\s+([^\s]+)/; ################################################################## sub main { @@ -40,8 +40,6 @@ ); # print STDERR "AJAX3 $$: $user->{uid}, $op\n"; -#$Slash::ResKey::DEBUG = 2; - $ops->{$op}{function} ||= loadCoderef($ops->{$op}{class}, $ops->{$op}{subroutine}); $op = 'default' unless $ops->{$op}{function}; @@ -58,7 +56,7 @@ if ($reskey_name ne 'NA') { my $reskey = getObject('Slash::ResKey'); - my $rkey = $reskey->key($reskey_name); + my $rkey = $reskey->key($reskey_name); #, { debug => 1 }); if (!$rkey) { print STDERR scalar(localtime) . " ajax.pl main no rkey for op='$op' name='$reskey_name'\n"; return; @@ -72,17 +70,17 @@ $rkey->use; } if (!$rkey->success) { + # feel free to send msgdiv => 'thisdivhere' to the ajax call, + # and any reskey error messages will be sent to it if ($form->{msgdiv}) { header_ajax({ content_type => 'application/json' }); (my $msgdiv = $form->{msgdiv}) =~ s/[^\w-]+//g; print Data::JavaScript::Anon->anon_dump({ - html => { $msgdiv => $rkey->errstr }, + html => { $msgdiv => $rkey->errstr }, + eval_last => "\$('#$msgdiv').show()" }); } - printf STDERR "AJAXE %d: UID:%d, op:%s: %s (%s:%s:%s:%s:%s:%s:%s)\n", - $$, $user->{uid}, $op, $rkey->errstr, $rkey->reskey, - $rkey->type, $rkey->resname, $rkey->rkrid, $rkey->code, $rkey->static, - $user->{srcids}{ 24 }; + $rkey->ERROR($op); return; } } @@ -281,12 +279,21 @@ my $discussion = $slashdb->getDiscussion($sid); my $comment = preProcessComment($form, $user, $discussion, \$error_message); if (!$error_message) { - $options->{rkey}->use or $error_message = $options->{rkey}->errstr; + unless ($options->{rkey}->use) { + $error_message = $options->{rkey}->errstr; + } } $saved_comment = saveComment($form, $comment, $user, $discussion, \$error_message) unless $error_message; my $cid = $saved_comment && $saved_comment ne '-1' ? $saved_comment->{cid} : 0; + if ($error_message) { + $error_message = getData('inline preview warning') . $error_message + unless $options->{rkey}->death; + # go back to HumanConf if we still have errors left to display + $error_message .= slashDisplay('hc_comment', { pid => $pid }, { Return => 1 }); + } + $options->{content_type} = 'application/json'; my %to_dump = ( cid => $cid, error => $error_message ); #use Data::Dumper; print STDERR Dumper \%to_dump; @@ -301,15 +308,18 @@ $user->{state}{ajax_accesslog_op} = 'comments_preview_reply'; - my($error_message, $preview, $html); + my $html = my $error_message = ''; my $discussion = $slashdb->getDiscussion($sid); my $comment = preProcessComment($form, $user, $discussion, \$error_message); if ($comment && $comment ne '-1') { - $preview = postProcessComment({ %$comment, %$form, %$user }, 0, $discussion); + my $preview = postProcessComment({ %$comment, %$form, %$user }, 0, $discussion); $html = prevComment($preview, $user); } - $error_message ||= 'This comment will not be saved until you click the Submit button below.'; + if ($html) { + $error_message = getData('inline preview warning') . $error_message; + $error_message .= slashDisplay('hc_comment', { pid => $pid }, { Return => 1 }); + } $options->{content_type} = 'application/json'; my %to_dump = ( error => $error_message, @@ -339,7 +349,7 @@ preProcessReplyForm($form, $reply); my $reskey = getObject('Slash::ResKey'); - my $rkey = $reskey->key('comments', { nostate => 1 }); + my $rkey = $reskey->key('comments', { nostate => 1 }); #, debug => 1 }); $rkey->create; my %to_dump; @@ -386,15 +396,14 @@ sub fetchComments { my($slashdb, $constants, $user, $form, $options) = @_; - my $cids = [ grep /^\d+$/, split /,/, ($form->{cids} || '') ]; + my $cids = [ grep { defined && /^\d+$/ } ($form->{_multi}{cids} ? @{$form->{_multi}{cids}} : $form->{cids}) ]; my $id = $form->{discussion_id} || 0; my $cid = $form->{cid} || 0; # root id my $d2_seen = $form->{d2_seen}; - my $placeholders = $form->{placeholders}; - my @placeholders; + my $placeholders = [ grep { defined && /^\d+$/ } ($form->{_multi}{placeholders} ? @{$form->{_multi}{placeholders}} : $form->{placeholders}) ]; $user->{state}{ajax_accesslog_op} = "ajax_comments_fetch"; -#use Data::Dumper; print STDERR Dumper [ $cids, $id, $cid, $d2_seen ]; +#use Data::Dumper; print STDERR Dumper [ $form, $cids, $id, $cid, $d2_seen ]; # XXX error? return unless $id && (@$cids || $d2_seen); @@ -439,17 +448,16 @@ #delete $comments->{0}; # non-comment data my %data; - if ($d2_seen || $placeholders) { + if ($d2_seen || @$placeholders) { my $special_cids; if ($d2_seen) { $special_cids = $cids = [ sort { $a <=> $b } grep { $_ && !$seen{$_} } keys %$comments ]; - } elsif ($placeholders) { - @placeholders = split /[,;]/, $placeholders; - $special_cids = [ sort { $a <=> $b } @placeholders ]; + } elsif (@$placeholders) { + $special_cids = [ sort { $a <=> $b } @$placeholders ]; if ($form->{d2_seen_ex}) { my @seen; my $lastcid = 0; - my %check = (%seen, map { $_ => 1 } @placeholders); + my %check = (%seen, map { $_ => 1 } @$placeholders); for my $cid (sort { $a <=> $b } keys(%check)) { push @seen, $lastcid ? $cid - $lastcid : $cid; $lastcid = $cid; @@ -587,9 +595,9 @@ $to_dump{eval_first} ||= ''; $to_dump{eval_first} .= "d2_seen = '$d2_seen_0'; updateMoreNum($total);"; } - if ($placeholders) { + if (@$placeholders) { $to_dump{eval_first} ||= ''; - $to_dump{eval_first} .= "placeholder_no_update = " . Data::JavaScript::Anon->anon_dump({ map { $_ => 1 } @placeholders }) . ';'; + $to_dump{eval_first} .= "placeholder_no_update = " . Data::JavaScript::Anon->anon_dump({ map { $_ => 1 } @$placeholders }) . ';'; } writeLog($id); return Data::JavaScript::Anon->anon_dump(\%to_dump); @@ -746,7 +754,7 @@ my $moddb = getObject("Slash::$constants->{m1_pluginname}"); if ($moddb) { # we hijack "tabbed" as our cid -- pudge - return $moddb->dispModCommentLog('cid', $form->{'tabbed'}, { + my $return = $moddb->dispModCommentLog('cid', $form->{'tabbed'}, { show_m2s => ($constants->{m2} ? (defined($form->{show_m2s}) ? $form->{show_m2s} @@ -756,6 +764,8 @@ need_m2_button => $constants->{m2}, title => " " }); + $return ||= getData('no modcommentlog'); + return $return; } } else { Modified: slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/admin.js =================================================================== --- slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/admin.js 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/admin.js 2008-04-06 23:11:14 UTC (rev 569) @@ -1,4 +1,4 @@ -// $Id: admin.js,v 1.48 2008/03/18 16:28:44 tvroom Exp $ +// $Id: admin.js,v 1.49 2008/03/27 20:12:17 tvroom Exp $ function um_ajax(the_behaviors, the_events) { var params = {}; @@ -200,7 +200,7 @@ if(use_fh_interval) { interval = getFirehoseUpdateInterval(); } - setTimeout("console_update(" + use_fh_interval + "," + fh_is_timed_out +")", interval); + setTimeout("console_update(" + use_fh_interval + "," + fh_is_timed_out +")", interval * 2); } function firehose_usage() { Modified: slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/common.js =================================================================== --- slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/common.js 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/common.js 2008-04-06 23:11:14 UTC (rev 569) @@ -1,10 +1,46 @@ // _*_ Mode: JavaScript; tab-width: 8; indent-tabs-mode: true _*_ -// $Id: common.js,v 1.183 2008/03/18 16:28:44 tvroom Exp $ +// $Id: common.js,v 1.194 2008/04/03 19:14:51 tvroom Exp $ function $dom( id ) { return document.getElementById(id); } +jQuery.fn.extend({ + + mapClass: function( map ) { + map['?'] = map['?'] || []; + return this.each(function() { + var unique = {}; + var cl = []; + $.each($.map(this.className.split(/\s+/), function(k){ + return k in map ? map[k] : ('*' in map ? map['*'] : k) + }).concat(map['+']), function(i, k) { + if ( k && !(k in unique) ) { + unique[k] = true; + cl.push(k); + } + }); + this.className = (cl.length ? cl : map['?']).join(' '); + }); + }, + + setClass: function( c1 ) { + return this.each(function() { + this.className = c1 + }); + }, + + toggleClasses: function( c1, c2, force ) { + var map = { '?': force }; + map[c1]=c2; + map[c2]=c1; + return this.mapClass(map); + } + +}); + +var reskey_static = ''; + // global settings, but a firehose might use a local settings object instead var firehose_settings = {}; firehose_settings.startdate = ''; @@ -18,8 +54,10 @@ firehose_settings.is_embedded = 0; firehose_settings.not_id = 0; firehose_settings.section = 0; + firehose_settings.more_num = 0; // Settings to port out of settings object + firehose_item_count = 0; firehose_updates = Array(0); firehose_updates_size = 0; firehose_ordered = Array(0); @@ -78,23 +116,11 @@ } function createPopupButtons() { - var buttons = ""; - if (arguments.length > 0) { - buttons = ''; - } - for (var i=0; i" + arguments[i] + ""; - } - - buttons = buttons + ""; - return buttons; + return '' + $.makeArray(arguments).join('') + ''; } function closePopup(id, refresh) { - var el = $dom(id); - if (el) { - el.parentNode.removeChild(el); - } + $('#'+id).remove(); if (refresh) { window.location.reload(); } @@ -134,87 +160,44 @@ } function getXYForId(id, addWidth, addHeight) { - var div = $dom(id); - var offset = jQuery(div).offset(); - var xy = [ offset.left, offset.top ]; - if (addWidth) { - xy[0] = xy[0] + div.offsetWidth; - } - if (addHeight) { - xy[1] = xy[1] + div.offsetHeight; - } - return xy; + var div = $('#'+id); + var offset = div.offset(); + if (addWidth) offset.left += div.attr('offsetWidth'); + if (addHeight) offset.top += div.attr('offsetHeight'); + return [ offset.left, offset.top ]; } function firehose_toggle_advpref() { - var obj = $dom('fh_advprefs'); - if (obj.className == 'hide') { - obj.className = ""; - } else { - obj.className = "hide"; - } + $('#fh_advprefs').toggleClass('hide'); } function firehose_open_prefs() { - var obj = $dom('fh_advprefs'); - obj.className = ""; + $('#fh_advprefs').removeClass(); } -function toggleId(id, first, second) { - var obj = $dom(id); - if (obj.className == first) { - obj.className = second; - } else if (obj.className == second) { - obj.className = first; - } else { - obj.className = first; - } +function toggleId(id, c1, c2) { + $('#'+id).toggleClasses(c1, c2, c1); } function toggleIntro(id, toggleid) { - var obj = $dom(id); - var toggle = $dom(toggleid); - if (obj.className == 'introhide') { - obj.className = "intro" - toggle.innerHTML = "[-]"; - toggle.className = "expanded"; - } else { - obj.className = "introhide" - toggle.innerHTML = "[+]"; - toggle.className = "condensed"; + var new_class = 'condensed'; + var new_html = '[+]'; + if ( $('#'+id).toggleClasses('introhide', 'intro').hasClass('intro') ) { + new_class = 'expanded'; + new_html = '[-]'; } + $('#'+toggleid).setClass(new_class).html(new_html); } function tagsToggleStoryDiv(id, is_admin, type) { - var bodyid = 'toggletags-body-' + id; - var tagsbody = $dom(bodyid); - if (tagsbody.className == 'tagshide') { - tagsShowBody(id, is_admin, '', type); - } else { - tagsHideBody(id); - } + ($('#toggletags-body-'+id).hasClass('tagshide') ? tagsShowBody : tagsHideBody)(id, is_admin, '', type); } function tagsHideBody(id) { - // Make the body of the tagbox vanish - var tagsbodyid = 'toggletags-body-' + id; - var tagsbody = $dom(tagsbodyid); - tagsbody.className = "tagshide" - - // Make the title of the tagbox change back to regular - var titleid = 'tagbox-title-' + id; - var title = $dom(titleid); - title.className = "tagtitleclosed"; - - // Make the tagbox change back to regular. - var tagboxid = 'tagbox-' + id; - var tagbox = $dom(tagboxid); - tagbox.className = "tags"; - - // Toggle the button back. - var tagsbuttonid = 'toggletags-button-' + id; - var tagsbutton = $dom(tagsbuttonid); - tagsbutton.innerHTML = "[+]"; + $('#toggletags-body-'+id).setClass('tagshide'); // Make the body of the tagbox vanish + $('#tagbox-title-'+id).setClass('tagtitleclosed'); // Make the title of the tagbox change back to regular + $('#tagbox-'+id).setClass('tags'); // Make the tagbox change back to regular. + $('#toggletags-button-'+id).html('[+]'); // Toggle the button back. } function tagsShowBody(id, is_admin, newtagspreloadtext, type) { @@ -229,37 +212,19 @@ } //alert("Tags show body / Type: " + type ); + $('#toggletags-button-'+id).html("[-]"); // Toggle the button to show the click was received + $('#tagbox-'+id).setClass("tags"); // Make the tagbox change to the slashbox class + $('#tagbox-title-'+id).setClass("tagtitleopen"); // Make the title of the tagbox change to white-on-green + $('#toggletags-body-'+id).setClass("tagbody"); // Make the body of the tagbox visible - // Toggle the button to show the click was received - var tagsbuttonid = 'toggletags-button-' + id; - var tagsbutton = $dom(tagsbuttonid); - tagsbutton.innerHTML = "[-]"; - - // Make the tagbox change to the slashbox class - var tagboxid = 'tagbox-' + id; - var tagbox = $dom(tagboxid); - tagbox.className = "tags"; - - // Make the title of the tagbox change to white-on-green - var titleid = 'tagbox-title-' + id; - var title = $dom(titleid); - title.className = "tagtitleopen"; - - // Make the body of the tagbox visible - var tagsbodyid = 'toggletags-body-' + id; - var tagsbody = $dom(tagsbodyid); - - tagsbody.className = "tagbody"; - // If the tags-user div hasn't been filled, fill it. - var tagsuserid = 'tags-user-' + id; - var tagsuser = $dom(tagsuserid); - if (tagsuser.innerHTML == "") { + var tagsuser = $('#tags-user-' + id); + if (tagsuser.html() == "") { // The tags-user-123 div is empty, and needs to be // filled with the tags this user has already // specified for this story, and a reskey to allow // the user to enter more tags. - tagsuser.innerHTML = "Retrieving..."; + tagsuser.html("Retrieving..."); var params = {}; if (type == "stories") { params['op'] = 'tags_get_user_story'; @@ -275,12 +240,10 @@ params['newtagspreloadtext'] = newtagspreloadtext; var handlers = { onComplete: function() { - var textid = 'newtags-' + id; - var input = $dom(textid); - input.focus(); + $dom('newtags-'+id).focus(); } } - ajax_update(params, tagsuserid, handlers); + ajax_update(params, 'tags-user-' + id, handlers); //alert('after ajax_update ' + tagsuserid); // Also fill the admin div. Note that if the user @@ -311,9 +274,8 @@ // that we append some text to the user text. // We can't do that by passing it in, so do it // manually now. - var textinputid = 'newtags-' + id; - var textinput = $dom(textinputid); - textinput.value = textinput.value + ' ' + newtagspreloadtext; + var textinput = $dom('newtags-'+id); + textinput.value += ' ' + newtagspreloadtext; textinput.focus(); } } @@ -391,7 +353,7 @@ params['type'] = type; if ( fh_is_admin && ("_#)^*".indexOf(tag[0]) != -1) ) { params['op'] = 'tags_admin_commands'; - params['reskey'] = $dom('admin_commands-reskey-' + id).value; + params['reskey'] = $('#admin_commands-reskey-' + id).val(); params['command'] = tag; } else { params['op'] = 'tags_create_tag'; @@ -405,68 +367,53 @@ } function tagsCreateForStory(id) { - var toggletags_message_id = 'toggletags-message-' + id; - var toggletags_message_el = $dom(toggletags_message_id); - toggletags_message_el.innerHTML = 'Saving tags...'; + var status = $('#toggletags-message-'+id).html('Saving tags...'); - var params = {}; - params['op'] = 'tags_create_for_story'; - params['sidenc'] = id; - var newtagsel = $dom('newtags-' + id); - params['tags'] = newtagsel.value; - var reskeyel = $dom('newtags-reskey-' + id); - params['reskey'] = reskeyel.value; + ajax_update({ + op: 'tags_create_for_story', + sidenc: id, + tags: $('#newtags-'+id).val(), + reskey: $('#newtags-reskey-'+id).val() + }, 'tags-user-' + id); - ajax_update(params, 'tags-user-' + id); - // XXX How to determine failure here? - toggletags_message_el.innerHTML = 'Tags saved.'; + status.html('Tags saved.'); } function tagsCreateForUrl(id) { - var toggletags_message_id = 'toggletags-message-' + id; - var toggletags_message_el = $dom(toggletags_message_id); - toggletags_message_el.innerHTML = 'Saving tags...'; + var status = $('#toggletags-message-'+id).html('Saving tags...'); - var params = {}; - params['op'] = 'tags_create_for_url'; - params['id'] = id; - var newtagsel = $dom('newtags-' + id); - params['tags'] = newtagsel.value; - var reskeyel = $dom('newtags-reskey-' + id); - params['reskey'] = reskeyel.value; + ajax_update({ + op: 'tags_create_for_url', + id: id, + tags: $('#newtags-'+id).val(), + reskey: $('#newtags-reskey-'+id).val() + }, 'tags-user-' + id); - ajax_update(params, 'tags-user-' + id); - // XXX How to determine failure here? - toggletags_message_el.innerHTML = 'Tags saved.'; + status.html('Tags saved.'); } //Firehose functions begin function setOneTopTagForFirehose(id, newtag) { - var params = {}; - params['op'] = 'firehose_update_one_tag'; - params['id'] = id; - params['tags'] = newtag; - // params['reskey'] = reskeyel.value; - ajax_update(params, ''); + ajax_update({ + op: 'firehose_update_one_tag', + id: id, + tags: newtag + }); } function tagsCreateForFirehose(id) { - var toggletags_message_id = 'toggletags-message-' + id; - var toggletags_message_el = $dom(toggletags_message_id); - toggletags_message_el.innerHTML = 'Saving tags...'; + var status = $('#toggletags-message-'+id).html('Saving tags...'); - var params = {}; - params['op'] = 'tags_create_for_firehose'; - params['id'] = id; - var newtagsel = $dom('newtags-' + id); - params['tags'] = newtagsel.value; - var reskeyel = $dom('newtags-reskey-' + id); - params['reskey'] = reskeyel.value; + ajax_update({ + op: 'tags_create_for_firehose', + id: id, + tags: $('#newtags-'+id).val(), + reskey: $('#newtags-reskey-'+id).val() + }, 'tags-user-'+id); - ajax_update(params, 'tags-user-' + id); - toggletags_message_el.innerHTML = 'Tags saved.'; + status.html('Tags saved.'); } function toggle_firehose_body(id, is_admin) { @@ -487,11 +434,7 @@ } }; params['reskey'] = reskey_static; - if (is_admin) { - ajax_update(params, 'fhbody-'+id, handlers); - } else { - ajax_update(params, 'fhbody-'+id); - } + ajax_update(params, 'fhbody-'+id, is_admin ? handlers : null); fhbody.className = "body"; fh.className = "article" + usertype; if (is_admin) @@ -510,12 +453,7 @@ } function toggleFirehoseTagbox(id) { - var fhtb = $dom('fhtagbox-'+id); - if (fhtb.className == "hide") { - fhtb.className = "tagbox"; - } else { - fhtb.className = "hide"; - } + $('#fhtagbox-'+id).toggleClasses('tagbox', 'hide'); } function firehose_set_options(name, value) { @@ -555,14 +493,7 @@ } if (classname) { - var els = document.getElementsByClassName(classname, $dom('firehoselist')); - var classval = classname; - if (value) { - classval = classval + " hide"; - } - for (i = 0; i< els.length; i++) { - els[i].className = classval; - } + $('#firehoselist .'+classname).setClass(classname + value ? ' hide' : ''); } } @@ -573,6 +504,7 @@ } } firehose_settings.page = 0; + firehose_settings.more_num = 0; } if (name != "color") { for (i=0; i< pairs.length; i++) { @@ -628,20 +560,19 @@ firehose_settings.startdate = value; firehose_settings.duration = 1; firehose_settings.page = 0; + firehose_settings.more_num = 0; var issuedate = firehose_settings.issue.substr(5,2) + "/" + firehose_settings.issue.substr(8,2) + "/" + firehose_settings.issue.substr(10,2); - if ($dom('fhcalendar')) { - $dom('fhcalendar')._widget.setDate(issuedate, "day"); - } - if ($dom('fhcalendar_pag')) { - $dom('fhcalendar_pag')._widget.setDate(issuedate, "day"); - } + $('#fhcalendar, #fhcalendar_pag').each(function(){ + this._widget.setDate(issuedate, "day"); + }); } if (name == "color") { firehose_settings.color = value; } if (name == "pagesize") { firehose_settings.page = 0; + firehose_settings.more_num = 0; } } @@ -669,14 +600,7 @@ } function firehose_remove_all_items() { - var fhl = $dom('firehoselist'); - var children = fhl.childNodes; - for (var i = children.length -1 ; i >= 0; i--) { - var el = children[i]; - if (el.id) { - el.parentNode.removeChild(el); - } - } + $('#firehoselist').children().remove(); } @@ -684,24 +608,15 @@ if (!check_logged_in()) return; setFirehoseAction(); - var params = {}; - var handlers = { - onComplete: json_handler - }; - params['op'] = 'firehose_up_down'; - params['id'] = id; - params['reskey'] = reskey_static; - params['dir'] = dir; - var updown = $dom('updown-' + id); - ajax_update(params, '', handlers); - if (updown) { - if (dir == "+") { - updown.className = "votedup"; - } else if (dir == "-") { - updown.className = "voteddown"; - } - } + ajax_update({ + op: 'firehose_up_down', + id: id, + reskey: reskey_static, + dir: dir + }, '', { onComplete: json_handler }); + $('#updown-'+id).setClass(dir=='+' ? 'votedup' : 'voteddown'); + if (dir == "-" && fh_is_admin) { firehose_collapse_entry(id); } @@ -709,15 +624,12 @@ function firehose_remove_tab(tabid) { setFirehoseAction(); - var params = {}; - var handlers = { - onComplete: json_handler - }; - params['op'] = 'firehose_remove_tab'; - params['tabid'] = tabid; - params['reskey'] = reskey_static; - params['section'] = firehose_settings.section; - ajax_update(params, '', handlers); + ajax_update({ + op: 'firehose_remove_tab', + tabid: tabid, + reskey: reskey_static, + section: firehose_settings.section + }, '', { onComplete: json_handler }); } @@ -733,12 +645,12 @@ url: request_url || '/ajax.pl', data: request_params, type: 'POST', - contentType: 'application/x-www-form-urlencoded', + contentType: 'application/x-www-form-urlencoded' }; if ( id ) { opts['success'] = function(html){ - jQuery('#'+id).html(html); + $('#'+id).html(html); } } @@ -782,37 +694,34 @@ if (response.html) { for (el in response.html) { - if ($dom(el)) - $dom(el).innerHTML = response.html[el]; + $('#'+el).html(response.html[el]); } } if (response.value) { for (el in response.value) { - if ($dom(el)) - $dom(el).value = response.value[el]; + $('#'+el).val(response.value[el]); } } if (response.html_append) { for (el in response.html_append) { - if ($dom(el)) - $dom(el).innerHTML = $dom(el).innerHTML + response.html_append[el]; + $('#'+el).each(function(){ + this.innerHTML += response.html_append[el]; + }); } } if (response.html_append_substr) { for (el in response.html_append_substr) { - if ($dom(el)) { - var this_html = $dom(el).innerHTML; - var i = $dom(el).innerHTML.search(/ ?<\/span>[\s\S]*$/i); - if (i == -1) { - $dom(el).innerHTML += response.html_append_substr[el]; - } else { - $dom(el).innerHTML = $dom(el).innerHTML.substr(0, i) + - response.html_append_substr[el]; - } + var found = $('#'+el); + if (found.size()) { + var this_html = found.html(); + var pos = this_html.search(/ ?<\/span>[\s\S]*$/i); + if ( pos != -1 ) + this_html = this_html.substr(0, pos); + found.html(this_html + response.html_append_substr[el]); } } } @@ -833,14 +742,14 @@ var fh = 'firehose-' + el[1]; var wait_interval = 800; if(el[0] == "add") { - if (firehose_before[el[1]] && jQuery('#firehose-' + firehose_before[el[1]]).size()) { - jQuery('#firehose-' + firehose_before[el[1]]).after(el[2]); - } else if (firehose_after[el[1]] && jQuery('#firehose-' + firehose_after[el[1]]).size()) { - jQuery('#firehose-' + firehose_after[el[1]]).before(el[2]); + if (firehose_before[el[1]] && $('#firehose-' + firehose_before[el[1]]).size()) { + $('#firehose-' + firehose_before[el[1]]).after(el[2]); + } else if (firehose_after[el[1]] && $('#firehose-' + firehose_after[el[1]]).size()) { + $('#firehose-' + firehose_after[el[1]]).before(el[2]); } else if (insert_new_at == "bottom") { - jQuery('#firehoselist').append(el[2]); + $('#firehoselist').append(el[2]); } else { - jQuery('#firehoselist').prepend(el[2]); + $('#firehoselist').prepend(el[2]); } var toheight = 50; @@ -937,28 +846,21 @@ function firehose_reorder() { if (firehose_ordered) { - var fhlist = $dom('firehoselist'); + var fhlist = $('#firehoselist'); if (fhlist) { - var item_count = 0; - for (i = 0; i < firehose_ordered.length; i++) { - if (/^\d+$/.test(firehose_ordered[i])) { - item_count++; + firehose_item_count = firehose_ordered.length; + for (i = 0; i < firehose_ordered.length; ++i) { + if (!/^\d+$/.test(firehose_ordered[i])) { + --firehose_item_count; } - var fhel = $dom('firehose-' + firehose_ordered[i]); - if (fhlist && fhel) { - fhlist.appendChild(fhel); - } + $('#firehose-'+firehose_ordered[i]).appendTo(fhlist); if ( firehose_future[firehose_ordered[i]] ) { - if ($dom("ttype-" + firehose_ordered[i])) { - $dom("ttype-" + firehose_ordered[i]).className = "future"; - } + $('#ttype-'+firehose_ordered[i]).setClass('future'); } else { - if ($dom("ttype-" + firehose_ordered[i]) && $dom("ttype-" + firehose_ordered[i]).className == "future") { - $dom("ttype-" + firehose_ordered[i]).className = "story"; - } + $('#ttype-'+firehose_ordered[i]+'.future').setClass('story'); } } - document.title = "[% sitename %] - " + (console_updating ? "Console" : "Firehose") + " (" + item_count + ")"; + document.title = "[% sitename %] - " + (console_updating ? "Console" : "Firehose") + " (" + firehose_item_count + ")"; } } @@ -973,9 +875,7 @@ function firehose_get_updates_handler(transport) { - if ($dom('busy')) { - $dom('busy').className = "hide"; - } + $('#busy').setClass('hide'); var response = eval_response(transport); var processed = 0; firehose_removals = response.update_data.removals; @@ -1005,24 +905,9 @@ } function firehose_get_item_idstring() { - var fhl = $dom('firehoselist'); - var str = ""; - var children; - if (fhl) { - var id; - children = fhl.childNodes; - if (children) { - for (var i = 0; i < children.length; i++) { - if (children[i].id) { - id = children[i].id; - id = id.replace(/^firehose-/g, ""); - id = id.replace(/^\s+|\s+$/g, ""); - str = str + id + ","; - } - } - } - } - return str; + return $('#firehoselist > [id]').map(function(){ + return this.id.replace(/firehose-(\S+)/, '$1'); + }).get().join(','); } @@ -1039,26 +924,20 @@ while(id = fh_update_timerids.pop()) { clearTimeout(id) }; } fh_is_updating = 1 - var params = {}; - var handlers = { - onComplete: firehose_get_updates_handler + var params = { + op: 'firehose_get_updates', + ids: firehose_get_item_idstring(), + updatetime: update_time, + fh_pageval: firehose_settings.pageval, + embed: firehose_settings.is_embedded }; - params['op'] = 'firehose_get_updates'; - params['ids'] = firehose_get_item_idstring(); - params['updatetime'] = update_time; for (i in firehose_settings) { params[i] = firehose_settings[i]; } - if ( firehose_settings.is_embedded ) { - params['embed'] = 1; - } - params['fh_pageval'] = firehose_settings.pageval; - if ($dom('busy')) { - $dom('busy').className = ""; - } - ajax_update(params, '', handlers); + $('#busy').removeClass(); + ajax_update(params, '', { onComplete: firehose_get_updates_handler }); } @@ -1100,8 +979,7 @@ var secs = getSecsSinceLastFirehoseAction(); if (secs > inactivity_timeout) { fh_is_timed_out = 1; - if ($dom('message_area')) - $dom('message_area').innerHTML = "Automatic updates have been slowed due to inactivity"; + $('#message_area').html("Automatic updates have been slowed due to inactivity") //firehose_pause(); } } @@ -1110,36 +988,21 @@ fh_play = 1; setFirehoseAction(); firehose_set_options('pause', '0'); - var pausepanel = $dom('pauseorplay'); - if ($dom('message_area')) - $dom('message_area').innerHTML = ""; - if (pausepanel) { - pausepanel.innerHTML = "Updated"; - } - var pause = $dom('pause'); - - var play_div = $dom('play'); - if (play_div) { - play_div.className = "hide"; - } - if (pause) { - pause.className = "show"; - } + $('#message_area').html(''); + $('#pauseorplay').html('Updated'); + $('#play').setClass('hide'); + $('#pause').setClass('show'); } function is_firehose_playing() { - return YAHOO.util.Dom.hasClass('play', 'hide'); + return fh_play==1; } function firehose_pause() { fh_play = 0; - var pause = $dom('pause'); - var play_div = $dom('play'); - pause.className = "hide"; - play_div.className = "show"; - if ($dom('pauseorplay')) { - $dom('pauseorplay').innerHTML = "Paused"; - } + $('#pause').setClass('hide'); + $('#play').setClass('show'); + $('#pauseorplay').html('Paused'); firehose_set_options('pause', '1'); } @@ -1148,14 +1011,8 @@ } function firehose_collapse_entry(id) { - var fhbody = $dom('fhbody-'+id); - var fh = $dom('firehose-'+id); - if (fhbody && fhbody.className == "body") { - fhbody.className = "hide"; - } - if (fh) { - fh.className = "briefarticle"; - } + $('#fhbody-'+id+'.body').setClass('hide'); + $('#firehose-'+id).setClass('briefarticle'); tagsHideBody(id) } @@ -1275,38 +1132,25 @@ } function logToDiv(id, message) { - var div = $dom(id); - if (div) { - div.innerHTML = div.innerHTML + message + "
    "; - } + $('#'+id).append(message + '
    '); } function firehose_open_tab(id) { - var tf = $dom('tab-form-'+id); - var tt = $dom('tab-text-'+id); - var ti = $dom('tab-input-'+id); - tf.className=""; - ti.focus(); - tt.className="hide"; + $('#tab-form-'+id).removeClass(); + $dom('tab-input-'+id).focus(); + $('#tab-text-'+id).setClass('hide'); } function firehose_save_tab(id) { - var tf = $dom('tab-form-'+id); - var tt = $dom('tab-text-'+id); - var ti = $dom('tab-input-'+id); - var params = {}; - var handlers = { - onComplete: json_handler - }; - params['op'] = 'firehose_save_tab'; - params['tabname'] = ti.value; - params['section'] = firehose_settings.section; - - params['tabid'] = id; - ajax_update(params, '', handlers); - tf.className = "hide"; - tt.className = ""; + ajax_update({ + op: 'firehose_save_tab', + tabname: $('#tab-input-'+id).val(), + section: firehose_settings.section, + tabid: id + }, '', { onComplete: json_handler }); + $('#tab-form-'+id).setClass('hide'); + $('#tab-text-'+id).removeClass(); } @@ -1424,6 +1268,8 @@ } function getModalPrefs(section, title, tabbed) { + if (!reskey_static) + return show_login_box(); document.getElementById('preference_title').innerHTML = title; var params = {}; params['op'] = 'getModalPrefs'; @@ -1464,28 +1310,17 @@ } function ajaxSaveSlashboxes() { - var wrapper = document.getElementById('slashboxes'); - var titles = YAHOO.util.Dom.getElementsByClassName('title', 'div', wrapper); - var sep = ""; - var all = ""; - for ( i=0; i #'+id).remove().size() ) { ajaxSaveSlashboxes(); } } @@ -1517,7 +1352,7 @@ } function admin_signoff(stoid, type, id) { - var params = []; + var params = {}; params['op'] = 'admin_signoff'; params['stoid'] = stoid; params['reskey'] = reskey_static; @@ -1530,7 +1365,6 @@ function scrollWindowToFirehose(fhid) { var firehose_y = getOffsetTop($('firehose-' + fhid)); - console.log(firehose_y); scroll(viewWindowLeft(), firehose_y); } @@ -1621,6 +1455,7 @@ var pos = firehose_get_pos_of_id(cur); if (pos < (firehose_ordered.length - 1)) { pos++; + } else { } firehose_set_cur(firehose_ordered[pos]); scrollWindowToFirehose(firehose_cur); @@ -1637,4 +1472,14 @@ } +function firehose_more() { + var increment_by = 10; + firehose_settings.more_num = firehose_settings.more_num + increment_by; + + if (((firehose_item_count + increment_by) >= 200) && !fh_is_admin) { + $('#firehose_more').hide(); + } + firehose_set_options('more_num', firehose_settings.more_num); +} + Modified: slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/nodnix.js =================================================================== --- slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/nodnix.js 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/nodnix.js 2008-04-06 23:11:14 UTC (rev 569) @@ -1,5 +1,5 @@ // _*_ Mode: JavaScript; tab-width: 8; indent-tabs-mode: true _*_ -// $Id: nodnix.js,v 1.17 2008/03/14 15:48:06 scc Exp $ +// $Id: nodnix.js,v 1.20 2008/03/28 22:04:32 pudge Exp $ var nod_completer = null; var nix_completer = null; @@ -17,16 +17,17 @@ } function get_predefined_nodnix_tags() { - var tags = []; - var query = _get_nodnix('input').getAttribute("updown"); - var listEl = query=="+" ? document.getElementById('static-nod-completions') - : document.getElementById('static-nix-completions'); - if ( listEl ) { - var itemEls = listEl.getElementsByTagName('li'); - for ( var i=0; i! x
  • '; function handle_completer_key( type, args ) { - var key = args[0]; - var event = args[1]; - var stay_open = false; - switch ( key ) { - case YAHOO.util.KeyListener.KEY.ESCAPE: - hide_nodnix_menu(); - break; - case YAHOO.util.KeyListener.KEY.SPACE: - YAHOO.util.Event.stopEvent(event); - stay_open = true; - // fall through - case YAHOO.util.KeyListener.KEY.ENTER: - handle_nodnix_select("", [null, null, _get_nodnix('input').value], stay_open); - break; - } + var key = args[0]; + var event = args[1]; + var stay_open = false; + switch ( key ) { + case YAHOO.util.KeyListener.KEY.ESCAPE: + hide_nodnix_menu(); + break; + case YAHOO.util.KeyListener.KEY.SPACE: + YAHOO.util.Event.stopEvent(event); + stay_open = true; + // fall through + case YAHOO.util.KeyListener.KEY.ENTER: + handle_nodnix_select("", [null, null, _get_nodnix('input').value], stay_open); + break; + } } Modified: slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/sd_autocomplete.js =================================================================== --- slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/sd_autocomplete.js 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/sd_autocomplete.js 2008-04-06 23:11:14 UTC (rev 569) @@ -1,69 +1,68 @@ // _*_ Mode: JavaScript; tab-width: 8; indent-tabs-mode: true _*_ -// $Id: sd_autocomplete.js,v 1.50 2008/03/11 16:38:18 scc Exp $ +// $Id: sd_autocomplete.js,v 1.52 2008/03/28 20:53:43 pudge Exp $ YAHOO.namespace("slashdot"); -YAHOO.slashdot.DS_JSArray = function(aData, oConfigs) - { - if ( typeof oConfigs == "object" ) - for ( var sConfig in oConfigs ) - this[sConfig] = oConfigs[sConfig]; +YAHOO.slashdot.DS_JSArray = function(aData, oConfigs) { + if ( typeof oConfigs == "object" ) + for ( var sConfig in oConfigs ) + this[sConfig] = oConfigs[sConfig]; - if ( !aData || (aData.constructor != Array) ) - return + if ( !aData || (aData.constructor != Array) ) + return - this.data = aData; - this._init(); - } + this.data = aData; + this._init(); +} YAHOO.slashdot.DS_JSArray.prototype = new YAHOO.widget.DataSource(); YAHOO.slashdot.DS_JSArray.prototype.data = null; YAHOO.slashdot.DS_JSArray.prototype.doQuery = function(oCallbackFn, sQuery, oParent) { - var aData = this.data; // the array - var aResults = []; // container for results - var bMatchFound = false; - var bMatchContains = this.queryMatchContains; + var aData = this.data; // the array + var aResults = []; // container for results + var bMatchFound = false; + var bMatchContains = this.queryMatchContains; - if(sQuery && !this.queryMatchCase) { - sQuery = sQuery.toLowerCase(); - } + if(sQuery && !this.queryMatchCase) { + sQuery = sQuery.toLowerCase(); + } - // Loop through each element of the array... - // which can be a string or an array of strings - for(var i = aData.length-1; i >= 0; i--) { - var aDataset = []; + // Loop through each element of the array... + // which can be a string or an array of strings + for(var i = aData.length-1; i >= 0; i--) { + var aDataset = []; - if(aData[i]) { - if(aData[i].constructor == String) { - aDataset[0] = aData[i]; - } - else if(aData[i].constructor == Array) { - aDataset = aData[i]; - } - } + if(aData[i]) { + if(aData[i].constructor == String) { + aDataset[0] = aData[i]; + } + else if(aData[i].constructor == Array) { + aDataset = aData[i]; + } + } - if(aDataset[0] && (aDataset[0].constructor == String)) { - var sKeyIndex = 0; - if (sQuery) { - sKeyIndex = (this.queryMatchCase) ? - encodeURIComponent(aDataset[0]).indexOf(sQuery): - encodeURIComponent(aDataset[0]).toLowerCase().indexOf(sQuery); - } + if(aDataset[0] && (aDataset[0].constructor == String)) { + var sKeyIndex = 0; + if (sQuery) { + sKeyIndex = (this.queryMatchCase) ? + encodeURIComponent(aDataset[0]).indexOf(sQuery): + encodeURIComponent(aDataset[0]).toLowerCase().indexOf(sQuery); + } - // A STARTSWITH match is when the query is found at the beginning of the key string... - if((!bMatchContains && (sKeyIndex === 0)) || - // A CONTAINS match is when the query is found anywhere within the key string... - (bMatchContains && (sKeyIndex > -1))) { - // Stash a match into aResults[]. - aResults.unshift(aDataset); - } - } - } + // A STARTSWITH match is when the query is found at the beginning of the key string... + if((!bMatchContains && (sKeyIndex === 0)) || + // A CONTAINS match is when the query is found anywhere within the key string... + (bMatchContains && (sKeyIndex > -1))) { + // Stash a match into aResults[]. + aResults.unshift(aDataset); + } + } + } - this.getResultsEvent.fire(this, oParent, sQuery, aResults); - oCallbackFn(sQuery, aResults, oParent); + this.getResultsEvent.fire(this, oParent, sQuery, aResults); + oCallbackFn(sQuery, aResults, oParent); }; @@ -282,242 +281,219 @@ "neverdisplay" ]; - var feedbackDS = new YAHOO.slashdot.DS_JSArray(YAHOO.slashdot.feedbackTags); - var actionsDS = new YAHOO.slashdot.DS_JSArray(YAHOO.slashdot.actionTags); - var sectionsDS = new YAHOO.slashdot.DS_JSArray(YAHOO.slashdot.sectionTags); - var topicsDS = new YAHOO.slashdot.DS_JSArray(YAHOO.slashdot.topicTags); - var fhitemDS = new YAHOO.slashdot.DS_JSArray(YAHOO.slashdot.fhitemOpts); - var storyDS = new YAHOO.slashdot.DS_JSArray(YAHOO.slashdot.storyOpts); +var feedbackDS = new YAHOO.slashdot.DS_JSArray(YAHOO.slashdot.feedbackTags); +var actionsDS = new YAHOO.slashdot.DS_JSArray(YAHOO.slashdot.actionTags); +var sectionsDS = new YAHOO.slashdot.DS_JSArray(YAHOO.slashdot.sectionTags); +var topicsDS = new YAHOO.slashdot.DS_JSArray(YAHOO.slashdot.topicTags); +var fhitemDS = new YAHOO.slashdot.DS_JSArray(YAHOO.slashdot.fhitemOpts); +var storyDS = new YAHOO.slashdot.DS_JSArray(YAHOO.slashdot.storyOpts); - var tagsDS = new YAHOO.widget.DS_XHR("./ajax.pl", ["\n", "\t"]); - // tagsDS.maxCacheEntries = 0; // turn off local cacheing, because Jamie says the query is fast - tagsDS.queryMatchSubset = false; - tagsDS.responseType = YAHOO.widget.DS_XHR.TYPE_FLAT; - tagsDS.scriptQueryParam = "prefix"; - tagsDS.scriptQueryAppend = "op=tags_list_tagnames"; - tagsDS.queryMethod = "POST"; +var tagsDS = new YAHOO.widget.DS_XHR("./ajax.pl", ["\n", "\t"]); +// tagsDS.maxCacheEntries = 0; // turn off local cacheing, because Jamie says the query is fast +tagsDS.queryMatchSubset = false; +tagsDS.responseType = YAHOO.widget.DS_XHR.TYPE_FLAT; +tagsDS.scriptQueryParam = "prefix"; +tagsDS.scriptQueryAppend = "op=tags_list_tagnames"; +tagsDS.queryMethod = "POST"; - var fhtabsDS = new YAHOO.widget.DS_XHR("./ajax.pl", ["\n", "\t"]); - fhtabsDS.queryMatchSubset = false; - fhtabsDS.responseType = YAHOO.widget.DS_XHR.TYPE_FLAT; - fhtabsDS.scriptQueryParam = "prefix"; - fhtabsDS.scriptQueryAppend = "op=firehose_list_tabs"; - fhtabsDS.queryMethod = "POST"; +var fhtabsDS = new YAHOO.widget.DS_XHR("./ajax.pl", ["\n", "\t"]); +fhtabsDS.queryMatchSubset = false; +fhtabsDS.responseType = YAHOO.widget.DS_XHR.TYPE_FLAT; +fhtabsDS.scriptQueryParam = "prefix"; +fhtabsDS.scriptQueryAppend = "op=firehose_list_tabs"; +fhtabsDS.queryMethod = "POST"; YAHOO.slashdot.dataSources = [tagsDS, actionsDS, sectionsDS, topicsDS, feedbackDS, storyDS, fhitemDS, fhtabsDS ]; -YAHOO.slashdot.AutoCompleteWidget = function() - { - this._widget = document.getElementById("ac-select-widget"); - this._spareInput = document.getElementById("ac-select-input"); +YAHOO.slashdot.AutoCompleteWidget = function() { + this._widget = document.getElementById("ac-select-widget"); + this._spareInput = document.getElementById("ac-select-input"); - this._sourceEl = null; - this._denyNextAttachTo = null; + this._sourceEl = null; + this._denyNextAttachTo = null; - YAHOO.util.Event.addListener(document.body, "click", this._onSdClick, this, true); - // add body/window blur to detect changing windows? - } + YAHOO.util.Event.addListener(document.body, "click", this._onSdClick, this, true); + // add body/window blur to detect changing windows? +} -YAHOO.slashdot.AutoCompleteWidget.prototype._textField = function() - { - if ( this._sourceEl==null || this._sourceEl.type=='text' || this._sourceEl.type=='textarea' ) - return this._sourceEl; +YAHOO.slashdot.AutoCompleteWidget.prototype._textField = function() { + if ( this._sourceEl==null || this._sourceEl.type=='text' || this._sourceEl.type=='textarea' ) + return this._sourceEl; - return this._spareInput; - } + return this._spareInput; +} -YAHOO.slashdot.AutoCompleteWidget.prototype._needsSpareInput = function() - { - // return this._textField() == this._spareInput; - return this._sourceEl && (this._sourceEl.type != "text") && (this._sourceEl.type != "textarea"); - } +YAHOO.slashdot.AutoCompleteWidget.prototype._needsSpareInput = function() { + // return this._textField() == this._spareInput; + return this._sourceEl && (this._sourceEl.type != "text") && (this._sourceEl.type != "textarea"); +} -YAHOO.slashdot.AutoCompleteWidget.prototype._newCompleter = function( tagDomain ) - { - var c = null; - if ( this._needsSpareInput() ) - { - c = new YAHOO.widget.AutoComplete("ac-select-input", "ac-choices", YAHOO.slashdot.dataSources[tagDomain]); - c.minQueryLength = 0; +YAHOO.slashdot.AutoCompleteWidget.prototype._newCompleter = function( tagDomain ) { + var c = null; + if ( this._needsSpareInput() ) { + c = new YAHOO.widget.AutoComplete("ac-select-input", "ac-choices", YAHOO.slashdot.dataSources[tagDomain]); + c.minQueryLength = 0; - // hack? -- override YUI's private member function so that for top tags auto-complete, right arrow means select - c._jumpSelection = function() { if ( this._oCurItem ) this._selectItem(this._oCurItem); }; - } - else - { - c = new YAHOO.widget.AutoComplete(this._sourceEl, "ac-choices", YAHOO.slashdot.dataSources[tagDomain]); - c.delimChar = " "; - c.minQueryLength = 3; - } - c.typeAhead = false; - c.forceSelection = false; - c.allowBrowserAutocomplete = false; - c.maxResultsDisplayed = 25; - c.animVert = false; + // hack? -- override YUI's private member function so that for top tags auto-complete, right arrow means select + c._jumpSelection = function() { if ( this._oCurItem ) this._selectItem(this._oCurItem); }; + } else { + c = new YAHOO.widget.AutoComplete(this._sourceEl, "ac-choices", YAHOO.slashdot.dataSources[tagDomain]); + c.delimChar = " "; + c.minQueryLength = 3; + } + c.typeAhead = false; + c.forceSelection = false; + c.allowBrowserAutocomplete = false; + c.maxResultsDisplayed = 25; + c.animVert = false; - return c; - } + return c; +} -YAHOO.slashdot.AutoCompleteWidget.prototype._show = function( obj, callbackParams, tagDomain ) - { - // onTextboxBlur should have already hidden the previous instance (if any), but if events - // come out of order, we must hide now to prevent broken listeners - if ( this._sourceEl ) - this._hide(); +YAHOO.slashdot.AutoCompleteWidget.prototype._show = function( obj, callbackParams, tagDomain ) { + // onTextboxBlur should have already hidden the previous instance (if any), but if events + // come out of order, we must hide now to prevent broken listeners + if ( this._sourceEl ) + this._hide(); - this._sourceEl = obj; + this._sourceEl = obj; - if ( this._sourceEl ) - { - this._callbackParams = callbackParams; - this._callbackParams._tagDomain = tagDomain; - this._completer = this._newCompleter(tagDomain); - - if ( typeof callbackParams.yui == "object" ) - for ( var field in callbackParams.yui ) - this._completer[field] = callbackParams.yui[field]; + if ( this._sourceEl ) { + this._callbackParams = callbackParams; + this._callbackParams._tagDomain = tagDomain; + this._completer = this._newCompleter(tagDomain); - if ( callbackParams.delayAutoHighlight ) - this._completer.autoHighlight = false; - + if ( typeof callbackParams.yui == "object" ) + for ( var field in callbackParams.yui ) + this._completer[field] = callbackParams.yui[field]; - // widget must be visible to move - YAHOO.util.Dom.removeClass(this._widget, "hidden"); - // move widget to be near the 'source' - var pos = YAHOO.util.Dom.getXY(this._sourceEl); - pos[1] += this._sourceEl.offsetHeight; - YAHOO.util.Dom.setXY(this._widget, pos); + if ( callbackParams.delayAutoHighlight ) + this._completer.autoHighlight = false; - YAHOO.util.Dom.addClass(this._sourceEl, "ac-source"); + // widget must be visible to move + YAHOO.util.Dom.removeClass(this._widget, "hidden"); + // move widget to be near the 'source' + var pos = YAHOO.util.Dom.getXY(this._sourceEl); + pos[1] += this._sourceEl.offsetHeight; + YAHOO.util.Dom.setXY(this._widget, pos); - if ( this._needsSpareInput() ) - { - YAHOO.util.Dom.removeClass(this._spareInput, "hidden"); - this._spareInput.value = ""; - this._spareInput.focus(); - this._pending_hide = setTimeout(YAHOO.slashdot.gCompleterWidget._hide, 15000); - } - else - YAHOO.util.Dom.addClass(this._spareInput, "hidden"); + YAHOO.util.Dom.addClass(this._sourceEl, "ac-source"); - this._completer.itemSelectEvent.subscribe(this._onSdItemSelectEvent, this); - this._completer.unmatchedItemSelectEvent.subscribe(this._onSdItemSelectEvent, this); - this._completer.textboxBlurEvent.subscribe(this._onSdTextboxBlurEvent, this); + if ( this._needsSpareInput() ) { + YAHOO.util.Dom.removeClass(this._spareInput, "hidden"); + this._spareInput.value = ""; + this._spareInput.focus(); + this._pending_hide = setTimeout(YAHOO.slashdot.gCompleterWidget._hide, 15000); + } else + YAHOO.util.Dom.addClass(this._spareInput, "hidden"); - YAHOO.util.Event.addListener(this._textField(), "keydown", this._onSdTextboxKeyDown, this, true); - } - } + this._completer.itemSelectEvent.subscribe(this._onSdItemSelectEvent, this); + this._completer.unmatchedItemSelectEvent.subscribe(this._onSdItemSelectEvent, this); + this._completer.textboxBlurEvent.subscribe(this._onSdTextboxBlurEvent, this); -YAHOO.slashdot.AutoCompleteWidget.prototype._hide = function() - { - if ( this._pending_hide ) - { - clearTimeout(this._pending_hide); - this._pending_hide = null; - } + YAHOO.util.Event.addListener(this._textField(), "keydown", this._onSdTextboxKeyDown, this, true); + } +} - YAHOO.util.Dom.addClass(this._widget, "hidden"); - YAHOO.util.Dom.addClass(this._spareInput, "hidden"); - if ( this._sourceEl ) - { - YAHOO.util.Dom.removeClass(this._sourceEl, "ac-source"); +YAHOO.slashdot.AutoCompleteWidget.prototype._hide = function() { + if ( this._pending_hide ) { + clearTimeout(this._pending_hide); + this._pending_hide = null; + } - YAHOO.util.Event.removeListener(this._textField(), "keydown", this._onSdTextboxKeyDown, this, true); - this._completer.itemSelectEvent.unsubscribe(this._onSdItemSelectEvent, this); - this._completer.unmatchedItemSelectEvent.unsubscribe(this._onSdItemSelectEvent, this); - this._completer.textboxBlurEvent.unsubscribe(this._onSdTextboxBlurEvent, this); + YAHOO.util.Dom.addClass(this._widget, "hidden"); + YAHOO.util.Dom.addClass(this._spareInput, "hidden"); + if ( this._sourceEl ) { + YAHOO.util.Dom.removeClass(this._sourceEl, "ac-source"); - this._sourceEl = null; - this._callbackParams = null; - this._completer = null; - } + YAHOO.util.Event.removeListener(this._textField(), "keydown", this._onSdTextboxKeyDown, this, true); + this._completer.itemSelectEvent.unsubscribe(this._onSdItemSelectEvent, this); + this._completer.unmatchedItemSelectEvent.unsubscribe(this._onSdItemSelectEvent, this); + this._completer.textboxBlurEvent.unsubscribe(this._onSdTextboxBlurEvent, this); - this._denyNextAttachTo = null; - } + this._sourceEl = null; + this._callbackParams = null; + this._completer = null; + } -YAHOO.slashdot.AutoCompleteWidget.prototype.attach = function( obj, callbackParams, tagDomain ) - { - var newSourceEl = obj; - if ( typeof obj == "string" ) - newSourceEl = document.getElementById(obj); + this._denyNextAttachTo = null; +} - // act like a menu: if we click on the same trigger while visible, hide - var denyThisAttach = this._denyNextAttachTo == newSourceEl; - this._denyNextAttachTo = null; - if ( denyThisAttach ) - return; +YAHOO.slashdot.AutoCompleteWidget.prototype.attach = function( obj, callbackParams, tagDomain ) { + var newSourceEl = obj; + if ( typeof obj == "string" ) + newSourceEl = document.getElementById(obj); - if ( newSourceEl && newSourceEl !== this._sourceEl ) - { - callbackParams._sourceEl = newSourceEl; - this._show(newSourceEl, callbackParams, tagDomain); + // act like a menu: if we click on the same trigger while visible, hide + var denyThisAttach = this._denyNextAttachTo == newSourceEl; + this._denyNextAttachTo = null; + if ( denyThisAttach ) + return; - var q = callbackParams.queryOnAttach; - if ( q ) - this._completer.sendQuery((typeof q == "string") ? q : ""); - } - } + if ( newSourceEl && newSourceEl !== this._sourceEl ) { + callbackParams._sourceEl = newSourceEl; + this._show(newSourceEl, callbackParams, tagDomain); -YAHOO.slashdot.AutoCompleteWidget.prototype._onSdClick = function( e, me ) - { - // if the user re-clicked the item to which I'm attached, then they mean to hide me - // I'm going to hide automatically, because a click outside the text will blur, and that makes me go away - // but I need to remember _not_ to let the current click re-show me - var reclicked = me._sourceEl && YAHOO.util.Event.getTarget(e, true) == me._sourceEl; - me._denyNextAttachTo = reclicked ? me._sourceEl : null; - } + var q = callbackParams.queryOnAttach; + if ( q ) + this._completer.sendQuery((typeof q == "string") ? q : ""); + } +} -YAHOO.slashdot.AutoCompleteWidget.prototype._onSdItemSelectEvent = function( type, args, me ) - { - var tagname = args[2]; - if ( tagname !== undefined && tagname !== null ) { - if ( typeof tagname != 'string' ) - tagname = tagname[0]; +YAHOO.slashdot.AutoCompleteWidget.prototype._onSdClick = function( e, me ) { + // if the user re-clicked the item to which I'm attached, then they mean to hide me + // I'm going to hide automatically, because a click outside the text will blur, and that makes me go away + // but I need to remember _not_ to let the current click re-show me + var reclicked = me._sourceEl && YAHOO.util.Event.getTarget(e, true) == me._sourceEl; + me._denyNextAttachTo = reclicked ? me._sourceEl : null; +} - var p = me._callbackParams; - if ( p.action0 !== undefined ) - p.action0(tagname, p); - me._hide(); - if ( p.action1 !== undefined ) - p.action1(tagname, p); +YAHOO.slashdot.AutoCompleteWidget.prototype._onSdItemSelectEvent = function( type, args, me ) { + var tagname = args[2]; + if ( tagname !== undefined && tagname !== null ) { + if ( typeof tagname != 'string' ) + tagname = tagname[0]; - } else { - me._hide(); - } - } + var p = me._callbackParams; + if ( p.action0 !== undefined ) + p.action0(tagname, p); + me._hide(); + if ( p.action1 !== undefined ) + p.action1(tagname, p); -YAHOO.slashdot.AutoCompleteWidget.prototype._onSdTextboxBlurEvent = function( type, args, me ) - { - var o = me._denyNextAttachTo; - me._hide(); - me._denyNextAttachTo = o; - } + } else { + me._hide(); + } +} -YAHOO.slashdot.AutoCompleteWidget.prototype._onSdTextboxKeyDown = function( e, me ) - { - if ( me._callbackParams && me._callbackParams.delayAutoHighlight ) - { - me._callbackParams.delayAutoHighlight = false; - me._completer.autoHighlight = true; - } +YAHOO.slashdot.AutoCompleteWidget.prototype._onSdTextboxBlurEvent = function( type, args, me ) { + var o = me._denyNextAttachTo; + me._hide(); + me._denyNextAttachTo = o; +} - switch ( e.keyCode ) - { - case 27: // esc - // any other keys?... - me._hide(); - break; - case 13: - // I'm sorry to say we have to test first, something somehow somewhere can still - // leave this listener dangling; want to look deeper into this, as this would _still_ - // leave the listener dangling - if ( me._completer ) - me._completer.unmatchedItemSelectEvent.fire(me._completer, me, me._completer._sCurQuery); - break; - default: - if ( me._pending_hide ) - clearTimeout(me._pending_hide); - if ( me._needsSpareInput() ) - me._pending_hide = setTimeout(YAHOO.slashdot.gCompleterWidget._hide, 15000); - } - } +YAHOO.slashdot.AutoCompleteWidget.prototype._onSdTextboxKeyDown = function( e, me ) { + if ( me._callbackParams && me._callbackParams.delayAutoHighlight ) { + me._callbackParams.delayAutoHighlight = false; + me._completer.autoHighlight = true; + } + + switch ( e.keyCode ) { + case 27: // esc + // any other keys?... + me._hide(); + break; + case 13: + // I'm sorry to say we have to test first, something somehow somewhere can still + // leave this listener dangling; want to look deeper into this, as this would _still_ + // leave the listener dangling + if ( me._completer ) + me._completer.unmatchedItemSelectEvent.fire(me._completer, me, me._completer._sCurQuery); + break; + default: + if ( me._pending_hide ) + clearTimeout(me._pending_hide); + if ( me._needsSpareInput() ) + me._pending_hide = setTimeout(YAHOO.slashdot.gCompleterWidget._hide, 15000); + } +} Modified: slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/sd_calendar.js =================================================================== --- slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/sd_calendar.js 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/sd_calendar.js 2008-04-06 23:11:14 UTC (rev 569) @@ -1,275 +1,275 @@ // _*_ Mode: JavaScript; tab-width: 8; indent-tabs-mode: true _*_ -// $Id: sd_calendar.js,v 1.7 2007/06/05 19:04:12 scc Exp $ +// $Id: sd_calendar.js,v 1.9 2008/03/28 20:53:43 pudge Exp $ YAHOO.namespace("slashdot"); function _datesToSelector( selectorFormat, dates ) { - function format( d ) { - return selectorFormat(d.getFullYear(), d.getMonth()+1, d.getDate(), d.getDay()); - } + function format( d ) { + return selectorFormat(d.getFullYear(), d.getMonth()+1, d.getDate(), d.getDay()); + } - var s = format(dates[0]); - if ( dates[1] !== undefined ) - s += "-" + format(dates[1]); - return s; + var s = format(dates[0]); + if ( dates[1] !== undefined ) + s += "-" + format(dates[1]); + return s; } function _bundleDates( date1, date2 ) { - if ( date1 instanceof Array ) - return date1; - else if ( date2 === undefined ) - return [ date1 ]; - else - return [ date1, date2 ]; + if ( date1 instanceof Array ) + return date1; + else if ( date2 === undefined ) + return [ date1 ]; + else + return [ date1, date2 ]; } function datesToHumanReadable( date1, date2 ) { - var day_name = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; + var day_name = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; - function day_ordinal( d ) { - switch ( d ) { - case 1: case 21: case 31: return d+"st"; - case 2: case 22: return d+"nd"; - case 3: case 23: return d+"rd"; - default: return d+"th"; - } - } + function day_ordinal( d ) { + switch ( d ) { + case 1: case 21: case 31: return d+"st"; + case 2: case 22: return d+"nd"; + case 3: case 23: return d+"rd"; + default: return d+"th"; + } + } - var month_name = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; + var month_name = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; - function minimalHumanReadable( y, m, d, wd ) { - var now = new Date(); - if ( now.getFullYear() == y ) { - if ( now.getMonth()+1 == m ) { - } - } - } + function minimalHumanReadable( y, m, d, wd ) { + var now = new Date(); + if ( now.getFullYear() == y ) { + if ( now.getMonth()+1 == m ) { + } + } + } - - return _datesToSelector(function(y,m,d){return ""+d+" "+month_name[m-1]+" "+y;}, _bundleDates(date1, date2)); + + return _datesToSelector(function(y,m,d){return ""+d+" "+month_name[m-1]+" "+y;}, _bundleDates(date1, date2)); } function datesToYUISelector( date1, date2 ) { - return _datesToSelector(function(y,m,d){return ""+m+"/"+d+"/"+y;}, _bundleDates(date1, date2)); + return _datesToSelector(function(y,m,d){return ""+m+"/"+d+"/"+y;}, _bundleDates(date1, date2)); } function datesToKinoSelector( date1, date2 ) { - function formatter( y, m, d ) { - if ( m < 10 ) m = "0" + m; - if ( d < 10 ) d = "0" + d; - return "" + y + m + d; - } - return _datesToSelector(formatter, _bundleDates(date1, date2)); + function formatter( y, m, d ) { + if ( m < 10 ) m = "0" + m; + if ( d < 10 ) d = "0" + d; + return "" + y + m + d; + } + return _datesToSelector(formatter, _bundleDates(date1, date2)); } // Kino format to YUI format: "20070428".replace(/(....)(..)(..)/, "$2/$3/$1") function weekOf( date ) { - var dayStart = new Date(datesToYUISelector(date)); - var dayCount = Math.round(dayStart.getTime() / 86400000); - var weekStart = dayCount - dayStart.getDay() + 1; - var weekStop = weekStart + 6; - var startDate = new Date(weekStart * 86400000); - var endDate = new Date(weekStop * 86400000); - return [startDate, endDate]; + var dayStart = new Date(datesToYUISelector(date)); + var dayCount = Math.round(dayStart.getTime() / 86400000); + var weekStart = dayCount - dayStart.getDay() + 1; + var weekStop = weekStart + 6; + var startDate = new Date(weekStart * 86400000); + var endDate = new Date(weekStop * 86400000); + return [startDate, endDate]; } var gOpenCalendarPane = null; YAHOO.slashdot.DateWidget = function( params ) { - this.init(params); + this.init(params); } YAHOO.slashdot.DateWidget.prototype.init = function( params ) { // id, mode, date, initCallback - var peer = null; - if ( params.peer !== undefined ) { - peer = document.getElementById(params.peer); - params.mode = peer._widget._mode; - params.date = peer._widget.getDate(); + var peer = null; + if ( params.peer !== undefined ) { + peer = document.getElementById(params.peer); + params.mode = peer._widget._mode; + params.date = peer._widget.getDate(); - this.subscribeToPeer(peer); - this._peer = peer; - } + this.subscribeToPeer(peer); + this._peer = peer; + } - this._mode = (params.mode !== undefined) ? params.mode : "now"; + this._mode = (params.mode !== undefined) ? params.mode : "now"; - var root = document.getElementById(params.id); - var find1st = function(name, kind) { - return YAHOO.util.Dom.getElementsByClassName(name, kind, root)[0]; - } + var root = document.getElementById(params.id); + var find1st = function(name, kind) { + return YAHOO.util.Dom.getElementsByClassName(name, kind, root)[0]; + } - var widget = this; + var widget = this; - this._element = root; - this._dateTab = find1st('date-tab', 'span'); - this._dateTab._widget = this; - this._label = find1st('day-label', 'option'); - this._calendarPane = find1st('calendar-pane', 'div'); - this.toggleCalendarPane(false); + this._element = root; + this._dateTab = find1st('date-tab', 'span'); + this._dateTab._widget = this; + this._label = find1st('day-label', 'option'); + this._calendarPane = find1st('calendar-pane', 'div'); + this.toggleCalendarPane(false); - this._popup = find1st('date-span-popup', 'select'); - this._popup._widget = this; + this._popup = find1st('date-span-popup', 'select'); + this._popup._widget = this; - this._calendar = new YAHOO.widget.Calendar(params.id+'-calendar-table', this._calendarPane.id, {maxdate:datesToYUISelector(new Date())}); - this._calendar.selectEvent.subscribe(this.handleCalendarSelect, this, true); + this._calendar = new YAHOO.widget.Calendar(params.id+'-calendar-table', this._calendarPane.id, {maxdate:datesToYUISelector(new Date())}); + this._calendar.selectEvent.subscribe(this.handleCalendarSelect, this, true); - root._widget = this; - root.setDate = function(d, m) { widget.setDate(d, m); } - root.getDateRange = function() { return widget.getDateRange(); } - root.changeEvent = new YAHOO.util.CustomEvent("change"); + root._widget = this; + root.setDate = function(d, m) { widget.setDate(d, m); } + root.getDateRange = function() { return widget.getDateRange(); } + root.changeEvent = new YAHOO.util.CustomEvent("change"); - this._muteEvents = 0; + this._muteEvents = 0; - this.setDate(params.date); + this.setDate(params.date); - if ( peer ) - peer._widget.subscribeToPeer(this._element); + if ( peer ) + peer._widget.subscribeToPeer(this._element); - if ( params.init !== undefined ) - params.init(root); + if ( params.init !== undefined ) + params.init(root); } function attachDateWidgetTo( params ) { - return new YAHOO.slashdot.DateWidget(params); + return new YAHOO.slashdot.DateWidget(params); } YAHOO.slashdot.DateWidget.prototype.muteEvents = function() { - ++this._muteEvents; + ++this._muteEvents; } YAHOO.slashdot.DateWidget.prototype.unmuteEvents = function() { - --this._muteEvents; + --this._muteEvents; } YAHOO.slashdot.DateWidget.prototype._reportChanged = function() { - if ( ! this._muteEvents ) - this._element.changeEvent.fire(this.getDateRange(), this._mode, this.getDate()); + if ( ! this._muteEvents ) + this._element.changeEvent.fire(this.getDateRange(), this._mode, this.getDate()); } YAHOO.slashdot.DateWidget.prototype.severPeer = function() { - if ( this._peer !== undefined ) { - this._peer._widget.unsubscribeFromPeer(this); - this.unsubscribeFromPeer(this._peer); - delete this._peer; - } + if ( this._peer !== undefined ) { + this._peer._widget.unsubscribeFromPeer(this); + this.unsubscribeFromPeer(this._peer); + delete this._peer; + } } YAHOO.slashdot.DateWidget.prototype.subscribeToPeer = function( peer ) { - peer.changeEvent.subscribe(this.handlePeerChange, this, true); + peer.changeEvent.subscribe(this.handlePeerChange, this, true); } YAHOO.slashdot.DateWidget.prototype.unsubscribeFromPeer = function( peer ) { - peer.changeEvent.unsubscribe(this.handlePeerChange, this); + peer.changeEvent.unsubscribe(this.handlePeerChange, this); } YAHOO.slashdot.DateWidget.prototype.setMode = function( newMode ) { - var oldMode = this._mode; - var modeChanged = (newMode !== undefined) && (newMode != oldMode); - if ( modeChanged ) { - if ( newMode == "all" ) - this.toggleCalendarPane(false); - YAHOO.util.Dom.replaceClass(this._element, oldMode, newMode); - this._mode = newMode; - this._popup.value = newMode; - } + var oldMode = this._mode; + var modeChanged = (newMode !== undefined) && (newMode != oldMode); + if ( modeChanged ) { + if ( newMode == "all" ) + this.toggleCalendarPane(false); + YAHOO.util.Dom.replaceClass(this._element, oldMode, newMode); + this._mode = newMode; + this._popup.value = newMode; + } - if ( modeChanged ) - this._reportChanged(); + if ( modeChanged ) + this._reportChanged(); - return modeChanged; + return modeChanged; } YAHOO.slashdot.DateWidget.prototype.setDate = function( date, mode ) { - this.muteEvents(); - if ( date === undefined ) - date = new Date(); - this._calendar.select(date); - this._calendar.render(); - var dateChanged = this._setDateFromSelection(date); + this.muteEvents(); + if ( date === undefined ) + date = new Date(); + this._calendar.select(date); + this._calendar.render(); + var dateChanged = this._setDateFromSelection(date); - var modeChanged = false; - if ( mode !== undefined ) - modeChanged = this.setMode(mode); - this.unmuteEvents(); + var modeChanged = false; + if ( mode !== undefined ) + modeChanged = this.setMode(mode); + this.unmuteEvents(); - if ( dateChanged || modeChanged ) - this._reportChanged(); + if ( dateChanged || modeChanged ) + this._reportChanged(); } YAHOO.slashdot.DateWidget.prototype._setDateFromSelection = function( date, allowModeChange ) { - var oldLabel = this._label.innerHTML; - var newLabel = "Day of " + datesToHumanReadable(date); - var labelChanged = oldLabel != newLabel; - if ( labelChanged ) - this._label.innerHTML = newLabel; + var oldLabel = this._label.innerHTML; + var newLabel = "Day of " + datesToHumanReadable(date); + var labelChanged = oldLabel != newLabel; + if ( labelChanged ) + this._label.innerHTML = newLabel; - var modeChanged = false; - if ( allowModeChange==true ) { - var today = new Date(); - var newMode = ( date.getFullYear() == today.getFullYear() - && date.getMonth() == today.getMonth() - && date.getDate() == today.getDate() ) ? "now" : "day"; + var modeChanged = false; + if ( allowModeChange==true ) { + var today = new Date(); + var newMode = ( date.getFullYear() == today.getFullYear() + && date.getMonth() == today.getMonth() + && date.getDate() == today.getDate() ) ? "now" : "day"; - this.muteEvents(); - modeChanged = this.setMode(newMode); - this.unmuteEvents(); - } + this.muteEvents(); + modeChanged = this.setMode(newMode); + this.unmuteEvents(); + } - if ( labelChanged || modeChanged ) - this._reportChanged(); + if ( labelChanged || modeChanged ) + this._reportChanged(); - return labelChanged || modeChanged; + return labelChanged || modeChanged; } YAHOO.slashdot.DateWidget.prototype.getDate = function() { - return this._calendar.getSelectedDates()[0]; + return this._calendar.getSelectedDates()[0]; } YAHOO.slashdot.DateWidget.prototype.getDateRange = function() { - var range = { duration: -1 }; + var range = { duration: -1 }; - var start = null; - if ( this._mode == "day" ) { - start = this.getDate(); - range.duration = 1; - } else if ( this._mode == "now" ) { - range.duration = 7; - } + var start = null; + if ( this._mode == "day" ) { + start = this.getDate(); + range.duration = 1; + } else if ( this._mode == "now" ) { + range.duration = 7; + } - if ( start !== null ) - range.startdate = datesToKinoSelector(start); + if ( start !== null ) + range.startdate = datesToKinoSelector(start); - return range; + return range; } YAHOO.slashdot.DateWidget.prototype.toggleCalendarPane = function( show ) { - if ( gOpenCalendarPane !== null && gOpenCalendarPane !== this ) { - gOpenCalendarPane.toggleCalendarPane(false); - } - this._calendarPane.style.display = show ? 'block' : 'none'; - YAHOO.util.Dom[ show ? 'addClass' : 'removeClass' ](this._dateTab, 'active'); - gOpenCalendarPane = show ? this : null; + if ( gOpenCalendarPane !== null && gOpenCalendarPane !== this ) { + gOpenCalendarPane.toggleCalendarPane(false); + } + this._calendarPane.style.display = show ? 'block' : 'none'; + YAHOO.util.Dom[ show ? 'addClass' : 'removeClass' ](this._dateTab, 'active'); + gOpenCalendarPane = show ? this : null; } YAHOO.slashdot.DateWidget.prototype.handleDateTabClick = function() { - this.toggleCalendarPane( ! YAHOO.util.Dom.hasClass(this._dateTab, 'active') ); + this.toggleCalendarPane( ! YAHOO.util.Dom.hasClass(this._dateTab, 'active') ); } YAHOO.slashdot.DateWidget.prototype.handleCalendarSelect = function( type, args, obj ) { - this._setDateFromSelection(this._calendar._toDate(args[0][0]), true); - this.toggleCalendarPane(false); + this._setDateFromSelection(this._calendar._toDate(args[0][0]), true); + this.toggleCalendarPane(false); } YAHOO.slashdot.DateWidget.prototype.handleRangePopupSelect = function( obj ) { - this.setMode(obj.value); + this.setMode(obj.value); } YAHOO.slashdot.DateWidget.prototype.handlePeerChange = function( type, args, obj ) { - this.muteEvents(); - this.setDate(args[2], args[1]); - this.unmuteEvents(); + this.muteEvents(); + this.setDate(args[2], args[1]); + this.unmuteEvents(); } Modified: slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/slashbox.js =================================================================== --- slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/slashbox.js 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/slashbox.js 2008-04-06 23:11:14 UTC (rev 569) @@ -1,101 +1,90 @@ YAHOO.namespace("slashdot"); -YAHOO.slashdot.SlashBox = function( id, sGroup, config ) - { - if ( id ) - { - this.init(id, sGroup, config); - this.initFrame(); - this.logger = this.logger || YAHOO; - } +YAHOO.slashdot.SlashBox = function( id, sGroup, config ) { + if ( id ) { + this.init(id, sGroup, config); + this.initFrame(); + this.logger = this.logger || YAHOO; + } - this.deleteBoundaryId = sGroup; - } + this.deleteBoundaryId = sGroup; +} YAHOO.extend(YAHOO.slashdot.SlashBox, YAHOO.util.DDProxy); -YAHOO.slashdot.SlashBox.prototype.createFrame() - { - // ... - } +YAHOO.slashdot.SlashBox.prototype.createFrame = function() { + // ... +} -YAHOO.slashdot.SlashBox.prototype.startDrag = function(x, y) - { - var dragEl = this.getDragEl(); - var clickEl = this.getEl(); +YAHOO.slashdot.SlashBox.prototype.startDrag = function(x, y) { + var dragEl = this.getDragEl(); + var clickEl = this.getEl(); - dragEl.innerHTML = clickEl.innerHTML; - dragEl.className = clickEl.className; + dragEl.innerHTML = clickEl.innerHTML; + dragEl.className = clickEl.className; - YAHOO.util.Dom.addClass(clickEl, "to-be-moved"); - // so we can style the object-to-be-moved in CSS - } + YAHOO.util.Dom.addClass(clickEl, "to-be-moved"); + // so we can style the object-to-be-moved in CSS +} -YAHOO.slashdot.SlashBox.prototype.endDrag = function(e) - { - YAHOO.util.Dom.removeClass(this.getEl(), "to-be-moved"); - // done moving, back to your regularly scheduled CSS (see this.startDrag) - } +YAHOO.slashdot.SlashBox.prototype.endDrag = function(e) { + YAHOO.util.Dom.removeClass(this.getEl(), "to-be-moved"); + // done moving, back to your regularly scheduled CSS (see this.startDrag) +} -YAHOO.slashdot.SlashBox.prototype.onDragOver = function(e, id) - { - if ( id == this.deleteBoundaryId ) - return; +YAHOO.slashdot.SlashBox.prototype.onDragOver = function(e, id) { + if ( id == this.deleteBoundaryId ) + return; - var pointer_y = YAHOO.util.Event.getPageY(e); - var dragged_box = this.getEl(); - var fixed_box; - - if ("string" == typeof id) - fixed_box = YAHOO.util.DDM.getElement(id); - else - fixed_box = YAHOO.util.DDM.getBestMatch(id).getEl(); + var pointer_y = YAHOO.util.Event.getPageY(e); + var dragged_box = this.getEl(); + var fixed_box; - var parent = fixed_box.parentNode; + if ("string" == typeof id) + fixed_box = YAHOO.util.DDM.getElement(id); + else + fixed_box = YAHOO.util.DDM.getBestMatch(id).getEl(); - var dragged_top = YAHOO.util.DDM.getPosY(dragged_box); - var fixed_top = YAHOO.util.DDM.getPosY(fixed_box); - - var fixed_mid = fixed_top + ( Math.floor(fixed_box.offsetHeight / 2)); + var parent = fixed_box.parentNode; - var dragging_down = dragged_top < fixed_top; + var dragged_top = YAHOO.util.DDM.getPosY(dragged_box); + var fixed_top = YAHOO.util.DDM.getPosY(fixed_box); + + var fixed_mid = fixed_top + ( Math.floor(fixed_box.offsetHeight / 2)); + var dragging_down = dragged_top < fixed_top; - if ( dragging_down && pointer_y > fixed_mid ) - parent.insertBefore(fixed_box, dragged_box); - else if ( !dragging_down && pointer_y < fixed_mid ) - parent.insertBefore(dragged_box, fixed_box); - else - return; - } -YAHOO.slashdot.SlashBox.prototype.onDragEnter = function(e, id) - { - if ( id == this.deleteBoundaryId ) - { - var dragEl = this.getDragEl(); - var clickEl = this.getEl(); - YAHOO.util.Dom.removeClass(dragEl, "to-be-deleted"); - YAHOO.util.Dom.removeClass(clickEl, "to-be-deleted"); - // so we can style the object-to-be-moved in CSS - } - } + if ( dragging_down && pointer_y > fixed_mid ) + parent.insertBefore(fixed_box, dragged_box); + else if ( !dragging_down && pointer_y < fixed_mid ) + parent.insertBefore(dragged_box, fixed_box); + else + return; +} -YAHOO.slashdot.SlashBox.prototype.onDragOut = function(e, id) - { - if ( id == this.deleteBoundaryId ) - { - var dragEl = this.getDragEl(); - var clickEl = this.getEl(); - YAHOO.util.Dom.addClass(dragEl, "to-be-deleted"); - YAHOO.util.Dom.addClass(clickEl, "to-be-deleted"); - // so we can style the object-to-be-moved in CSS - } - } +YAHOO.slashdot.SlashBox.prototype.onDragEnter = function(e, id) { + if ( id == this.deleteBoundaryId ) { + var dragEl = this.getDragEl(); + var clickEl = this.getEl(); + YAHOO.util.Dom.removeClass(dragEl, "to-be-deleted"); + YAHOO.util.Dom.removeClass(clickEl, "to-be-deleted"); + // so we can style the object-to-be-moved in CSS + } +} -YAHOO.slashdot.SlashBox.prototype.onDragDrop = function(e, id) - { - ajaxSaveSlashboxes(); - } +YAHOO.slashdot.SlashBox.prototype.onDragOut = function(e, id) { + if ( id == this.deleteBoundaryId ) { + var dragEl = this.getDragEl(); + var clickEl = this.getEl(); + YAHOO.util.Dom.addClass(dragEl, "to-be-deleted"); + YAHOO.util.Dom.addClass(clickEl, "to-be-deleted"); + // so we can style the object-to-be-moved in CSS + } +} + +YAHOO.slashdot.SlashBox.prototype.onDragDrop = function(e, id) { + ajaxSaveSlashboxes(); +} Modified: slashjp/branches/upstream/current/plugins/Ajax/templates/data;ajax;default =================================================================== --- slashjp/branches/upstream/current/plugins/Ajax/templates/data;ajax;default 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/plugins/Ajax/templates/data;ajax;default 2008-04-06 23:11:14 UTC (rev 569) @@ -10,11 +10,20 @@ en_US __name__ data -__seclev__ -10000 __template__ [% SWITCH value %] [% CASE 'set_section_prefs_success_msg' %] Close + +[% CASE 'inline preview warning' %] +

    This comment will not be saved until you click the Submit button below.

    + +[% CASE 'no modcommentlog' %] +

    No comment history available.

    + [% END %] +__seclev__ +1000 +__version__ +$Id: data;ajax;default,v 1.11 2008/03/27 00:44:21 pudge Exp $ Modified: slashjp/branches/upstream/current/plugins/Ajax/templates/edit_comment;ajax;default =================================================================== --- slashjp/branches/upstream/current/plugins/Ajax/templates/edit_comment;ajax;default 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/plugins/Ajax/templates/edit_comment;ajax;default 2008-04-06 23:11:14 UTC (rev 569) @@ -19,58 +19,68 @@ __name__ edit_comment __template__ -
    -[% this_title = pid ? reply.subject : discussion.title; - this_title = this_title | strip_html; - PROCESS titlebar title="Reply to: $this_title" %] +
    +[% IF user.is_anon %] +

    + [% IF constants.allow_anonymous %] + You are not logged in. You can log + in now, or Create an Account. + [% ELSE %] + You are not logged in. You can log + in now, Create an Account, + or post as [% user.nickname | strip_literal %]. + [% END %] +

    +[% END %] -

    If you have difficulty with this form, please use the old form.

    - -[% IF user.is_anon %]

    - [% IF constants.allow_anonymous %] -You are not logged in. You can log -in now, or Create an Account. - [% ELSE %] -You are not logged in. You can log -in now, Create an Account, -or post as [% user.nickname | strip_literal %]. - [% END %] -

    [% END %] - [% IF !user.is_anon || constants.allow_anonymous %] - -
    -
    - -[% IF pid %][% END %] - -[% reskey_label = "reskey_reply_$pid"; PROCESS reskey_tag %] -

    -[% UNLESS user.is_anon %][Options] -[%- IF constants.allow_anonymous && user.karma > -1 && (discussion.commentstatus == 'enabled' || discussion.commentstatus == 'logged_in') -%] - Post Anonymously -[%- END %]

    [% END %] -

    - -
    -
    -
    - - -[%- IF pid # not for root-level reply %] -[% END %] - - - -
    - +
    +
    +
    + + [% IF pid %][% END %] + + [% reskey_label = "reskey_reply_$pid"; PROCESS reskey_tag %] +
    +
    +

    + + [% UNLESS user.is_anon %] + [%- IF constants.allow_anonymous && user.karma > -1 && (discussion.commentstatus == 'enabled' || discussion.commentstatus == 'logged_in') -%] + Post Anonymously + [%- END %] + [% END %] +

    + [% UNLESS user.is_anon %]Preferences[% END %] +
    +
    +
    +

    If you have difficulty with this form, please use the old form.

    + +
    +
    + +
    + + + [%- IF pid # not for root-level reply %] + [% END %] + [%- UNLESS user.is_anon %] + [% END %] + + + + + +
    + [% END # IF !user.is_anon || constants.allow_anonymous %]
    - __seclev__ 1000 __version__ -$Id: edit_comment;ajax;default,v 1.5 2008/03/19 08:25:31 pudge Exp $ +$Id: edit_comment;ajax;default,v 1.11 2008/04/03 04:38:36 pudge Exp $ Added: slashjp/branches/upstream/current/plugins/Ajax/templates/hc_comment;ajax;default =================================================================== --- slashjp/branches/upstream/current/plugins/Ajax/templates/hc_comment;ajax;default (rev 0) +++ slashjp/branches/upstream/current/plugins/Ajax/templates/hc_comment;ajax;default 2008-04-06 23:11:14 UTC (rev 569) @@ -0,0 +1,29 @@ +__section__ +default +__description__ +Template which renders the comment editor. + +* error_message = error message if there is an error +* preview = preview of comment, if applicable +* reply = hashref of comment replying to +* hide_name = hide name / log out link +* hide_email = hide email display +* extras = array of any extras associated with this comment + +__title__ + +__page__ +ajax +__lang__ +en_US +__name__ +hc_comment +__template__ +[% IF user.state.hc && !user.state.hcinvalid %] +

    [% user.state.hcquestion; user.state.hchtml %] + +[% END %] +__seclev__ +1000 +__version__ +$Id: hc_comment;ajax;default,v 1.1 2008/03/25 18:46:24 pudge Exp $ Modified: slashjp/branches/upstream/current/plugins/Console/console.pl =================================================================== --- slashjp/branches/upstream/current/plugins/Console/console.pl 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/plugins/Console/console.pl 2008-04-06 23:11:14 UTC (rev 569) @@ -2,7 +2,7 @@ # This code is a part of Slash, and is released under the GPL. # Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: console.pl,v 1.7 2007/12/11 12:53:04 jamiemccarthy Exp $ +# $Id: console.pl,v 1.8 2008/03/21 16:53:32 tvroom Exp $ use strict; use warnings; @@ -14,7 +14,7 @@ use Slash::XML; use vars qw($VERSION); -($VERSION) = ' $Revision: 1.7 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.8 $ ' =~ /\$Revision:\s+([^\s]+)/; sub main { @@ -65,8 +65,7 @@ my $tagnamesbox = ''; my $tags = getObject('Slash::Tags'); if ($tags) { - my $rtoi_ar = $tags->getRecentTagnamesOfInterest(); - $tagnamesbox = $tags->showRecentTagnamesBox(); + $tagnamesbox = $tags->showRecentTagnamesBox({ box_only => 1}); } slashDisplay('display', { Modified: slashjp/branches/upstream/current/plugins/FireHose/FireHose.pm =================================================================== --- slashjp/branches/upstream/current/plugins/FireHose/FireHose.pm 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/plugins/FireHose/FireHose.pm 2008-04-06 23:11:14 UTC (rev 569) @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. # Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: FireHose.pm,v 1.226 2008/03/18 16:16:02 tvroom Exp $ +# $Id: FireHose.pm,v 1.231 2008/04/03 19:16:05 tvroom Exp $ package Slash::FireHose; @@ -41,7 +41,7 @@ use base 'Slash::DB::MySQL'; use vars qw($VERSION); -($VERSION) = ' $Revision: 1.226 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.231 $ ' =~ /\$Revision:\s+([^\s]+)/; sub createFireHose { my($self, $data) = @_; $data->{dept} ||= ""; @@ -378,6 +378,9 @@ $options ||= {}; $options->{limit} ||= 50; + my $ps = $options->{limit}; + + $options->{limit} += $options->{more_num} if $options->{more_num}; my $pop; $pop = $self->getMinPopularityForColorLevel($colors->{$options->{color}}) @@ -607,9 +610,10 @@ $other = 'GROUP BY firehose.id' if $options->{tagged_by_uid}; my $count_other = $other; + my $offset; if (1 || !$doublecheck) { # do always for now - my $offset = defined $options->{offset} ? $options->{offset} : ''; + $offset = defined $options->{offset} ? $options->{offset} : ''; $offset = '' if $offset !~ /^\d+$/; $offset = "$offset, " if length $offset; $limit_str = "LIMIT $offset $options->{limit}" unless $options->{nolimit}; @@ -628,10 +632,11 @@ } - my $page_size = $options->{limit} || 1; + my $page_size = $ps || 1; $results->{records_pages} ||= ceil($count / $page_size); $results->{records_page} ||= (int(($options->{offset} || 0) / $options->{limit}) + 1) || 1; + my $future_count = $count - $options->{limit} - ($options->{offset} || 0); if (keys %$filter_globjids) { for my $i (0 .. $#{$hr_ar}) { @@ -662,7 +667,7 @@ $items = $hr_ar; } - return($items, $results, $count); + return($items, $results, $count, $future_count); } # A single-globjid wrapper around getUserFireHoseVotesForGlobjs. @@ -1015,7 +1020,7 @@ } my $eval_first = ""; - for my $o (qw(startdate mode fhfilter orderdir orderby startdate duration color)) { + for my $o (qw(startdate mode fhfilter orderdir orderby startdate duration color more_num)) { my $value = $opts->{$o}; if ($o eq 'orderby' && $value eq 'editorpop') { $value = 'popularity'; @@ -1023,6 +1028,9 @@ if ($o eq 'startdate') { $value =~ s/-//g; } + if ($o eq 'more_num') { + $value ||= 0; + } $eval_first .= "firehose_settings.$o = " . Data::JavaScript::Anon->anon_dump("$value") . "; "; } @@ -1160,7 +1168,7 @@ my %ids = map { $_ => 1 } @ids; my %ids_orig = ( %ids ) ; my $opts = $firehose->getAndSetOptions({ no_set => 1 }); - my($items, $results) = $firehose_reader->getFireHoseEssentials($opts); + my($items, $results, $count, $future_count) = $firehose_reader->getFireHoseEssentials($opts); my $num_items = scalar @$items; my $future = {}; my $globjs = []; @@ -1302,6 +1310,7 @@ $html->{filter_text} = "Filtered to ".strip_literal($opts->{color})." '".strip_literal($opts->{fhfilter})."'"; $html->{gmt_update_time} = " (".timeCalc($slashdb->getTime(), "%H:%M", 0)." GMT) " if $user->{is_admin}; $html->{itemsreturned} = $num_items == 0 ? getData("noitems", { options => $opts }, 'firehose') : ""; + $html->{firehose_more} = getData("firehose_more_link", { options => $opts, future_count => $future_count, contentsonly => 1}, 'firehose'); my $data_dump = Data::JavaScript::Anon->anon_dump({ html => $html, @@ -2145,6 +2154,15 @@ if ($form->{not_id} && $form->{not_id} =~ /^\d+$/) { $options->{not_id} = $form->{not_id}; } + + + if ($form->{more_num} && $form->{more_num} =~ /^\d+$/) { + $options->{more_num} = $form->{more_num}; + if (!$user->{is_admin} && (($options->{limit} + $options->{more_num}) > 200)) { + $options->{more_num} = 200 - $options->{limit} ; + } + } + return $options; } @@ -2269,7 +2287,7 @@ if ($featured && $featured->{id}) { $options->{not_id} = $featured->{id}; } - my($items, $results) = $firehose_reader->getFireHoseEssentials($options); + my($items, $results, $count, $future_count) = $firehose_reader->getFireHoseEssentials($options); my $itemnum = scalar @$items; @@ -2338,6 +2356,8 @@ $section = $gSkin->{skid}; } + my $firehose_more = getData('firehose_more_link', { future_count => $future_count, options => $options }, 'firehose'); + slashDisplay("list", { itemstext => $itemstext, itemnum => $itemnum, @@ -2353,7 +2373,8 @@ fh_page => $base_page, search_results => $results, featured => $featured, - section => $section + section => $section, + firehose_more => $firehose_more }, { Page => "firehose", Return => 1 }); } @@ -2637,4 +2658,4 @@ =head1 VERSION -$Id: FireHose.pm,v 1.226 2008/03/18 16:16:02 tvroom Exp $ +$Id: FireHose.pm,v 1.231 2008/04/03 19:16:05 tvroom Exp $ Modified: slashjp/branches/upstream/current/plugins/FireHose/templates/data;firehose;default =================================================================== --- slashjp/branches/upstream/current/plugins/FireHose/templates/data;firehose;default 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/plugins/FireHose/templates/data;firehose;default 2008-04-06 23:11:14 UTC (rev 569) @@ -93,9 +93,27 @@ [% END %]

    +[% CASE 'firehose_more_link' %] + [% extra_onclick = '' %] + [% IF !contentsonly %] +

    + [% END %] + [% IF day_label && day_count; + label = day_count _ " more " _ $day_label _ "..."; + ELSIF future_count > 0; + label = future_count _ " more..."; + ELSIF future_count <= 0 && !options.startdate && options.duration != -1 && options.orderby == "createtime"; + label = "Get more..."; + extra_onclick = 'firehose_set_options(\'duration\', -1); '; + END; + %] + [% label %] + [% IF !contentsonly %] +
    + [% END %] [% CASE 'notavailable' %] The item you're trying to view either does not exist, or is not viewable to you. [% END %] __version__ -$Id: data;firehose;default,v 1.23 2007/10/24 00:30:08 scc Exp $ +$Id: data;firehose;default,v 1.25 2008/04/02 15:00:56 tvroom Exp $ Modified: slashjp/branches/upstream/current/plugins/FireHose/templates/dispTopicFireHose;misc;default =================================================================== --- slashjp/branches/upstream/current/plugins/FireHose/templates/dispTopicFireHose;misc;default 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/plugins/FireHose/templates/dispTopicFireHose;misc;default 2008-04-06 23:11:14 UTC (rev 569) @@ -14,12 +14,16 @@ 10000 __template__ [% topic = Slash.db.getTopic(item.tid) %] -[% IF (item.thumb && (item.type == "story" || (item.type == "submission" && adminmode))) %] +[% IF item.type == "story"; + story = Slash.db.getStory(item.srcid); + + END %] +[% IF item.thumb && ((item.type == "story" && (!story.thumb_signoff_needed || adminmode)) || (item.type == "submission" && adminmode)) %] [% file = Slash.db.getStaticFile(item.thumb); %] [% fh = Slash.getObject("Slash::FireHose"); link_url = fh.linkFireHose(item); %] - thumbnail
    [% IF item.media %][% END %]
    [% IF item.media %]
    Watch[% END %] + thumbnail
    [% IF item.media %][% END %]
    [% IF item.media %]
    Watch[% END %][% END %] [% ELSIF user.noicons || user.simpledesign || user.lowbandwidth %] [ [% topic.textname %] ] @@ -29,4 +33,4 @@ [% END %] __version__ -$Id: dispTopicFireHose;misc;default,v 1.7 2008/02/12 17:26:29 tvroom Exp $ +$Id: dispTopicFireHose;misc;default,v 1.10 2008/04/03 18:34:23 tvroom Exp $ Modified: slashjp/branches/upstream/current/plugins/FireHose/templates/fireHoseForm;misc;default =================================================================== --- slashjp/branches/upstream/current/plugins/FireHose/templates/fireHoseForm;misc;default 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/plugins/FireHose/templates/fireHoseForm;misc;default 2008-04-06 23:11:14 UTC (rev 569) @@ -48,8 +48,8 @@ [% END %] [% IF needjssubmit %] [% END %] __version__ -$Id: fireHoseForm;misc;default,v 1.9 2006/12/19 22:17:55 tvroom Exp $ +$Id: fireHoseForm;misc;default,v 1.10 2008/03/21 14:30:58 tvroom Exp $ Modified: slashjp/branches/upstream/current/plugins/FireHose/templates/firehose_pages;misc;default =================================================================== --- slashjp/branches/upstream/current/plugins/FireHose/templates/firehose_pages;misc;default 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/plugins/FireHose/templates/firehose_pages;misc;default 2008-04-06 23:11:14 UTC (rev 569) @@ -66,7 +66,7 @@ IF i_page == start_page_num %] [% END; IF i_page == page_cur %][% i_page %][% ELSE; i_page; END; - IF i_page == end_page_num %] [% END %] + IF i_page == end_page_num %] [% END %] [% END; END; @@ -76,4 +76,4 @@ __seclev__ 10000 __version__ -$Id: firehose_pages;misc;default,v 1.16 2008/02/20 18:42:47 tvroom Exp $ +$Id: firehose_pages;misc;default,v 1.18 2008/04/01 19:34:00 tvroom Exp $ Modified: slashjp/branches/upstream/current/plugins/FireHose/templates/list;firehose;default =================================================================== --- slashjp/branches/upstream/current/plugins/FireHose/templates/list;firehose;default 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/plugins/FireHose/templates/list;firehose;default 2008-04-06 23:11:14 UTC (rev 569) @@ -153,6 +153,7 @@ [% IF itemnum == 0; Slash.getData('noitems', { options => options }, 'firehose'); END %] +[% firehose_more %] [% PROCESS paginate options = options ulid = "fh-paginate" divid = "fh-pag-div" num_items = itemnum fh_page = fh_page %] __version__ -$Id: list;firehose;default,v 1.112 2008/02/27 02:35:28 tvroom Exp $ +$Id: list;firehose;default,v 1.113 2008/04/01 19:34:00 tvroom Exp $ Modified: slashjp/branches/upstream/current/plugins/HumanConf/HumanConf.pm =================================================================== --- slashjp/branches/upstream/current/plugins/HumanConf/HumanConf.pm 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/plugins/HumanConf/HumanConf.pm 2008-04-06 23:11:14 UTC (rev 569) @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. # Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: HumanConf.pm,v 1.12 2007/10/12 07:23:03 jamiemccarthy Exp $ +# $Id: HumanConf.pm,v 1.14 2008/03/25 18:46:24 pudge Exp $ package Slash::HumanConf; @@ -16,7 +16,7 @@ use base 'Slash::DB::Utility'; use base 'Slash::DB::MySQL'; -($VERSION) = ' $Revision: 1.12 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.14 $ ' =~ /\$Revision:\s+([^\s]+)/; sub new { my($class, $user) = @_; @@ -36,25 +36,26 @@ } sub _formnameNeedsHC { - my($self, $formname) = @_; + my($self, $formname, $options) = @_; + return 1 if $options->{needs_hc}; my $regex = getCurrentStatic('hc_formname_regex') || '^comments$'; return 1 if $formname =~ /$regex/; return 0; } sub createFormkeyHC { - my($self, $formname) = @_; + my($self, $formname, $options) = @_; # Only certain formnames need human confirmation. From any # other formname, just return 1, meaning everything is ok # (no humanconf necessary). - return 'ok' if !$self->_formnameNeedsHC($formname); + return 'ok' if !$self->_formnameNeedsHC($formname, $options); my $slashdb = getCurrentDB(); my $form = getCurrentForm(); my $user = getCurrentUser(); my $constants = getCurrentStatic(); - my $formkey = $form->{formkey}; + my $formkey = $options->{frkey} || $form->{formkey}; return 0 unless $formkey; # Decide which question we're asking. @@ -113,7 +114,7 @@ return 0 unless $success; my $hcid = $slashdb->getLastInsertId(); - $user->{state}{hcid} = $hcid; # for debugging + $user->{state}{hcid} = $hcid; $user->{state}{hc} = 1; $user->{state}{hcinvalid} = 0; $user->{state}{hcquestion} = $question; @@ -121,25 +122,34 @@ return 1; } +sub updateFormkeyHCValue { + my($self, $hcid, $formkey) = @_; + my $slashdb = getCurrentDB(); + return $slashdb->sqlUpdate('humanconf', { + formkey => $formkey + }, 'hcid=' . $slashdb->sqlQuote($hcid) + ); +} + sub reloadFormkeyHC { - my($self, $formname) = @_; + my($self, $formname, $options) = @_; my $user = getCurrentUser(); # Only certain formnames need human confirmation. Other formnames # won't even have HC data created for them, so there's no need to # waste time hitting the DB. - if (!$self->_formnameNeedsHC($formname)) { + if (!$self->_formnameNeedsHC($formname, $options)) { $user->{state}{hc} = 0; - return ; + return; } $user->{state}{hc} = 1; my $slashdb = getCurrentDB(); my $form = getCurrentForm(); my $constants = getCurrentStatic(); - my $formkey = $form->{formkey}; - my $formkey_quoted = $slashdb->sqlQuote($form->{formkey}); + my $formkey = $options->{frkey} || $form->{formkey}; + my $formkey_quoted = $slashdb->sqlQuote($formkey); my($hcid, $html, $question, $tries_left) = $slashdb->sqlSelect( "hcid, html, question, tries_left", @@ -156,22 +166,23 @@ $user->{state}{hcinvalid} = 1; $user->{state}{hcerror} = getData('nomorechances', {}, 'humanconf'); } + return !$user->{state}{hcinvalid}; } sub validFormkeyHC { - my($self, $formname) = @_; + my($self, $formname, $options) = @_; # Only certain formnames need human confirmation. Other formnames # won't even have HC data created for them, so there's no need to # waste time hitting the DB. - return 'ok' if !$self->_formnameNeedsHC($formname); + return 'ok' if !$self->_formnameNeedsHC($formname, $options); my $slashdb = getCurrentDB(); my $form = getCurrentForm(); - my $formkey = $form->{formkey}; + my $formkey = $options->{frkey} || $form->{formkey}; return 'invalidhc' unless $formkey; - my $formkey_quoted = $slashdb->sqlQuote($form->{formkey}); + my $formkey_quoted = $slashdb->sqlQuote($formkey); # If this formkey is valid, and there is a corresponding humanconf # entry, check that as well. Note that if there is an hcid in the @@ -183,7 +194,7 @@ "humanconf, humanconf_pool", "humanconf.formkey = $formkey_quoted AND humanconf_pool.hcpid = humanconf.hcpid - AND tries_left > 0" + AND tries_left > 0" ); if (!$hcid) { # No humanconf associated with this formkey. Either there Modified: slashjp/branches/upstream/current/plugins/Journal/journal.pl =================================================================== --- slashjp/branches/upstream/current/plugins/Journal/journal.pl 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/plugins/Journal/journal.pl 2008-04-06 23:11:14 UTC (rev 569) @@ -2,7 +2,7 @@ # This code is a part of Slash, and is released under the GPL. # Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: journal.pl,v 1.143 2007/04/05 21:44:36 pudge Exp $ +# $Id: journal.pl,v 1.144 2008/04/02 14:20:23 entweichen Exp $ use strict; use Slash 2.003; # require Slash 2.3.x @@ -13,7 +13,7 @@ use Slash::XML; use vars qw($VERSION); -($VERSION) = ' $Revision: 1.143 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.144 $ ' =~ /\$Revision:\s+([^\s]+)/; sub main { my $journal = getObject('Slash::Journal'); @@ -583,6 +583,7 @@ } my $slashdb = getCurrentDB(); + my $event_id; if ($form->{id}) { my %update; my $article = $journal_reader->get($form->{id}); @@ -614,6 +615,7 @@ url => "$rootdir/~" . fixparam($user->{nickname}) . "/journal/$form->{id}", }); $update{discussion} = $did; + $event_id = $did; # update description if changed } elsif (!$form->{comments_on} && $article->{discussion} && $article->{description} ne $description) { @@ -655,6 +657,7 @@ url => "$rootdir/~" . fixparam($user->{nickname}) . "/journal/$id", }); $journal->set($id, { discussion => $did }); + $event_id = $did; } slashHook('journal_save_success', { id => $id }); @@ -695,6 +698,44 @@ }) if $validator; } + # Add the User2 event. + my $events = $slashdb->sqlSelectAllHashref( + 'eid', 'eid, date', 'user_events', "uid = " . $user->{uid} . " and code = 2"); + + if ((scalar keys %$events) == 5) { + my $eid = [sort keys %$events]->[0]; + $slashdb->sqlDelete('user_events', "uid = " . $user->{uid} . " and code = 2 and eid = $eid"); + } + + $slashdb->sqlInsert('user_events', { + code => 2, + uid => $user->{uid}, + event => $event_id, + -date => 'NOW()', + }); + + my $event_blocks = $slashdb->sqlSelectAllHashref( + 'uid', 'bid, uid, block', 'user_event_blocks', "uid = " . $user->{uid} . " and code = 2"); + + if (!%$event_blocks) { + $slashdb->sqlInsert('user_event_blocks', { + code => 2, + uid => $user->{uid}, + block => $event_id, + }); + } else { + my @blocks = split(/,/, $event_blocks->{$user->{uid}}->{block}); + + if (scalar @blocks == 5) { + @blocks = @blocks[1 .. 4]; + } + + $blocks[$#blocks + 1] = $event_id; + my $new_blocks = join(",", @blocks); + + $slashdb->sqlUpdate('user_event_blocks', { block => $new_blocks }, "uid = " . $user->{uid} . " and code = 2"); + } + return 0; } Modified: slashjp/branches/upstream/current/plugins/Moderation/Moderation.pm =================================================================== --- slashjp/branches/upstream/current/plugins/Moderation/Moderation.pm 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/plugins/Moderation/Moderation.pm 2008-04-06 23:11:14 UTC (rev 569) @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. # Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Moderation.pm,v 1.9 2008/03/19 08:25:31 pudge Exp $ +# $Id: Moderation.pm,v 1.10 2008/03/27 00:44:21 pudge Exp $ package Slash::Moderation; @@ -17,7 +17,7 @@ use base 'Slash::DB::Utility'; use base 'Slash::DB::MySQL'; -($VERSION) = ' $Revision: 1.9 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.10 $ ' =~ /\$Revision:\s+([^\s]+)/; sub new { my($class, $user) = @_; @@ -955,7 +955,7 @@ } } - my $removed_text = slashDisplay('undo_mod', { removed => $removed }, { Return => 1 }); + my $removed_text = slashDisplay('undo_mod', { removed => $removed }, { Return => 1, Page => 'comments' }); return $removed_text; } Modified: slashjp/branches/upstream/current/plugins/ResKey/MANIFEST =================================================================== --- slashjp/branches/upstream/current/plugins/ResKey/MANIFEST 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/plugins/ResKey/MANIFEST 2008-04-06 23:11:14 UTC (rev 569) @@ -6,8 +6,11 @@ ResKey/Checks/AL2/AnonNoPost.pm ResKey/Checks/AL2/NoPost.pm ResKey/Checks/AL2/NoPostAnon.pm +ResKey/Checks/AL2/NoSubmit.pm +ResKey/Checks/AL2/Spammer.pm ResKey/Checks/AL2.pm ResKey/Checks/Duration.pm +ResKey/Checks/HumanConf.pm ResKey/Checks/Moderate.pm ResKey/Checks/Post.pm ResKey/Checks/ProxyScan.pm Modified: slashjp/branches/upstream/current/plugins/ResKey/ResKey/Checks/Duration.pm =================================================================== --- slashjp/branches/upstream/current/plugins/ResKey/ResKey/Checks/Duration.pm 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/plugins/ResKey/ResKey/Checks/Duration.pm 2008-04-06 23:11:14 UTC (rev 569) @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. # Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Duration.pm,v 1.10 2006/03/15 20:49:30 pudge Exp $ +# $Id: Duration.pm,v 1.12 2008/03/27 00:44:21 pudge Exp $ package Slash::ResKey::Checks::Duration; @@ -13,7 +13,7 @@ use base 'Slash::ResKey::Key'; -our($VERSION) = ' $Revision: 1.10 $ ' =~ /\$Revision:\s+([^\s]+)/; +our($VERSION) = ' $Revision: 1.12 $ ' =~ /\$Revision:\s+([^\s]+)/; sub doCheckCreate { @@ -140,9 +140,8 @@ my($self, $reskey_obj) = @_; my $slashdb = getCurrentDB(); - my $check_vars = $self->getCheckVars; - my $limit = $check_vars->{duration_uses}; + my $limit = &duration; if ($limit) { my $where = $self->getWhereUserClause; $where .= ' AND rkrid=' . $self->rkrid; @@ -186,4 +185,56 @@ } +sub duration { + my($self, $reskey_obj) = @_; + (my $caller = (caller(1))[3]) =~ s/^.*:(\w+)$/$1/; + + my $reader = getObject('Slash::DB', { db_type => 'reader' }); + my $constants = getCurrentStatic(); + my $form = getCurrentForm(); + my $user = getCurrentUser(); + + my $check_vars = $self->getCheckVars; + my $limit = $constants->{reskey_timeframe}; + my $duration = 0; + + if ($caller eq 'minDurationBetweenUses') { + my $duration_name = 'duration_uses'; + my $duration_name_anon = "$duration_name-anon"; + # this is kinda ugly ... i'd like a better way to know anon, and + # this constant should be a reskey constant i think -- pudge 2008.03.21 + my $is_anon = $user->{is_anon} || $form->{postanon} || $user->{karma} < $constants->{formkey_minloggedinkarma}; + $duration = $check_vars->{$is_anon ? $duration_name_anon : $duration_name} || 0; + + # If this user has access modifiers applied, check for possible + # different speed limits based on those. First match, if any, + # wins. (taken from MySQL::checkPostInterval() + my $al2_hr = $user->{srcids} ? $reader->getAL2($user->{srcids}) : { }; + my $al2_name_used = "_none_"; # for debugging + for my $al2_name (sort keys %$al2_hr) { + my $sl_name_al2 = $is_anon + ? "$duration_name_anon-$al2_name" + : "$duration_name-$al2_name"; + if (defined $check_vars->{$sl_name_al2}) { + $al2_name_used = $al2_name; + $duration = $check_vars->{$sl_name_al2}; + last; + } + } + + if ($self->resname eq 'comments' && $is_anon) { + my $multiplier = $check_vars->{"$duration_name_anon-mult"}; + if ($multiplier && $multiplier != 1) { + my $num_comm = $reader->getNumCommPostedAnonByIPID($user->{ipid}); + $duration *= ($multiplier ** $num_comm); + $duration = int($duration + 0.5); + } + } + } + + + return $duration; +} + + 1; Added: slashjp/branches/upstream/current/plugins/ResKey/ResKey/Checks/HumanConf.pm =================================================================== --- slashjp/branches/upstream/current/plugins/ResKey/ResKey/Checks/HumanConf.pm (rev 0) +++ slashjp/branches/upstream/current/plugins/ResKey/ResKey/Checks/HumanConf.pm 2008-04-06 23:11:14 UTC (rev 569) @@ -0,0 +1,105 @@ +# This code is a part of Slash, and is released under the GPL. +# Copyright 1997-2005 by Open Source Technology Group. See README +# and COPYING for more information, or see http://slashcode.com/. +# $Id: HumanConf.pm,v 1.3 2008/04/02 15:15:45 pudge Exp $ + +package Slash::ResKey::Checks::HumanConf; + +use warnings; +use strict; + +use Slash::Utility; +use Slash::Constants ':reskey'; + +use base 'Slash::ResKey::Key'; + +our($VERSION) = ' $Revision: 1.3 $ ' =~ /\$Revision:\s+([^\s]+)/; + +sub updateResKey { + my($self) = @_; + return unless useHumanConf($self); + + my $user = getCurrentUser(); + return unless $user; + + my $hc = getObject('Slash::HumanConf'); + return unless $hc; + + $hc->updateFormkeyHCValue($user->{state}{hcid}, $self->reskey); +} + +sub doCheckCreate { + my($self) = @_; + + return RESKEY_SUCCESS unless useHumanConf($self); + + my $hc = getObject('Slash::HumanConf'); + + if (!$hc || !$hc->createFormkeyHC($self->resname, { frkey => $self->reskey, needs_hc => 1 })) { + return(RESKEY_DEATH, ["HumanConf failure"]); + } + + return RESKEY_SUCCESS; +} + +sub doCheckTouch { + my($self) = @_; + return RESKEY_SUCCESS unless useHumanConf($self); + + my $hc = getObject('Slash::HumanConf'); + if (!$hc || !$hc->reloadFormkeyHC($self->resname, { frkey => $self->reskey, needs_hc => 1 })) { + return(RESKEY_DEATH, ['invalidhc']); + } + + return RESKEY_SUCCESS; +} + +sub doCheckUse { + my($self) = @_; + return RESKEY_SUCCESS unless useHumanConf($self); + + my $hc = getObject('Slash::HumanConf'); + return(RESKEY_DEATH, ["HumanConf failure"]) if !$hc; + + # form->{hcanswer} + my $return = $hc->validFormkeyHC($self->resname, { frkey => $self->reskey, needs_hc => 1 }); + if ($return ne 'ok') { + $hc->reloadFormkeyHC($self->resname, { frkey => $self->reskey, needs_hc => 1 }); + return(($return =~ /retry/ ? RESKEY_FAILURE : RESKEY_DEATH), [$return]); + } + + return RESKEY_SUCCESS; +} + + +sub useHumanConf { + my($self) = @_; + my $constants = getCurrentStatic(); + my $user = getCurrentUser(); + + return 0 if + # HumanConf is not running... + !$constants->{plugin}{HumanConf} + || !$constants->{hc}; + + # stolen from comments.pl + if ($self->resname eq 'comments') { + return 0 if + # ...or it's turned off for comments... + $constants->{hc_sw_comments} == 0 + # ...or it's turned off for logged-in users + # and this user is logged-in... + || $constants->{hc_sw_comments} == 1 + && !$user->{is_anon} + # ...or it's turned off for logged-in users + # with high enough karma, and this user + # qualifies. + || $constants->{hc_sw_comments} == 2 + && !$user->{is_anon} + && $user->{karma} > $constants->{hc_maxkarma}; + } + + return 1; +} + +1; Modified: slashjp/branches/upstream/current/plugins/ResKey/ResKey/Key.pm =================================================================== --- slashjp/branches/upstream/current/plugins/ResKey/ResKey/Key.pm 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/plugins/ResKey/ResKey/Key.pm 2008-04-06 23:11:14 UTC (rev 569) @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. # Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Key.pm,v 1.23 2008/02/07 00:51:22 pudge Exp $ +# $Id: Key.pm,v 1.28 2008/04/03 21:20:56 pudge Exp $ package Slash::ResKey::Key; @@ -118,7 +118,7 @@ use Slash::Utility; our($AUTOLOAD); -our($VERSION) = ' $Revision: 1.23 $ ' =~ /\$Revision:\s+([^\s]+)/; +our($VERSION) = ' $Revision: 1.28 $ ' =~ /\$Revision:\s+([^\s]+)/; #======================================================================== sub new { @@ -141,7 +141,15 @@ if ($reskey) { $reskey =~ s|[^a-zA-Z0-9_]+||g; } elsif (!defined $reskey) { - $reskey = $opts->{nostate} ? '' : getCurrentForm('reskey'); + $reskey = getCurrentForm('reskey') unless $opts->{nostate}; # if we already have one + if (!$reskey) { + if ($self->static) { + $reskey = $self->makeStaticKey; + } else { + $reskey = $self->createResKey; + $self->unsaved(1); # still needs to be inserted/checked + } + } } # reskey() to set the value is called only here and from dbCreate @@ -233,7 +241,7 @@ if ($name =~ /^(?:noop|success|failure|death)$/) { $sub = _createStatusAccessor($name, \@_); - } elsif ($name =~ /^(?:error|reskey|debug|rkrid|resname|origtype|type|code|opts|static)$/) { + } elsif ($name =~ /^(?:error|reskey|debug|rkrid|resname|origtype|type|code|opts|static|unsaved)$/) { $sub = _createAccessor($name, \@_); } elsif ($name =~ /^(?:create|touch|use|createuse)$/) { @@ -315,9 +323,7 @@ # create is done for use, too. if ($self->type eq 'createuse') { $self->type('use'); - unless ($self->reskey) { - $self->dbCreate; - } + $self->dbCreate if $self->unsaved; } if ($self->type eq 'use' && !$self->static) { @@ -413,6 +419,11 @@ } #======================================================================== +sub createResKey { + return getAnonId(1, 20); +} + +#======================================================================== sub dbCreate { my($self) = @_; $self->_flow; @@ -431,16 +442,16 @@ # bothering). When we do pull it out, remember to lose # the 'use Time::HiRes' :) if ($self->static) { - $self->reskey($self->makeStaticKey); $ok = 1; } else { - my $reskey = ''; + my $reskey; + $reskey = $self->reskey if $self->unsaved; my $srcid = $self->getSrcid; my $try_num = 1; my $num_tries = 10; while ($try_num < $num_tries) { - $reskey = getAnonId(1, 20); + $reskey ||= $self->createResKey; my $rows = $slashdb->sqlInsert('reskeys', { reskey => $reskey, rkrid => $self->rkrid, @@ -451,10 +462,14 @@ if ($rows > 0) { $self->reskey($reskey); + $self->unsaved(0); $ok = 1; last; } + # blank for next try + $reskey = ''; + # The INSERT failed because $reskey is already being # used. Presumably this would be due to a collision # in the randomly-generated string, which indicates @@ -470,7 +485,13 @@ Time::HiRes::sleep(rand($try_num)); } if ($try_num > 1) { + $try_num--; errorLog("Slash::ResKey::Key->create INSERT failed $try_num times: uid=$user->{uid} rkrid=$self->{rkrid} reskey=$reskey"); + # XXX: this should be more modularized, bad to keep + # this all here, but OK to hack in for now -- pudge + if (defined &Slash::ResKey::Checks::HumanConf::updateResKey) { + Slash::ResKey::Checks::HumanConf::updateResKey($self); + } } } @@ -973,6 +994,15 @@ return $salts; } +sub ERROR { + my($self, $extra, $user) = @_; + $extra ||= ''; + $user ||= getCurrentUser(); + printf STDERR "AJAXE %d: UID:%d, extra:%s: %s (%s) (%s:%s:%s:%s:%s:%s:%s)\n", + $$, $user->{uid}, $extra, $self->errstr, $self->error->[0], $self->reskey, + $self->type, $self->resname, $self->rkrid, $self->code, $self->static, + $user->{srcids}{ 24 }; +} 1; @@ -985,4 +1015,4 @@ =head1 VERSION -$Id: Key.pm,v 1.23 2008/02/07 00:51:22 pudge Exp $ +$Id: Key.pm,v 1.28 2008/04/03 21:20:56 pudge Exp $ Modified: slashjp/branches/upstream/current/plugins/ResKey/example.plx =================================================================== --- slashjp/branches/upstream/current/plugins/ResKey/example.plx 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/plugins/ResKey/example.plx 2008-04-06 23:11:14 UTC (rev 569) @@ -11,28 +11,35 @@ for (1..1) { $reskey = getObject('Slash::ResKey'); - $lkey = $reskey->key('comments-moderation-ajax', { - debug => $debug - }); +# $lkey = $reskey->key('comments-moderation-ajax', { +# debug => $debug +# }); +# +# handle($lkey, 'create'); +# handle($lkey, 'use') for 0..19; +# +# +# $rkey = $reskey->key('pollbooth', { +# debug => $debug, +# qid => 1 +# }); +# handle($rkey, 'createuse'); - handle($lkey, 'create'); - handle($lkey, 'use') for 0..19; - - $rkey = $reskey->key('pollbooth', { - debug => $debug, - qid => 1 - }); - handle($rkey, 'createuse'); - - $rkey1 = $reskey->key('comments', { debug => $debug }); handle($rkey1, 'create'); handle($rkey1, 'touch'); + chomp(my $answer = <>); + getCurrentForm()->{hcanswer} = $answer; + handle($rkey1, 'use'); +use Data::Dumper; +print $rkey1; +exit; + $rkey2 = $reskey->key('comments', { debug => $debug, reskey => $rkey1->reskey, Modified: slashjp/branches/upstream/current/plugins/ResKey/mysql_dump.sql =================================================================== --- slashjp/branches/upstream/current/plugins/ResKey/mysql_dump.sql 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/plugins/ResKey/mysql_dump.sql 2008-04-06 23:11:14 UTC (rev 569) @@ -1,5 +1,5 @@ # -# $Id: mysql_dump.sql,v 1.21 2008/03/19 21:09:47 pudge Exp $ +# $Id: mysql_dump.sql,v 1.22 2008/03/25 18:46:24 pudge Exp $ # ### NOTE: reserved reskey IDs: @@ -54,6 +54,7 @@ INSERT INTO reskey_resource_checks VALUES (NULL, 1, 'all', 'Slash::ResKey::Checks::AL2::NoPost', 501); INSERT INTO reskey_resource_checks VALUES (NULL, 1, 'all', 'Slash::ResKey::Checks::AL2::Spammer', 531); INSERT INTO reskey_resource_checks VALUES (NULL, 1, 'all', 'Slash::ResKey::Checks::Duration', 601); +INSERT INTO reskey_resource_checks VALUES (NULL, 1, 'all', 'Slash::ResKey::Checks::HumanConf', 701); #INSERT INTO reskey_resource_checks VALUES (NULL, 1, 'use', 'Slash::ResKey::Checks::ProxyScan', 1001); # dummy example of how to disable the Slash::ResKey::Checks::User check for "touch" @@ -68,6 +69,10 @@ INSERT INTO reskey_vars VALUES (1, 'duration_max-failures', 10, 'how many failures per reskey'); INSERT INTO reskey_vars VALUES (1, 'duration_uses', 60, 'min duration (in seconds) between uses'); INSERT INTO reskey_vars VALUES (1, 'duration_creation-use', 10, 'min duration between (in seconds) creation and use'); +INSERT INTO reskey_vars VALUES (1, 'duration_uses-anon', 300, 'duration_uses for anon'); +INSERT INTO reskey_vars VALUES (1, 'duration_uses-anon-trolla', 3600, 'duration_uses for anon + trolla AL2'); +INSERT INTO reskey_vars VALUES (1, 'duration_uses-trolla', 300, 'duration_uses for tolla AL2'); +INSERT INTO reskey_vars VALUES (1, 'duration_uses-anon-mult', 1.5, 'multiply by this amount for each comment previously posted in the past 24 hours'); Modified: slashjp/branches/upstream/current/plugins/ResKey/templates/data;reskey;default =================================================================== --- slashjp/branches/upstream/current/plugins/ResKey/templates/data;reskey;default 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/plugins/ResKey/templates/data;reskey;default 2008-04-06 23:11:14 UTC (rev 569) @@ -75,6 +75,16 @@ You must wait a little bit before using this resource; please try again later. +[%# HumanConf %] +[% CASE 'invalidhcretry' %] + You failed to confirm you are a human. Please double-check the image and + make sure you typed in what it says. + +[% CASE 'invalidhc' %] + You failed to confirm you are a human. Please start from the beginning + and try again. If you are a human, we apologize for the inconvenience. + + [%# ProxyScan %] [% CASE 'open proxy' %] You may not post using an open proxy. @@ -123,4 +133,4 @@ __seclev__ 10000 __version__ -$Id: data;reskey;default,v 1.9 2006/09/20 01:51:58 pudge Exp $ +$Id: data;reskey;default,v 1.10 2008/03/25 18:46:24 pudge Exp $ Modified: slashjp/branches/upstream/current/plugins/TagDataView/TagDataView.pm =================================================================== --- slashjp/branches/upstream/current/plugins/TagDataView/TagDataView.pm 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/plugins/TagDataView/TagDataView.pm 2008-04-06 23:11:14 UTC (rev 569) @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. # Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: TagDataView.pm,v 1.2 2007/12/18 23:40:03 pudge Exp $ +# $Id: TagDataView.pm,v 1.3 2008/03/25 18:42:17 pudge Exp $ package Slash::TagDataView; @@ -33,7 +33,7 @@ use base 'Slash::DB::MySQL'; use vars qw($VERSION); -($VERSION) = ' $Revision: 1.2 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.3 $ ' =~ /\$Revision:\s+([^\s]+)/; sub getGlobjidsMissingHistory { my($self, $max_mins, $max_min_incrs, $max_globjids) = @_; @@ -105,7 +105,6 @@ my $tagsdb = getObject('Slash::Tags'); my $tagnames = $tagsdb->getNegativeTags; $tagnames = ['nix'] unless @$tagnames; - #$constants->{tags_negative_tagnames} || $constants->{tags_downvote_tagname} || 'nix'; my $tagnameids = join ',', grep $_, map { s/\s+//g; $tagsdb->getTagnameidFromNameIfExists($_) @@ -134,5 +133,5 @@ =head1 VERSION -$Id: TagDataView.pm,v 1.2 2007/12/18 23:40:03 pudge Exp $ +$Id: TagDataView.pm,v 1.3 2008/03/25 18:42:17 pudge Exp $ Modified: slashjp/branches/upstream/current/plugins/TagModeration/TagModeration.pm =================================================================== --- slashjp/branches/upstream/current/plugins/TagModeration/TagModeration.pm 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/plugins/TagModeration/TagModeration.pm 2008-04-06 23:11:14 UTC (rev 569) @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. # Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: TagModeration.pm,v 1.10 2008/03/19 08:25:31 pudge Exp $ +# $Id: TagModeration.pm,v 1.11 2008/03/27 00:44:21 pudge Exp $ package Slash::TagModeration; @@ -17,7 +17,7 @@ use base 'Slash::DB::Utility'; use base 'Slash::DB::MySQL'; -($VERSION) = ' $Revision: 1.10 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.11 $ ' =~ /\$Revision:\s+([^\s]+)/; sub new { my($class, $user) = @_; @@ -955,7 +955,7 @@ } } - my $removed_text = slashDisplay('undo_mod', { removed => $removed }, { Return => 1 }); + my $removed_text = slashDisplay('undo_mod', { removed => $removed }, { Return => 1, Page => 'comments' }); return $removed_text; } Modified: slashjp/branches/upstream/current/plugins/Tags/Clout/Describe.pm =================================================================== --- slashjp/branches/upstream/current/plugins/Tags/Clout/Describe.pm 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/plugins/Tags/Clout/Describe.pm 2008-04-06 23:11:14 UTC (rev 569) @@ -8,7 +8,7 @@ use vars qw($VERSION); -($VERSION) = ' $Revision: 1.7 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.9 $ ' =~ /\$Revision:\s+([^\s]+)/; sub init { my($self) = @_; @@ -19,19 +19,36 @@ # propagate up to 50% of the weight, the second another 25%, the # third another 12.5% etc. $self->{cumfrac} = 0.5; - $self->{debug_uids} = { }; + my $constants = getCurrentStatic(); + $self->{debug_uids} = { map { ($_, 1) } split / /, + ($constants->{tags_updateclouts_debuguids} || '') + }; $self->{debug} = 0; 1; } sub getUserClout { my($self, $user_stub) = @_; - my $clout = $user_stub->{karma} >= -3 - ? log($user_stub->{karma}+10) - : 0; + my $clout; + my $karma = $user_stub->{karma}; + if ($karma >= 1) { + # Full graduated clout for positive karma. + $clout = log($karma+5); # karma 1 clout 1.8 ; karma 50 clout 4.0 + } elsif ($karma == 0) { + # Karma of 0 means low clout. + $clout = 0.2; + } elsif ($karma >= -2) { + # Mild negative karma means extremely low clout. + $clout = ($karma+3)*0.01; + } else { + # Significant negative karma means no clout. + $clout = 0; + } $clout += 5 if $user_stub->{seclev} > 1; $clout *= $user_stub->{tag_clout}; + # An account created within the past 3 days has low clout. + # Once an account reaches 30 days old, it gets full clout. my $created_at_ut; if (defined($user_stub->{created_at_ut})) { $created_at_ut = $user_stub->{created_at_ut}; Modified: slashjp/branches/upstream/current/plugins/Tags/Clout/Vote.pm =================================================================== --- slashjp/branches/upstream/current/plugins/Tags/Clout/Vote.pm 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/plugins/Tags/Clout/Vote.pm 2008-04-06 23:11:14 UTC (rev 569) @@ -8,7 +8,7 @@ use vars qw($VERSION); -($VERSION) = ' $Revision: 1.7 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.9 $ ' =~ /\$Revision:\s+([^\s]+)/; sub init { my($self) = @_; @@ -19,16 +19,33 @@ # propagate up to 50% of the weight, the second another 25%, the # third another 12.5% etc. $self->{cumfrac} = 0.45; - $self->{debug_uids} = { }; + my $constants = getCurrentStatic(); + $self->{debug_uids} = { map { ($_, 1) } split / /, + ($constants->{tags_updateclouts_debuguids} || '') + }; $self->{debug} = 0; 1; } sub getUserClout { my($self, $user_stub) = @_; - my $clout = $user_stub->{karma} >= -3 - ? log($user_stub->{karma}+10)/50 - : 0; + + my $clout; + my $karma = $user_stub->{karma}; + if ($karma >= 1) { + # Full graduated clout for positive karma. + $clout = log($karma+5); # karma 1 clout 1.8 ; karma 50 clout 4.0 + } elsif ($karma == 0) { + # Karma of 0 means low clout. + $clout = 0.3; + } elsif ($karma >= -2) { + # Mild negative karma means extremely low clout. + $clout = ($karma+3)*0.01; + } else { + # Significant negative karma means no clout. + $clout = 0; + } + $clout *= $user_stub->{tag_clout}; my $created_at_ut; @@ -38,7 +55,7 @@ $created_at_ut = str2time( $user_stub->{created_at} ) || 0; } my $secs_since = time - $created_at_ut; - my $frac = $secs_since / (120*86400); + my $frac = $secs_since / (30*86400); $frac = 0.1 if $frac < 0.1; $frac = 1 if $frac > 1; $clout *= $frac; Modified: slashjp/branches/upstream/current/plugins/Tags/PLUGIN =================================================================== --- slashjp/branches/upstream/current/plugins/Tags/PLUGIN 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/plugins/Tags/PLUGIN 2008-04-06 23:11:14 UTC (rev 569) @@ -1,4 +1,4 @@ -# $Id: PLUGIN,v 1.15 2008/03/19 14:49:35 jamiemccarthy Exp $ +# $Id: PLUGIN,v 1.16 2008/03/24 20:18:01 jamiemccarthy Exp $ name=Tags description="Tags" htdoc=tags.pl @@ -20,4 +20,6 @@ template=templates/tagsurldivadmin;misc;default template=templates/taghistory;misc;default template=templates/usertaghistory;users;default +template=templates/usertagnames;users;default template=templates/usertags;users;default +template=templates/usertagsforname;users;default Modified: slashjp/branches/upstream/current/plugins/Tags/Tags.pm =================================================================== --- slashjp/branches/upstream/current/plugins/Tags/Tags.pm 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/plugins/Tags/Tags.pm 2008-04-06 23:11:14 UTC (rev 569) @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. # Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Tags.pm,v 1.107 2008/03/19 14:49:35 jamiemccarthy Exp $ +# $Id: Tags.pm,v 1.112 2008/04/03 22:01:38 pudge Exp $ package Slash::Tags; @@ -17,7 +17,7 @@ use base 'Slash::DB::Utility'; use base 'Slash::DB::MySQL'; -($VERSION) = ' $Revision: 1.107 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.112 $ ' =~ /\$Revision:\s+([^\s]+)/; # FRY: And where would a giant nerd be? THE LIBRARY! @@ -728,6 +728,8 @@ my $orderdir = uc($options->{orderdir}) eq "DESC" ? "DESC" : "ASC"; my $inact_clause = $options->{include_inactive} ? '' : ' AND inactivated IS NULL'; my $private_clause = $options->{include_private} ? '' : " AND private='no'"; + my $tagname_clause = $options->{tagnameid} + ? ' AND tags.tagnameid=' . $self->sqlQuote($options->{tagnameid}) : ''; my($table_extra, $where_extra) = ("",""); my $uid_q = $self->sqlQuote($uid); @@ -752,7 +754,7 @@ 'tags.*', "tags $table_extra", "tags.uid = $uid_q - $inact_clause $private_clause $where_extra", + $inact_clause $private_clause $tagname_clause $where_extra", "ORDER BY $orderby $orderdir $limit"); return [ ] unless $ar && @$ar; $self->dataConversionForHashrefArray($ar); @@ -845,6 +847,7 @@ sub getAllObjectsTagname { my($self, $name, $options) = @_; + my $constants = getCurrentStatic(); # my $mcd = undef; # my $mcdkey = undef; # if (!$options->{include_private}) { @@ -855,15 +858,24 @@ # my $value = $mcd->get("$mcdkey$name"); # return $value if defined $value; # } - my $private_clause = ref($options) && $options->{include_private} ? '' : " AND private='no'"; + $options = { } if !$options || !ref $options; + my $private_clause = $options->{include_private} ? '' : " AND private='no'"; my $id = $self->getTagnameidFromNameIfExists($name); return [ ] if !$id; + # XXX make this degrade gracefully if plugins/FireHose not installed + my $firehose_db = getObject('Slash::FireHose'); + my $min_pop = $options->{min_pop} + || $firehose_db->getMinPopularityForColorLevel( $constants->{tags_active_mincare} || 5 ); + # 117K rows unjoined, 7 seconds ; 10K rows unjoined, 3 seconds ; 10K rows joined, 18 seconds my $hr_ar = $self->sqlSelectAllHashrefArray( '*, UNIX_TIMESTAMP(created_at) AS created_at_ut', - 'tags', - "tagnameid=$id AND inactivated IS NULL $private_clause", - 'ORDER BY tagid'); + 'tags, firehose', + "tags.globjid=firehose.globjid AND popularity >= $min_pop + AND tagnameid=$id AND inactivated IS NULL $private_clause", + 'ORDER BY tagid DESC LIMIT 5000'); + # 117K rows, 6 minutes ; 10K rows, 30 seconds $self->addGlobjEssentialsToHashrefArray($hr_ar); + # 117K rows, 8 minutes ; 10K rows, 60 seconds $self->addCloutsToTagArrayref($hr_ar); # if ($mcd) { # my $constants = getCurrentStatic(); @@ -1701,6 +1713,7 @@ sub listTagnamesAll { my($self, $options) = @_; + $options = { } if !$options || !ref $options; my $tagname_ar; if ($options->{really_all}) { $tagname_ar = $self->sqlSelectColArrayref('tagname', 'tagnames', @@ -1720,10 +1733,12 @@ sub listTagnamesActive { my($self, $options) = @_; my $constants = getCurrentStatic(); - my $max_num = ref($options) && $options->{max_num} || 100; - my $seconds = ref($options) && $options->{seconds} || (3600*6); - my $include_private = ref($options) && $options->{include_private} || 0; - my $min_slice = ref($options) && $options->{min_slice} || 0; + $options = { } if !$options || !ref $options; + my $max_num = defined($options->{max_num}) ? $options->{max_num} : 100; + my $seconds = defined($options->{seconds}) ? $options->{seconds} : (3600*6); + my $include_private = defined($options->{include_private}) ? $options->{include_private} : 0; + my $min_slice = defined($options->{min_slice}) ? $options->{min_slice} : 0; + my $min_clout = defined($options->{min_clout}) ? $options->{min_clout} : $constants->{tags_stories_top_minscore} || 0; $min_slice = 0 if !$constants->{plugin}{FireHose}; # This seems like a horrendous query, but I _think_ it will run @@ -1809,7 +1824,7 @@ # List all tags with at least a minimum clout. my @tagnames = grep - { $tagname_clout{$_} >= $constants->{tags_stories_top_minscore} } + { $tagname_clout{$_} >= $min_clout } keys %tagname_clout; # Sort by sum of normalized clout and (opposite of) last-seen time. @@ -1828,8 +1843,9 @@ sub listTagnamesRecent { my($self, $options) = @_; my $constants = getCurrentStatic(); - my $seconds = ref($options) && $options->{seconds} || (3600*6); - my $include_private = ref($options) && $options->{include_private} || 0; + $options = { } if !$options || !ref $options; + my $seconds = $options->{seconds} || (3600*6); + my $include_private = $options->{include_private} || 0; my $private_clause = $include_private ? '' : " AND private='no'"; my $recent_ar = $self->sqlSelectColArrayref( 'DISTINCT tagnames.tagname', @@ -2015,19 +2031,48 @@ 'tagnameid, tagname', 'tagnames', "tagname IN ($tagname_str)"); - my $tagnameid_str = join(',', map { $self->sqlQuote($_) } sort keys %$tagnameid_to_name); + my $tagnameid_recent_ar = [ sort { $a <=> $b } keys %$tagnameid_to_name ]; my $tagname_to_id = { reverse %$tagnameid_to_name }; - # Next, build a hash identifying which of those are new tagnames, - # i.e. which were used for the first time within the same recent - # time interval we're looking at. - my $tagname_firstrecent_ar = $self->sqlSelectColArrayref( - 'tagname, MIN(created_at) AS firstuse', - 'tagnames, tags', - "tagnames.tagnameid IN ($tagnameid_str) - AND tagnames.tagnameid=tags.tagnameid", - "GROUP BY tagname - HAVING firstuse >= DATE_SUB(NOW(), INTERVAL $secsback SECOND)"); + # Heuristic to optimize the selection process. Right now we have + # a list of many tagnameids (say, around 1000), most of which are + # not new (were used prior to the time interval in question). + # We eliminate those known not to be new by finding the newest + # tagnameid for the day prior to the time interval, then grepping + # out tagnameids in our list less than that. + # + # That should leave us with a much shorter list which will be + # processed much faster. On a non-busy site or during a + # pathological case where nobody types in any new tagnames for an + # entire day, the worst case here is that the processing is as + # slow as it was prior to this optimization (up to a minute or so + # on Slashdot). + my $tagid_secsback = $self->sqlSelect('MIN(tagid)', 'tags', + "created_at >= DATE_SUB(NOW(), INTERVAL $secsback SECOND)") + || 0; + my $secsback_1moreday = $secsback + 86400; + my $tagid_secsback_1moreday = $self->sqlSelect('MIN(tagid)', 'tags', + "created_at >= DATE_SUB(NOW(), INTERVAL $secsback_1moreday SECOND)") + || 0; + my $max_previously_known_tagnameid = $self->sqlSelect('MAX(tagnameid)', 'tags', + "tagid BETWEEN $tagid_secsback_1moreday AND $tagid_secsback") + || 0; + $tagnameid_recent_ar = [ + grep { $_ > $max_previously_known_tagnameid } + @$tagnameid_recent_ar ] + if $max_previously_known_tagnameid > 0; + my $tagnameid_str = join(',', map { $self->sqlQuote($_) } @$tagnameid_recent_ar); + + # Now do the select to find the actually-new tagnameids. + my $tagnameid_firstrecent_ar = $self->sqlSelectColArrayref( + 'DISTINCT tagnameid', + 'tags', + "tagid >= $tagid_secsback AND tagnameid IN ($tagnameid_str)"); + + # Run through the hash we built earlier to convert ids back to names. + my $tagname_firstrecent_ar = [ + map { $tagnameid_to_name->{$_} } + @$tagnameid_firstrecent_ar ]; my %tagname_firstrecent = ( map { ($_, 1) } @$tagname_firstrecent_ar ); # Build a regex that will identify tagnames that begin with an @@ -2081,7 +2126,7 @@ '*', 'tags', "tagnameid IN ($tagnameids_of_interest_str) - AND created_at >= DATE_SUB(NOW(), INTERVAL $secsback SECOND)"); + AND tagid >= $tagid_secsback"); $self->addCloutsToTagArrayref($tags_ar); my %tagnameid_weightsum = ( ); my %t_globjid_weightsum = ( ); @@ -2154,11 +2199,16 @@ sub showRecentTagnamesBox { my($self, $options) = @_; - my $rtoi_ar = $self->getRecentTagnamesOfInterest($options); + $options ||= {}; - my $text = slashDisplay('recenttagnamesbox', { - rtoi => $rtoi_ar, - }, { Return => 1 }); + my $text = " "; + + unless ($options->{box_only}) { + my $rtoi_ar = $self->getRecentTagnamesOfInterest(); + $text = slashDisplay('recenttagnamesbox', { + rtoi => $rtoi_ar, + }, { Return => 1 }); + } return $text if $options->{contents_only}; Modified: slashjp/branches/upstream/current/plugins/Tags/mysql_dump.sql =================================================================== --- slashjp/branches/upstream/current/plugins/Tags/mysql_dump.sql 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/plugins/Tags/mysql_dump.sql 2008-04-06 23:11:14 UTC (rev 569) @@ -1,9 +1,10 @@ # -# $Id: mysql_dump.sql,v 1.36 2008/03/11 19:57:26 jamiemccarthy Exp $ +# $Id: mysql_dump.sql,v 1.40 2008/04/03 20:39:11 jamiemccarthy Exp $ # INSERT INTO vars (name, value, description) VALUES ('memcached_exptime_tags', '3600', 'Seconds to cache tag data in memcached'); INSERT INTO vars (name, value, description) VALUES ('memcached_exptime_tags_brief', '300', 'Seconds to cache tag data that only needs brief caching, in memcached'); +INSERT INTO vars (name, value, description) VALUES ('tags_active_maxshow', '200', 'Maximum number of tagged objects to display on /tags/foo'); INSERT INTO vars (name, value, description) VALUES ('tags_active_mincare', '5', 'Minimum color slice number to "care" about tags for the Slashdot Recent Tags box (only matters if FireHose installed and if you are Slashdot)'); INSERT INTO vars (name, value, description) VALUES ('tags_admin_private_tags', '', 'List of tags separated by | that are private for admins'); INSERT INTO vars (name, value, description) VALUES ('tags_admin_autoaddstorytopics', '1', 'Auto-add tags for story topic keywords?'); @@ -34,10 +35,11 @@ INSERT INTO vars (name, value, description) VALUES ('tags_urls_neg_tags', 'minus|binspam', '| separated list of tags applied which negatively affect url popularity'); INSERT INTO vars (name, value, description) VALUES ('tags_userfrac_read', '1', 'Fraction (0.0-1.0) of user UIDs which are allowed to read tags, if tags_*_allow* is set that way'); INSERT INTO vars (name, value, description) VALUES ('tags_userfrac_write', '0.95', 'Fraction (0.0-1.0) of user UIDs which are allowed to tag, if tags_*_allow* is set that way'); +INSERT INTO vars (name, value, description) VALUES ('tags_usershow_cutoff', '200', 'More tags than this, and instead of showing the full taglist /~user/tags will show the list of tagnames'); INSERT INTO vars (name, value, description) VALUES ('tags_tagname_regex', '^\!?[a-z][a-z0-9/]{0,63}$', 'Regex that tag names must conform to'); +INSERT INTO vars (name, value, description) VALUES ('tags_updateclouts_debuguids', '', 'UIDs to print debug info on during clout recalculation'); INSERT INTO vars (name, value, description) VALUES ('tags_upvote_tagname', 'nod', 'Tag for upvote'); INSERT INTO vars (name, value, description) VALUES ('tags_downvote_tagname', 'nix', 'Tag for downvote'); -INSERT INTO vars (name, value, description) VALUES ('tags_negative_tagnames', 'nix,dupe,whocares', 'Negative tags (comma separated)'); INSERT INTO vars (name, value, description) VALUES ('tags_viewed_tagname', 'viewed', 'Tagname to assign to stories and other items a user has viewed'); INSERT INTO ajax_ops VALUES (NULL, 'tags_get_user_story', 'Slash::Tags', 'ajaxGetUserStory', 'ajax_tags_write', 'createuse'); Modified: slashjp/branches/upstream/current/plugins/Tags/tags.pl =================================================================== --- slashjp/branches/upstream/current/plugins/Tags/tags.pl 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/plugins/Tags/tags.pl 2008-04-06 23:11:14 UTC (rev 569) @@ -2,7 +2,7 @@ # This code is a part of Slash, and is released under the GPL. # Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: tags.pl,v 1.10 2007/09/26 21:25:51 jamiemccarthy Exp $ +# $Id: tags.pl,v 1.13 2008/04/03 22:06:52 jamiemccarthy Exp $ use strict; use Slash; @@ -35,11 +35,11 @@ : 'active'; if ($type eq 'all') { - $index_hr->{tagnames} = $tags_reader->listTagnamesAll('describe'); + $index_hr->{tagnames} = $tags_reader->listTagnamesAll(); } elsif ($type eq 'active') { - $index_hr->{tagnames} = $tags_reader->listTagnamesActive('describe'); + $index_hr->{tagnames} = $tags_reader->listTagnamesActive(); } else { # recent - $index_hr->{tagnames} = $tags_reader->listTagnamesRecent('describe'); + $index_hr->{tagnames} = $tags_reader->listTagnamesRecent(); } $title = getData('head1'); @@ -61,7 +61,7 @@ @objects = @$value; #print STDERR "tags.pl got '$mcdkey$tagname' as " . scalar(@objects) . " objects\n"; } else { - my $objects = $tags_reader->getAllObjectsTagname($tagname, 'describe'); + my $objects = $tags_reader->getAllObjectsTagname($tagname); my %globjids = ( map { ( $_->{globjid}, 1 ) } @$objects ); my $mintc = defined($constants->{tags_list_mintc}) ? $constants->{tags_list_mintc} : 4; for my $globjid (keys %globjids) { @@ -73,12 +73,18 @@ push @objects, { url => $objs[0]{url}, title => $objs[0]{title}, - count => $sum_tc, + clout => $sum_tc, } if $sum_tc >= $mintc; } - @objects = sort { $b->{count} <=> $a->{count} || ($a->{title}||'') cmp ($b->{title}||'') } @objects; + @objects = sort { + $b->{clout} <=> $a->{clout} + || ($a->{title}||'') cmp ($b->{title}||'') + } @objects; + my $max_display = $constants->{tags_active_maxshow} || 200; + if (scalar @objects > $max_display) { + $#objects = $max_display-1; + } if ($mcd) { - my $constants = getCurrentStatic(); my $secs = $constants->{memcached_exptime_tags_brief} || 300; $mcd->set("$mcdkey$tagname", \@objects, $secs); #print STDERR "tags.pl set '$mcdkey$tagname' to " . scalar(@objects) . " objects\n"; Modified: slashjp/branches/upstream/current/plugins/Tags/templates/usertaghistory;users;default =================================================================== --- slashjp/branches/upstream/current/plugins/Tags/templates/usertaghistory;users;default 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/plugins/Tags/templates/usertaghistory;users;default 2008-04-06 23:11:14 UTC (rev 569) @@ -24,7 +24,7 @@ [% IF tag.globj_type == "stories" %] [% PROCESS linkStory dynamic=1 sid=tag.story.sid text=tag.story.title title=tag.story.title %] [% ELSIF tag.globj_type == "urls" %] - [% tag.url.bookmark.title || tag.url.validtitle || tag.url.initialtitle | strip_literal %] + [% tag.url.bookmark.title || tag.url.validtitle || tag.url.initialtitle | strip_literal %] [% ELSIF tag.globj_type == "journals" %] [% nick = Slash.db.getUser(tag.journal.uid, 'nickname') %] [% tag.journal.description | strip_literal %] @@ -42,4 +42,4 @@ __seclev__ 10000 __version__ -$Id: usertaghistory;users;default,v 1.3 2007/04/04 19:09:08 tvroom Exp $ +$Id: usertaghistory;users;default,v 1.4 2008/04/02 15:27:13 jamiemccarthy Exp $ Added: slashjp/branches/upstream/current/plugins/Tags/templates/usertagnames;users;default =================================================================== --- slashjp/branches/upstream/current/plugins/Tags/templates/usertagnames;users;default (rev 0) +++ slashjp/branches/upstream/current/plugins/Tags/templates/usertagnames;users;default 2008-04-06 23:11:14 UTC (rev 569) @@ -0,0 +1,43 @@ +__section__ +default +__description__ +useredit = user whose tags are being displayed +user_submenu = html text of user submenu, if any +tagnames = array of tagnames + +This template and its API will likely change. + +__title__ + +__page__ +users +__lang__ +en_US +__name__ +usertagnames +__template__ +[% thisnickname = useredit.nickname | strip_literal; + url_nick = useredit.nickname | strip_paramattr; + url_base = "$gSkin.rootdir/~$url_nick/"; + uid = useredit.uid; + title = "Tags by $thisnickname ($uid)"; + PROCESS user_titlebar tab_selected='tags' %] + +[% IF user.tags_canread_stories && tagnames.size %] +
    Select
    Thumb
    Click to
    add to body
    Select
    Thumb
    Click to
    add to body
    Click to add
    to media
    + [% IF mfile.filetype == "image" %] + + [% ELSE %] + Add [% filename %] + [% END %] +
    [% author_info.$author.nickname %]
    Non-Admins
    [% author.nickname %][% cnt %] of [% num_stories %] [% IF cnt > 0 %] - [% avg_time = author_info.$author.$days.tot_time / cnt %] + [% avg_time = author.$days.tot_time / cnt %] [% avg_time.int %] m [% ELSE %] N/A Modified: slashjp/trunk/plugins/Ajax/PLUGIN =================================================================== --- slashjp/trunk/plugins/Ajax/PLUGIN 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/plugins/Ajax/PLUGIN 2008-04-01 04:03:21 UTC (rev 563) @@ -28,7 +28,7 @@ htdoc=htdocs/images/slashbox.js htdoc=htdocs/images/common.js htdoc=htdocs/images/nodnix.js -htdoc=htdocs/images/prototype.js +htdoc=htdocs/images/jquery-1.2.3.js htdoc=htdocs/images/sectionprefs.js requiresplugin=ResKey template=templates/ajax_reskey_signoff;misc;default Modified: slashjp/trunk/plugins/Ajax/htdocs/ajax.pl =================================================================== --- slashjp/trunk/plugins/Ajax/htdocs/ajax.pl 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/plugins/Ajax/htdocs/ajax.pl 2008-04-01 04:03:21 UTC (rev 563) @@ -54,6 +54,8 @@ # print STDERR "AJAX5 $$: $user->{uid}, $op\n"; + my $options = {}; + if ($reskey_name ne 'NA') { my $reskey = getObject('Slash::ResKey'); my $rkey = $reskey->key($reskey_name); @@ -61,6 +63,7 @@ print STDERR scalar(localtime) . " ajax.pl main no rkey for op='$op' name='$reskey_name'\n"; return; } + $options->{rkey} = $rkey; if ($ops->{$op}{reskey_type} eq 'createuse') { $rkey->createuse; } elsif ($ops->{$op}{reskey_type} eq 'touch') { @@ -85,7 +88,6 @@ } # print STDERR "AJAX6 $$: $user->{uid}, $op\n"; - my $options = {}; my $retval = $ops->{$op}{function}->( $slashdb, $constants, $user, $form, $options ); @@ -273,6 +275,23 @@ my $pid = $form->{pid} || 0; my $sid = $form->{sid} or return; + $user->{state}{ajax_accesslog_op} = 'comments_submit_reply'; + + my($error_message, $saved_comment); + my $discussion = $slashdb->getDiscussion($sid); + my $comment = preProcessComment($form, $user, $discussion, \$error_message); + if (!$error_message) { + $options->{rkey}->use or $error_message = $options->{rkey}->errstr; + } + $saved_comment = saveComment($form, $comment, $user, $discussion, \$error_message) + unless $error_message; + my $cid = $saved_comment && $saved_comment ne '-1' ? $saved_comment->{cid} : 0; + + $options->{content_type} = 'application/json'; + my %to_dump = ( cid => $cid, error => $error_message ); +#use Data::Dumper; print STDERR Dumper \%to_dump; + + return Data::JavaScript::Anon->anon_dump(\%to_dump); } sub previewReply { @@ -282,14 +301,24 @@ $user->{state}{ajax_accesslog_op} = 'comments_preview_reply'; + my($error_message, $preview, $html); my $discussion = $slashdb->getDiscussion($sid); - my $comment = preProcessComment($form, $user, $discussion); - my $preview = postProcessComment({ %$comment, %$user }, 0, $discussion); - my $html = prevComment($preview, $user); + my $comment = preProcessComment($form, $user, $discussion, \$error_message); + if ($comment && $comment ne '-1') { + $preview = postProcessComment({ %$comment, %$form, %$user }, 0, $discussion); + $html = prevComment($preview, $user); + } - + $error_message ||= 'This comment will not be saved until you click the Submit button below.'; $options->{content_type} = 'application/json'; - my %to_dump = (html => { "replyto_preview_$pid" => $html }); + my %to_dump = ( + error => $error_message, + ); + $to_dump{html} = { "replyto_preview_$pid" => $html } if $html; + $to_dump{eval_first} = "\$('gotmodwarning_$pid').value = 1;" + if $form->{gotmodwarning} || ($error_message && $error_message eq + Slash::Utility::Comments::getError("moderations to be lost") + ); #use Data::Dumper; print STDERR Dumper \%to_dump; return Data::JavaScript::Anon->anon_dump(\%to_dump); @@ -304,8 +333,10 @@ $user->{state}{ajax_accesslog_op} = 'comments_reply_form'; my($reply, $pid_reply); + my $discussion = $slashdb->getDiscussion($sid); $reply = $slashdb->getCommentReply($sid, $pid) if $pid; $pid_reply = prepareQuoteReply($reply) if $pid && $reply; + preProcessReplyForm($form, $reply); my $reskey = getObject('Slash::ResKey'); my $rkey = $reskey->key('comments', { nostate => 1 }); @@ -314,10 +345,11 @@ my %to_dump; if ($rkey->success) { my $reply_html = slashDisplay('edit_comment', { - sid => $sid, - pid => $pid, - reply => $reply, - rkey => $rkey + discussion => $discussion, + sid => $sid, + pid => $pid, + reply => $reply, + rkey => $rkey }, { Return => 1 }); %to_dump = (html => { "replyto_$pid" => $reply_html }); } else { @@ -326,7 +358,6 @@ $options->{content_type} = 'application/json'; $to_dump{eval_first} = "comment_body_reply[$pid] = '$pid_reply';" if $pid_reply; - #use Data::Dumper; print STDERR Dumper \%to_dump; return Data::JavaScript::Anon->anon_dump(\%to_dump); @@ -711,6 +742,22 @@ { Page => 'misc', Skin => 'idle', Return => 1 } ); + } elsif ($form->{'section'} eq 'modcommentlog') { + my $moddb = getObject("Slash::$constants->{m1_pluginname}"); + if ($moddb) { + # we hijack "tabbed" as our cid -- pudge + return $moddb->dispModCommentLog('cid', $form->{'tabbed'}, { + show_m2s => ($constants->{m2} + ? (defined($form->{show_m2s}) + ? $form->{show_m2s} + : $user->{m2_with_comm_mod} + ) : 0), + need_m2_form => $constants->{m2}, + need_m2_button => $constants->{m2}, + title => " " + }); + } + } else { return @@ -731,7 +778,7 @@ my $url = URI->new('//e.a/?' . $form->{'data'}); my %params = $url->query_form; - # D2 display + # D2 display my $user_edits_table; if ($params{'formname'} eq 'd2_display') { $user_edits_table = { @@ -744,7 +791,7 @@ }; } - # D2 posting + # D2 posting if ($params{'formname'} eq 'd2_posting') { $user_edits_table = { emaildisplay => $params{'emaildisplay'} || undef, @@ -758,7 +805,17 @@ }; } - # Messages + # Messages + if ($params{'formname'} eq 'metamoderate') { + if ($constants->{m2} && $user->{is_admin}) { + # metaModerate uses $form ... whether it should or not! -- pudge + @$form{keys %params} = values %params; + my $metamod_db = getObject('Slash::Metamod'); + $metamod_db->metaModerate($user->{is_admin}) if $metamod_db; + } + } + + # Messages if ($params{'formname'} eq 'messages') { my $messages = getObject('Slash::Messages'); my $messagecodes = $messages->getDescriptions('messagecodes'); @@ -1043,9 +1100,9 @@ my %mainops = ( comments_submit_reply => { - function => \&previewReply, + function => \&submitReply, reskey_name => 'comments', - reskey_type => 'use', + reskey_type => 'touch', }, comments_preview_reply => { function => \&previewReply, Modified: slashjp/trunk/plugins/Ajax/htdocs/images/admin.js =================================================================== --- slashjp/trunk/plugins/Ajax/htdocs/images/admin.js 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/plugins/Ajax/htdocs/images/admin.js 2008-04-01 04:03:21 UTC (rev 563) @@ -1,7 +1,7 @@ // $Id$ function um_ajax(the_behaviors, the_events) { - var params =[]; + var params = {}; params['op'] = 'um_ajax'; params['behaviors'] = the_behaviors; params['events'] = the_events; @@ -9,32 +9,20 @@ } function um_fetch_settings() { - var params =[]; + var params = {}; params['op'] = 'um_fetch_settings'; ajax_update(params, 'links-vendors-content'); } function um_set_settings(behavior) { - var params =[]; + var params = {}; params['op'] = 'um_set_settings'; params['behavior'] = behavior; ajax_update(params, 'links-vendors-content'); } -function admin_signoff(stoid, type, id) { - var params = []; - var reskeyel = $('signoff-reskey-' + stoid); - params['op'] = 'admin_signoff'; - params['stoid'] = stoid; - params['reskey'] = reskeyel.value; - ajax_update(params, 'signoff_' + stoid); - if (type == "firehose") { - firehose_collapse_entry(id); - } -} - function admin_neverdisplay(stoid, type, fhid) { - var params = []; + var params = {}; params['op'] = 'admin_neverdisplay'; params['reskey'] = reskey_static; params['stoid'] = stoid; @@ -48,22 +36,22 @@ } function admin_submit_memory(fhid) { - var params = []; + var params = {}; params['op'] = 'admin_submit_memory'; params['reskey'] = reskey_static; - params['submatch'] = $('submatch-'+fhid).value; - params['subnote'] = $('subnote-'+fhid).value; + params['submatch'] = $dom('submatch-'+fhid).value; + params['subnote'] = $dom('subnote-'+fhid).value; ajax_update(params, 'sub_mem_message-'+fhid); } function adminTagsCommands(id, type) { - var toggletags_message_id = 'toggletags-message-' + id; - var toggletags_message_el = $(toggletags_message_id); + var toggletags_message_id = '#toggletags-message-' + id; + var toggletags_message_el = jQuery(toggletags_message_id)[0]; if (toggletags_message_el) { toggletags_message_el.innerHTML = 'Executing commands...'; } - var params = []; + var params = {}; type = type || "stories"; params['op'] = 'tags_admin_commands'; if (type == "stories") { @@ -74,9 +62,9 @@ params['id'] = id; } params['type'] = type; - var tags_admin_commands_el = $('tags_admin_commands-' + id); + var tags_admin_commands_el = $dom('tags_admin_commands-' + id); params['commands'] = tags_admin_commands_el.value; - var reskeyel = $('admin_commands-reskey-' + id); + var reskeyel = $dom('admin_commands-reskey-' + id); params['reskey'] = reskeyel.value; ajax_update(params, 'tags-admin-' + id); @@ -84,7 +72,7 @@ } function tagsHistory(id, type) { - var params = []; + var params = {}; type = type || "stories"; params['type'] = type; params['op'] = 'tags_history'; @@ -103,17 +91,17 @@ } function remarks_create() { - var reskey = $('remarks_reskey'); - var remark = $('remarks_new'); + var reskey = $dom('remarks_reskey'); + var remark = $dom('remarks_new'); if (!remark || !remark.value || !reskey || !reskey.value) { return false; } - var params = []; + var params = {}; params['op'] = 'remarks_create'; params['remark'] = remark.value; params['reskey'] = reskey.value; - remarks_max = $('remarks_max'); + remarks_max = $dom('remarks_max'); if (remarks_max && remarks_max.value) { params['limit'] = remarks_max.value; } @@ -121,7 +109,7 @@ } function remarks_fetch(secs, limit) { - var params = []; + var params = {}; params['op'] = 'remarks_fetch'; params['limit'] = limit; // run it every 30 seconds; don't need to call again @@ -129,7 +117,7 @@ } function remarks_popup() { - var params = []; + var params = {}; params['op'] = 'remarks_config'; var title = "Remarks Config "; var buttons = createPopupButtons('[X]'); @@ -140,11 +128,11 @@ } function remarks_config_save() { - var params = []; - var reskey = $('remarks_reskey'); - var min_priority = $('remarks_min_priority'); - var limit = $('remarks_limit'); - var filter = $('remarks_filter'); + var params = {}; + var reskey = $dom('remarks_reskey'); + var min_priority = $dom('remarks_min_priority'); + var limit = $dom('remarks_limit'); + var filter = $dom('remarks_filter'); params['op'] = 'remarks_config_save'; if (!reskey && !reskey.value) { return false; @@ -158,7 +146,7 @@ if (filter) { params['filter'] = filter.value; } - var message = $('remarksconfig-message'); + var message = $dom('remarksconfig-message'); if (message) { message.innerHTML = "Saving..."; } @@ -166,31 +154,31 @@ } function admin_slashdbox_fetch(secs) { - var params = []; + var params = {}; params['op'] = 'admin_slashdbox'; ajax_periodic_update(secs, params, "slashdbox-content"); } function admin_perfbox_fetch(secs) { - var params = []; + var params = {}; params['op'] = 'admin_perfbox'; ajax_periodic_update(secs, params, "performancebox-content"); } function admin_authorbox_fetch(secs) { - var params = []; + var params = {}; params['op'] = 'admin_authorbox'; ajax_periodic_update(secs, params, "authoractivity-content"); } function admin_storyadminbox_fetch(secs) { - var params = []; + var params = {}; params['op'] = 'admin_storyadminbox'; ajax_periodic_update(secs, params, "storyadmin-content"); } function admin_recenttagnamesbox_fetch(secs) { - var params = []; + var params = {}; params['op'] = 'admin_recenttagnamesbox'; ajax_periodic_update(secs, params, "recenttagnames-content"); } @@ -202,7 +190,7 @@ return; } - var params = []; + var params = {}; params['op'] = 'console_update' var handlers = { onComplete: json_handler @@ -216,11 +204,11 @@ } function firehose_usage() { - var params = []; + var params = {}; params['op'] = 'firehose_usage' var interval = 300000; ajax_update(params, 'firehose_usage-content'); - setTimeout("firehose_usage()", interval); + setTimeout(firehose_usage, interval); } function make_spelling_correction(misspelled_word, form_element) { @@ -234,7 +222,7 @@ // Either learning a word or making a correction. if (selected_index >= 1) { if (selected_index == 1) { - var params = []; + var params = {}; params['op'] = 'admin_learnword'; params['word'] = misspelled_word; ajax_update(params); @@ -265,8 +253,8 @@ } function firehose_reject (el) { - var params = []; - var fh = $('firehose-' + el.value); + var params = {}; + var fh = $dom('firehose-' + el.value); params['op'] = 'firehose_reject'; params['id'] = el.value; params['reskey'] = reskey_static; @@ -275,19 +263,19 @@ } function firehose_open_note(id) { - var nf = $('note-form-'+id); - var nt = $('note-text-'+id); - var ni = $('note-input-'+id); + var nf = $dom('note-form-'+id); + var nt = $dom('note-text-'+id); + var ni = $dom('note-input-'+id); nf.className=""; ni.focus(); nt.className="hide"; } function firehose_save_note(id) { - var nf = $('note-form-'+id); - var nt = $('note-text-'+id); - var ni = $('note-input-'+id); - var params = []; + var nf = $dom('note-form-'+id); + var nt = $dom('note-text-'+id); + var ni = $dom('note-input-'+id); + var params = {}; params['op'] = 'firehose_save_note'; params['note'] = ni.value; params['id'] = id; @@ -297,30 +285,43 @@ } function firehose_get_admin_extras(id) { - var params=[]; + var params = {}; params['id'] = id; params['op'] = 'firehose_get_admin_extras'; var handlers = { - onComplete: json_handler + onComplete: function(transport) { + json_handler(transport); + if (firehoseIsInWindow(id)) { + scrollToWindowFirehose(id); + } + } }; ajax_update(params, '', handlers); } function firehose_get_and_post(id) { - var params=[]; + var params = {}; params['id'] = id; params['op'] = 'firehose_get_form'; firehose_collapse_entry(id); var handlers = { - onComplete: function() { $('postform-'+id).submit();} + onComplete: function() { $dom('postform-'+id).submit();} }; ajax_update(params, 'postform-'+id, handlers); } function appendToBodytext(text) { - var obj = $('admin-bodytext'); + var obj = $dom('admin-bodytext'); if (obj) { obj.className = "show"; obj.value = obj.value + text; } } + +function appendToMedia(text) { + var obj = $dom('admin-media'); + if (obj) { + obj.className = "show"; + obj.value = obj.value + text; + } +} Modified: slashjp/trunk/plugins/Ajax/htdocs/images/common.js =================================================================== --- slashjp/trunk/plugins/Ajax/htdocs/images/common.js 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/plugins/Ajax/htdocs/images/common.js 2008-04-01 04:03:21 UTC (rev 563) @@ -1,6 +1,10 @@ // _*_ Mode: JavaScript; tab-width: 8; indent-tabs-mode: true _*_ // $Id$ +function $dom( id ) { + return document.getElementById(id); +} + // global settings, but a firehose might use a local settings object instead var firehose_settings = {}; firehose_settings.startdate = ''; @@ -25,6 +29,8 @@ firehose_removals = null; firehose_future = null; + var firehose_cur = 0; + // globals we haven't yet decided to move into |firehose_settings| var fh_play = 0; var fh_is_timed_out = 0; @@ -43,9 +49,6 @@ var is_ie = ua.match("/MSIE/"); -// eventually add site specific constants like this to a separate .js -var sitename = "Slashdot"; - function createPopup(xy, titlebar, name, contents, message, onmouseout) { var body = document.getElementsByTagName("body")[0]; var div = document.createElement("div"); @@ -88,7 +91,7 @@ } function closePopup(id, refresh) { - var el = $(id); + var el = $dom(id); if (el) { el.parentNode.removeChild(el); } @@ -131,8 +134,9 @@ } function getXYForId(id, addWidth, addHeight) { - var div = $(id); - var xy = Position.cumulativeOffset(div); + var div = $dom(id); + var offset = jQuery(div).offset(); + var xy = [ offset.left, offset.top ]; if (addWidth) { xy[0] = xy[0] + div.offsetWidth; } @@ -143,7 +147,7 @@ } function firehose_toggle_advpref() { - var obj = $('fh_advprefs'); + var obj = $dom('fh_advprefs'); if (obj.className == 'hide') { obj.className = ""; } else { @@ -152,12 +156,12 @@ } function firehose_open_prefs() { - var obj = $('fh_advprefs'); + var obj = $dom('fh_advprefs'); obj.className = ""; } function toggleId(id, first, second) { - var obj =$(id); + var obj = $dom(id); if (obj.className == first) { obj.className = second; } else if (obj.className == second) { @@ -168,8 +172,8 @@ } function toggleIntro(id, toggleid) { - var obj = $(id); - var toggle = $(toggleid); + var obj = $dom(id); + var toggle = $dom(toggleid); if (obj.className == 'introhide') { obj.className = "intro" toggle.innerHTML = "[-]"; @@ -183,7 +187,7 @@ function tagsToggleStoryDiv(id, is_admin, type) { var bodyid = 'toggletags-body-' + id; - var tagsbody = $(bodyid); + var tagsbody = $dom(bodyid); if (tagsbody.className == 'tagshide') { tagsShowBody(id, is_admin, '', type); } else { @@ -194,22 +198,22 @@ function tagsHideBody(id) { // Make the body of the tagbox vanish var tagsbodyid = 'toggletags-body-' + id; - var tagsbody = $(tagsbodyid); + var tagsbody = $dom(tagsbodyid); tagsbody.className = "tagshide" // Make the title of the tagbox change back to regular var titleid = 'tagbox-title-' + id; - var title = $(titleid); + var title = $dom(titleid); title.className = "tagtitleclosed"; // Make the tagbox change back to regular. var tagboxid = 'tagbox-' + id; - var tagbox = $(tagboxid); + var tagbox = $dom(tagboxid); tagbox.className = "tags"; // Toggle the button back. var tagsbuttonid = 'toggletags-button-' + id; - var tagsbutton = $(tagsbuttonid); + var tagsbutton = $dom(tagsbuttonid); tagsbutton.innerHTML = "[+]"; } @@ -228,35 +232,35 @@ // Toggle the button to show the click was received var tagsbuttonid = 'toggletags-button-' + id; - var tagsbutton = $(tagsbuttonid); + var tagsbutton = $dom(tagsbuttonid); tagsbutton.innerHTML = "[-]"; // Make the tagbox change to the slashbox class var tagboxid = 'tagbox-' + id; - var tagbox = $(tagboxid); + var tagbox = $dom(tagboxid); tagbox.className = "tags"; // Make the title of the tagbox change to white-on-green var titleid = 'tagbox-title-' + id; - var title = $(titleid); + var title = $dom(titleid); title.className = "tagtitleopen"; // Make the body of the tagbox visible var tagsbodyid = 'toggletags-body-' + id; - var tagsbody = $(tagsbodyid); + var tagsbody = $dom(tagsbodyid); tagsbody.className = "tagbody"; // If the tags-user div hasn't been filled, fill it. var tagsuserid = 'tags-user-' + id; - var tagsuser = $(tagsuserid); + var tagsuser = $dom(tagsuserid); if (tagsuser.innerHTML == "") { // The tags-user-123 div is empty, and needs to be // filled with the tags this user has already // specified for this story, and a reskey to allow // the user to enter more tags. tagsuser.innerHTML = "Retrieving..."; - var params = []; + var params = {}; if (type == "stories") { params['op'] = 'tags_get_user_story'; params['sidenc'] = id; @@ -272,7 +276,7 @@ var handlers = { onComplete: function() { var textid = 'newtags-' + id; - var input = $(textid); + var input = $dom(textid); input.focus(); } } @@ -287,7 +291,7 @@ // user is not actually an admin. if (is_admin) { var tagsadminid = 'tags-admin-' + id; - params = []; + params = {}; if (type == "stories") { params['op'] = 'tags_get_admin_story'; params['sidenc'] = id; @@ -308,7 +312,7 @@ // We can't do that by passing it in, so do it // manually now. var textinputid = 'newtags-' + id; - var textinput = $(textinputid); + var textinput = $dom(textinputid); textinput.value = textinput.value + ' ' + newtagspreloadtext; textinput.focus(); } @@ -382,12 +386,12 @@ } function createTag(tag, id, type) { - var params = []; + var params = {}; params['id'] = id; params['type'] = type; if ( fh_is_admin && ("_#)^*".indexOf(tag[0]) != -1) ) { params['op'] = 'tags_admin_commands'; - params['reskey'] = $('admin_commands-reskey-' + id).value; + params['reskey'] = $dom('admin_commands-reskey-' + id).value; params['command'] = tag; } else { params['op'] = 'tags_create_tag'; @@ -402,15 +406,15 @@ function tagsCreateForStory(id) { var toggletags_message_id = 'toggletags-message-' + id; - var toggletags_message_el = $(toggletags_message_id); + var toggletags_message_el = $dom(toggletags_message_id); toggletags_message_el.innerHTML = 'Saving tags...'; - var params = []; + var params = {}; params['op'] = 'tags_create_for_story'; params['sidenc'] = id; - var newtagsel = $('newtags-' + id); + var newtagsel = $dom('newtags-' + id); params['tags'] = newtagsel.value; - var reskeyel = $('newtags-reskey-' + id); + var reskeyel = $dom('newtags-reskey-' + id); params['reskey'] = reskeyel.value; ajax_update(params, 'tags-user-' + id); @@ -421,15 +425,15 @@ function tagsCreateForUrl(id) { var toggletags_message_id = 'toggletags-message-' + id; - var toggletags_message_el = $(toggletags_message_id); + var toggletags_message_el = $dom(toggletags_message_id); toggletags_message_el.innerHTML = 'Saving tags...'; - var params = []; + var params = {}; params['op'] = 'tags_create_for_url'; params['id'] = id; - var newtagsel = $('newtags-' + id); + var newtagsel = $dom('newtags-' + id); params['tags'] = newtagsel.value; - var reskeyel = $('newtags-reskey-' + id); + var reskeyel = $dom('newtags-reskey-' + id); params['reskey'] = reskeyel.value; ajax_update(params, 'tags-user-' + id); @@ -440,7 +444,7 @@ //Firehose functions begin function setOneTopTagForFirehose(id, newtag) { - var params = []; + var params = {}; params['op'] = 'firehose_update_one_tag'; params['id'] = id; params['tags'] = newtag; @@ -450,15 +454,15 @@ function tagsCreateForFirehose(id) { var toggletags_message_id = 'toggletags-message-' + id; - var toggletags_message_el = $(toggletags_message_id); + var toggletags_message_el = $dom(toggletags_message_id); toggletags_message_el.innerHTML = 'Saving tags...'; - var params = []; + var params = {}; params['op'] = 'tags_create_for_firehose'; params['id'] = id; - var newtagsel = $('newtags-' + id); + var newtagsel = $dom('newtags-' + id); params['tags'] = newtagsel.value; - var reskeyel = $('newtags-reskey-' + id); + var reskeyel = $dom('newtags-reskey-' + id); params['reskey'] = reskeyel.value; ajax_update(params, 'tags-user-' + id); @@ -466,16 +470,19 @@ } function toggle_firehose_body(id, is_admin) { - var params = []; + var params = {}; setFirehoseAction(); params['op'] = 'firehose_fetch_text'; params['id'] = id; - var fhbody = $('fhbody-'+id); - var fh = $('firehose-'+id); + var fhbody = $dom('fhbody-'+id); + var fh = $dom('firehose-'+id); var usertype = fh_is_admin ? " adminmode" : " usermode"; if (fhbody.className == "empty") { var handlers = { - onComplete: function() { + onComplete: function() { + if(firehoseIsInWindow(id)) { + scrollToWindowFirehose(id); + } firehose_get_admin_extras(id); } }; @@ -503,7 +510,7 @@ } function toggleFirehoseTagbox(id) { - var fhtb = $('fhtagbox-'+id); + var fhtb = $dom('fhtagbox-'+id); if (fhtb.className == "hide") { fhtb.className = "tagbox"; } else { @@ -521,7 +528,7 @@ ["mode", "full", "abbrev", "full", "fulltitle"], ["mode", "fulltitle", "full", "abbrev", "full"] ]; - var params = []; + var params = {}; params['op'] = 'firehose_set_options'; params['reskey'] = reskey_static; var theForm = document.forms["firehoseform"]; @@ -548,7 +555,7 @@ } if (classname) { - var els = document.getElementsByClassName(classname, $('firehoselist')); + var els = document.getElementsByClassName(classname, $dom('firehoselist')); var classval = classname; if (value) { classval = classval + " hide"; @@ -572,12 +579,12 @@ var el = pairs[i]; if (name == el[0] && value == el[1]) { firehose_settings[name] = value; - if ($(el[2])) { - $(el[2]).id = el[3]; - if($(el[3])) { + if ($dom(el[2])) { + $dom(el[2]).id = el[3]; + if($dom(el[3])) { var namenew = el[0]; var valuenew = el[4]; - $(el[3]).firstChild.onclick = function() { firehose_set_options(namenew, valuenew); return false;} + $dom(el[3]).firstChild.onclick = function() { firehose_set_options(namenew, valuenew); return false;} } } } @@ -587,7 +594,7 @@ if (name == "mode") { fh_view_mode = value; } - if ($('firehoselist')) { + if ($dom('firehoselist')) { // set page page = 0; @@ -598,12 +605,12 @@ var myAnim = new YAHOO.util.Anim("firehoselist", attributes); myAnim.duration = 1; myAnim.onComplete.subscribe(function() { - $('firehoselist').style.opacity = "1"; + $dom('firehoselist').style.opacity = "1"; }); myAnim.animate(); } // remove elements - setTimeout("firehose_remove_all_items()", 600); + setTimeout(firehose_remove_all_items, 600); } } } @@ -623,11 +630,11 @@ firehose_settings.page = 0; var issuedate = firehose_settings.issue.substr(5,2) + "/" + firehose_settings.issue.substr(8,2) + "/" + firehose_settings.issue.substr(10,2); - if ($('fhcalendar')) { - $('fhcalendar')._widget.setDate(issuedate, "day"); + if ($dom('fhcalendar')) { + $dom('fhcalendar')._widget.setDate(issuedate, "day"); } - if ($('fhcalendar_pag')) { - $('fhcalendar_pag')._widget.setDate(issuedate, "day"); + if ($dom('fhcalendar_pag')) { + $dom('fhcalendar_pag')._widget.setDate(issuedate, "day"); } } if (name == "color") { @@ -662,7 +669,7 @@ } function firehose_remove_all_items() { - var fhl = $('firehoselist'); + var fhl = $dom('firehoselist'); var children = fhl.childNodes; for (var i = children.length -1 ; i >= 0; i--) { var el = children[i]; @@ -677,7 +684,7 @@ if (!check_logged_in()) return; setFirehoseAction(); - var params = []; + var params = {}; var handlers = { onComplete: json_handler }; @@ -685,7 +692,7 @@ params['id'] = id; params['reskey'] = reskey_static; params['dir'] = dir; - var updown = $('updown-' + id); + var updown = $dom('updown-' + id); ajax_update(params, '', handlers); if (updown) { if (dir == "+") { @@ -702,7 +709,7 @@ function firehose_remove_tab(tabid) { setFirehoseAction(); - var params = []; + var params = {}; var handlers = { onComplete: json_handler }; @@ -718,39 +725,34 @@ // firehose functions end // helper functions -function ajax_update(params, onsucc, options, url) { - var h = $H(params); +function ajax_update(request_params, id, handlers, request_url) { + // make an ajax request to request_url with request_params, on success, + // update the innerHTML of the element with id - if (!url) - url = '/ajax.pl'; + var opts = { + url: request_url || '/ajax.pl', + data: request_params, + type: 'POST', + contentType: 'application/x-www-form-urlencoded', + }; - if (!options) - options = {}; + if ( id ) { + opts['success'] = function(html){ + jQuery('#'+id).html(html); + } + } - options.method = 'post'; - options.parameters = h.toQueryString(); + if ( handlers && handlers.onComplete ) { + opts['complete'] = handlers.onComplete; + } - var ajax = new Ajax.Updater( - { success: onsucc }, - url, - options - ); + jQuery.ajax(opts); } -function ajax_periodic_update(secs, params, onsucc, options, url) { - var h = $H(params); - - if (!url) - url = '/ajax.pl'; - - if (!options) - options = {}; - - options.frequency = secs; - options.method = 'post'; - options.parameters = h.toQueryString(); - - var ajax = new Ajax.PeriodicalUpdater({ success: onsucc }, url, options); +function ajax_periodic_update(interval_in_seconds, request_params, id, handlers, request_url) { + setInterval(function(){ + ajax_update(request_params, id, handlers, request_url); + }, interval_in_seconds*1000); } function eval_response(transport) { @@ -766,6 +768,7 @@ function json_handler(transport) { var response = eval_response(transport); json_update(response); + return response; } function json_update(response) { @@ -779,35 +782,35 @@ if (response.html) { for (el in response.html) { - if ($(el)) - $(el).innerHTML = response.html[el]; + if ($dom(el)) + $dom(el).innerHTML = response.html[el]; } } if (response.value) { for (el in response.value) { - if ($(el)) - $(el).value = response.value[el]; + if ($dom(el)) + $dom(el).value = response.value[el]; } } if (response.html_append) { for (el in response.html_append) { - if ($(el)) - $(el).innerHTML = $(el).innerHTML + response.html_append[el]; + if ($dom(el)) + $dom(el).innerHTML = $dom(el).innerHTML + response.html_append[el]; } } if (response.html_append_substr) { for (el in response.html_append_substr) { - if ($(el)) { - var this_html = $(el).innerHTML; - var i = $(el).innerHTML.search(/ ?<\/span>[\s\S]*$/i); + if ($dom(el)) { + var this_html = $dom(el).innerHTML; + var i = $dom(el).innerHTML.search(/ ?<\/span>[\s\S]*$/i); if (i == -1) { - $(el).innerHTML += response.html_append_substr[el]; + $dom(el).innerHTML += response.html_append_substr[el]; } else { - $(el).innerHTML = $(el).innerHTML.substr(0, i) + + $dom(el).innerHTML = $dom(el).innerHTML.substr(0, i) + response.html_append_substr[el]; } } @@ -830,16 +833,14 @@ var fh = 'firehose-' + el[1]; var wait_interval = 800; if(el[0] == "add") { - if (firehose_before[el[1]] && $('firehose-' + firehose_before[el[1]])) { - new Insertion.After('firehose-' + firehose_before[el[1]], el[2]); - - - } else if (firehose_after[el[1]] && $('firehose-' + firehose_after[el[1]])) { - new Insertion.Before('firehose-' + firehose_after[el[1]], el[2]); + if (firehose_before[el[1]] && jQuery('#firehose-' + firehose_before[el[1]]).size()) { + jQuery('#firehose-' + firehose_before[el[1]]).after(el[2]); + } else if (firehose_after[el[1]] && jQuery('#firehose-' + firehose_after[el[1]]).size()) { + jQuery('#firehose-' + firehose_after[el[1]]).before(el[2]); } else if (insert_new_at == "bottom") { - new Insertion.Bottom('firehoselist', el[2]); + jQuery('#firehoselist').append(el[2]); } else { - new Insertion.Top('firehoselist', el[2]); + jQuery('#firehoselist').prepend(el[2]); } var toheight = 50; @@ -871,8 +872,8 @@ } myAnim.onComplete.subscribe(function() { - if ($(fh)) { - $(fh).style.height = ""; + if ($dom(fh)) { + $dom(fh).style.height = ""; if (fh_use_jquery) { jQuery("#" + fh + " h3 a[class!='skin']").click( function(){ @@ -886,7 +887,7 @@ }); myAnim.animate(); } else if (el[0] == "remove") { - var fh_node = $(fh); + var fh_node = $dom(fh); if (fh_is_admin && fh_view_mode == "fulltitle" && fh_node && fh_node.className == "article" ) { // Don't delete admin looking at this in expanded view } else { @@ -919,7 +920,7 @@ }); myAnim.animate(); } else { - var elem = $(fh); + var elem = $dom(fh); wait_interval = 25; if (elem && elem.parentNode) { elem.parentNode.removeChild(elem); @@ -927,7 +928,7 @@ } } } - setTimeout("firehose_handle_update()", wait_interval); + setTimeout(firehose_handle_update, wait_interval); } else { firehose_reorder(); firehose_get_next_updates(); @@ -936,32 +937,28 @@ function firehose_reorder() { if (firehose_ordered) { - var fhlist = $('firehoselist'); + var fhlist = $dom('firehoselist'); if (fhlist) { var item_count = 0; for (i = 0; i < firehose_ordered.length; i++) { if (/^\d+$/.test(firehose_ordered[i])) { item_count++; } - var fhel = $('firehose-' + firehose_ordered[i]); + var fhel = $dom('firehose-' + firehose_ordered[i]); if (fhlist && fhel) { fhlist.appendChild(fhel); } if ( firehose_future[firehose_ordered[i]] ) { - if ($("ttype-" + firehose_ordered[i])) { - $("ttype-" + firehose_ordered[i]).className = "future"; + if ($dom("ttype-" + firehose_ordered[i])) { + $dom("ttype-" + firehose_ordered[i]).className = "future"; } } else { - if ($("ttype-" + firehose_ordered[i]) && $("ttype-" + firehose_ordered[i]).className == "future") { - $("ttype-" + firehose_ordered[i]).className = "story"; + if ($dom("ttype-" + firehose_ordered[i]) && $dom("ttype-" + firehose_ordered[i]).className == "future") { + $dom("ttype-" + firehose_ordered[i]).className = "story"; } } } - if (console_updating) { - document.title = sitename + " - Console (" + item_count + ")"; - } else { - document.title = sitename + " - Firehose (" + item_count + ")"; - } + document.title = "[% sitename %] - " + (console_updating ? "Console" : "Firehose") + " (" + item_count + ")"; } } @@ -971,13 +968,13 @@ var interval = getFirehoseUpdateInterval(); //alert("fh_get_next_updates"); fh_is_updating = 0; - firehose_add_update_timerid(setTimeout("firehose_get_updates()", interval)); + firehose_add_update_timerid(setTimeout(firehose_get_updates, interval)); } function firehose_get_updates_handler(transport) { - if ($('busy')) { - $('busy').className = "hide"; + if ($dom('busy')) { + $dom('busy').className = "hide"; } var response = eval_response(transport); var processed = 0; @@ -1008,7 +1005,7 @@ } function firehose_get_item_idstring() { - var fhl = $('firehoselist'); + var fhl = $dom('firehoselist'); var str = ""; var children; if (fhl) { @@ -1033,7 +1030,7 @@ options = options || {}; run_before_update(); if ((fh_play == 0 && !options.oneupdate) || fh_is_updating == 1) { - firehose_add_update_timerid(setTimeout("firehose_get_updates()", 2000)); + firehose_add_update_timerid(setTimeout(firehose_get_updates, 2000)); // alert("wait loop: " + fh_is_updating); return; } @@ -1042,7 +1039,7 @@ while(id = fh_update_timerids.pop()) { clearTimeout(id) }; } fh_is_updating = 1 - var params = []; + var params = {}; var handlers = { onComplete: firehose_get_updates_handler }; @@ -1058,8 +1055,8 @@ params['embed'] = 1; } params['fh_pageval'] = firehose_settings.pageval; - if ($('busy')) { - $('busy').className = ""; + if ($dom('busy')) { + $dom('busy').className = ""; } ajax_update(params, '', handlers); } @@ -1103,8 +1100,8 @@ var secs = getSecsSinceLastFirehoseAction(); if (secs > inactivity_timeout) { fh_is_timed_out = 1; - if ($('message_area')) - $('message_area').innerHTML = "¥µ¡¼¥Ð¤ÎÈ¿±þ¤¬Îɤ¯¤Ê¤¤¤Î¤Ç¼«Æ°¹¹¿·¤ÏÃÙ¤ì¤Þ¤¹"; + if ($dom('message_area')) + $dom('message_area').innerHTML = "¥µ¡¼¥Ð¤ÎÈ¿±þ¤¬Îɤ¯¤Ê¤¤¤Î¤Ç¼«Æ°¹¹¿·¤ÏÃÙ¤ì¤Þ¤¹"; //firehose_pause(); } } @@ -1113,15 +1110,15 @@ fh_play = 1; setFirehoseAction(); firehose_set_options('pause', '0'); - var pausepanel = $('pauseorplay'); - if ($('message_area')) - $('message_area').innerHTML = ""; + var pausepanel = $dom('pauseorplay'); + if ($dom('message_area')) + $dom('message_area').innerHTML = ""; if (pausepanel) { pausepanel.innerHTML = "¹¹¿·"; } - var pause = $('pause'); + var pause = $dom('pause'); - var play_div = $('play'); + var play_div = $dom('play'); if (play_div) { play_div.className = "hide"; } @@ -1130,14 +1127,18 @@ } } +function is_firehose_playing() { + return YAHOO.util.Dom.hasClass('play', 'hide'); +} + function firehose_pause() { fh_play = 0; - var pause = $('pause'); - var play_div = $('play'); + var pause = $dom('pause'); + var play_div = $dom('play'); pause.className = "hide"; play_div.className = "show"; - if ($('pauseorplay')) { - $('pauseorplay').innerHTML = "Ää»ß"; + if ($dom('pauseorplay')) { + $dom('pauseorplay').innerHTML = "Ää»ß"; } firehose_set_options('pause', '1'); } @@ -1147,8 +1148,8 @@ } function firehose_collapse_entry(id) { - var fhbody = $('fhbody-'+id); - var fh = $('firehose-'+id); + var fhbody = $dom('fhbody-'+id); + var fh = $dom('firehose-'+id); if (fhbody && fhbody.className == "body") { fhbody.className = "hide"; } @@ -1160,7 +1161,7 @@ } function firehose_remove_entry(id) { - var fh = $('firehose-' + id); + var fh = $dom('firehose-' + id); if (fh) { var attributes = { height: { to: 0 } @@ -1205,7 +1206,7 @@ fh_slider_init_set = 1; } var color = fh_colors[ newVal / fh_ticksize ]; - $('fh_slider_img').title = "Firehose filtered to " + color; + $dom('fh_slider_img').title = "Firehose filtered to " + color; if (fh_slider_init_set) { firehose_set_options("color", color) } @@ -1222,7 +1223,7 @@ function pausePopVendorStory(id) { vendor_popup_id=id; closePopup('vendorStory-26-popup'); - vendor_popup_timerids[id] = setTimeout("vendorStoryPopup()", 500); + vendor_popup_timerids[id] = setTimeout(vendorStoryPopup, 500); } function clearVendorPopupTimers() { @@ -1242,7 +1243,7 @@ } }; createPopup(getXYForId('sponsorlinks', 0, 0), title, "vendorStory-" + id, "Loading", "", closepopup ); - var params = []; + var params = {}; params['op'] = 'getTopVendorStory'; params['skid'] = id; ajax_update(params, "vendorStory-" + id + "-contents"); @@ -1251,7 +1252,7 @@ function pausePopVendorStory2(id) { vendor_popup_id=id; closePopup('vendorStory-26-popup'); - vendor_popup_timerids[id] = setTimeout("vendorStoryPopup2()", 500); + vendor_popup_timerids[id] = setTimeout(vendorStoryPopup2, 500); } function vendorStoryPopup2() { @@ -1267,14 +1268,14 @@ } }; createPopup(getXYForId('sponsorlinks2', 0, 0), title, "vendorStory-" + id, "Loading", "", closepopup ); - var params = []; + var params = {}; params['op'] = 'getTopVendorStory'; params['skid'] = id; ajax_update(params, "vendorStory-" + id + "-contents"); } function logToDiv(id, message) { - var div = $(id); + var div = $dom(id); if (div) { div.innerHTML = div.innerHTML + message + "
    "; } @@ -1282,19 +1283,19 @@ function firehose_open_tab(id) { - var tf = $('tab-form-'+id); - var tt = $('tab-text-'+id); - var ti = $('tab-input-'+id); + var tf = $dom('tab-form-'+id); + var tt = $dom('tab-text-'+id); + var ti = $dom('tab-input-'+id); tf.className=""; ti.focus(); tt.className="hide"; } function firehose_save_tab(id) { - var tf = $('tab-form-'+id); - var tt = $('tab-text-'+id); - var ti = $('tab-input-'+id); - var params = []; + var tf = $dom('tab-form-'+id); + var tt = $dom('tab-text-'+id); + var ti = $dom('tab-input-'+id); + var params = {}; var handlers = { onComplete: json_handler }; @@ -1375,8 +1376,8 @@ var modal_inst = 0; function init_modal_divs() { - modal_cover = $('modal_cover'); - modal_box = $('modal_box'); + modal_cover = $dom('modal_cover'); + modal_box = $dom('modal_box'); } function install_modal() { @@ -1392,7 +1393,7 @@ modal_cover.parentNode.removeChild(modal_cover); modal_box.parentNode.removeChild(modal_box); - var modal_parent = $('top_parent'); + var modal_parent = $dom('top_parent'); modal_parent.parentNode.insertBefore(modal_cover, modal_parent); modal_parent.parentNode.insertBefore(modal_box, modal_parent); modal_inst = 1; @@ -1423,12 +1424,12 @@ } function getModalPrefs(section, title, tabbed) { - document.getElementById('preference_title').innerHTML = title; - var params = []; + document.getElementById('preference_title').innerHTML = title; + var params = {}; params['op'] = 'getModalPrefs'; params['section'] = section; params['reskey'] = reskey_static; - params['tabbed'] = tabbed; + params['tabbed'] = tabbed; var handlers = {onComplete:show_modal_box}; ajax_update(params, 'modal_box_content', handlers); @@ -1436,21 +1437,21 @@ } function firehose_get_media_popup(id) { - if ($('preference_title')) { - $('preference_title').innerHTML = "Media"; + if ($dom('preference_title')) { + $dom('preference_title').innerHTML = "Media"; } - var params = []; + var params = {}; params['op'] = 'firehose_get_media'; params['id'] = id; show_modal_box(); - $('modal_box_content').innerHTML = "

    Loading...

    "; + $dom('modal_box_content').innerHTML = "

    Loading...

    "; ajax_update(params, 'modal_box_content'); } function saveModalPrefs() { - var params = []; + var params = {}; params['op'] = 'saveModalPrefs'; - params['data'] = Form.serialize(document.forms['modal_prefs']); + params['data'] = jQuery("#modal_prefs").serialize(); params['reskey'] = reskey_static; var handlers = { onComplete: function() { @@ -1473,7 +1474,7 @@ sep = ","; } - var params = []; + var params = {}; params['op'] = 'page_save_user_boxes'; params['reskey'] = reskey_static; params['bids'] = all; @@ -1496,14 +1497,14 @@ } function toggle_filter_prefs() { - var fps = $('filter_play_status'); - var fp = $('filter_prefs'); + var fps = $dom('filter_play_status'); + var fp = $dom('filter_prefs'); if (fps) { if (fps.className == "") { fps.className = "hide"; if (fp) { fp.className = ""; - setTimeout("firehose_slider_init()",500); + setTimeout(firehose_slider_init,500); } } else if (fps.className == "hide") { fps.className = ""; @@ -1514,3 +1515,126 @@ } } + +function admin_signoff(stoid, type, id) { + var params = []; + params['op'] = 'admin_signoff'; + params['stoid'] = stoid; + params['reskey'] = reskey_static; + ajax_update(params, 'signoff_' + stoid); + if (type == "firehose") { + firehose_collapse_entry(id); + } +} + + +function scrollWindowToFirehose(fhid) { + var firehose_y = getOffsetTop($('firehose-' + fhid)); + console.log(firehose_y); + scroll(viewWindowLeft(), firehose_y); +} + +function viewWindowLeft() { + if (self.pageXOffset) // all except Explorer + { + return self.pageXOffset; + } + else if (document.documentElement && document.documentElement.scrollTop) + // Explorer 6 Strict + { + return document.documentElement.scrollLeft; + } + else if (document.body) // all other Explorers + { + return document.body.scrollLeft; + } +} + +function getOffsetTop (el) { + if (!el) + return false; + var ot = el.offsetTop; + while((el = el.offsetParent) != null) + ot += el.offsetTop; + return ot; +} + +function firehoseIsInWindow(fhid, just_head) { + var in_window = isInWindow($('firehose-' + fhid)); + return in_window; +} + +function isInWindow(obj) { + var y = getOffsetTop(obj); + + if (y > viewWindowTop() && y < viewWindowBottom()) { + return 1; + } + return 0; +} + +function viewWindowTop() { + if (self.pageYOffset) // all except Explorer + { + return self.pageYOffset; + } + else if (document.documentElement && document.documentElement.scrollTop) + // Explorer 6 Strict + { + return document.documentElement.scrollTop; + } + else if (document.body) // all other Explorers + { + return document.body.scrollTop; + } + return; +} + +function viewWindowBottom() { + return viewWindowTop() + (window.innerHeight || document.documentElement.clientHeight); +} + +function firehose_get_cur() { + if (!firehose_cur) { + firehose_cur = firehose_ordered[0]; + firehose_set_cur(firehose_cur); + } + return firehose_cur; +} + +function firehose_set_cur(id) { + firehose_cur = id; +} + +function firehose_get_pos_of_id(id) { + var ret; + for (var i=0; i< firehose_ordered.length; i++) { + if (firehose_ordered[i] == id) { + ret = i; + } + } + return ret; +} + +function firehose_go_next() { + var cur = firehose_get_cur(); + var pos = firehose_get_pos_of_id(cur); + if (pos < (firehose_ordered.length - 1)) { + pos++; + } + firehose_set_cur(firehose_ordered[pos]); + scrollWindowToFirehose(firehose_cur); +} + +function firehose_go_prev() { + var cur = firehose_get_cur(); + var pos = firehose_get_pos_of_id(cur); + if (pos>0) { + pos--; + } + firehose_set_cur(firehose_ordered[pos]); + scrollWindowToFirehose(firehose_cur); + +} + + Copied: slashjp/trunk/plugins/Ajax/htdocs/images/jquery-1.2.3.js (from rev 561, slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/jquery-1.2.3.js) =================================================================== --- slashjp/trunk/plugins/Ajax/htdocs/images/jquery-1.2.3.js (rev 0) +++ slashjp/trunk/plugins/Ajax/htdocs/images/jquery-1.2.3.js 2008-04-01 04:03:21 UTC (rev 563) @@ -0,0 +1,11 @@ +/* + * jQuery 1.2.3 - New Wave Javascript + * + * Copyright (c) 2008 John Resig (jquery.com) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * $Date: 2008/03/14 15:48:06 $ + * $Rev: 4663 $ + */ +eval(function(p,a,c,k,e,r){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('(J(){7(1e.3N)L w=1e.3N;L E=1e.3N=J(a,b){K 1B E.2l.4T(a,b)};7(1e.$)L D=1e.$;1e.$=E;L u=/^[^<]*(<(.|\\s)+>)[^>]*$|^#(\\w+)$/;L G=/^.[^:#\\[\\.]*$/;E.1n=E.2l={4T:J(d,b){d=d||T;7(d.15){6[0]=d;6.M=1;K 6}N 7(1o d=="25"){L c=u.2O(d);7(c&&(c[1]||!b)){7(c[1])d=E.4a([c[1]],b);N{L a=T.5J(c[3]);7(a)7(a.2w!=c[3])K E().2s(d);N{6[0]=a;6.M=1;K 6}N d=[]}}N K 1B E(b).2s(d)}N 7(E.1q(d))K 1B E(T)[E.1n.21?"21":"3U"](d);K 6.6E(d.1k==1M&&d||(d.5h||d.M&&d!=1e&&!d.15&&d[0]!=10&&d[0].15)&&E.2I(d)||[d])},5h:"1.2.3",87:J(){K 6.M},M:0,22:J(a){K a==10?E.2I(6):6[a]},2F:J(b){L a=E(b);a.54=6;K a},6E:J(a){6.M=0;1M.2l.1g.1i(6,a);K 6},R:J(a,b){K E.R(6,a,b)},4X:J(b){L a=-1;6.R(J(i){7(6==b)a=i});K a},1J:J(c,a,b){L d=c;7(c.1k==4e)7(a==10)K 6.M&&E[b||"1J"](6[0],c)||10;N{d={};d[c]=a}K 6.R(J(i){Q(c 1p d)E.1J(b?6.W:6,c,E.1l(6,d[c],b,i,c))})},1j:J(b,a){7((b==\'27\'||b==\'1R\')&&2M(a)<0)a=10;K 6.1J(b,a,"2o")},1u:J(b){7(1o b!="3V"&&b!=V)K 6.4x().3t((6[0]&&6[0].2i||T).5r(b));L a="";E.R(b||6,J(){E.R(6.3p,J(){7(6.15!=8)a+=6.15!=1?6.6K:E.1n.1u([6])})});K a},5m:J(b){7(6[0])E(b,6[0].2i).5k().3o(6[0]).2c(J(){L a=6;2b(a.1C)a=a.1C;K a}).3t(6);K 6},8w:J(a){K 6.R(J(){E(6).6z().5m(a)})},8p:J(a){K 6.R(J(){E(6).5m(a)})},3t:J(){K 6.3O(18,P,S,J(a){7(6.15==1)6.38(a)})},6q:J(){K 6.3O(18,P,P,J(a){7(6.15==1)6.3o(a,6.1C)})},6o:J(){K 6.3O(18,S,S,J(a){6.1a.3o(a,6)})},5a:J(){K 6.3O(18,S,P,J(a){6.1a.3o(a,6.2B)})},3h:J(){K 6.54||E([])},2s:J(b){L c=E.2c(6,J(a){K E.2s(b,a)});K 6.2F(/[^+>] [^+>]/.17(b)||b.1f("..")>-1?E.57(c):c)},5k:J(e){L f=6.2c(J(){7(E.14.1d&&!E.3E(6)){L a=6.69(P),4Y=T.3s("1x");4Y.38(a);K E.4a([4Y.3d])[0]}N K 6.69(P)});L d=f.2s("*").4R().R(J(){7(6[F]!=10)6[F]=V});7(e===P)6.2s("*").4R().R(J(i){7(6.15==3)K;L c=E.O(6,"2R");Q(L a 1p c)Q(L b 1p c[a])E.16.1b(d[i],a,c[a][b],c[a][b].O)});K f},1E:J(b){K 6.2F(E.1q(b)&&E.3y(6,J(a,i){K b.1P(a,i)})||E.3e(b,6))},56:J(b){7(b.1k==4e)7(G.17(b))K 6.2F(E.3e(b,6,P));N b=E.3e(b,6);L a=b.M&&b[b.M-1]!==10&&!b.15;K 6.1E(J(){K a?E.33(6,b)<0:6!=b})},1b:J(a){K!a?6:6.2F(E.37(6.22(),a.1k==4e?E(a).22():a.M!=10&&(!a.12||E.12(a,"3u"))?a:[a]))},3H:J(a){K a?E.3e(a,6).M>0:S},7j:J(a){K 6.3H("."+a)},5O:J(b){7(b==10){7(6.M){L c=6[0];7(E.12(c,"2k")){L e=c.3T,5I=[],11=c.11,2X=c.U=="2k-2X";7(e<0)K V;Q(L i=2X?e:0,2f=2X?e+1:11.M;i<2f;i++){L d=11[i];7(d.2p){b=E.14.1d&&!d.9J.1A.9y?d.1u:d.1A;7(2X)K b;5I.1g(b)}}K 5I}N K(6[0].1A||"").1r(/\\r/g,"")}K 10}K 6.R(J(){7(6.15!=1)K;7(b.1k==1M&&/5u|5t/.17(6.U))6.3k=(E.33(6.1A,b)>=0||E.33(6.31,b)>=0);N 7(E.12(6,"2k")){L a=b.1k==1M?b:[b];E("98",6).R(J(){6.2p=(E.33(6.1A,a)>=0||E.33(6.1u,a)>=0)});7(!a.M)6.3T=-1}N 6.1A=b})},3q:J(a){K a==10?(6.M?6[0].3d:V):6.4x().3t(a)},6S:J(a){K 6.5a(a).1V()},6Z:J(i){K 6.2K(i,i+1)},2K:J(){K 6.2F(1M.2l.2K.1i(6,18))},2c:J(b){K 6.2F(E.2c(6,J(a,i){K b.1P(a,i,a)}))},4R:J(){K 6.1b(6.54)},O:J(d,b){L a=d.23(".");a[1]=a[1]?"."+a[1]:"";7(b==V){L c=6.5n("8P"+a[1]+"!",[a[0]]);7(c==10&&6.M)c=E.O(6[0],d);K c==V&&a[1]?6.O(a[0]):c}N K 6.1N("8K"+a[1]+"!",[a[0],b]).R(J(){E.O(6,d,b)})},35:J(a){K 6.R(J(){E.35(6,a)})},3O:J(g,f,h,d){L e=6.M>1,3n;K 6.R(J(){7(!3n){3n=E.4a(g,6.2i);7(h)3n.8D()}L b=6;7(f&&E.12(6,"1O")&&E.12(3n[0],"4v"))b=6.3S("1U")[0]||6.38(6.2i.3s("1U"));L c=E([]);E.R(3n,J(){L a=e?E(6).5k(P)[0]:6;7(E.12(a,"1m")){c=c.1b(a)}N{7(a.15==1)c=c.1b(E("1m",a).1V());d.1P(b,a)}});c.R(6A)})}};E.2l.4T.2l=E.2l;J 6A(i,a){7(a.3Q)E.3P({1c:a.3Q,3l:S,1H:"1m"});N E.5g(a.1u||a.6x||a.3d||"");7(a.1a)a.1a.34(a)}E.1s=E.1n.1s=J(){L b=18[0]||{},i=1,M=18.M,5c=S,11;7(b.1k==8d){5c=b;b=18[1]||{};i=2}7(1o b!="3V"&&1o b!="J")b={};7(M==1){b=6;i=0}Q(;i-1}},68:J(b,c,a){L e={};Q(L d 1p c){e[d]=b.W[d];b.W[d]=c[d]}a.1P(b);Q(L d 1p c)b.W[d]=e[d]},1j:J(d,e,c){7(e=="27"||e=="1R"){L b,46={43:"4W",4U:"1Z",19:"3D"},3c=e=="27"?["7O","7M"]:["7J","7I"];J 5E(){b=e=="27"?d.7H:d.7F;L a=0,2N=0;E.R(3c,J(){a+=2M(E.2o(d,"7E"+6,P))||0;2N+=2M(E.2o(d,"2N"+6+"5X",P))||0});b-=24.7C(a+2N)}7(E(d).3H(":4d"))5E();N E.68(d,46,5E);K 24.2f(0,b)}K E.2o(d,e,c)},2o:J(e,k,j){L d;J 3x(b){7(!E.14.2d)K S;L a=T.4c.4K(b,V);K!a||a.4M("3x")==""}7(k=="1w"&&E.14.1d){d=E.1J(e.W,"1w");K d==""?"1":d}7(E.14.2z&&k=="19"){L c=e.W.50;e.W.50="0 7r 7o";e.W.50=c}7(k.1D(/4g/i))k=y;7(!j&&e.W&&e.W[k])d=e.W[k];N 7(T.4c&&T.4c.4K){7(k.1D(/4g/i))k="4g";k=k.1r(/([A-Z])/g,"-$1").2h();L h=T.4c.4K(e,V);7(h&&!3x(e))d=h.4M(k);N{L f=[],2C=[];Q(L a=e;a&&3x(a);a=a.1a)2C.4J(a);Q(L i=0;i<2C.M;i++)7(3x(2C[i])){f[i]=2C[i].W.19;2C[i].W.19="3D"}d=k=="19"&&f[2C.M-1]!=V?"2H":(h&&h.4M(k))||"";Q(L i=0;i]*?)\\/>/g,J(b,a,c){K c.1D(/^(aa|a6|7e|a5|4D|7a|a0|3m|9W|9U|9S)$/i)?b:a+">"});L f=E.3g(d).2h(),1x=h.3s("1x");L e=!f.1f("<9P")&&[1,"<2k 74=\'74\'>",""]||!f.1f("<9M")&&[1,"<73>",""]||f.1D(/^<(9G|1U|9E|9B|9x)/)&&[1,"<1O>",""]||!f.1f("<4v")&&[2,"<1O><1U>",""]||(!f.1f("<9w")||!f.1f("<9v"))&&[3,"<1O><1U><4v>",""]||!f.1f("<7e")&&[2,"<1O><1U><6V>",""]||E.14.1d&&[1,"1x<1x>",""]||[0,"",""];1x.3d=e[1]+d+e[2];2b(e[0]--)1x=1x.5o;7(E.14.1d){L g=!f.1f("<1O")&&f.1f("<1U")<0?1x.1C&&1x.1C.3p:e[1]=="<1O>"&&f.1f("<1U")<0?1x.3p:[];Q(L j=g.M-1;j>=0;--j)7(E.12(g[j],"1U")&&!g[j].3p.M)g[j].1a.34(g[j]);7(/^\\s/.17(d))1x.3o(h.5r(d.1D(/^\\s*/)[0]),1x.1C)}d=E.2I(1x.3p)}7(d.M===0&&(!E.12(d,"3u")&&!E.12(d,"2k")))K;7(d[0]==10||E.12(d,"3u")||d.11)k.1g(d);N k=E.37(k,d)});K k},1J:J(d,e,c){7(!d||d.15==3||d.15==8)K 10;L f=E.3E(d)?{}:E.46;7(e=="2p"&&E.14.2d)d.1a.3T;7(f[e]){7(c!=10)d[f[e]]=c;K d[f[e]]}N 7(E.14.1d&&e=="W")K E.1J(d.W,"9u",c);N 7(c==10&&E.14.1d&&E.12(d,"3u")&&(e=="9r"||e=="9o"))K d.9m(e).6K;N 7(d.28){7(c!=10){7(e=="U"&&E.12(d,"4D")&&d.1a)6Q"U 9i 9h\'t 9g 9e";d.9b(e,""+c)}7(E.14.1d&&/6O|3Q/.17(e)&&!E.3E(d))K d.4z(e,2);K d.4z(e)}N{7(e=="1w"&&E.14.1d){7(c!=10){d.6k=1;d.1E=(d.1E||"").1r(/6M\\([^)]*\\)/,"")+(2M(c).3X()=="96"?"":"6M(1w="+c*6L+")")}K d.1E&&d.1E.1f("1w=")>=0?(2M(d.1E.1D(/1w=([^)]*)/)[1])/6L).3X():""}e=e.1r(/-([a-z])/95,J(a,b){K b.2E()});7(c!=10)d[e]=c;K d[e]}},3g:J(a){K(a||"").1r(/^\\s+|\\s+$/g,"")},2I:J(b){L a=[];7(1o b!="93")Q(L i=0,M=b.M;i*",6).1V();2b(6.1C)6.34(6.1C)}},J(a,b){E.1n[a]=J(){K 6.R(b,18)}});E.R(["8f","5X"],J(i,c){L b=c.2h();E.1n[b]=J(a){K 6[0]==1e?E.14.2z&&T.1h["5e"+c]||E.14.2d&&1e["8e"+c]||T.6F=="79"&&T.1F["5e"+c]||T.1h["5e"+c]:6[0]==T?24.2f(24.2f(T.1h["5d"+c],T.1F["5d"+c]),24.2f(T.1h["5L"+c],T.1F["5L"+c])):a==10?(6.M?E.1j(6[0],b):V):6.1j(b,a.1k==4e?a:a+"2S")}});L C=E.14.2d&&4s(E.14.5K)<8c?"(?:[\\\\w*4r-]|\\\\\\\\.)":"(?:[\\\\w\\8b-\\8a*4r-]|\\\\\\\\.)",6v=1B 4q("^>\\\\s*("+C+"+)"),6u=1B 4q("^("+C+"+)(#)("+C+"+)"),6s=1B 4q("^([#.]?)("+C+"*)");E.1s({6r:{"":J(a,i,m){K m[2]=="*"||E.12(a,m[2])},"#":J(a,i,m){K a.4z("2w")==m[2]},":":{89:J(a,i,m){K im[3]-0},2Z:J(a,i,m){K m[3]-0==i},6Z:J(a,i,m){K m[3]-0==i},3j:J(a,i){K i==0},3J:J(a,i,m,r){K i==r.M-1},6n:J(a,i){K i%2==0},6l:J(a,i){K i%2},"3j-4p":J(a){K a.1a.3S("*")[0]==a},"3J-4p":J(a){K E.2Z(a.1a.5o,1,"4t")==a},"83-4p":J(a){K!E.2Z(a.1a.5o,2,"4t")},6B:J(a){K a.1C},4x:J(a){K!a.1C},82:J(a,i,m){K(a.6x||a.81||E(a).1u()||"").1f(m[3])>=0},4d:J(a){K"1Z"!=a.U&&E.1j(a,"19")!="2H"&&E.1j(a,"4U")!="1Z"},1Z:J(a){K"1Z"==a.U||E.1j(a,"19")=="2H"||E.1j(a,"4U")=="1Z"},80:J(a){K!a.2Y},2Y:J(a){K a.2Y},3k:J(a){K a.3k},2p:J(a){K a.2p||E.1J(a,"2p")},1u:J(a){K"1u"==a.U},5u:J(a){K"5u"==a.U},5t:J(a){K"5t"==a.U},59:J(a){K"59"==a.U},3I:J(a){K"3I"==a.U},58:J(a){K"58"==a.U},6j:J(a){K"6j"==a.U},6i:J(a){K"6i"==a.U},2G:J(a){K"2G"==a.U||E.12(a,"2G")},4D:J(a){K/4D|2k|6h|2G/i.17(a.12)},3Y:J(a,i,m){K E.2s(m[3],a).M},7X:J(a){K/h\\d/i.17(a.12)},7W:J(a){K E.3y(E.3G,J(b){K a==b.Y}).M}}},6g:[/^(\\[) *@?([\\w-]+) *([!*$^~=]*) *(\'?"?)(.*?)\\4 *\\]/,/^(:)([\\w-]+)\\("?\'?(.*?(\\(.*?\\))?[^(]*?)"?\'?\\)/,1B 4q("^([:.#]*)("+C+"+)")],3e:J(a,c,b){L d,2m=[];2b(a&&a!=d){d=a;L f=E.1E(a,c,b);a=f.t.1r(/^\\s*,\\s*/,"");2m=b?c=f.r:E.37(2m,f.r)}K 2m},2s:J(t,p){7(1o t!="25")K[t];7(p&&p.15!=1&&p.15!=9)K[];p=p||T;L d=[p],2r=[],3J,12;2b(t&&3J!=t){L r=[];3J=t;t=E.3g(t);L o=S;L g=6v;L m=g.2O(t);7(m){12=m[1].2E();Q(L i=0;d[i];i++)Q(L c=d[i].1C;c;c=c.2B)7(c.15==1&&(12=="*"||c.12.2E()==12))r.1g(c);d=r;t=t.1r(g,"");7(t.1f(" ")==0)6w;o=P}N{g=/^([>+~])\\s*(\\w*)/i;7((m=g.2O(t))!=V){r=[];L l={};12=m[2].2E();m=m[1];Q(L j=0,3f=d.M;j<3f;j++){L n=m=="~"||m=="+"?d[j].2B:d[j].1C;Q(;n;n=n.2B)7(n.15==1){L h=E.O(n);7(m=="~"&&l[h])1Q;7(!12||n.12.2E()==12){7(m=="~")l[h]=P;r.1g(n)}7(m=="+")1Q}}d=r;t=E.3g(t.1r(g,""));o=P}}7(t&&!o){7(!t.1f(",")){7(p==d[0])d.4l();2r=E.37(2r,d);r=d=[p];t=" "+t.6e(1,t.M)}N{L k=6u;L m=k.2O(t);7(m){m=[0,m[2],m[3],m[1]]}N{k=6s;m=k.2O(t)}m[2]=m[2].1r(/\\\\/g,"");L f=d[d.M-1];7(m[1]=="#"&&f&&f.5J&&!E.3E(f)){L q=f.5J(m[2]);7((E.14.1d||E.14.2z)&&q&&1o q.2w=="25"&&q.2w!=m[2])q=E(\'[@2w="\'+m[2]+\'"]\',f)[0];d=r=q&&(!m[3]||E.12(q,m[3]))?[q]:[]}N{Q(L i=0;d[i];i++){L a=m[1]=="#"&&m[3]?m[3]:m[1]!=""||m[0]==""?"*":m[2];7(a=="*"&&d[i].12.2h()=="3V")a="3m";r=E.37(r,d[i].3S(a))}7(m[1]==".")r=E.55(r,m[2]);7(m[1]=="#"){L e=[];Q(L i=0;r[i];i++)7(r[i].4z("2w")==m[2]){e=[r[i]];1Q}r=e}d=r}t=t.1r(k,"")}}7(t){L b=E.1E(t,r);d=r=b.r;t=E.3g(b.t)}}7(t)d=[];7(d&&p==d[0])d.4l();2r=E.37(2r,d);K 2r},55:J(r,m,a){m=" "+m+" ";L c=[];Q(L i=0;r[i];i++){L b=(" "+r[i].1t+" ").1f(m)>=0;7(!a&&b||a&&!b)c.1g(r[i])}K c},1E:J(t,r,h){L d;2b(t&&t!=d){d=t;L p=E.6g,m;Q(L i=0;p[i];i++){m=p[i].2O(t);7(m){t=t.7V(m[0].M);m[2]=m[2].1r(/\\\\/g,"");1Q}}7(!m)1Q;7(m[1]==":"&&m[2]=="56")r=G.17(m[3])?E.1E(m[3],r,P).r:E(r).56(m[3]);N 7(m[1]==".")r=E.55(r,m[2],h);N 7(m[1]=="["){L g=[],U=m[3];Q(L i=0,3f=r.M;i<3f;i++){L a=r[i],z=a[E.46[m[2]]||m[2]];7(z==V||/6O|3Q|2p/.17(m[2]))z=E.1J(a,m[2])||\'\';7((U==""&&!!z||U=="="&&z==m[5]||U=="!="&&z!=m[5]||U=="^="&&z&&!z.1f(m[5])||U=="$="&&z.6e(z.M-m[5].M)==m[5]||(U=="*="||U=="~=")&&z.1f(m[5])>=0)^h)g.1g(a)}r=g}N 7(m[1]==":"&&m[2]=="2Z-4p"){L e={},g=[],17=/(-?)(\\d*)n((?:\\+|-)?\\d*)/.2O(m[3]=="6n"&&"2n"||m[3]=="6l"&&"2n+1"||!/\\D/.17(m[3])&&"7U+"+m[3]||m[3]),3j=(17[1]+(17[2]||1))-0,d=17[3]-0;Q(L i=0,3f=r.M;i<3f;i++){L j=r[i],1a=j.1a,2w=E.O(1a);7(!e[2w]){L c=1;Q(L n=1a.1C;n;n=n.2B)7(n.15==1)n.4k=c++;e[2w]=P}L b=S;7(3j==0){7(j.4k==d)b=P}N 7((j.4k-d)%3j==0&&(j.4k-d)/3j>=0)b=P;7(b^h)g.1g(j)}r=g}N{L f=E.6r[m[1]];7(1o f=="3V")f=f[m[2]];7(1o f=="25")f=6c("S||J(a,i){K "+f+";}");r=E.3y(r,J(a,i){K f(a,i,m,r)},h)}}K{r:r,t:t}},4u:J(b,c){L d=[];L a=b[c];2b(a&&a!=T){7(a.15==1)d.1g(a);a=a[c]}K d},2Z:J(a,e,c,b){e=e||1;L d=0;Q(;a;a=a[c])7(a.15==1&&++d==e)1Q;K a},5i:J(n,a){L r=[];Q(;n;n=n.2B){7(n.15==1&&(!a||n!=a))r.1g(n)}K r}});E.16={1b:J(f,i,g,e){7(f.15==3||f.15==8)K;7(E.14.1d&&f.53!=10)f=1e;7(!g.2D)g.2D=6.2D++;7(e!=10){L h=g;g=J(){K h.1i(6,18)};g.O=e;g.2D=h.2D}L j=E.O(f,"2R")||E.O(f,"2R",{}),1v=E.O(f,"1v")||E.O(f,"1v",J(){L a;7(1o E=="10"||E.16.5f)K a;a=E.16.1v.1i(18.3R.Y,18);K a});1v.Y=f;E.R(i.23(/\\s+/),J(c,b){L a=b.23(".");b=a[0];g.U=a[1];L d=j[b];7(!d){d=j[b]={};7(!E.16.2y[b]||E.16.2y[b].4j.1P(f)===S){7(f.3F)f.3F(b,1v,S);N 7(f.6b)f.6b("4i"+b,1v)}}d[g.2D]=g;E.16.2a[b]=P});f=V},2D:1,2a:{},1V:J(e,h,f){7(e.15==3||e.15==8)K;L i=E.O(e,"2R"),29,4X;7(i){7(h==10||(1o h=="25"&&h.7T(0)=="."))Q(L g 1p i)6.1V(e,g+(h||""));N{7(h.U){f=h.2q;h=h.U}E.R(h.23(/\\s+/),J(b,a){L c=a.23(".");a=c[0];7(i[a]){7(f)2V i[a][f.2D];N Q(f 1p i[a])7(!c[1]||i[a][f].U==c[1])2V i[a][f];Q(29 1p i[a])1Q;7(!29){7(!E.16.2y[a]||E.16.2y[a].4h.1P(e)===S){7(e.67)e.67(a,E.O(e,"1v"),S);N 7(e.66)e.66("4i"+a,E.O(e,"1v"))}29=V;2V i[a]}}})}Q(29 1p i)1Q;7(!29){L d=E.O(e,"1v");7(d)d.Y=V;E.35(e,"2R");E.35(e,"1v")}}},1N:J(g,c,d,f,h){c=E.2I(c||[]);7(g.1f("!")>=0){g=g.2K(0,-1);L a=P}7(!d){7(6.2a[g])E("*").1b([1e,T]).1N(g,c)}N{7(d.15==3||d.15==8)K 10;L b,29,1n=E.1q(d[g]||V),16=!c[0]||!c[0].36;7(16)c.4J(6.4Z({U:g,2L:d}));c[0].U=g;7(a)c[0].65=P;7(E.1q(E.O(d,"1v")))b=E.O(d,"1v").1i(d,c);7(!1n&&d["4i"+g]&&d["4i"+g].1i(d,c)===S)b=S;7(16)c.4l();7(h&&E.1q(h)){29=h.1i(d,b==V?c:c.71(b));7(29!==10)b=29}7(1n&&f!==S&&b!==S&&!(E.12(d,\'a\')&&g=="4V")){6.5f=P;1S{d[g]()}1X(e){}}6.5f=S}K b},1v:J(c){L a;c=E.16.4Z(c||1e.16||{});L b=c.U.23(".");c.U=b[0];L f=E.O(6,"2R")&&E.O(6,"2R")[c.U],42=1M.2l.2K.1P(18,1);42.4J(c);Q(L j 1p f){L d=f[j];42[0].2q=d;42[0].O=d.O;7(!b[1]&&!c.65||d.U==b[1]){L e=d.1i(6,42);7(a!==S)a=e;7(e===S){c.36();c.44()}}}7(E.14.1d)c.2L=c.36=c.44=c.2q=c.O=V;K a},4Z:J(c){L a=c;c=E.1s({},a);c.36=J(){7(a.36)a.36();a.7S=S};c.44=J(){7(a.44)a.44();a.7R=P};7(!c.2L)c.2L=c.7Q||T;7(c.2L.15==3)c.2L=a.2L.1a;7(!c.4S&&c.5w)c.4S=c.5w==c.2L?c.7P:c.5w;7(c.64==V&&c.63!=V){L b=T.1F,1h=T.1h;c.64=c.63+(b&&b.2v||1h&&1h.2v||0)-(b.62||0);c.7N=c.7L+(b&&b.2x||1h&&1h.2x||0)-(b.60||0)}7(!c.3c&&((c.4f||c.4f===0)?c.4f:c.5Z))c.3c=c.4f||c.5Z;7(!c.7b&&c.5Y)c.7b=c.5Y;7(!c.3c&&c.2G)c.3c=(c.2G&1?1:(c.2G&2?3:(c.2G&4?2:0)));K c},2y:{21:{4j:J(){5M();K},4h:J(){K}},3C:{4j:J(){7(E.14.1d)K S;E(6).2j("4P",E.16.2y.3C.2q);K P},4h:J(){7(E.14.1d)K S;E(6).3w("4P",E.16.2y.3C.2q);K P},2q:J(a){7(I(a,6))K P;18[0].U="3C";K E.16.1v.1i(6,18)}},3B:{4j:J(){7(E.14.1d)K S;E(6).2j("4O",E.16.2y.3B.2q);K P},4h:J(){7(E.14.1d)K S;E(6).3w("4O",E.16.2y.3B.2q);K P},2q:J(a){7(I(a,6))K P;18[0].U="3B";K E.16.1v.1i(6,18)}}}};E.1n.1s({2j:J(c,a,b){K c=="4H"?6.2X(c,a,b):6.R(J(){E.16.1b(6,c,b||a,b&&a)})},2X:J(d,b,c){K 6.R(J(){E.16.1b(6,d,J(a){E(6).3w(a);K(c||b).1i(6,18)},c&&b)})},3w:J(a,b){K 6.R(J(){E.16.1V(6,a,b)})},1N:J(c,a,b){K 6.R(J(){E.16.1N(c,a,6,P,b)})},5n:J(c,a,b){7(6[0])K E.16.1N(c,a,6[0],S,b);K 10},2g:J(){L b=18;K 6.4V(J(a){6.4N=0==6.4N?1:0;a.36();K b[6.4N].1i(6,18)||S})},7D:J(a,b){K 6.2j(\'3C\',a).2j(\'3B\',b)},21:J(a){5M();7(E.2Q)a.1P(T,E);N E.3A.1g(J(){K a.1P(6,E)});K 6}});E.1s({2Q:S,3A:[],21:J(){7(!E.2Q){E.2Q=P;7(E.3A){E.R(E.3A,J(){6.1i(T)});E.3A=V}E(T).5n("21")}}});L x=S;J 5M(){7(x)K;x=P;7(T.3F&&!E.14.2z)T.3F("5W",E.21,S);7(E.14.1d&&1e==3b)(J(){7(E.2Q)K;1S{T.1F.7B("26")}1X(3a){3z(18.3R,0);K}E.21()})();7(E.14.2z)T.3F("5W",J(){7(E.2Q)K;Q(L i=0;i=0){L i=g.2K(e,g.M);g=g.2K(0,e)}c=c||J(){};L f="4Q";7(d)7(E.1q(d)){c=d;d=V}N{d=E.3m(d);f="61"}L h=6;E.3P({1c:g,U:f,1H:"3q",O:d,1y:J(a,b){7(b=="1W"||b=="5U")h.3q(i?E("<1x/>").3t(a.4b.1r(/<1m(.|\\s)*?\\/1m>/g,"")).2s(i):a.4b);h.R(c,[a.4b,b,a])}});K 6},7n:J(){K E.3m(6.5T())},5T:J(){K 6.2c(J(){K E.12(6,"3u")?E.2I(6.7m):6}).1E(J(){K 6.31&&!6.2Y&&(6.3k||/2k|6h/i.17(6.12)||/1u|1Z|3I/i.17(6.U))}).2c(J(i,c){L b=E(6).5O();K b==V?V:b.1k==1M?E.2c(b,J(a,i){K{31:c.31,1A:a}}):{31:c.31,1A:b}}).22()}});E.R("5S,6d,5R,6D,5Q,6m".23(","),J(i,o){E.1n[o]=J(f){K 6.2j(o,f)}});L B=(1B 3v).3L();E.1s({22:J(d,b,a,c){7(E.1q(b)){a=b;b=V}K E.3P({U:"4Q",1c:d,O:b,1W:a,1H:c})},7l:J(b,a){K E.22(b,V,a,"1m")},7k:J(c,b,a){K E.22(c,b,a,"3i")},7i:J(d,b,a,c){7(E.1q(b)){a=b;b={}}K E.3P({U:"61",1c:d,O:b,1W:a,1H:c})},85:J(a){E.1s(E.4I,a)},4I:{2a:P,U:"4Q",2U:0,5P:"4o/x-7h-3u-7g",5N:P,3l:P,O:V,6p:V,3I:V,49:{3M:"4o/3M, 1u/3M",3q:"1u/3q",1m:"1u/4m, 4o/4m",3i:"4o/3i, 1u/4m",1u:"1u/a7",4G:"*/*"}},4F:{},3P:J(s){L f,2W=/=\\?(&|$)/g,1z,O;s=E.1s(P,s,E.1s(P,{},E.4I,s));7(s.O&&s.5N&&1o s.O!="25")s.O=E.3m(s.O);7(s.1H=="4E"){7(s.U.2h()=="22"){7(!s.1c.1D(2W))s.1c+=(s.1c.1D(/\\?/)?"&":"?")+(s.4E||"7d")+"=?"}N 7(!s.O||!s.O.1D(2W))s.O=(s.O?s.O+"&":"")+(s.4E||"7d")+"=?";s.1H="3i"}7(s.1H=="3i"&&(s.O&&s.O.1D(2W)||s.1c.1D(2W))){f="4E"+B++;7(s.O)s.O=(s.O+"").1r(2W,"="+f+"$1");s.1c=s.1c.1r(2W,"="+f+"$1");s.1H="1m";1e[f]=J(a){O=a;1W();1y();1e[f]=10;1S{2V 1e[f]}1X(e){}7(h)h.34(g)}}7(s.1H=="1m"&&s.1T==V)s.1T=S;7(s.1T===S&&s.U.2h()=="22"){L i=(1B 3v()).3L();L j=s.1c.1r(/(\\?|&)4r=.*?(&|$)/,"$a4="+i+"$2");s.1c=j+((j==s.1c)?(s.1c.1D(/\\?/)?"&":"?")+"4r="+i:"")}7(s.O&&s.U.2h()=="22"){s.1c+=(s.1c.1D(/\\?/)?"&":"?")+s.O;s.O=V}7(s.2a&&!E.5H++)E.16.1N("5S");7((!s.1c.1f("a3")||!s.1c.1f("//"))&&s.1H=="1m"&&s.U.2h()=="22"){L h=T.3S("6f")[0];L g=T.3s("1m");g.3Q=s.1c;7(s.7c)g.a2=s.7c;7(!f){L l=S;g.9Z=g.9Y=J(){7(!l&&(!6.39||6.39=="5V"||6.39=="1y")){l=P;1W();1y();h.34(g)}}}h.38(g);K 10}L m=S;L k=1e.78?1B 78("9X.9V"):1B 76();k.9T(s.U,s.1c,s.3l,s.6p,s.3I);1S{7(s.O)k.4C("9R-9Q",s.5P);7(s.5C)k.4C("9O-5A-9N",E.4F[s.1c]||"9L, 9K 9I 9H 5z:5z:5z 9F");k.4C("X-9C-9A","76");k.4C("9z",s.1H&&s.49[s.1H]?s.49[s.1H]+", */*":s.49.4G)}1X(e){}7(s.6Y)s.6Y(k);7(s.2a)E.16.1N("6m",[k,s]);L c=J(a){7(!m&&k&&(k.39==4||a=="2U")){m=P;7(d){6I(d);d=V}1z=a=="2U"&&"2U"||!E.6X(k)&&"3a"||s.5C&&E.6J(k,s.1c)&&"5U"||"1W";7(1z=="1W"){1S{O=E.6W(k,s.1H)}1X(e){1z="5x"}}7(1z=="1W"){L b;1S{b=k.5q("6U-5A")}1X(e){}7(s.5C&&b)E.4F[s.1c]=b;7(!f)1W()}N E.5v(s,k,1z);1y();7(s.3l)k=V}};7(s.3l){L d=53(c,13);7(s.2U>0)3z(J(){7(k){k.9t();7(!m)c("2U")}},s.2U)}1S{k.9s(s.O)}1X(e){E.5v(s,k,V,e)}7(!s.3l)c();J 1W(){7(s.1W)s.1W(O,1z);7(s.2a)E.16.1N("5Q",[k,s])}J 1y(){7(s.1y)s.1y(k,1z);7(s.2a)E.16.1N("5R",[k,s]);7(s.2a&&!--E.5H)E.16.1N("6d")}K k},5v:J(s,a,b,e){7(s.3a)s.3a(a,b,e);7(s.2a)E.16.1N("6D",[a,s,e])},5H:0,6X:J(r){1S{K!r.1z&&9q.9p=="59:"||(r.1z>=6T&&r.1z<9n)||r.1z==6R||r.1z==9l||E.14.2d&&r.1z==10}1X(e){}K S},6J:J(a,c){1S{L b=a.5q("6U-5A");K a.1z==6R||b==E.4F[c]||E.14.2d&&a.1z==10}1X(e){}K S},6W:J(r,b){L c=r.5q("9k-U");L d=b=="3M"||!b&&c&&c.1f("3M")>=0;L a=d?r.9j:r.4b;7(d&&a.1F.28=="5x")6Q"5x";7(b=="1m")E.5g(a);7(b=="3i")a=6c("("+a+")");K a},3m:J(a){L s=[];7(a.1k==1M||a.5h)E.R(a,J(){s.1g(3r(6.31)+"="+3r(6.1A))});N Q(L j 1p a)7(a[j]&&a[j].1k==1M)E.R(a[j],J(){s.1g(3r(j)+"="+3r(6))});N s.1g(3r(j)+"="+3r(a[j]));K s.6a("&").1r(/%20/g,"+")}});E.1n.1s({1G:J(c,b){K c?6.2e({1R:"1G",27:"1G",1w:"1G"},c,b):6.1E(":1Z").R(J(){6.W.19=6.5s||"";7(E.1j(6,"19")=="2H"){L a=E("<"+6.28+" />").6y("1h");6.W.19=a.1j("19");7(6.W.19=="2H")6.W.19="3D";a.1V()}}).3h()},1I:J(b,a){K b?6.2e({1R:"1I",27:"1I",1w:"1I"},b,a):6.1E(":4d").R(J(){6.5s=6.5s||E.1j(6,"19");6.W.19="2H"}).3h()},6N:E.1n.2g,2g:J(a,b){K E.1q(a)&&E.1q(b)?6.6N(a,b):a?6.2e({1R:"2g",27:"2g",1w:"2g"},a,b):6.R(J(){E(6)[E(6).3H(":1Z")?"1G":"1I"]()})},9f:J(b,a){K 6.2e({1R:"1G"},b,a)},9d:J(b,a){K 6.2e({1R:"1I"},b,a)},9c:J(b,a){K 6.2e({1R:"2g"},b,a)},9a:J(b,a){K 6.2e({1w:"1G"},b,a)},99:J(b,a){K 6.2e({1w:"1I"},b,a)},97:J(c,a,b){K 6.2e({1w:a},c,b)},2e:J(l,k,j,h){L i=E.6P(k,j,h);K 6[i.2P===S?"R":"2P"](J(){7(6.15!=1)K S;L g=E.1s({},i);L f=E(6).3H(":1Z"),4A=6;Q(L p 1p l){7(l[p]=="1I"&&f||l[p]=="1G"&&!f)K E.1q(g.1y)&&g.1y.1i(6);7(p=="1R"||p=="27"){g.19=E.1j(6,"19");g.32=6.W.32}}7(g.32!=V)6.W.32="1Z";g.40=E.1s({},l);E.R(l,J(c,a){L e=1B E.2t(4A,g,c);7(/2g|1G|1I/.17(a))e[a=="2g"?f?"1G":"1I":a](l);N{L b=a.3X().1D(/^([+-]=)?([\\d+-.]+)(.*)$/),1Y=e.2m(P)||0;7(b){L d=2M(b[2]),2A=b[3]||"2S";7(2A!="2S"){4A.W[c]=(d||1)+2A;1Y=((d||1)/e.2m(P))*1Y;4A.W[c]=1Y+2A}7(b[1])d=((b[1]=="-="?-1:1)*d)+1Y;e.45(1Y,d,2A)}N e.45(1Y,a,"")}});K P})},2P:J(a,b){7(E.1q(a)||(a&&a.1k==1M)){b=a;a="2t"}7(!a||(1o a=="25"&&!b))K A(6[0],a);K 6.R(J(){7(b.1k==1M)A(6,a,b);N{A(6,a).1g(b);7(A(6,a).M==1)b.1i(6)}})},94:J(b,c){L a=E.3G;7(b)6.2P([]);6.R(J(){Q(L i=a.M-1;i>=0;i--)7(a[i].Y==6){7(c)a[i](P);a.72(i,1)}});7(!c)6.5p();K 6}});L A=J(b,c,a){7(!b)K 10;c=c||"2t";L q=E.O(b,c+"2P");7(!q||a)q=E.O(b,c+"2P",a?E.2I(a):[]);K q};E.1n.5p=J(a){a=a||"2t";K 6.R(J(){L q=A(6,a);q.4l();7(q.M)q[0].1i(6)})};E.1s({6P:J(b,a,c){L d=b&&b.1k==92?b:{1y:c||!c&&a||E.1q(b)&&b,2u:b,3Z:c&&a||a&&a.1k!=91&&a};d.2u=(d.2u&&d.2u.1k==51?d.2u:{90:8Z,9D:6T}[d.2u])||8X;d.5y=d.1y;d.1y=J(){7(d.2P!==S)E(6).5p();7(E.1q(d.5y))d.5y.1i(6)};K d},3Z:{70:J(p,n,b,a){K b+a*p},5j:J(p,n,b,a){K((-24.8V(p*24.8U)/2)+0.5)*a+b}},3G:[],3W:V,2t:J(b,c,a){6.11=c;6.Y=b;6.1l=a;7(!c.47)c.47={}}});E.2t.2l={4y:J(){7(6.11.30)6.11.30.1i(6.Y,[6.2J,6]);(E.2t.30[6.1l]||E.2t.30.4G)(6);7(6.1l=="1R"||6.1l=="27")6.Y.W.19="3D"},2m:J(a){7(6.Y[6.1l]!=V&&6.Y.W[6.1l]==V)K 6.Y[6.1l];L r=2M(E.1j(6.Y,6.1l,a));K r&&r>-8Q?r:2M(E.2o(6.Y,6.1l))||0},45:J(c,b,d){6.5B=(1B 3v()).3L();6.1Y=c;6.3h=b;6.2A=d||6.2A||"2S";6.2J=6.1Y;6.4B=6.4w=0;6.4y();L e=6;J t(a){K e.30(a)}t.Y=6.Y;E.3G.1g(t);7(E.3W==V){E.3W=53(J(){L a=E.3G;Q(L i=0;i6.11.2u+6.5B){6.2J=6.3h;6.4B=6.4w=1;6.4y();6.11.40[6.1l]=P;L b=P;Q(L i 1p 6.11.40)7(6.11.40[i]!==P)b=S;7(b){7(6.11.19!=V){6.Y.W.32=6.11.32;6.Y.W.19=6.11.19;7(E.1j(6.Y,"19")=="2H")6.Y.W.19="3D"}7(6.11.1I)6.Y.W.19="2H";7(6.11.1I||6.11.1G)Q(L p 1p 6.11.40)E.1J(6.Y.W,p,6.11.47[p])}7(b&&E.1q(6.11.1y))6.11.1y.1i(6.Y);K S}N{L n=t-6.5B;6.4w=n/6.11.2u;6.4B=E.3Z[6.11.3Z||(E.3Z.5j?"5j":"70")](6.4w,n,0,1,6.11.2u);6.2J=6.1Y+((6.3h-6.1Y)*6.4B);6.4y()}K P}};E.2t.30={2v:J(a){a.Y.2v=a.2J},2x:J(a){a.Y.2x=a.2J},1w:J(a){E.1J(a.Y.W,"1w",a.2J)},4G:J(a){a.Y.W[a.1l]=a.2J+a.2A}};E.1n.5L=J(){L b=0,3b=0,Y=6[0],5l;7(Y)8M(E.14){L d=Y.1a,41=Y,1K=Y.1K,1L=Y.2i,5D=2d&&4s(5K)<8J&&!/a1/i.17(v),2T=E.1j(Y,"43")=="2T";7(Y.6G){L c=Y.6G();1b(c.26+24.2f(1L.1F.2v,1L.1h.2v),c.3b+24.2f(1L.1F.2x,1L.1h.2x));1b(-1L.1F.62,-1L.1F.60)}N{1b(Y.5G,Y.5F);2b(1K){1b(1K.5G,1K.5F);7(48&&!/^t(8H|d|h)$/i.17(1K.28)||2d&&!5D)2N(1K);7(!2T&&E.1j(1K,"43")=="2T")2T=P;41=/^1h$/i.17(1K.28)?41:1K;1K=1K.1K}2b(d&&d.28&&!/^1h|3q$/i.17(d.28)){7(!/^8G|1O.*$/i.17(E.1j(d,"19")))1b(-d.2v,-d.2x);7(48&&E.1j(d,"32")!="4d")2N(d);d=d.1a}7((5D&&(2T||E.1j(41,"43")=="4W"))||(48&&E.1j(41,"43")!="4W"))1b(-1L.1h.5G,-1L.1h.5F);7(2T)1b(24.2f(1L.1F.2v,1L.1h.2v),24.2f(1L.1F.2x,1L.1h.2x))}5l={3b:3b,26:b}}J 2N(a){1b(E.2o(a,"a8",P),E.2o(a,"a9",P))}J 1b(l,t){b+=4s(l)||0;3b+=4s(t)||0}K 5l}})();',62,631,'||||||this|if||||||||||||||||||||||||||||||||||||||function|return|var|length|else|data|true|for|each|false|document|type|null|style||elem||undefined|options|nodeName||browser|nodeType|event|test|arguments|display|parentNode|add|url|msie|window|indexOf|push|body|apply|css|constructor|prop|script|fn|typeof|in|isFunction|replace|extend|className|text|handle|opacity|div|complete|status|value|new|firstChild|match|filter|documentElement|show|dataType|hide|attr|offsetParent|doc|Array|trigger|table|call|break|height|try|cache|tbody|remove|success|catch|start|hidden||ready|get|split|Math|string|left|width|tagName|ret|global|while|map|safari|animate|max|toggle|toLowerCase|ownerDocument|bind|select|prototype|cur||curCSS|selected|handler|done|find|fx|duration|scrollLeft|id|scrollTop|special|opera|unit|nextSibling|stack|guid|toUpperCase|pushStack|button|none|makeArray|now|slice|target|parseFloat|border|exec|queue|isReady|events|px|fixed|timeout|delete|jsre|one|disabled|nth|step|name|overflow|inArray|removeChild|removeData|preventDefault|merge|appendChild|readyState|error|top|which|innerHTML|multiFilter|rl|trim|end|json|first|checked|async|param|elems|insertBefore|childNodes|html|encodeURIComponent|createElement|append|form|Date|unbind|color|grep|setTimeout|readyList|mouseleave|mouseenter|block|isXMLDoc|addEventListener|timers|is|password|last|runtimeStyle|getTime|xml|jQuery|domManip|ajax|src|callee|getElementsByTagName|selectedIndex|load|object|timerId|toString|has|easing|curAnim|offsetChild|args|position|stopPropagation|custom|props|orig|mozilla|accepts|clean|responseText|defaultView|visible|String|charCode|float|teardown|on|setup|nodeIndex|shift|javascript|currentStyle|application|child|RegExp|_|parseInt|previousSibling|dir|tr|state|empty|update|getAttribute|self|pos|setRequestHeader|input|jsonp|lastModified|_default|unload|ajaxSettings|unshift|getComputedStyle|styleSheets|getPropertyValue|lastToggle|mouseout|mouseover|GET|andSelf|relatedTarget|init|visibility|click|absolute|index|container|fix|outline|Number|removeAttribute|setInterval|prevObject|classFilter|not|unique|submit|file|after|windowData|deep|scroll|client|triggered|globalEval|jquery|sibling|swing|clone|results|wrapAll|triggerHandler|lastChild|dequeue|getResponseHeader|createTextNode|oldblock|checkbox|radio|handleError|fromElement|parsererror|old|00|Modified|startTime|ifModified|safari2|getWH|offsetTop|offsetLeft|active|values|getElementById|version|offset|bindReady|processData|val|contentType|ajaxSuccess|ajaxComplete|ajaxStart|serializeArray|notmodified|loaded|DOMContentLoaded|Width|ctrlKey|keyCode|clientTop|POST|clientLeft|clientX|pageX|exclusive|detachEvent|removeEventListener|swap|cloneNode|join|attachEvent|eval|ajaxStop|substr|head|parse|textarea|reset|image|zoom|odd|ajaxSend|even|before|username|prepend|expr|quickClass|uuid|quickID|quickChild|continue|textContent|appendTo|contents|evalScript|parent|defaultValue|ajaxError|setArray|compatMode|getBoundingClientRect|styleFloat|clearInterval|httpNotModified|nodeValue|100|alpha|_toggle|href|speed|throw|304|replaceWith|200|Last|colgroup|httpData|httpSuccess|beforeSend|eq|linear|concat|splice|fieldset|multiple|cssFloat|XMLHttpRequest|webkit|ActiveXObject|CSS1Compat|link|metaKey|scriptCharset|callback|col|pixelLeft|urlencoded|www|post|hasClass|getJSON|getScript|elements|serialize|black|keyup|keypress|solid|change|mousemove|mouseup|dblclick|resize|focus|blur|stylesheet|rel|doScroll|round|hover|padding|offsetHeight|mousedown|offsetWidth|Bottom|Top|keydown|clientY|Right|pageY|Left|toElement|srcElement|cancelBubble|returnValue|charAt|0n|substring|animated|header|noConflict|line|enabled|innerText|contains|only|weight|ajaxSetup|font|size|gt|lt|uFFFF|u0128|417|Boolean|inner|Height|toggleClass|removeClass|addClass|removeAttr|replaceAll|insertAfter|prependTo|contentWindow|contentDocument|wrap|iframe|children|siblings|prevAll|nextAll|prev|wrapInner|next|parents|maxLength|maxlength|readOnly|readonly|reverse|class|htmlFor|inline|able|boxModel|522|setData|compatible|with|1px|ie|getData|10000|ra|it|rv|PI|cos|userAgent|400|navigator|600|slow|Function|Object|array|stop|ig|NaN|fadeTo|option|fadeOut|fadeIn|setAttribute|slideToggle|slideUp|changed|slideDown|be|can|property|responseXML|content|1223|getAttributeNode|300|method|protocol|location|action|send|abort|cssText|th|td|cap|specified|Accept|With|colg|Requested|fast|tfoot|GMT|thead|1970|Jan|attributes|01|Thu|leg|Since|If|opt|Type|Content|embed|open|area|XMLHTTP|hr|Microsoft|onreadystatechange|onload|meta|adobeair|charset|http|1_|img|br|plain|borderLeftWidth|borderTopWidth|abbr'.split('|'),0,{})) Modified: slashjp/trunk/plugins/Ajax/htdocs/images/nodnix.js =================================================================== --- slashjp/trunk/plugins/Ajax/htdocs/images/nodnix.js 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/plugins/Ajax/htdocs/images/nodnix.js 2008-04-01 04:03:21 UTC (rev 563) @@ -100,6 +100,17 @@ firehose_up_down(g_nodnix_item_id, up_down); } +function nodnix_not_tag( old_tag ) { + var new_tag = old_tag[0]=='!' ? old_tag.slice(1) : '!'+old_tag; + createTag(new_tag, g_nodnix_item_id, "firehose"); + var tag_list = _get_nodnix('ol'); + // XXX not a good idea if the tag happens to be 'span' or 'li', etc + tag_list.innerHTML = tag_list.innerHTML.replace(old_tag, new_tag, "g"); +} + +function nodnix_del_tag( tag ) { +} + function hide_nod_menu() { get_nod_menu().style.display = 'none'; } @@ -117,7 +128,7 @@ } else { if ( g_pending_hidemenu ) clearTimeout(g_pending_hidemenu); - g_pending_hidemenu = setTimeout("hide_nodnix_menu()", delay); + g_pending_hidemenu = setTimeout(hide_nodnix_menu, delay); } } @@ -204,7 +215,21 @@ YAHOO.util.Dom.removeClass(get_nix_menu(), 'soon'); } +function refresh_tag_bar( tag_list ) { + // ajax request to fill the user tags list + var params = {}; + params['op'] = 'tags_get_user_firehose'; + params['id'] = g_nodnix_item_id; + params['nodnix'] = 1; + ajax_update(params, tag_list, {}); +} + function begin_nodnix_editing() { + if ( is_firehose_playing() ) { + firehose_pause(); + end_nodnix_editing.restore_firehose_state = firehose_play; + } + get_nodnix_listener().disable(); YAHOO.util.Dom.addClass(get_nod_menu(), 'soon'); YAHOO.util.Dom.addClass(get_nix_menu(), 'soon'); @@ -215,17 +240,22 @@ var input = _get_nodnix('input'); input.value = ""; input.focus(); - - _get_nodnix('ol').innerHTML = ""; + var tag_list = _get_nodnix('ol'); + tag_list.innerHTML = ""; + refresh_tag_bar(tag_list); + (input.getAttribute("updown")=="+" ? nod_completer : nix_completer).sendQuery(); - setTimeout("soon_is_now()", 225); + setTimeout(soon_is_now, 225); } function end_nodnix_editing() { YAHOO.util.Dom.removeClass(get_nod_menu(), 'editing'); YAHOO.util.Dom.removeClass(get_nix_menu(), 'editing'); + end_nodnix_editing.restore_firehose_state(); + end_nodnix_editing.restore_firehose_state = function(){} } +end_nodnix_editing.restore_firehose_state = function(){} function handle_nodnix_blur( type, args ) { hide_nodnix_menu(); @@ -239,13 +269,16 @@ nodnix_tag(tagname); // now 'harden' the tag var list = _get_nodnix('ol'); - list.innerHTML = '
  • ' + tagname + '
  • ' + list.innerHTML; + list.innerHTML = handle_nodnix_select.template_string.split('$').join(tagname) + list.innerHTML; _get_nodnix('input').value = ""; } if ( !stay_open ) hide_nodnix_menu(); } + // WARNING: keep this string in sync with tagsnodnixuser;misc;default +handle_nodnix_select.template_string = '
  • $! x
  • '; + function handle_completer_key( type, args ) { var key = args[0]; var event = args[1]; Deleted: slashjp/trunk/plugins/Ajax/htdocs/images/prototype.js =================================================================== --- slashjp/trunk/plugins/Ajax/htdocs/images/prototype.js 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/plugins/Ajax/htdocs/images/prototype.js 2008-04-01 04:03:21 UTC (rev 563) @@ -1,1785 +0,0 @@ -/* Prototype JavaScript framework, version 1.4.0 - * (c) 2005 Sam Stephenson - * - * THIS FILE IS AUTOMATICALLY GENERATED. When sending patches, please diff - * against the source tree, available from the Prototype darcs repository. - * - * Prototype is freely distributable under the terms of an MIT-style license. - * - * For details, see the Prototype web site: http://prototype.conio.net/ - * -/*--------------------------------------------------------------------------*/ - -var Prototype = { - Version: '1.4.0', - ScriptFragment: '(?:)((\n|\r|.)*?)(?:<\/script>)', - - emptyFunction: function() {}, - K: function(x) {return x} -} - -var Class = { - create: function() { - return function() { - this.initialize.apply(this, arguments); - } - } -} - -var Abstract = new Object(); - -Object.extend = function(destination, source) { - for (property in source) { - destination[property] = source[property]; - } - return destination; -} - -Object.inspect = function(object) { - try { - if (object == undefined) return 'undefined'; - if (object == null) return 'null'; - return object.inspect ? object.inspect() : object.toString(); - } catch (e) { - if (e instanceof RangeError) return '...'; - throw e; - } -} - -Function.prototype.bind = function() { - var __method = this, args = $A(arguments), object = args.shift(); - return function() { - return __method.apply(object, args.concat($A(arguments))); - } -} - -Function.prototype.bindAsEventListener = function(object) { - var __method = this; - return function(event) { - return __method.call(object, event || window.event); - } -} - -Object.extend(Number.prototype, { - toColorPart: function() { - var digits = this.toString(16); - if (this < 16) return '0' + digits; - return digits; - }, - - succ: function() { - return this + 1; - }, - - times: function(iterator) { - $R(0, this, true).each(iterator); - return this; - } -}); - -var Try = { - these: function() { - var returnValue; - - for (var i = 0; i < arguments.length; i++) { - var lambda = arguments[i]; - try { - returnValue = lambda(); - break; - } catch (e) {} - } - - return returnValue; - } -} - -/*--------------------------------------------------------------------------*/ - -var PeriodicalExecuter = Class.create(); -PeriodicalExecuter.prototype = { - initialize: function(callback, frequency) { - this.callback = callback; - this.frequency = frequency; - this.currentlyExecuting = false; - - this.registerCallback(); - }, - - registerCallback: function() { - setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); - }, - - onTimerEvent: function() { - if (!this.currentlyExecuting) { - try { - this.currentlyExecuting = true; - this.callback(); - } finally { - this.currentlyExecuting = false; - } - } - } -} - -/*--------------------------------------------------------------------------*/ - -function $() { - var elements = new Array(); - - for (var i = 0; i < arguments.length; i++) { - var element = arguments[i]; - if (typeof element == 'string') - element = document.getElementById(element); - - if (arguments.length == 1) - return element; - - elements.push(element); - } - - return elements; -} -Object.extend(String.prototype, { - stripTags: function() { - return this.replace(/<\/?[^>]+>/gi, ''); - }, - - stripScripts: function() { - return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); - }, - - extractScripts: function() { - var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); - var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); - return (this.match(matchAll) || []).map(function(scriptTag) { - return (scriptTag.match(matchOne) || ['', ''])[1]; - }); - }, - - evalScripts: function() { - return this.extractScripts().map(eval); - }, - - escapeHTML: function() { - var div = document.createElement('div'); - var text = document.createTextNode(this); - div.appendChild(text); - return div.innerHTML; - }, - - unescapeHTML: function() { - var div = document.createElement('div'); - div.innerHTML = this.stripTags(); - return div.childNodes[0] ? div.childNodes[0].nodeValue : ''; - }, - - toQueryParams: function() { - var pairs = this.match(/^\??(.*)$/)[1].split('&'); - return pairs.inject({}, function(params, pairString) { - var pair = pairString.split('='); - params[pair[0]] = pair[1]; - return params; - }); - }, - - toArray: function() { - return this.split(''); - }, - - camelize: function() { - var oStringList = this.split('-'); - if (oStringList.length == 1) return oStringList[0]; - - var camelizedString = this.indexOf('-') == 0 - ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1) - : oStringList[0]; - - for (var i = 1, len = oStringList.length; i < len; i++) { - var s = oStringList[i]; - camelizedString += s.charAt(0).toUpperCase() + s.substring(1); - } - - return camelizedString; - }, - - inspect: function() { - return "'" + this.replace('\\', '\\\\').replace("'", '\\\'') + "'"; - } -}); - -String.prototype.parseQuery = String.prototype.toQueryParams; - -var $break = new Object(); -var $continue = new Object(); - -var Enumerable = { - each: function(iterator) { - var index = 0; - try { - this._each(function(value) { - try { - iterator(value, index++); - } catch (e) { - if (e != $continue) throw e; - } - }); - } catch (e) { - if (e != $break) throw e; - } - }, - - all: function(iterator) { - var result = true; - this.each(function(value, index) { - result = result && !!(iterator || Prototype.K)(value, index); - if (!result) throw $break; - }); - return result; - }, - - any: function(iterator) { - var result = true; - this.each(function(value, index) { - if (result = !!(iterator || Prototype.K)(value, index)) - throw $break; - }); - return result; - }, - - collect: function(iterator) { - var results = []; - this.each(function(value, index) { - results.push(iterator(value, index)); - }); - return results; - }, - - detect: function (iterator) { - var result; - this.each(function(value, index) { - if (iterator(value, index)) { - result = value; - throw $break; - } - }); - return result; - }, - - findAll: function(iterator) { - var results = []; - this.each(function(value, index) { - if (iterator(value, index)) - results.push(value); - }); - return results; - }, - - grep: function(pattern, iterator) { - var results = []; - this.each(function(value, index) { - var stringValue = value.toString(); - if (stringValue.match(pattern)) - results.push((iterator || Prototype.K)(value, index)); - }) - return results; - }, - - include: function(object) { - var found = false; - this.each(function(value) { - if (value == object) { - found = true; - throw $break; - } - }); - return found; - }, - - inject: function(memo, iterator) { - this.each(function(value, index) { - memo = iterator(memo, value, index); - }); - return memo; - }, - - invoke: function(method) { - var args = $A(arguments).slice(1); - return this.collect(function(value) { - return value[method].apply(value, args); - }); - }, - - max: function(iterator) { - var result; - this.each(function(value, index) { - value = (iterator || Prototype.K)(value, index); - if (value >= (result || value)) - result = value; - }); - return result; - }, - - min: function(iterator) { - var result; - this.each(function(value, index) { - value = (iterator || Prototype.K)(value, index); - if (value <= (result || value)) - result = value; - }); - return result; - }, - - partition: function(iterator) { - var trues = [], falses = []; - this.each(function(value, index) { - ((iterator || Prototype.K)(value, index) ? - trues : falses).push(value); - }); - return [trues, falses]; - }, - - pluck: function(property) { - var results = []; - this.each(function(value, index) { - results.push(value[property]); - }); - return results; - }, - - reject: function(iterator) { - var results = []; - this.each(function(value, index) { - if (!iterator(value, index)) - results.push(value); - }); - return results; - }, - - sortBy: function(iterator) { - return this.collect(function(value, index) { - return {value: value, criteria: iterator(value, index)}; - }).sort(function(left, right) { - var a = left.criteria, b = right.criteria; - return a < b ? -1 : a > b ? 1 : 0; - }).pluck('value'); - }, - - toArray: function() { - return this.collect(Prototype.K); - }, - - zip: function() { - var iterator = Prototype.K, args = $A(arguments); - if (typeof args.last() == 'function') - iterator = args.pop(); - - var collections = [this].concat(args).map($A); - return this.map(function(value, index) { - iterator(value = collections.pluck(index)); - return value; - }); - }, - - inspect: function() { - return '#'; - } -} - -Object.extend(Enumerable, { - map: Enumerable.collect, - find: Enumerable.detect, - select: Enumerable.findAll, - member: Enumerable.include, - entries: Enumerable.toArray -}); -var $A = Array.from = function(iterable) { - if (!iterable) return []; - if (iterable.toArray) { - return iterable.toArray(); - } else { - var results = []; - for (var i = 0; i < iterable.length; i++) - results.push(iterable[i]); - return results; - } -} - -Object.extend(Array.prototype, Enumerable); - -Array.prototype._reverse = Array.prototype.reverse; - -Object.extend(Array.prototype, { - _each: function(iterator) { - for (var i = 0; i < this.length; i++) - iterator(this[i]); - }, - - clear: function() { - this.length = 0; - return this; - }, - - first: function() { - return this[0]; - }, - - last: function() { - return this[this.length - 1]; - }, - - compact: function() { - return this.select(function(value) { - return value != undefined || value != null; - }); - }, - - flatten: function() { - return this.inject([], function(array, value) { - return array.concat(value.constructor == Array ? - value.flatten() : [value]); - }); - }, - - without: function() { - var values = $A(arguments); - return this.select(function(value) { - return !values.include(value); - }); - }, - - indexOf: function(object) { - for (var i = 0; i < this.length; i++) - if (this[i] == object) return i; - return -1; - }, - - reverse: function(inline) { - return (inline !== false ? this : this.toArray())._reverse(); - }, - - shift: function() { - var result = this[0]; - for (var i = 0; i < this.length - 1; i++) - this[i] = this[i + 1]; - this.length--; - return result; - }, - - inspect: function() { - return '[' + this.map(Object.inspect).join(', ') + ']'; - } -}); -var Hash = { - _each: function(iterator) { - for (key in this) { - var value = this[key]; - if (typeof value == 'function') continue; - - var pair = [key, value]; - pair.key = key; - pair.value = value; - iterator(pair); - } - }, - - keys: function() { - return this.pluck('key'); - }, - - values: function() { - return this.pluck('value'); - }, - - merge: function(hash) { - return $H(hash).inject($H(this), function(mergedHash, pair) { - mergedHash[pair.key] = pair.value; - return mergedHash; - }); - }, - - toQueryString: function() { - return this.map(function(pair) { - return pair.map(encodeURIComponent).join('='); - }).join('&'); - }, - - inspect: function() { - return '#'; - } -} - -function $H(object) { - var hash = Object.extend({}, object || {}); - Object.extend(hash, Enumerable); - Object.extend(hash, Hash); - return hash; -} -ObjectRange = Class.create(); -Object.extend(ObjectRange.prototype, Enumerable); -Object.extend(ObjectRange.prototype, { - initialize: function(start, end, exclusive) { - this.start = start; - this.end = end; - this.exclusive = exclusive; - }, - - _each: function(iterator) { - var value = this.start; - do { - iterator(value); - value = value.succ(); - } while (this.include(value)); - }, - - include: function(value) { - if (value < this.start) - return false; - if (this.exclusive) - return value < this.end; - return value <= this.end; - } -}); - -var $R = function(start, end, exclusive) { - return new ObjectRange(start, end, exclusive); -} - -var Ajax = { - getTransport: function() { - return Try.these( - function() {return new ActiveXObject('Msxml2.XMLHTTP')}, - function() {return new ActiveXObject('Microsoft.XMLHTTP')}, - function() {return new XMLHttpRequest()} - ) || false; - }, - - activeRequestCount: 0 -} - -Ajax.Responders = { - responders: [], - - _each: function(iterator) { - this.responders._each(iterator); - }, - - register: function(responderToAdd) { - if (!this.include(responderToAdd)) - this.responders.push(responderToAdd); - }, - - unregister: function(responderToRemove) { - this.responders = this.responders.without(responderToRemove); - }, - - dispatch: function(callback, request, transport, json) { - this.each(function(responder) { - if (responder[callback] && typeof responder[callback] == 'function') { - try { - responder[callback].apply(responder, [request, transport, json]); - } catch (e) {} - } - }); - } -}; - -Object.extend(Ajax.Responders, Enumerable); - -Ajax.Responders.register({ - onCreate: function() { - Ajax.activeRequestCount++; - }, - - onComplete: function() { - Ajax.activeRequestCount--; - } -}); - -Ajax.Base = function() {}; -Ajax.Base.prototype = { - setOptions: function(options) { - this.options = { - method: 'post', - asynchronous: true, - parameters: '' - } - Object.extend(this.options, options || {}); - }, - - responseIsSuccess: function() { - return this.transport.status == undefined - || this.transport.status == 0 - || (this.transport.status >= 200 && this.transport.status < 300); - }, - - responseIsFailure: function() { - return !this.responseIsSuccess(); - } -} - -Ajax.Request = Class.create(); -Ajax.Request.Events = - ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; - -Ajax.Request.prototype = Object.extend(new Ajax.Base(), { - initialize: function(url, options) { - this.transport = Ajax.getTransport(); - this.setOptions(options); - this.request(url); - }, - - request: function(url) { - var parameters = this.options.parameters || ''; - if (parameters.length > 0) parameters += '&_='; - - try { - this.url = url; - if (this.options.method == 'get' && parameters.length > 0) - this.url += (this.url.match(/\?/) ? '&' : '?') + parameters; - - Ajax.Responders.dispatch('onCreate', this, this.transport); - - this.transport.open(this.options.method, this.url, - this.options.asynchronous); - - if (this.options.asynchronous) { - this.transport.onreadystatechange = this.onStateChange.bind(this); - setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10); - } - - this.setRequestHeaders(); - - var body = this.options.postBody ? this.options.postBody : parameters; - this.transport.send(this.options.method == 'post' ? body : null); - - } catch (e) { - this.dispatchException(e); - } - }, - - setRequestHeaders: function() { - var requestHeaders = - ['X-Requested-With', 'XMLHttpRequest', - 'X-Prototype-Version', Prototype.Version]; - - if (this.options.method == 'post') { - requestHeaders.push('Content-type', - 'application/x-www-form-urlencoded'); - - /* Force "Connection: close" for Mozilla browsers to work around - * a bug where XMLHttpReqeuest sends an incorrect Content-length - * header. See Mozilla Bugzilla #246651. - */ - if (this.transport.overrideMimeType) - requestHeaders.push('Connection', 'close'); - } - - if (this.options.requestHeaders) - requestHeaders.push.apply(requestHeaders, this.options.requestHeaders); - - for (var i = 0; i < requestHeaders.length; i += 2) - this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]); - }, - - onStateChange: function() { - var readyState = this.transport.readyState; - if (readyState != 1) - this.respondToReadyState(this.transport.readyState); - }, - - header: function(name) { - try { - return this.transport.getResponseHeader(name); - } catch (e) {} - }, - - evalJSON: function() { - try { - return eval(this.header('X-JSON')); - } catch (e) {} - }, - - evalResponse: function() { - try { - return eval(this.transport.responseText); - } catch (e) { - this.dispatchException(e); - } - }, - - respondToReadyState: function(readyState) { - var event = Ajax.Request.Events[readyState]; - var transport = this.transport, json = this.evalJSON(); - - if (event == 'Complete') { - try { - (this.options['on' + this.transport.status] - || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')] - || Prototype.emptyFunction)(transport, json); - } catch (e) { - this.dispatchException(e); - } - - if ((this.header('Content-type') || '').match(/^text\/javascript/i)) - this.evalResponse(); - } - - try { - (this.options['on' + event] || Prototype.emptyFunction)(transport, json); - Ajax.Responders.dispatch('on' + event, this, transport, json); - } catch (e) { - this.dispatchException(e); - } - - /* Avoid memory leak in MSIE: clean up the oncomplete event handler */ - if (event == 'Complete') - this.transport.onreadystatechange = Prototype.emptyFunction; - }, - - dispatchException: function(exception) { - (this.options.onException || Prototype.emptyFunction)(this, exception); - Ajax.Responders.dispatch('onException', this, exception); - } -}); - -Ajax.Updater = Class.create(); - -Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), { - initialize: function(container, url, options) { - this.containers = { - success: container.success ? $(container.success) : $(container), - failure: container.failure ? $(container.failure) : - (container.success ? null : $(container)) - } - - this.transport = Ajax.getTransport(); - this.setOptions(options); - - var onComplete = this.options.onComplete || Prototype.emptyFunction; - this.options.onComplete = (function(transport, object) { - this.updateContent(); - onComplete(transport, object); - }).bind(this); - - this.request(url); - }, - - updateContent: function() { - var receiver = this.responseIsSuccess() ? - this.containers.success : this.containers.failure; - var response = this.transport.responseText; - - if (!this.options.evalScripts) - response = response.stripScripts(); - - if (receiver) { - if (this.options.insertion) { - new this.options.insertion(receiver, response); - } else { - Element.update(receiver, response); - } - } - - if (this.responseIsSuccess()) { - if (this.onComplete) - setTimeout(this.onComplete.bind(this), 10); - } - } -}); - -Ajax.PeriodicalUpdater = Class.create(); -Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), { - initialize: function(container, url, options) { - this.setOptions(options); - this.onComplete = this.options.onComplete; - - this.frequency = (this.options.frequency || 2); - this.decay = (this.options.decay || 1); - - this.updater = {}; - this.container = container; - this.url = url; - - this.start(); - }, - - start: function() { - this.options.onComplete = this.updateComplete.bind(this); - this.onTimerEvent(); - }, - - stop: function() { - this.updater.onComplete = undefined; - clearTimeout(this.timer); - (this.onComplete || Prototype.emptyFunction).apply(this, arguments); - }, - - updateComplete: function(request) { - if (this.options.decay) { - this.decay = (request.responseText == this.lastText ? - this.decay * this.options.decay : 1); - - this.lastText = request.responseText; - } - this.timer = setTimeout(this.onTimerEvent.bind(this), - this.decay * this.frequency * 1000); - }, - - onTimerEvent: function() { - this.updater = new Ajax.Updater(this.container, this.url, this.options); - } -}); -document.getElementsByClassName = function(className, parentElement) { - var children = ($(parentElement) || document.body).getElementsByTagName('*'); - return $A(children).inject([], function(elements, child) { - if (child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)"))) - elements.push(child); - return elements; - }); -} - -/*--------------------------------------------------------------------------*/ - -if (!window.Element) { - var Element = new Object(); -} - -Object.extend(Element, { - visible: function(element) { - return $(element).style.display != 'none'; - }, - - toggle: function() { - for (var i = 0; i < arguments.length; i++) { - var element = $(arguments[i]); - Element[Element.visible(element) ? 'hide' : 'show'](element); - } - }, - - hide: function() { - for (var i = 0; i < arguments.length; i++) { - var element = $(arguments[i]); - element.style.display = 'none'; - } - }, - - show: function() { - for (var i = 0; i < arguments.length; i++) { - var element = $(arguments[i]); - element.style.display = ''; - } - }, - - remove: function(element) { - element = $(element); - element.parentNode.removeChild(element); - }, - - update: function(element, html) { - $(element).innerHTML = html.stripScripts(); - setTimeout(function() {html.evalScripts()}, 10); - }, - - getHeight: function(element) { - element = $(element); - return element.offsetHeight; - }, - - classNames: function(element) { - return new Element.ClassNames(element); - }, - - hasClassName: function(element, className) { - if (!(element = $(element))) return; - return Element.classNames(element).include(className); - }, - - addClassName: function(element, className) { - if (!(element = $(element))) return; - return Element.classNames(element).add(className); - }, - - removeClassName: function(element, className) { - if (!(element = $(element))) return; - return Element.classNames(element).remove(className); - }, - - // removes whitespace-only text node children - cleanWhitespace: function(element) { - element = $(element); - for (var i = 0; i < element.childNodes.length; i++) { - var node = element.childNodes[i]; - if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) - Element.remove(node); - } - }, - - empty: function(element) { - return $(element).innerHTML.match(/^\s*$/); - }, - - scrollTo: function(element) { - element = $(element); - var x = element.x ? element.x : element.offsetLeft, - y = element.y ? element.y : element.offsetTop; - window.scrollTo(x, y); - }, - - getStyle: function(element, style) { - element = $(element); - var value = element.style[style.camelize()]; - if (!value) { - if (document.defaultView && document.defaultView.getComputedStyle) { - var css = document.defaultView.getComputedStyle(element, null); - value = css ? css.getPropertyValue(style) : null; - } else if (element.currentStyle) { - value = element.currentStyle[style.camelize()]; - } - } - - if (window.opera && ['left', 'top', 'right', 'bottom'].include(style)) - if (Element.getStyle(element, 'position') == 'static') value = 'auto'; - - return value == 'auto' ? null : value; - }, - - setStyle: function(element, style) { - element = $(element); - for (name in style) - element.style[name.camelize()] = style[name]; - }, - - getDimensions: function(element) { - element = $(element); - if (Element.getStyle(element, 'display') != 'none') - return {width: element.offsetWidth, height: element.offsetHeight}; - - // All *Width and *Height properties give 0 on elements with display none, - // so enable the element temporarily - var els = element.style; - var originalVisibility = els.visibility; - var originalPosition = els.position; - els.visibility = 'hidden'; - els.position = 'absolute'; - els.display = ''; - var originalWidth = element.clientWidth; - var originalHeight = element.clientHeight; - els.display = 'none'; - els.position = originalPosition; - els.visibility = originalVisibility; - return {width: originalWidth, height: originalHeight}; - }, - - makePositioned: function(element) { - element = $(element); - var pos = Element.getStyle(element, 'position'); - if (pos == 'static' || !pos) { - element._madePositioned = true; - element.style.position = 'relative'; - // Opera returns the offset relative to the positioning context, when an - // element is position relative but top and left have not been defined - if (window.opera) { - element.style.top = 0; - element.style.left = 0; - } - } - }, - - undoPositioned: function(element) { - element = $(element); - if (element._madePositioned) { - element._madePositioned = undefined; - element.style.position = - element.style.top = - element.style.left = - element.style.bottom = - element.style.right = ''; - } - }, - - makeClipping: function(element) { - element = $(element); - if (element._overflow) return; - element._overflow = element.style.overflow; - if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden') - element.style.overflow = 'hidden'; - }, - - undoClipping: function(element) { - element = $(element); - if (element._overflow) return; - element.style.overflow = element._overflow; - element._overflow = undefined; - } -}); - -var Toggle = new Object(); -Toggle.display = Element.toggle; - -/*--------------------------------------------------------------------------*/ - -Abstract.Insertion = function(adjacency) { - this.adjacency = adjacency; -} - -Abstract.Insertion.prototype = { - initialize: function(element, content) { - this.element = $(element); - this.content = content.stripScripts(); - - if (this.adjacency && this.element.insertAdjacentHTML) { - try { - this.element.insertAdjacentHTML(this.adjacency, this.content); - } catch (e) { - if (this.element.tagName.toLowerCase() == 'tbody') { - this.insertContent(this.contentFromAnonymousTable()); - } else { - throw e; - } - } - } else { - this.range = this.element.ownerDocument.createRange(); - if (this.initializeRange) this.initializeRange(); - this.insertContent([this.range.createContextualFragment(this.content)]); - } - - setTimeout(function() {content.evalScripts()}, 10); - }, - - contentFromAnonymousTable: function() { - var div = document.createElement('div'); - div.innerHTML = '' + this.content + '
    '; - return $A(div.childNodes[0].childNodes[0].childNodes); - } -} - -var Insertion = new Object(); - -Insertion.Before = Class.create(); -Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), { - initializeRange: function() { - this.range.setStartBefore(this.element); - }, - - insertContent: function(fragments) { - fragments.each((function(fragment) { - this.element.parentNode.insertBefore(fragment, this.element); - }).bind(this)); - } -}); - -Insertion.Top = Class.create(); -Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), { - initializeRange: function() { - this.range.selectNodeContents(this.element); - this.range.collapse(true); - }, - - insertContent: function(fragments) { - fragments.reverse(false).each((function(fragment) { - this.element.insertBefore(fragment, this.element.firstChild); - }).bind(this)); - } -}); - -Insertion.Bottom = Class.create(); -Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), { - initializeRange: function() { - this.range.selectNodeContents(this.element); - this.range.collapse(this.element); - }, - - insertContent: function(fragments) { - fragments.each((function(fragment) { - this.element.appendChild(fragment); - }).bind(this)); - } -}); - -Insertion.After = Class.create(); -Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), { - initializeRange: function() { - this.range.setStartAfter(this.element); - }, - - insertContent: function(fragments) { - fragments.each((function(fragment) { - this.element.parentNode.insertBefore(fragment, - this.element.nextSibling); - }).bind(this)); - } -}); - -/*--------------------------------------------------------------------------*/ - -Element.ClassNames = Class.create(); -Element.ClassNames.prototype = { - initialize: function(element) { - this.element = $(element); - }, - - _each: function(iterator) { - this.element.className.split(/\s+/).select(function(name) { - return name.length > 0; - })._each(iterator); - }, - - set: function(className) { - this.element.className = className; - }, - - add: function(classNameToAdd) { - if (this.include(classNameToAdd)) return; - this.set(this.toArray().concat(classNameToAdd).join(' ')); - }, - - remove: function(classNameToRemove) { - if (!this.include(classNameToRemove)) return; - this.set(this.select(function(className) { - return className != classNameToRemove; - }).join(' ')); - }, - - toString: function() { - return this.toArray().join(' '); - } -} - -Object.extend(Element.ClassNames.prototype, Enumerable); -var Field = { - clear: function() { - for (var i = 0; i < arguments.length; i++) - $(arguments[i]).value = ''; - }, - - focus: function(element) { - $(element).focus(); - }, - - present: function() { - for (var i = 0; i < arguments.length; i++) - if ($(arguments[i]).value == '') return false; - return true; - }, - - select: function(element) { - $(element).select(); - }, - - activate: function(element) { - element = $(element); - element.focus(); - if (element.select) - element.select(); - } -} - -/*--------------------------------------------------------------------------*/ - -var Form = { - serialize: function(form) { - var elements = Form.getElements($(form)); - var queryComponents = new Array(); - - for (var i = 0; i < elements.length; i++) { - var queryComponent = Form.Element.serialize(elements[i]); - if (queryComponent) - queryComponents.push(queryComponent); - } - - return queryComponents.join('&'); - }, - - getElements: function(form) { - form = $(form); - var elements = new Array(); - - for (tagName in Form.Element.Serializers) { - var tagElements = form.getElementsByTagName(tagName); - for (var j = 0; j < tagElements.length; j++) - elements.push(tagElements[j]); - } - return elements; - }, - - getInputs: function(form, typeName, name) { - form = $(form); - var inputs = form.getElementsByTagName('input'); - - if (!typeName && !name) - return inputs; - - var matchingInputs = new Array(); - for (var i = 0; i < inputs.length; i++) { - var input = inputs[i]; - if ((typeName && input.type != typeName) || - (name && input.name != name)) - continue; - matchingInputs.push(input); - } - - return matchingInputs; - }, - - disable: function(form) { - var elements = Form.getElements(form); - for (var i = 0; i < elements.length; i++) { - var element = elements[i]; - element.blur(); - element.disabled = 'true'; - } - }, - - enable: function(form) { - var elements = Form.getElements(form); - for (var i = 0; i < elements.length; i++) { - var element = elements[i]; - element.disabled = ''; - } - }, - - findFirstElement: function(form) { - return Form.getElements(form).find(function(element) { - return element.type != 'hidden' && !element.disabled && - ['input', 'select', 'textarea'].include(element.tagName.toLowerCase()); - }); - }, - - focusFirstElement: function(form) { - Field.activate(Form.findFirstElement(form)); - }, - - reset: function(form) { - $(form).reset(); - } -} - -Form.Element = { - serialize: function(element) { - element = $(element); - var method = element.tagName.toLowerCase(); - var parameter = Form.Element.Serializers[method](element); - - if (parameter) { - var key = encodeURIComponent(parameter[0]); - if (key.length == 0) return; - - if (parameter[1].constructor != Array) - parameter[1] = [parameter[1]]; - - return parameter[1].map(function(value) { - return key + '=' + encodeURIComponent(value); - }).join('&'); - } - }, - - getValue: function(element) { - element = $(element); - var method = element.tagName.toLowerCase(); - var parameter = Form.Element.Serializers[method](element); - - if (parameter) - return parameter[1]; - } -} - -Form.Element.Serializers = { - input: function(element) { - switch (element.type.toLowerCase()) { - case 'submit': - case 'hidden': - case 'password': - case 'text': - return Form.Element.Serializers.textarea(element); - case 'checkbox': - case 'radio': - return Form.Element.Serializers.inputSelector(element); - } - return false; - }, - - inputSelector: function(element) { - if (element.checked) - return [element.name, element.value]; - }, - - textarea: function(element) { - return [element.name, element.value]; - }, - - select: function(element) { - return Form.Element.Serializers[element.type == 'select-one' ? - 'selectOne' : 'selectMany'](element); - }, - - selectOne: function(element) { - var value = '', opt, index = element.selectedIndex; - if (index >= 0) { - opt = element.options[index]; - value = opt.value; - if (!value && !('value' in opt)) - value = opt.text; - } - return [element.name, value]; - }, - - selectMany: function(element) { - var value = new Array(); - for (var i = 0; i < element.length; i++) { - var opt = element.options[i]; - if (opt.selected) { - var optValue = opt.value; - if (!optValue && !('value' in opt)) - optValue = opt.text; - value.push(optValue); - } - } - return [element.name, value]; - } -} - -/*--------------------------------------------------------------------------*/ - -var $F = Form.Element.getValue; - -/*--------------------------------------------------------------------------*/ - -Abstract.TimedObserver = function() {} -Abstract.TimedObserver.prototype = { - initialize: function(element, frequency, callback) { - this.frequency = frequency; - this.element = $(element); - this.callback = callback; - - this.lastValue = this.getValue(); - this.registerCallback(); - }, - - registerCallback: function() { - setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); - }, - - onTimerEvent: function() { - var value = this.getValue(); - if (this.lastValue != value) { - this.callback(this.element, value); - this.lastValue = value; - } - } -} - -Form.Element.Observer = Class.create(); -Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { - getValue: function() { - return Form.Element.getValue(this.element); - } -}); - -Form.Observer = Class.create(); -Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { - getValue: function() { - return Form.serialize(this.element); - } -}); - -/*--------------------------------------------------------------------------*/ - -Abstract.EventObserver = function() {} -Abstract.EventObserver.prototype = { - initialize: function(element, callback) { - this.element = $(element); - this.callback = callback; - - this.lastValue = this.getValue(); - if (this.element.tagName.toLowerCase() == 'form') - this.registerFormCallbacks(); - else - this.registerCallback(this.element); - }, - - onElementEvent: function() { - var value = this.getValue(); - if (this.lastValue != value) { - this.callback(this.element, value); - this.lastValue = value; - } - }, - - registerFormCallbacks: function() { - var elements = Form.getElements(this.element); - for (var i = 0; i < elements.length; i++) - this.registerCallback(elements[i]); - }, - - registerCallback: function(element) { - if (element.type) { - switch (element.type.toLowerCase()) { - case 'checkbox': - case 'radio': - Event.observe(element, 'click', this.onElementEvent.bind(this)); - break; - case 'password': - case 'text': - case 'textarea': - case 'select-one': - case 'select-multiple': - Event.observe(element, 'change', this.onElementEvent.bind(this)); - break; - } - } - } -} - -Form.Element.EventObserver = Class.create(); -Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { - getValue: function() { - return Form.Element.getValue(this.element); - } -}); - -Form.EventObserver = Class.create(); -Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { - getValue: function() { - return Form.serialize(this.element); - } -}); -if (!window.Event) { - var Event = new Object(); -} - -Object.extend(Event, { - KEY_BACKSPACE: 8, - KEY_TAB: 9, - KEY_RETURN: 13, - KEY_ESC: 27, - KEY_LEFT: 37, - KEY_UP: 38, - KEY_RIGHT: 39, - KEY_DOWN: 40, - KEY_DELETE: 46, - - element: function(event) { - return event.target || event.srcElement; - }, - - isLeftClick: function(event) { - return (((event.which) && (event.which == 1)) || - ((event.button) && (event.button == 1))); - }, - - pointerX: function(event) { - return event.pageX || (event.clientX + - (document.documentElement.scrollLeft || document.body.scrollLeft)); - }, - - pointerY: function(event) { - return event.pageY || (event.clientY + - (document.documentElement.scrollTop || document.body.scrollTop)); - }, - - stop: function(event) { - if (event.preventDefault) { - event.preventDefault(); - event.stopPropagation(); - } else { - event.returnValue = false; - event.cancelBubble = true; - } - }, - - // find the first node with the given tagName, starting from the - // node the event was triggered on; traverses the DOM upwards - findElement: function(event, tagName) { - var element = Event.element(event); - while (element.parentNode && (!element.tagName || - (element.tagName.toUpperCase() != tagName.toUpperCase()))) - element = element.parentNode; - return element; - }, - - observers: false, - - _observeAndCache: function(element, name, observer, useCapture) { - if (!this.observers) this.observers = []; - if (element.addEventListener) { - this.observers.push([element, name, observer, useCapture]); - element.addEventListener(name, observer, useCapture); - } else if (element.attachEvent) { - this.observers.push([element, name, observer, useCapture]); - element.attachEvent('on' + name, observer); - } - }, - - unloadCache: function() { - if (!Event.observers) return; - for (var i = 0; i < Event.observers.length; i++) { - Event.stopObserving.apply(this, Event.observers[i]); - Event.observers[i][0] = null; - } - Event.observers = false; - }, - - observe: function(element, name, observer, useCapture) { - var element = $(element); - useCapture = useCapture || false; - - if (name == 'keypress' && - (navigator.appVersion.match(/Konqueror|Safari|KHTML/) - || element.attachEvent)) - name = 'keydown'; - - this._observeAndCache(element, name, observer, useCapture); - }, - - stopObserving: function(element, name, observer, useCapture) { - var element = $(element); - useCapture = useCapture || false; - - if (name == 'keypress' && - (navigator.appVersion.match(/Konqueror|Safari|KHTML/) - || element.detachEvent)) - name = 'keydown'; - - if (element.removeEventListener) { - element.removeEventListener(name, observer, useCapture); - } else if (element.detachEvent) { - element.detachEvent('on' + name, observer); - } - } -}); - -/* prevent memory leaks in IE */ -Event.observe(window, 'unload', Event.unloadCache, false); -var Position = { - // set to true if needed, warning: firefox performance problems - // NOT neeeded for page scrolling, only if draggable contained in - // scrollable elements - includeScrollOffsets: false, - - // must be called before calling withinIncludingScrolloffset, every time the - // page is scrolled - prepare: function() { - this.deltaX = window.pageXOffset - || document.documentElement.scrollLeft - || document.body.scrollLeft - || 0; - this.deltaY = window.pageYOffset - || document.documentElement.scrollTop - || document.body.scrollTop - || 0; - }, - - realOffset: function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.scrollTop || 0; - valueL += element.scrollLeft || 0; - element = element.parentNode; - } while (element); - return [valueL, valueT]; - }, - - cumulativeOffset: function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - element = element.offsetParent; - } while (element); - return [valueL, valueT]; - }, - - positionedOffset: function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - element = element.offsetParent; - if (element) { - p = Element.getStyle(element, 'position'); - if (p == 'relative' || p == 'absolute') break; - } - } while (element); - return [valueL, valueT]; - }, - - offsetParent: function(element) { - if (element.offsetParent) return element.offsetParent; - if (element == document.body) return element; - - while ((element = element.parentNode) && element != document.body) - if (Element.getStyle(element, 'position') != 'static') - return element; - - return document.body; - }, - - // caches x/y coordinate pair to use with overlap - within: function(element, x, y) { - if (this.includeScrollOffsets) - return this.withinIncludingScrolloffsets(element, x, y); - this.xcomp = x; - this.ycomp = y; - this.offset = this.cumulativeOffset(element); - - return (y >= this.offset[1] && - y < this.offset[1] + element.offsetHeight && - x >= this.offset[0] && - x < this.offset[0] + element.offsetWidth); - }, - - withinIncludingScrolloffsets: function(element, x, y) { - var offsetcache = this.realOffset(element); - - this.xcomp = x + offsetcache[0] - this.deltaX; - this.ycomp = y + offsetcache[1] - this.deltaY; - this.offset = this.cumulativeOffset(element); - - return (this.ycomp >= this.offset[1] && - this.ycomp < this.offset[1] + element.offsetHeight && - this.xcomp >= this.offset[0] && - this.xcomp < this.offset[0] + element.offsetWidth); - }, - - // within must be called directly before - overlap: function(mode, element) { - if (!mode) return 0; - if (mode == 'vertical') - return ((this.offset[1] + element.offsetHeight) - this.ycomp) / - element.offsetHeight; - if (mode == 'horizontal') - return ((this.offset[0] + element.offsetWidth) - this.xcomp) / - element.offsetWidth; - }, - - clone: function(source, target) { - source = $(source); - target = $(target); - target.style.position = 'absolute'; - var offsets = this.cumulativeOffset(source); - target.style.top = offsets[1] + 'px'; - target.style.left = offsets[0] + 'px'; - target.style.width = source.offsetWidth + 'px'; - target.style.height = source.offsetHeight + 'px'; - }, - - page: function(forElement) { - var valueT = 0, valueL = 0; - - var element = forElement; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - - // Safari fix - if (element.offsetParent==document.body) - if (Element.getStyle(element,'position')=='absolute') break; - - } while (element = element.offsetParent); - - element = forElement; - do { - valueT -= element.scrollTop || 0; - valueL -= element.scrollLeft || 0; - } while (element = element.parentNode); - - return [valueL, valueT]; - }, - - clone: function(source, target) { - var options = Object.extend({ - setLeft: true, - setTop: true, - setWidth: true, - setHeight: true, - offsetTop: 0, - offsetLeft: 0 - }, arguments[2] || {}) - - // find page position of source - source = $(source); - var p = Position.page(source); - - // find coordinate system to use - target = $(target); - var delta = [0, 0]; - var parent = null; - // delta [0,0] will do fine with position: fixed elements, - // position:absolute needs offsetParent deltas - if (Element.getStyle(target,'position') == 'absolute') { - parent = Position.offsetParent(target); - delta = Position.page(parent); - } - - // correct by body offsets (fixes Safari) - if (parent == document.body) { - delta[0] -= document.body.offsetLeft; - delta[1] -= document.body.offsetTop; - } - - // set position - if(options.setLeft) target.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; - if(options.setTop) target.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; - if(options.setWidth) target.style.width = source.offsetWidth + 'px'; - if(options.setHeight) target.style.height = source.offsetHeight + 'px'; - }, - - absolutize: function(element) { - element = $(element); - if (element.style.position == 'absolute') return; - Position.prepare(); - - var offsets = Position.positionedOffset(element); - var top = offsets[1]; - var left = offsets[0]; - var width = element.clientWidth; - var height = element.clientHeight; - - element._originalLeft = left - parseFloat(element.style.left || 0); - element._originalTop = top - parseFloat(element.style.top || 0); - element._originalWidth = element.style.width; - element._originalHeight = element.style.height; - - element.style.position = 'absolute'; - element.style.top = top + 'px';; - element.style.left = left + 'px';; - element.style.width = width + 'px';; - element.style.height = height + 'px';; - }, - - relativize: function(element) { - element = $(element); - if (element.style.position == 'relative') return; - Position.prepare(); - - element.style.position = 'relative'; - var top = parseFloat(element.style.top || 0) - (element._originalTop || 0); - var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); - - element.style.top = top + 'px'; - element.style.left = left + 'px'; - element.style.height = element._originalHeight; - element.style.width = element._originalWidth; - } -} - -// Safari returns margins on body which is incorrect if the child is absolutely -// positioned. For performance reasons, redefine Position.cumulativeOffset for -// KHTML/WebKit only. -if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) { - Position.cumulativeOffset = function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - if (element.offsetParent == document.body) - if (Element.getStyle(element, 'position') == 'absolute') break; - - element = element.offsetParent; - } while (element); - - return [valueL, valueT]; - } -} \ No newline at end of file Modified: slashjp/trunk/plugins/Ajax/htdocs/images/sd_autocomplete.js =================================================================== --- slashjp/trunk/plugins/Ajax/htdocs/images/sd_autocomplete.js 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/plugins/Ajax/htdocs/images/sd_autocomplete.js 2008-04-01 04:03:21 UTC (rev 563) @@ -79,6 +79,7 @@ "books", "bsd", "developers", +"entertainment", "features", "games", "hardware", @@ -86,12 +87,14 @@ "it", "linux", "mainpage", +"news", "politics", "polls", "radio", "science", "search", "tacohell", +"technology", "vendors", "vendor_amd", "yro" ]; @@ -126,7 +129,6 @@ "links", "movies", "money", -"news", "pilot", "starwars", "sun", @@ -201,7 +203,6 @@ "osnine", "osx", "portables", -"technology", "utilities", "wireless", "portables", @@ -380,9 +381,9 @@ this._completer.autoHighlight = false; - // widget must be visible to move + // widget must be visible to move YAHOO.util.Dom.removeClass(this._widget, "hidden"); - // move widget to be near the 'source' + // move widget to be near the 'source' var pos = YAHOO.util.Dom.getXY(this._sourceEl); pos[1] += this._sourceEl.offsetHeight; YAHOO.util.Dom.setXY(this._widget, pos); @@ -394,7 +395,7 @@ YAHOO.util.Dom.removeClass(this._spareInput, "hidden"); this._spareInput.value = ""; this._spareInput.focus(); - this._pending_hide = setTimeout("YAHOO.slashdot.gCompleterWidget._hide()", 15000); + this._pending_hide = setTimeout(YAHOO.slashdot.gCompleterWidget._hide, 15000); } else YAHOO.util.Dom.addClass(this._spareInput, "hidden"); @@ -507,9 +508,9 @@ me._hide(); break; case 13: - // I'm sorry to say we have to test first, something somehow somewhere can still leave - // leave this listener dangling; want to look deeper into this, as this would _still_ - // leave the listener dangling + // I'm sorry to say we have to test first, something somehow somewhere can still + // leave this listener dangling; want to look deeper into this, as this would _still_ + // leave the listener dangling if ( me._completer ) me._completer.unmatchedItemSelectEvent.fire(me._completer, me, me._completer._sCurQuery); break; @@ -517,6 +518,6 @@ if ( me._pending_hide ) clearTimeout(me._pending_hide); if ( me._needsSpareInput() ) - me._pending_hide = setTimeout("YAHOO.slashdot.gCompleterWidget._hide()", 15000); + me._pending_hide = setTimeout(YAHOO.slashdot.gCompleterWidget._hide, 15000); } } Modified: slashjp/trunk/plugins/Ajax/htdocs/images/sectionprefs.js =================================================================== --- slashjp/trunk/plugins/Ajax/htdocs/images/sectionprefs.js 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/plugins/Ajax/htdocs/images/sectionprefs.js 2008-04-01 04:03:21 UTC (rev 563) @@ -7,7 +7,7 @@ createPopup(getXYForId('links-sections-title'), title, "sectionprefs", "", "Loading..."); var url = 'ajax.pl'; - var params = []; + var params = {}; params['op'] = 'getSectionPrefsHTML'; ajax_update(params, 'sectionprefs-contents'); @@ -26,12 +26,11 @@ } function postSectionPrefChanges(el) { - var params = []; + var params = {}; params['op'] = 'setSectionNexusPrefs'; params[el.name] = el.value; - var h = $H(params); - var sec_pref_msg = $("sectionprefs-message"); + var sec_pref_msg = $dom("sectionprefs-message"); sec_pref_msg.innerHTML = "Saving..."; var url = 'ajax.pl'; ajax_update(params, 'sectionprefs-message'); Modified: slashjp/trunk/plugins/Ajax/mysql_dump.sql =================================================================== --- slashjp/trunk/plugins/Ajax/mysql_dump.sql 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/plugins/Ajax/mysql_dump.sql 2008-04-01 04:03:21 UTC (rev 563) @@ -155,7 +155,7 @@ INSERT INTO ajax_ops VALUES (NULL, 'remarks_config_save', 'Slash::Remarks', 'ajaxConfigSave', 'ajax_admin', 'createuse'); # signoff -INSERT INTO ajax_ops VALUES (NULL, 'admin_signoff', 'Slash::Admin', 'ajax_signoff', 'ajax_admin', 'use'); +INSERT INTO ajax_ops VALUES (NULL, 'admin_signoff', 'Slash::Admin', 'ajax_signoff', 'ajax_user_static', 'createuse'); # slashboxes INSERT INTO ajax_ops VALUES (NULL, 'admin_slashdbox', 'Slash::Admin', 'ajax_slashdbox', 'ajax_admin', 'createuse'); Modified: slashjp/trunk/plugins/Ajax/templates/edit_comment;ajax;default =================================================================== --- slashjp/trunk/plugins/Ajax/templates/edit_comment;ajax;default 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/plugins/Ajax/templates/edit_comment;ajax;default 2008-04-01 04:03:21 UTC (rev 563) @@ -20,16 +20,16 @@ edit_comment __template__
    -[% IF pid %] - [% PROCESS titlebar title="Reply to: $reply.subject" %] -[% ELSE %] - [% PROCESS titlebar title="Reply to: XXXXX" %] -[% END %] +[% this_title = pid ? reply.subject : discussion.title; + this_title = this_title | strip_html; + PROCESS titlebar title="Reply to: $this_title" %] +

    If you have difficulty with this form, please use the old form.

    + [% IF user.is_anon %]

    [% IF constants.allow_anonymous %] You are not logged in. You can log -in now, or Create an Account/ +in now, or Create an Account. [% ELSE %] You are not logged in. You can log in now, Create an Account, @@ -43,22 +43,28 @@

    [% IF pid %][% END %] -[% IF gotmodwarning %][% END # XXXXX %] + [% reskey_label = "reskey_reply_$pid"; PROCESS reskey_tag %] -

    -[Customize Posting Preferences]

    +

    +[% UNLESS user.is_anon %][Options] +[%- IF constants.allow_anonymous && user.karma > -1 && (discussion.commentstatus == 'enabled' || discussion.commentstatus == 'logged_in') -%] + Post Anonymously +[%- END %]

    [% END %]

    -[% IF constants.allow_anonymous && user.karma > -1 && !user.is_anon && (discussion.commentstatus == 'enabled' || discussion.commentstatus == 'logged_in') %] -

    Post Anonymously

    -[% END %] -
    -
    - - - +
    + + +[%- IF pid # not for root-level reply %] +[% END %] + + +
    [% END # IF !user.is_anon || constants.allow_anonymous %] Modified: slashjp/trunk/plugins/Ajax/templates/prefs_d2;ajax;default =================================================================== --- slashjp/trunk/plugins/Ajax/templates/prefs_d2;ajax;default 2008-04-01 03:48:35 UTC (rev 562) +++ slashjp/trunk/plugins/Ajax/templates/prefs_d2;ajax;default 2008-04-01 04:03:21 UTC (rev 563) @@ -42,7 +42,6 @@
    [% IF user.discussion2 && user.discussion2 == "slashdot" %] -
    Retrieve [% comment_q_name = (user.is_subscriber || user.is_admin) ? 'd2_comment_q_all' : 'd2_comment_q'; comment_q = Slash.db.getDescriptions(comment_q_name); @@ -54,7 +53,6 @@ comment_order_def = user.d2_comment_order || 0; # score Slash.createSelect('d2_comment_order', comment_order, comment_order_def, 1) %] Comments First
    -
    [% END %] -
    +
    Never show link domains
    Show the links domain only in recommended situations
    Always show link domains -
    +
    Moderatee [% IF constants.m2 %]/ Metamoderator[% END %]
    - [%# XXX really? %] + [%- IF constants.modal_prefs_active %] + + + + [%- ELSE %] + + [%- END %]
    +[% FOREACH tagname = tagnames %] + +[% END %] +
    [% tagname | strip_html %]
    +[% ELSE %] + [% IF !user.tags_canread_stories %] +
    You are unable to read tags at this time.
    + [% ELSE %] +
    No tags have been assigned.
    + [% END %] +[% END %] + +__seclev__ +10000 +__version__ +$Id: usertagnames;users;default,v 1.1 2008/03/27 00:10:26 jamiemccarthy Exp $ Modified: slashjp/branches/upstream/current/plugins/Tags/templates/usertags;users;default =================================================================== --- slashjp/branches/upstream/current/plugins/Tags/templates/usertags;users;default 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/plugins/Tags/templates/usertags;users;default 2008-04-06 23:11:14 UTC (rev 569) @@ -18,6 +18,7 @@ __template__ [% thisnickname = useredit.nickname | strip_literal; url_nick = useredit.nickname | strip_paramattr; + url_base = "$gSkin.rootdir/~$url_nick/"; uid = useredit.uid; title = "Tags by $thisnickname ($uid)"; PROCESS user_titlebar tab_selected='tags' %] @@ -28,18 +29,18 @@ tagname_shown = 0; FOREACH tag = tags_grouped.$tagname %] [% UNLESS tag.globj_type == "submissions" %] - [% IF !tagname_shown; tagname_shown = 1 %][% tagname | strip_html %][% ELSE %] [% END %] + [% IF !tagname_shown; tagname_shown = 1 %][% tagname | strip_literal %][% ELSE %] [% END %]   - - [% IF tag.globj_type == "stories" %] - [% PROCESS linkStory dynamic=1 sid=tag.story.sid text=tag.story.title title=tag.story.title %] - [% ELSIF tag.globj_type == "urls" %] - [% tag.url.bookmark.title || tag.url.validtitle || tag.url.initialtitle | strip_literal %] - [% ELSIF tag.globj_type == "journals" %] - [% nick = Slash.db.getUser(tag.journal.uid, 'nickname') %] - [% tag.journal.description | strip_literal %] - [% END %] - + + [% IF tag.globj_type == "stories" %] + [% PROCESS linkStory dynamic=1 sid=tag.story.sid text=tag.story.title title=tag.story.title %] + [% ELSIF tag.globj_type == "urls" %] + [% tag.url.bookmark.title || tag.url.validtitle || tag.url.initialtitle | strip_literal %] + [% ELSIF tag.globj_type == "journals" %] + [% nick = Slash.db.getUser(tag.journal.uid, 'nickname') %] + [% tag.journal.description | strip_literal %] + [% END %] + [% END %] [% END; @@ -56,4 +57,4 @@ __seclev__ 10000 __version__ -$Id: usertags;users;default,v 1.9 2006/10/11 20:42:15 tvroom Exp $ +$Id: usertags;users;default,v 1.11 2008/04/02 15:27:13 jamiemccarthy Exp $ Added: slashjp/branches/upstream/current/plugins/Tags/templates/usertagsforname;users;default =================================================================== --- slashjp/branches/upstream/current/plugins/Tags/templates/usertagsforname;users;default (rev 0) +++ slashjp/branches/upstream/current/plugins/Tags/templates/usertagsforname;users;default 2008-04-06 23:11:14 UTC (rev 569) @@ -0,0 +1,58 @@ +__section__ +default +__description__ +useredit = user whose tags for a particular tagname are being displayed +tagname = the tagname +tags = an arrayref of hashrefs of the public tags applied by that user with that tagname + +This template and its API will likely change. + +__title__ + +__page__ +users +__lang__ +en_US +__name__ +usertagsforname +__template__ +[% thisnickname = useredit.nickname | strip_literal; + thistagname = tagname | strip_literal; + url_nick = useredit.nickname | strip_paramattr; + url_tagname = tagname | strip_paramattr; + url_base = "$gSkin.rootdir/~$url_nick/"; + uid = useredit.uid; + title = "Items tagged $thistagname by $thisnickname ($uid)"; + PROCESS user_titlebar tab_selected='tags' %] + +[% IF user.tags_canread_stories && tags.size %] +
    +[% FOREACH tag = tags %] + [% UNLESS tag.globj_type == "submissions" %] + + + + [% END; +END %] +
    + [% IF tag.globj_type == "stories" %] + [% PROCESS linkStory dynamic=1 sid=tag.story.sid text=tag.story.title title=tag.story.title %] + [% ELSIF tag.globj_type == "urls" %] + [% tag.url.bookmark.title || tag.url.validtitle || tag.url.initialtitle | strip_literal %] + [% ELSIF tag.globj_type == "journals" %] + [% nick = Slash.db.getUser(tag.journal.uid, 'nickname') %] + [% tag.journal.description | strip_literal %] + [% END %] +
    +[% ELSE %] + [% IF !user.tags_canread_stories %] +
    You are unable to read tags at this time.
    + [% ELSE %] +
    This user hasn't publicly tagged anything "[% thistagname %]".
    + [% END %] +[% END %] + +__seclev__ +10000 +__version__ +$Id: usertagsforname;users;default,v 1.2 2008/04/02 15:27:13 jamiemccarthy Exp $ Modified: slashjp/branches/upstream/current/sql/mysql/defaults.sql =================================================================== --- slashjp/branches/upstream/current/sql/mysql/defaults.sql 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/sql/mysql/defaults.sql 2008-04-06 23:11:14 UTC (rev 569) @@ -3,7 +3,7 @@ #-------------------------------------------------------- # Server version 3.23.26-beta-log # -# $Id: defaults.sql,v 1.394 2008/03/12 16:48:57 pudge Exp $ +# $Id: defaults.sql,v 1.396 2008/04/03 21:21:22 pudge Exp $ # # @@ -832,7 +832,7 @@ INSERT INTO vars (name, value, description) VALUES ('cur_performance_stats_lastid', '0', 'accesslogid to start searching at'); INSERT INTO vars (name, value, description) VALUES ('cur_performance_stats_weeks', '8', 'number of weeks back to compare current stats to'); INSERT INTO vars (name, value, description) VALUES ('currentqid',1,'The Current Question on the homepage pollbooth'); -INSERT INTO vars (name, value, description) VALUES ('cvs_tag_currentcode','T_2_5_0_197','The current cvs tag that the code was updated to - this does not affect site behavior but may be useful for your records'); +INSERT INTO vars (name, value, description) VALUES ('cvs_tag_currentcode','T_2_5_0_200','The current cvs tag that the code was updated to - this does not affect site behavior but may be useful for your records'); INSERT INTO vars (name, value, description) VALUES ('datadir','/usr/local/slash/www.example.com','What is the root of the install for Slash'); INSERT INTO vars (name, value, description) VALUES ('db_auto_increment_increment','1','If your master DB uses auto_increment_increment, i.e. multiple master replication, echo its value into this var'); INSERT INTO vars (name, value, description) VALUES ('dbsparklines_disp','0','Display dbsparklines in the currentAdminUsers box?'); Modified: slashjp/branches/upstream/current/sql/mysql/upgrades =================================================================== --- slashjp/branches/upstream/current/sql/mysql/upgrades 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/sql/mysql/upgrades 2008-04-06 23:11:14 UTC (rev 569) @@ -10,7 +10,7 @@ # after X started at the same time that X was tagged. # -# $Id: upgrades,v 1.1328 2008/03/21 02:44:47 pudge Exp $ +# $Id: upgrades,v 1.1340 2008/04/03 22:10:48 pudge Exp $ # # BEGIN tf23's additions @@ -5157,8 +5157,6 @@ # 2008-03-12 UPDATE vars SET value = 'T_2_5_0_197' WHERE name = 'cvs_tag_currentcode'; -# SLASHDOT LAST UPDATED HERE - # for plugins/Ajax UPDATE ajax_ops set reskey_name = 'ajax_user_static', reskey_type='createuse' WHERE op='admin_signoff'; @@ -5190,10 +5188,66 @@ UNIQUE tagname (tagname) ) TYPE=InnoDB; - # 2008-03-19 UPDATE vars SET value = 'T_2_5_0_198' WHERE name = 'cvs_tag_currentcode'; +# PUDGE LAST UPDATED HERE + +# for plugins/ResKey +INSERT INTO reskey_resource_checks VALUES (NULL, 1, 'all', 'Slash::ResKey::Checks::HumanConf', 701); +INSERT INTO reskey_vars VALUES (1, 'duration_uses-anon', 300, 'duration_uses for anon'); +INSERT INTO reskey_vars VALUES (1, 'duration_uses-anon-trolla', 3600, 'duration_uses for anon + trolla AL2'); +INSERT INTO reskey_vars VALUES (1, 'duration_uses-trolla', 300, 'duration_uses for tolla AL2'); +INSERT INTO reskey_vars VALUES (1, 'duration_uses-anon-mult', 1.5, 'multiply by this amount for each comment previously posted in the past 24 hours'); + +# for plugins/Tags +INSERT INTO vars (name, value, description) VALUES ('tags_usershow_cutoff', '200', 'More tags than this, and instead of showing the full taglist /~user/tags will show the list of tagnames'); +INSERT INTO vars (name, value, description) VALUES ('tags_active_maxshow', '200', 'Maximum number of tagged objects to display on /tags/foo'); + +# for tagboxes/FHEditorPop +INSERT INTO vars (name, value, description) VALUES ('tagbox_fheditorpop_susp_flagpop', '185', 'Admin score to artificially raise a suspicious host item to until an admin tags it'); +INSERT INTO vars (name, value, description) VALUES ('tagbox_fheditorpop_susp_maxtaggers', '7', 'Max number of unique users tagging (not voting) a low-scoring firehose item that should not raise suspicion'); +INSERT INTO vars (name, value, description) VALUES ('tagbox_fheditorpop_susp_minscore', '100', 'Min score required to not raise suspicion'); + +# for User2 +CREATE TABLE user_events ( + eid int UNSIGNED NOT NULL auto_increment, + code int UNSIGNED NOT NULL default 0, + uid mediumint(8) UNSIGNED NOT NULL default 0, + event int UNSIGNED NOT NULL default 0, + date datetime NOT NULL default '0000-00-00 00:00:00', + PRIMARY KEY eid (eid), + KEY uid (uid) +) TYPE=InnoDB; + +CREATE TABLE user_event_blocks ( + bid int UNSIGNED NOT NULL auto_increment, + uid mediumint UNSIGNED NOT NULL default 0, + code int UNSIGNED NOT NULL default 0, + block varchar(255) default NULL, + PRIMARY KEY bid (bid), + KEY uid (uid) +) TYPE=InnoDB; + +CREATE TABLE user_event_types ( + code smallint UNSIGNED NOT NULL auto_increment, + type varchar(32) NOT NULL default '', + PRIMARY KEY code (code) +) TYPE=InnoDB; + +# 2008-04-02 +UPDATE vars SET value = 'T_2_5_0_199' WHERE name = 'cvs_tag_currentcode'; + +# for tagboxes/RecentTags +INSERT IGNORE INTO vars (name, value, description) VALUES ('tagbox_recenttags_minclout', '4', 'Minimum clout sum to count a tagname'); + +# for plugins/Tags +INSERT INTO vars (name, value, description) VALUES ('tags_updateclouts_debuguids', '', 'UIDs to print debug info on during clout recalculation'); + +# 2008-04-03 +UPDATE vars SET value = 'T_2_5_0_200' WHERE name = 'cvs_tag_currentcode'; + # SLASHCODE/USEPERL LAST UPDATED HERE -# PUDGE LAST UPDATED HERE +# SLASHDOT LAST UPDATED HERE + Modified: slashjp/branches/upstream/current/tagboxes/FHEditorPop/FHEditorPop.pm =================================================================== --- slashjp/branches/upstream/current/tagboxes/FHEditorPop/FHEditorPop.pm 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/tagboxes/FHEditorPop/FHEditorPop.pm 2008-04-06 23:11:14 UTC (rev 569) @@ -2,7 +2,7 @@ # This code is a part of Slash, and is released under the GPL. # Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: FHEditorPop.pm,v 1.23 2008/01/30 22:57:28 jamiemccarthy Exp $ +# $Id: FHEditorPop.pm,v 1.24 2008/03/27 01:46:21 jamiemccarthy Exp $ # This goes by seclev right now but perhaps should define "editor" # to be more about author than admin seclev. In which case the @@ -32,7 +32,7 @@ use Data::Dumper; use vars qw( $VERSION ); -$VERSION = ' $Revision: 1.23 $ ' =~ /\$Revision:\s+([^\s]+)/; +$VERSION = ' $Revision: 1.24 $ ' =~ /\$Revision:\s+([^\s]+)/; use base 'Slash::DB::Utility'; # first for object init stuff, but really # needs to be second! figure it out. -- pudge @@ -217,9 +217,30 @@ $popularity += $extra_pop; } + # If more than a certain number of users have tagged this item with + # public non-voting tags and its popularity is low, there may be a + # bad reason why. Boost its editor score up so that an editor sees + # it and can review it. + if ($popularity >= ($constants->{tagbox_fheditorpop_susp_minscore} || 100)) { + my $max_taggers = $constants->{tagbox_fheditorpop_susp_maxtaggers} || 7; + my $flag_pop = $constants->{tagbox_fheditorpop_susp_flagpop} || 185; + my %tagger_uids = ( ); + my $tagged_by_admin = 0; + for my $tag_hr (@$tags_ar) { + next if $tag_hr->{tagnameid} == $upvoteid + || $tag_hr->{tagnameid} == $downvoteid + || $tag_hr->{private}; + my $uid = $tag_hr->{uid}; + $tagged_by_admin = 1, last if $admins->{$uid}; + $tagger_uids{$uid} = 1; + } + if (!$tagged_by_admin && scalar(keys %tagger_uids) > $max_taggers) { + $popularity = $flag_pop; + } + } + # If this is spam, its score goes way down. - my $firehose_db = getObject('Slash::FireHose'); - if ($fhitem->{is_spam} eq 'yes' || $firehose_db->itemHasSpamURL($fhitem)) { + if ($fhitem->{is_spam} eq 'yes' || $firehose->itemHasSpamURL($fhitem)) { my $max = defined($constants->{firehose_spam_score}) ? $constants->{firehose_spam_score} : -50; @@ -227,12 +248,12 @@ } # Set the corresponding firehose row to have this popularity. - warn "Slash::Tagbox::FHEditorPop->run bad data, fhid='$fhid' db='$firehose_db'" if !$fhid || !$firehose_db; + warn "Slash::Tagbox::FHEditorPop->run bad data, fhid='$fhid' db='$firehose'" if !$fhid || !$firehose; if ($options->{return_only}) { return $popularity; } main::tagboxLog(sprintf("FHEditorPop->run setting %d (%d) to %.6f", $fhid, $affected_id, $popularity)); - $firehose_db->setFireHose($fhid, { editorpop => $popularity }); + $firehose->setFireHose($fhid, { editorpop => $popularity }); } { # closure Modified: slashjp/branches/upstream/current/tagboxes/FHEditorPop/mysql_dump.sql =================================================================== --- slashjp/branches/upstream/current/tagboxes/FHEditorPop/mysql_dump.sql 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/tagboxes/FHEditorPop/mysql_dump.sql 2008-04-06 23:11:14 UTC (rev 569) @@ -1,5 +1,8 @@ -# $Id: mysql_dump.sql,v 1.3 2007/09/28 02:47:09 jamiemccarthy Exp $ +# $Id: mysql_dump.sql,v 1.4 2008/03/27 01:46:21 jamiemccarthy Exp $ INSERT INTO tagboxes (tbid, name, affected_type, clid, weight, last_run_completed, last_tagid_logged, last_tdid_logged, last_tuid_logged) VALUES (NULL, 'FHEditorPop', 'globj', 2, 1, '2000-01-01 00:00:00', 0, 0, 0); INSERT IGNORE INTO vars (name, value, description) VALUES ('tagbox_fheditorpop_edmult', '10', 'Multiplier by which editor nod/nixes are weighted for editor view'); INSERT IGNORE INTO vars (name, value, description) VALUES ('tagbox_fheditorpop_udcbasis', '1000', 'Basis for tags_udc vote clout weighting'); +INSERT IGNORE INTO vars (name, value, description) VALUES ('tagbox_fheditorpop_susp_flagpop', '185', 'Admin score to artificially raise a suspicious host item to until an admin tags it'); +INSERT IGNORE INTO vars (name, value, description) VALUES ('tagbox_fheditorpop_susp_maxtaggers', '7', 'Max number of unique users tagging (not voting) a low-scoring firehose item that should not raise suspicion'); +INSERT IGNORE INTO vars (name, value, description) VALUES ('tagbox_fheditorpop_susp_minscore', '100', 'Min score required to not raise suspicion'); Added: slashjp/branches/upstream/current/tagboxes/RecentTags/Makefile.PL =================================================================== --- slashjp/branches/upstream/current/tagboxes/RecentTags/Makefile.PL (rev 0) +++ slashjp/branches/upstream/current/tagboxes/RecentTags/Makefile.PL 2008-04-06 23:11:14 UTC (rev 569) @@ -0,0 +1,9 @@ +use ExtUtils::MakeMaker; +# See lib/ExtUtils/MakeMaker.pm for details of how to influence +# the contents of the Makefile that is written. +# $Id: Makefile.PL,v 1.1 2008/04/02 15:21:44 jamiemccarthy Exp $ +WriteMakefile( + 'NAME' => 'Slash::Tagbox::RecentTags', + 'VERSION_FROM' => 'RecentTags.pm', # finds $VERSION + 'PM' => { 'RecentTags.pm' => '$(INST_LIBDIR)/RecentTags.pm' }, +); Added: slashjp/branches/upstream/current/tagboxes/RecentTags/RecentTags.pm =================================================================== --- slashjp/branches/upstream/current/tagboxes/RecentTags/RecentTags.pm (rev 0) +++ slashjp/branches/upstream/current/tagboxes/RecentTags/RecentTags.pm 2008-04-06 23:11:14 UTC (rev 569) @@ -0,0 +1,175 @@ +#!/usr/bin/perl -w +# This code is a part of Slash, and is released under the GPL. +# Copyright 1997-2005 by Open Source Technology Group. See README +# and COPYING for more information, or see http://slashcode.com/. +# $Id: RecentTags.pm,v 1.4 2008/04/03 22:18:39 jamiemccarthy Exp $ + +package Slash::Tagbox::RecentTags; + +=head1 NAME + +Slash::Tagbox::RecentTags - update the Recent Tags slashbox + +=head1 SYNOPSIS + + my $tagbox_tcu = getObject("Slash::Tagbox::RecentTags"); + my $feederlog_ar = $tagbox_tcu->feed_newtags($users_ar); + $tagbox_tcu->run($affected_globjid); + +=cut + +use strict; + +use Slash; +use Slash::DB; +use Slash::Utility::Environment; +use Slash::Tagbox; + +use Data::Dumper; + +use vars qw( $VERSION ); +$VERSION = ' $Revision: 1.4 $ ' =~ /\$Revision:\s+([^\s]+)/; + +use base 'Slash::DB::Utility'; # first for object init stuff, but really + # needs to be second! figure it out. -- pudge +use base 'Slash::DB::MySQL'; + +sub new { + my($class, $user) = @_; + + return undef if !$class->isInstalled(); + + # Note that getTagboxes() would call back to this new() function + # if the tagbox objects have not yet been created -- but the + # no_objects option prevents that. See getTagboxes() for details. + my($tagbox_name) = $class =~ /(\w+)$/; + my %self_hash = %{ getObject('Slash::Tagbox')->getTagboxes($tagbox_name, undef, { no_objects => 1 }) }; + my $self = \%self_hash; + return undef if !$self || !keys %$self; + + bless($self, $class); + $self->{virtual_user} = $user; + $self->sqlConnect(); + + return $self; +} + +sub isInstalled { + my($class) = @_; + my $constants = getCurrentStatic(); + my($tagbox_name) = $class =~ /(\w+)$/; + return $constants->{plugin}{Tags} && $constants->{tagbox}{$tagbox_name} || 0; +} + +sub feed_newtags { + my($self, $tags_ar) = @_; + my $constants = getCurrentStatic(); + my $tagsdb = getObject('Slash::Tags'); + my $seconds_back = $constants->{tagbox_recenttags_secondsback}; + my $exclude_tagnames = $constants->{tagbox_top_excludetagnames} || 'yes no'; + my %exclude_tagnameid = ( + map { ($tagsdb->getTagnameidCreate($_), 1) } + split / /, $exclude_tagnames + ); + if (scalar(@$tags_ar) < 4) { + main::tagboxLog("RecentTags->feed_newtags called for tags '" . join(' ', map { $_->{tagid} } @$tags_ar) . "'"); + } else { + main::tagboxLog("RecentTags->feed_newtags called for " . scalar(@$tags_ar) . " tags " . $tags_ar->[0]{tagid} . " ... " . $tags_ar->[-1]{tagid}); + } + + my $ret_ar = [ ]; + for my $tag_hr (@$tags_ar) { + # Tags outside the window aren't important (maybe this tagbox + # is running through a backlog) + my $seconds_old = time - $tag_hr->{created_at_ut}; + next if $seconds_old > $seconds_back; + # Tags that the Top tagbox excludes aren't important. + next if $exclude_tagnameid{ $tag_hr->{tagnameid} }; + # Tags on a hose item under the minslice aren't important. + my $minslice = $constants->{tagbox_recenttags_minslice} || 4; + my $firehosedb = getObject('Slash::FireHose', { db_type => 'reader' }); + my $firehose_id = $firehosedb->getFireHoseIdFromGlobjid($tag_hr->{globjid}); + next unless $firehose_id; + my $firehose = $firehosedb->getFireHose($firehose_id); + my $pop = $firehose->{popularity} || 0; + my $minpop = $firehosedb->getMinPopularityForColorLevel($minslice); + next if $pop < $minpop; + my $ret_hr = { + affected_id => 1, + # We could here reduce importance if the tag is not Descriptive + # or has a reduced clout. XXX + importance => 0.1, + }; + # We identify this little chunk of importance by either + # tagid or tdid depending on whether the source data had + # the tdid field (which tells us whether feed_newtags was + # "really" called via feed_deactivatedtags). + if ($tag_hr->{tdid}) { $ret_hr->{tdid} = $tag_hr->{tdid} } + else { $ret_hr->{tagid} = $tag_hr->{tagid} } + push @$ret_ar, $ret_hr; + } + + return $ret_ar; +} + +sub feed_deactivatedtags { + my($self, $tags_ar) = @_; + main::tagboxLog("RecentTags->feed_deactivatedtags called: tags_ar='" . join(' ', map { $_->{tagid} } @$tags_ar) . "'"); + my $ret_ar = $self->feed_newtags($tags_ar); + main::tagboxLog("RecentTags->feed_deactivatedtags returning " . scalar(@$ret_ar)); + return $ret_ar; +} + +sub feed_userchanges { + my($self, $users_ar) = @_; + my $constants = getCurrentStatic(); + my $tagsdb = getObject('Slash::Tags'); + main::tagboxLog("RecentTags->feed_userchanges called (oddly); returning blank"); + return [ ]; +} + +sub run { + my($self, $affected_id) = @_; + my $constants = getCurrentStatic(); + my $tagsdb = getObject('Slash::Tags'); + my $tags_reader = getObject('Slash::Tags', { db_type => 'reader' }); + + my $exclude_tagnames = $constants->{tagbox_top_excludetagnames} || 'yes no'; + my %exclude_tagname = ( + map { ($_, 1) } + split / /, $exclude_tagnames + ); + my $num_wanted = $constants->{tagbox_recenttags_num} || 5; + my $max_num = $num_wanted + scalar(keys %exclude_tagname); + my $seconds_back = $constants->{tagbox_recenttags_secondsback} || 7200; + my $min_clout = $constants->{tagbox_recenttags_minclout} || 4.0; + my $tagnames_ar = $tags_reader->listTagnamesActive({ + max_num => $max_num, + seconds => $seconds_back, + min_clout => $min_clout, + }); + + # Strip out tagnames we want to exclude. + @$tagnames_ar = grep { !$exclude_tagname{$_} } @$tagnames_ar; + + # Max of 5 or whatever. + $#$tagnames_ar = 4 if scalar(@$tagnames_ar) > $num_wanted; + + if (scalar(@$tagnames_ar) < $num_wanted) { + # If we don't get as many as we wanted, leave up + # whatever was there before. + main::tagboxLog("RecentTags->run only " . scalar(@$tagnames_ar) . " so not changing"); + return; + } + # XXX this should be a template + my $block = '
      '; + for my $tagname (@$tagnames_ar) { + $block .= qq{
    • $tagname
    • }; + } + $block .= '
    '; + main::tagboxLog("RecentTags->run setting Recent Tags to '@$tagnames_ar' (" . length($block) . " chars)"); + $self->setBlock('activetags', { block => $block }); +} + +1; + Added: slashjp/branches/upstream/current/tagboxes/RecentTags/TAGBOX =================================================================== --- slashjp/branches/upstream/current/tagboxes/RecentTags/TAGBOX (rev 0) +++ slashjp/branches/upstream/current/tagboxes/RecentTags/TAGBOX 2008-04-06 23:11:14 UTC (rev 569) @@ -0,0 +1,4 @@ +# $Id: TAGBOX,v 1.1 2008/04/02 15:21:44 jamiemccarthy Exp $ +name=RecentTags +description=Update the Recent Tags homepage slashbox +mysql_dump=mysql_dump.sql Added: slashjp/branches/upstream/current/tagboxes/RecentTags/mysql_dump.sql =================================================================== --- slashjp/branches/upstream/current/tagboxes/RecentTags/mysql_dump.sql (rev 0) +++ slashjp/branches/upstream/current/tagboxes/RecentTags/mysql_dump.sql 2008-04-06 23:11:14 UTC (rev 569) @@ -0,0 +1,8 @@ +# $Id: mysql_dump.sql,v 1.2 2008/04/03 20:30:24 jamiemccarthy Exp $ +INSERT INTO tagboxes (tbid, name, affected_type, clid, weight, last_run_completed, last_tagid_logged, last_tdid_logged, last_tuid_logged) VALUES (NULL, 'RecentTags', 'globj', 1, 1, '2000-01-01 00:00:00', 0, 0, 0); + +INSERT IGNORE INTO vars (name, value, description) VALUES ('tagbox_recenttags_secondsback', '7200', 'Number of seconds to look back'); +INSERT IGNORE INTO vars (name, value, description) VALUES ('tagbox_recenttags_minclout', '4', 'Minimum clout sum to count a tagname'); +INSERT IGNORE INTO vars (name, value, description) VALUES ('tagbox_recenttags_minslice', '4', 'Minimum slice number to count tags on'); +INSERT IGNORE INTO vars (name, value, description) VALUES ('tagbox_recenttags_num', '5', 'Number of recent tags to list'); + Modified: slashjp/branches/upstream/current/tagboxes/Top/Top.pm =================================================================== --- slashjp/branches/upstream/current/tagboxes/Top/Top.pm 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/tagboxes/Top/Top.pm 2008-04-06 23:11:14 UTC (rev 569) @@ -2,7 +2,7 @@ # This code is a part of Slash, and is released under the GPL. # Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Top.pm,v 1.17 2008/02/28 19:51:01 jamiemccarthy Exp $ +# $Id: Top.pm,v 1.18 2008/03/25 18:42:55 pudge Exp $ package Slash::Tagbox::Top; @@ -28,7 +28,7 @@ use Data::Dumper; use vars qw( $VERSION ); -$VERSION = ' $Revision: 1.17 $ ' =~ /\$Revision:\s+([^\s]+)/; +$VERSION = ' $Revision: 1.18 $ ' =~ /\$Revision:\s+([^\s]+)/; use base 'Slash::DB::Utility'; # first for object init stuff, but really # needs to be second! figure it out. -- pudge @@ -205,7 +205,6 @@ grep { $_ } map { ($_, $tags_reader->getOppositeTagname($_)) } @{$tags_reader->getExcludedTags} -# split / /, ($constants->{tagbox_top_excludetagnames} || '') ); # Eliminate tagnames that are just the author's name. my @names = map { lc } @{ $tags_reader->getAuthorNames() }; Modified: slashjp/branches/upstream/current/themes/slashcode/THEME =================================================================== --- slashjp/branches/upstream/current/themes/slashcode/THEME 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/themes/slashcode/THEME 2008-04-06 23:11:14 UTC (rev 569) @@ -1,4 +1,4 @@ -# $Id: THEME,v 1.131 2008/03/14 17:57:33 scc Exp $ +# $Id: THEME,v 1.134 2008/04/02 14:43:55 entweichen Exp $ name=slashcode description="Slashcode.com theme" topic=htdocs/images/topics/topicbug.jpg @@ -59,6 +59,10 @@ image=htdocs/images/comm-minus.gif image=htdocs/images/comm-plus.gif image=htdocs/images/contract.gif +image=htdocs/images/corner_w_br.png +image=htdocs/images/corner_w_bl.png +image=htdocs/images/corner_w_tr.png +image=htdocs/images/corner_w_tl.png image=htdocs/images/cr.gif image=htdocs/images/ctl_grey.gif image=htdocs/images/ctl_red.gif @@ -126,6 +130,7 @@ htdoc=htdocs/robots.txt htdoc=htdocs/topics.pl htdoc=htdocs/users.pl +htdoc=htdocs/users2.pl htdoc=htdocs/images/comments.js htdoc=htdocs/images/dumper.js htdoc=htdocs/badge.pl @@ -317,9 +322,11 @@ template=templates/undo_mod;comments;default template=templates/url_related;misc;default template=templates/userboxes;misc;default +template=templates/userboxes2;misc;default template=templates/userCom;users;default template=templates/userFireHose;users;default template=templates/userInfo;users;default +template=templates/userInfo2;users;default template=templates/userSub;users;default template=templates/user_titlebar;misc;default template=templates/userlogin;misc;default Modified: slashjp/branches/upstream/current/themes/slashcode/htdocs/comments.css =================================================================== --- slashjp/branches/upstream/current/themes/slashcode/htdocs/comments.css 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/themes/slashcode/htdocs/comments.css 2008-04-06 23:11:14 UTC (rev 569) @@ -86,6 +86,7 @@ border: 1px solid #ddd; border-bottom: none; padding: .3em; + overflow: hidden; } .commentshrunk, .commentstatus, .commentload { font-weight: bold } @@ -118,7 +119,7 @@ margin: 0 0 0 -.3em; padding: 0 .3em; text-decoration: none; - background: url("http://images.slashcode.com/comm-minus.gif") 0 .2em no-repeat; + background: url("/images/comm-minus.gif") 0 .2em no-repeat; right: -1.4em; z-index: 2; cursor: pointer; @@ -129,7 +130,7 @@ margin: 0; padding: 0 .3em; text-decoration: none; - background: url("http://images.slashcode.com/comm-plus.gif") 0 .2em no-repeat; + background: url("/images/comm-plus.gif") 0 .2em no-repeat; right: -1.4em; z-index: 1; cursor: pointer; @@ -160,7 +161,7 @@ .comment > .oneline { border: 1px solid #e5e5e5; margin: 1em 0 0 0; - padding: .3em 0 0 0; + padding: 0.35em 0 0 0.25em; position: relative; width: 99%; height: 1.3em; @@ -168,7 +169,8 @@ } .comment > .currcomment { - border: 1px dotted #666; + margin: 0.85em 0px -0.15em -0.15em; + border: .15em solid rgb(142,142,142); } /* lots of space between lines */ @@ -379,3 +381,53 @@ #ccw-hide-bar-tab { border-top-width: 0; } .horizontal #ccw-abbr-bar-tab { border-bottom-width: 1px; border-right: none; } .horizontal #ccw-hide-bar-tab { border-top-width: 1px; border-left: none; } + + +/* Action Buttons */ + +.nbutton{ + background: #666 none top left no-repeat; + color:#fff; + margin:0.25em; + padding: .4em 0; +} +.nbutton p{ + display:inline; + background: transparent none top right no-repeat; + padding: .4em 0; +} +.nbutton p b{ + display:inline; + background: transparent none bottom left no-repeat; + padding: .4em 0; +} +.nbutton p b a { + background: transparent none bottom right no-repeat !important; + padding: .4em 1em; + color:#fff !important; + font-weight:normal; + text-decoration:none; +} +.nbutton:hover {background-color: #444} + +span.current {position: absolute; left: .5em; margin-top: -.2em; z-index: 0; font-weight: bold; font-size: 197%;} + +.contain { + border: .15em solid #d5d5d5; + border-top: none; +} + +.inline_comment {border: 2px solid #666; margin: 1em; position: relative;} +.inline_comment input[type="text"] {width: auto} +.inline_comment textarea {margin: 1em; width: auto} +.inline_comment .generalbody {margin: 0; padding: 0;} +.inline_comment .pref {position: absolute; right: 0; top: -.8em} +.inline_comment .pref a {right: 10px; background-image: url("/images/sic_icons.png"); color: #fff; background-repeat: no-repeat; background-position: 0px -1198px;padding: 5px 10px; position:absolute; text-decoration:none; text-indent:-7000em; top: .8em; } +.inline_comment .state { display: none } +.inline_comment .replyto_buttons, .inlinemsg {margin: .5em 1em;} +.inline_comment #commentlisting {padding: 0; margin: 0;} +.warning {background: #ffd; border: 1px solid #fe6; padding: .5em; margin: .5em 0 1em 0; color: #000;} +.inline_comment .replyto_msg {background: #fdd; border: 1px solid #fbb; padding: .5em; margin: .5em 1em 0; color: #000 } +.inline_comment .commentload {margin: 0 1em; font-weight: bold; color: #aaa;} +.inline_comment .contain {margin: 0; padding: 0; border: none} + Modified: slashjp/branches/upstream/current/themes/slashcode/htdocs/comments.pl =================================================================== --- slashjp/branches/upstream/current/themes/slashcode/htdocs/comments.pl 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/themes/slashcode/htdocs/comments.pl 2008-04-06 23:11:14 UTC (rev 569) @@ -2,7 +2,7 @@ # This code is a part of Slash, and is released under the GPL. # Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: comments.pl,v 1.272 2008/03/20 07:30:29 pudge Exp $ +# $Id: comments.pl,v 1.273 2008/04/02 14:14:10 entweichen Exp $ use strict; use Slash 2.003; # require Slash 2.3.x @@ -609,6 +609,46 @@ ); } + # Add user2 event. This will eventually live in its own method. + if (!$user->{is_anon}) { + my $uid = $user->{uid}; + my $cid = $saved_comment->{cid}; + my $events = $slashdb->sqlSelectAllHashref( + 'eid', 'eid, date', 'user_events', "uid = $uid and code = 1"); + + if ((scalar keys %$events) == 5) { + my $eid = [sort keys %$events]->[0]; + $slashdb->sqlDelete('user_events', "uid = $uid and code = 1 and eid = $eid"); + } + + $slashdb->sqlInsert('user_events', { + code => 1, + uid => $uid, + event => $cid, + -date => 'NOW()', + }); + + my $event_blocks = $slashdb->sqlSelectAllHashref( + 'uid', 'bid, uid, block', 'user_event_blocks', "uid = $uid and code = 1"); + + if (!%$event_blocks) { + $slashdb->sqlInsert('user_event_blocks', { + code => 1, + uid => $uid, + block => $cid, + }); + } else { + my @blocks = split(/,/, $event_blocks->{$uid}->{block}); + @blocks = @blocks[1 .. 4] if (scalar @blocks == 5); + $blocks[$#blocks + 1] = $cid; + my $new_blocks = join(",", @blocks); + + $slashdb->sqlUpdate('user_event_blocks', { block => $new_blocks }, "uid = $uid and code = 1"); + } + } + + + # OK -- if we make it all the way here, and there were # no errors so no header has been emitted, and we were # asked to redirect to a new URL, NOW we can finally Modified: slashjp/branches/upstream/current/themes/slashcode/htdocs/images/comments.js =================================================================== (Binary files differ) Modified: slashjp/branches/upstream/current/themes/slashcode/htdocs/slashcode_lite.css =================================================================== --- slashjp/branches/upstream/current/themes/slashcode/htdocs/slashcode_lite.css 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/themes/slashcode/htdocs/slashcode_lite.css 2008-04-06 23:11:14 UTC (rev 569) @@ -156,3 +156,6 @@ { background: #ddd !important;} +div.commentTop div.title h4, .comment .oneline div.title h4 a {background: transparent !important;} + .comment .oneline div.title h4 a {color: #00E !important} + Modified: slashjp/branches/upstream/current/themes/slashcode/htdocs/users.pl =================================================================== --- slashjp/branches/upstream/current/themes/slashcode/htdocs/users.pl 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/themes/slashcode/htdocs/users.pl 2008-04-06 23:11:14 UTC (rev 569) @@ -2,7 +2,7 @@ # This code is a part of Slash, and is released under the GPL. # Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: users.pl,v 1.345 2008/02/07 00:51:23 pudge Exp $ +# $Id: users.pl,v 1.347 2008/03/25 19:54:23 jamiemccarthy Exp $ use strict; use Digest::MD5 'md5_hex'; @@ -1611,6 +1611,11 @@ my $constants = getCurrentStatic(); my $tags_reader = getObject('Slash::Tags', { db_type => 'reader' }); + # XXX if $user_edit->{acl}{spammer}, either abort or put ref=nofollow in all links + + my $tagname = $form->{tagname} || ''; + $tagname = '' if !$tags_reader->tagnameSyntaxOK($tagname); + my($uid, $user_edit); if ($form->{uid} || $form->{nick}) { $uid = $form->{uid} || $tags_reader->getUserUID($form->{nick}); @@ -1627,11 +1632,41 @@ return; } - my $tags_ar = $tags_reader->getGroupedTagsFromUser($user_edit->{uid}); - slashDisplay('usertags', { - useredit => $user_edit, - tags_grouped => $tags_ar, - }); + my $tagnameid = $tags_reader->getTagnameidFromNameIfExists($tagname); + if ($tagnameid) { + # Show all user's tags for one particular tagname. + my $tags_hr = $tags_reader->getGroupedTagsFromUser($user_edit->{uid}, + { tagnameid => $tagnameid }); + my $tags_ar = $tags_hr->{$tagname} || [ ]; + slashDisplay('usertagsforname', { + useredit => $user_edit, + tagname => $tagname, + tags => $tags_ar, + }); + + } else { + my $tags_hr = $tags_reader->getGroupedTagsFromUser($user_edit->{uid}); + my $num_tags = 0; + for my $tn (keys %$tags_hr) { + $num_tags += scalar @{ $tags_hr->{$tn} }; + } + my $cutoff = $constants->{tags_usershow_cutoff} || 200; + if ($num_tags <= $cutoff) { + # Show all user's tags, grouped by tagname. + slashDisplay('usertags', { + useredit => $user_edit, + tags_grouped => $tags_hr, + }); + } else { + # Show all user's tagnames, with links to show all + # tags for each particular tagname. + my $tagname_ar = [ sort keys %$tags_hr ]; + slashDisplay('usertagnames', { + useredit => $user_edit, + tagnames => $tagname_ar, + }); + } + } } ################################################################# Added: slashjp/branches/upstream/current/themes/slashcode/htdocs/users2.pl =================================================================== --- slashjp/branches/upstream/current/themes/slashcode/htdocs/users2.pl (rev 0) +++ slashjp/branches/upstream/current/themes/slashcode/htdocs/users2.pl 2008-04-06 23:11:14 UTC (rev 569) @@ -0,0 +1,3762 @@ +#!/usr/bin/perl -w +# This code is a part of Slash, and is released under the GPL. +# Copyright 1997-2005 by Open Source Technology Group. See README +# and COPYING for more information, or see http://slashcode.com/. +# $Id: users2.pl,v 1.1 2008/04/02 14:38:23 entweichen Exp $ + +use strict; +use Digest::MD5 'md5_hex'; +use Slash; +use Slash::Display; +use Slash::Utility; +use Slash::Constants qw(:messages); + +################################################################# +sub main { + my $slashdb = getCurrentDB(); + my $constants = getCurrentStatic(); + my $user = getCurrentUser(); + my $form = getCurrentForm(); + my $gSkin = getCurrentSkin(); + my $formname = $0; + $formname =~ s/.*\/(\w+)\.pl/$1/; + + my $error_flag = 0; + my $formkey = $form->{formkey}; + + my $suadmin_flag = $user->{seclev} >= 10000 ? 1 : 0 ; + my $postflag = $user->{state}{post}; + my $op = lc($form->{op}); + + return if (!$user->{is_admin}); + + # savepasswd is a special case, because once it's called, you + # have to reload the form, and you don't want to do any checks if + # you've just saved. + my $savepass_flag = $op eq 'savepasswd' ? 1 : 0 ; + + my $ops = { + admin => { + function => \&adminDispatch, + seclev => 10000, # if this should be lower, + # then something else is + # broken, because it allows + # anyone with this seclev + # to change their own seclev + formname => $formname, + # just in case we need it for something else, we have it ... + checks => [ qw (generate_formkey) ], + }, + no_user => { + function => \&noUser, + seclev => 0, + formname => $formname, + checks => [], + }, + userinfo => { + function => \&showInfo, + #I made this change, not all sites are going to care. -Brian + seclev => $constants->{users_show_info_seclev}, + formname => $formname, + checks => [], + tab_selected_1 => 'me', + tab_selected_2 => 'info', + }, + userfirehose => { + function => \&showFireHose, + seclev => 0, + formname => $formname, + checks => [], + tab_selected_1 => 'me', + tab_selected_2 => 'firehose' + }, + usersubmissions => { + function => \&showSubmissions, + #I made this change, not all sites are going to care. -Brian + seclev => $constants->{users_show_info_seclev}, + checks => [], + tab_selected_1 => 'me', + }, + usercomments => { + function => \&showComments, + #I made this change, not all sites are going to care. -Brian + seclev => $constants->{users_show_info_seclev}, + checks => [], + tab_selected_1 => 'me', + }, + display => { + function => \&showInfo, + #I made this change, not all sites are going to care. -Brian + seclev => $constants->{users_show_info_seclev}, + formname => $formname, + checks => [], + tab_selected_1 => 'me', + tab_selected_2 => 'info', + }, +# savepasswd => { +# function => \&savePasswd, +# seclev => 1, +# post => 1, +# formname => $formname, +# checks => [ qw (max_post_check valid_check +# formkey_check regen_formkey) ], +# tab_selected_1 => 'preferences', +# tab_selected_2 => 'password', +# }, + saveuseradmin => { + function => \&saveUserAdmin, + seclev => 10000, + post => 1, + formname => $formname, + checks => [], + }, + savehome => { + function => \&saveHome, + seclev => 1, + post => 1, + formname => $formname, + checks => [ qw (valid_check + formkey_check regen_formkey) ], + tab_selected_1 => 'preferences', + tab_selected_2 => 'home', + }, + savecomm => { + function => \&saveComm, + seclev => 1, + post => 1, + formname => $formname, + checks => [ qw (valid_check + formkey_check regen_formkey) ], + tab_selected_1 => 'preferences', + tab_selected_2 => 'comments', + }, + saveuser => { + function => \&saveUser, + seclev => 1, + post => 1, + formname => $formname, + checks => [ qw (valid_check + formkey_check regen_formkey) ], + tab_selected_1 => 'preferences', + tab_selected_2 => 'user', + }, +# changepasswd => { +# function => \&changePasswd, +# seclev => 1, +# formname => $formname, +# checks => $savepass_flag ? [] : +# [ qw (generate_formkey) ], +# tab_selected_1 => 'preferences', +# tab_selected_2 => 'password', +# }, + editmiscopts => { + function => \&editMiscOpts, + seclev => 1, + formname => $formname, + checks => [ ], + tab_selected_1 => 'preferences', + tab_selected_2 => 'misc', + }, + savemiscopts => { + function => \&saveMiscOpts, + seclev => 1, + formname => $formname, + checks => [ ], + tab_selected_1 => 'preferences', + tab_selected_2 => 'misc', + }, + edituser => { + function => \&editUser, + seclev => 1, + formname => $formname, + checks => [ qw (generate_formkey) ], + tab_selected_1 => 'preferences', + tab_selected_2 => 'user', + }, + authoredit => { + function => \&editUser, + seclev => 10000, + formname => $formname, + checks => [], + }, + edithome => { + function => \&editHome, + seclev => 1, + formname => $formname, + checks => [ qw (generate_formkey) ], + tab_selected_1 => 'preferences', + tab_selected_2 => 'home', + }, + editcomm => { + function => \&editComm, + seclev => 1, + formname => $formname, + checks => [ qw (generate_formkey) ], + tab_selected_1 => 'preferences', + tab_selected_2 => 'comments', + }, +# newuser => { +# function => \&newUser, +# seclev => 0, +# formname => "${formname}/nu", +# checks => [ qw (max_post_check valid_check +# formkey_check regen_formkey) ], +# }, + newuseradmin => { + function => \&newUserForm, + seclev => 10000, + formname => "${formname}/nu", + checks => [], + }, + previewbox => { + function => \&previewSlashbox, + seclev => 0, + formname => $formname, + checks => [], + }, +# mailpasswd => { +# function => \&mailPasswd, +# seclev => 0, +# formname => "${formname}/mp", +# checks => [ qw (max_post_check valid_check +# interval_check formkey_check ) ], +# tab_selected_1 => 'preferences', +# tab_selected_2 => 'password', +# }, + validateuser => { + function => \&validateUser, + seclev => 1, + formname => $formname, + checks => ['regen_formkey'], + }, + showtags => { + function => \&showTags, + seclev => 1, + formname => $formname, + checks => [], + tab_selected => 'tags', + }, + showbookmarks => { + function => \&showBookmarks, + seclev => 0, + formname => $formname, + checks => [], + tab_selected => 'bookmarks', + }, + edittags => { + function => \&editTags, + seclev => 1, + formname => $formname, + checks => [], + tab_selected => 'tags', + }, + savetags => { + function => \&saveTags, + seclev => 1, + formname => $formname, + checks => [], + tab_selected => 'tags', + }, +# userclose => { +# function => \&displayForm, +# seclev => 0, +# formname => $formname, +# checks => [], +# }, +# newuserform => { +# function => \&displayForm, +# seclev => 0, +# formname => "${formname}/nu", +# checks => [ qw (max_post_check +# generate_formkey) ], +# }, +# mailpasswdform => { +# function => \&displayForm, +# seclev => 0, +# formname => "${formname}/mp", +# checks => [ qw (max_post_check +# generate_formkey) ], +# tab_selected_1 => 'preferences', +# tab_selected_2 => 'password', +# }, + displayform => { + function => \&displayForm, + seclev => 0, + formname => $formname, + checks => [ qw (generate_formkey) ], + tab_selected_1 => 'me', + }, + listreadonly => { + function => \&listReadOnly, + seclev => 100, + formname => $formname, + checks => [], + adminmenu => 'security', + tab_selected => 'readonly', + }, + listbanned => { + function => \&listBanned, + seclev => 100, + formname => $formname, + checks => [], + adminmenu => 'security', + tab_selected => 'banned', + }, + topabusers => { + function => \&topAbusers, + seclev => 100, + formname => $formname, + checks => [], + adminmenu => 'security', + tab_selected => 'abusers', + }, + listabuses => { + function => \&listAbuses, + seclev => 100, + formname => $formname, + checks => [], + }, + force_acct_verify => { + function => \&forceAccountVerify, + seclev => 100, + post => 1, + formname => $formname, + checks => [] + } + + } ; + + # Note this is NOT the default op. "userlogin" or "userinfo" is + # the default op, and it's set either 5 lines down or about 100 + # lines down, depending. Yes, that's dumb. Yes, we should + # change it. It would require tracing through a fair bit of logic + # though and I don't have the time right now. - Jamie + $ops->{default} = $ops->{displayform}; + for (qw(newuser newuserform mailpasswd mailpasswdform changepasswd savepasswd userlogin userclose)) { + $ops->{$_} = $ops->{default}; + } + + my $errornote = ""; + if ($form->{op} && ! defined $ops->{$op}) { + $errornote .= getError('bad_op', { op => $form->{op}}, 0, 1); + $op = $user->{is_anon} ? 'userlogin' : 'userinfo'; + } + + if ($op eq 'userlogin' && ! $user->{is_anon}) { + redirect(cleanRedirectUrl($form->{returnto} || '')); + return; + + # this will only redirect if it is a section-based rootdir with + # its rootdir different from real_rootdir + } elsif ($op eq 'userclose' && $gSkin->{rootdir} ne $constants->{real_rootdir}) { + redirect($constants->{real_rootdir} . '/login.pl?op=userclose'); + return; + + } elsif ($op =~ /^(?:newuser|newuserform|mailpasswd|mailpasswdform|changepasswd|savepasswd|userlogin|userclose|displayform)$/) { + my $op = $form->{op}; + $op = 'changeprefs' if $op eq 'changepasswd'; + $op = 'saveprefs' if $op eq 'savepasswd'; + redirect($constants->{real_rootdir} . '/login.pl?op=' . $op); + return; + + # never get here now + } elsif ($op eq 'savepasswd') { + my $error_flag = 0; + if ($user->{seclev} < 100) { + for my $check (@{$ops->{savepasswd}{checks}}) { + # the only way to save the error message is to pass by ref + # $errornote and add the message to note (you can't print + # it out before header is called) + $error_flag = formkeyHandler($check, $formname, $formkey, \$errornote); + last if $error_flag; + } + } + + if (! $error_flag) { + $error_flag = savePasswd({ noteref => \$errornote }) ; + } + # change op to edituser and let fall through; + # we need to have savePasswd set the cookie before + # header() is called -- pudge + if ($user->{seclev} < 100 && ! $error_flag) { + $slashdb->updateFormkey($formkey, length($ENV{QUERY_STRING})); + } + $op = $error_flag ? 'changepasswd' : 'userinfo'; + $form->{userfield} = $user->{uid}; + } + + # Figure out what the op really is. + $op = 'userinfo' if (! $form->{op} && ($form->{uid} || $form->{nick})); + $op ||= $user->{is_anon} ? 'userlogin' : 'userinfo'; + if ($user->{is_anon} && ( ($ops->{$op}{seclev} > 0) || ($op =~ /^newuserform|mailpasswdform|displayform$/) )) { + redirect($constants->{real_rootdir} . '/login.pl'); + return; + } elsif ($user->{seclev} < $ops->{$op}{seclev}) { + $op = 'userinfo'; + } + if ($ops->{$op}{post} && !$postflag) { + $op = $user->{is_anon} ? 'default' : 'userinfo'; + } + + # Print the header and very top stuff on the page. We have + # three ops that (may) end up routing into showInfo(), which + # needs to do some stuff before it calls header(), so for + # those three, don't bother. + my $header; + if ($op !~ /^(userinfo|display|saveuseradmin|admin|userfirehose$)/) { + my $data = { + adminmenu => $ops->{$op}{adminmenu} || 'admin', + tab_selected => $ops->{$op}{tab_selected}, + }; + header(getMessage('user_header'), '', $data) or return; + # This is a hardcoded position, bad idea and should be fixed -Brian + # Yeah, we should pull this into a template somewhere... + print getMessage('note', { note => $errornote }) if defined $errornote; + $header = 1; + } + + if ($constants->{admin_formkeys} || $user->{seclev} < 100) { + + my $done = 0; + $done = 1 if $op eq 'savepasswd'; # special case + $formname = $ops->{$op}{formname}; + + # No need for HumanConf if the constant for it is not + # switched on, or if the user's karma is high enough + # to get out of it. (But for "newuserform," the current + # user's karma doesn't get them out of having to prove + # they're a human for creating a *new* user.) + my $options = {}; + if ( !$constants->{plugin}{HumanConf} + || !$constants->{hc} + || !$constants->{hc_sw_newuser} + && ($formname eq 'users/nu' || $op eq 'newuserform') + || !$constants->{hc_sw_mailpasswd} + && ($formname eq 'users/mp' || $op eq 'mailpasswdform') + || $user->{karma} > $constants->{hc_maxkarma} + && !$user->{is_anon} + && !($op eq 'newuser' || $op eq 'newuserform') + ) { + $options->{no_hc} = 1; + } + + DO_CHECKS: while (!$done) { + for my $check (@{$ops->{$op}{checks}}) { + $ops->{$op}{update_formkey} = 1 if $check eq 'formkey_check'; + $error_flag = formkeyHandler($check, $formname, $formkey, + undef, $options); + if ($error_flag == -1) { + # Special error: HumanConf failed. Go + # back to the previous op, start over. + if ($op =~ /^(newuser|mailpasswd)$/) { + $op .= "form"; + $error_flag = 0; + next DO_CHECKS; + } + } elsif ($error_flag) { + $done = 1; + last; + } + } + $done = 1; + } + + if (!$error_flag && !$options->{no_hc}) { + my $hc = getObject("Slash::HumanConf"); + $hc->reloadFormkeyHC($formname) if $hc; + } + + } + + errorLog("users.pl error_flag '$error_flag'") if $error_flag; + + # call the method + my $retval; + $retval = $ops->{$op}{function}->({ + op => $op, + tab_selected_1 => $ops->{$op}{tab_selected_1} || "", + note => $errornote, + }) if !$error_flag; + + return if !$retval; + + if ($op eq 'mailpasswd' && $retval) { + $ops->{$op}{update_formkey} = 0; + } + + if ($ops->{$op}{update_formkey} && $user->{seclev} < 100 && ! $error_flag) { + # successful save action, no formkey errors, update existing formkey + # why assign to an unused variable? -- pudge + my $updated = $slashdb->updateFormkey($formkey, length($ENV{QUERY_STRING})); + } + # if there were legit error levels returned from the save methods + # I would have it clear the formkey in case of an error, but that + # needs to be sorted out later + # else { resetFormkey($formkey); } + + writeLog($user->{nickname}); + footer(); +} + +################################################################# +sub checkList { + my($string, $len) = @_; + my $constants = getCurrentStatic(); + + $string =~ s/[^\w,-]//g; + my @items = grep { $_ } split /,/, $string; + $string = join ",", @items; + + $len ||= $constants->{checklist_length} || 255; + if (length($string) > $len) { + print getError('checklist_err'); + $string = substr($string, 0, $len); + $string =~ s/,?\w*$//g; + } elsif (length($string) < 1) { + $string = ''; + } + + return $string; +} + +################################################################# +sub previewSlashbox { + my $reader = getObject('Slash::DB', { db_type => 'reader' }); + my $constants = getCurrentStatic(); + my $user = getCurrentUser(); + my $form = getCurrentForm(); + + my $block = $reader->getBlock($form->{bid}, ['title', 'block', 'url']); + my $is_editable = $user->{seclev} >= 1000; + + my $title = getTitle('previewslashbox_title', { blocktitle => $block->{title} }); + slashDisplay('previewSlashbox', { + width => '100%', + title => $title, + block => $block, + is_editable => $is_editable, + }); + + print portalbox($constants->{fancyboxwidth}, $block->{title}, + $block->{block}, '', $block->{url}); +} + +################################################################# +sub newUserForm { + my $user = getCurrentUser(); + my $suadmin_flag = $user->{seclev} >= 10000; + my $title = getTitle('newUserForm_title'); + + slashDisplay('newUserForm', { + title => $title, + suadmin_flag => $suadmin_flag, + }); +} + +################################################################# +sub newUser { + my $slashdb = getCurrentDB(); + my $form = getCurrentForm(); + my $user = getCurrentUser(); + my $constants = getCurrentStatic(); + + my $plugins = $slashdb->getDescriptions('plugins'); + my $title; + my $suadmin_flag = $user->{seclev} >= 10000 ? 1 : 0; + + # Check if User Exists + $form->{newusernick} = nickFix($form->{newusernick}); + my $matchname = nick2matchname($form->{newusernick}); + + if (!$form->{email} || $form->{email} !~ /\@/) { + print getError('email_invalid', 0, 1); + return; + } elsif ($form->{email} ne $form->{email2}) { + print getError('email_do_not_match', 0, 1); + return; + } elsif ($slashdb->existsEmail($form->{email})) { + print getError('emailexists_err', 0, 1); + return; + } elsif ($matchname ne '' && $form->{newusernick} ne '') { + if ($constants->{newuser_portscan}) { + my $is_trusted = $slashdb->checkAL2($user->{srcids}, 'trusted'); + if (!$is_trusted) { + my $is_proxy = $slashdb->checkForOpenProxy($user->{hostip}); + if ($is_proxy) { + print getError('new user open proxy', { + unencoded_ip => $ENV{REMOTE_ADDR}, + port => $is_proxy, + }); + return; + } + } + } + my $uid; + my $rootdir = getCurrentSkin('rootdir'); + + $uid = $slashdb->createUser( + $matchname, $form->{email}, $form->{newusernick} + ); + if ($uid) { + my $data = {}; + getOtherUserParams($data); + + for (qw(tzcode)) { + $data->{$_} = $form->{$_} if defined $form->{$_}; + } + $data->{creation_ipid} = $user->{ipid}; + + $slashdb->setUser($uid, $data) if keys %$data; + $title = getTitle('newUser_title'); + + $form->{pubkey} = $plugins->{'Pubkey'} ? + strip_nohtml($form->{pubkey}, 1) : ''; + print getMessage('newuser_msg', { + suadmin_flag => $suadmin_flag, + title => $title, + uid => $uid + }); + + if ($form->{newsletter} || $form->{comment_reply} || $form->{headlines}) { + my $messages = getObject('Slash::Messages'); + my %params; + $params{MSG_CODE_COMMENT_REPLY()} = MSG_MODE_EMAIL() + if $form->{comment_reply}; + $params{MSG_CODE_NEWSLETTER()} = MSG_MODE_EMAIL() + if $form->{newsletter}; + $params{MSG_CODE_HEADLINES()} = MSG_MODE_EMAIL() + if $form->{headlines}; + $messages->setPrefs($uid, \%params); + } + + mailPasswd({ uid => $uid }); + + return; + } else { + $slashdb->resetFormkey($form->{formkey}); + print getError('duplicate_user', { + nick => $form->{newusernick}, + }); + return; + } + + } else { + print getError('duplicate_user', { + nick => $form->{newusernick}, + }); + return; + } +} + +################################################################# +sub mailPasswd { + my($hr) = @_; + my $user = getCurrentUser(); + my $constants = getCurrentStatic(); + + my $uid = $hr->{uid} || 0; + + my $slashdb = getCurrentDB(); + my $reader = getObject('Slash::DB', { db_type => 'reader' }); + my $form = getCurrentForm(); + + print createMenu("users", { + style => 'tabbed', + justify => 'right', + color => 'colored', + tab_selected => $hr->{tab_selected_1} || "", + }); + + if (! $uid) { + if ($form->{unickname} =~ /\@/) { + $uid = $slashdb->getUserEmail($form->{unickname}); + + } elsif ($form->{unickname} =~ /^\d+$/) { + my $tmpuser = $slashdb->getUser($form->{unickname}, ['uid']); + $uid = $tmpuser->{uid}; + + } else { + $uid = $slashdb->getUserUID($form->{unickname}); + } + } + + my $user_edit; + my $err_name = ''; + my $err_opts = {}; + if (!$uid || isAnon($uid)) { + $err_name = 'mailpasswd_notmailed_err'; + } + if (!$err_name) { + # Check permissions of _this_ user, not the target + # user, to determine whether this IP is OK'd to + # send the mail to the target user. + # XXXSRCID This should check a separate field like + # 'openproxy' instead of piggybacking off of 'nopost' + my $srcids_to_check = $user->{srcids}; + $err_name = 'mailpasswd_readonly_err' + if $reader->checkAL2($srcids_to_check, 'nopost'); + } + if (!$err_name) { + $err_name = 'mailpasswd_toooften_err' + if $slashdb->checkMaxMailPasswords($user_edit); + } + + if (!$err_name) { + if ($constants->{mailpasswd_portscan}) { + my $is_trusted = $slashdb->checkAL2($user->{srcids}, 'trusted'); + if (!$is_trusted) { + my $is_proxy = $slashdb->checkForOpenProxy($user->{hostip}); + if ($is_proxy) { + $err_name = 'mailpasswd open proxy'; + $err_opts = { unencoded_ip => $ENV{REMOTE_ADDR}, port => $is_proxy }; + } + } + + } + } + + if ($err_name) { + print getError($err_name, $err_opts); + $slashdb->resetFormkey($form->{formkey}); + $form->{op} = 'mailpasswdform'; + displayForm(); + return(1); + } + + my $newpasswd = $slashdb->getNewPasswd($uid); + my $tempnick = $user_edit->{nickname}; + + my $emailtitle = getTitle('mailPassword_email_title', { + nickname => $user_edit->{nickname} + }, 1); + + # Pull out some data passed in with the request. Only the IP + # number is actually trustworthy, the others could be forged. + # Note that we strip the forgeable ones to make sure there + # aren't any "<>" chars which could fool a stupid mail client + # into parsing a plaintext email as HTML. + my $r = Apache->request; + my $remote_ip = $r->connection->remote_ip; + my $xff = $r->header_in('X-Forwarded-For') || ''; + $xff =~ s/\s+/ /g; + $xff = substr(strip_notags($xff), 0, 20); + my $ua = $r->header_in('User-Agent') || ''; + $ua =~ s/\s+/ /g; + $ua = substr(strip_attribute($ua), 0, 60); + + my $msg = getMessage('mailpasswd_msg', { + newpasswd => $newpasswd, + tempnick => $tempnick, + remote_ip => $remote_ip, + x_forwarded_for => $xff, + user_agent => $ua, + }, 1); + + doEmail($uid, $emailtitle, $msg) if $user_edit->{nickname}; + print getMessage('mailpasswd_mailed_msg', { name => $user_edit->{nickname} }); + $slashdb->setUserMailPasswd($user_edit); +} + + +################################################################# +sub showSubmissions { + my($hr) = @_; + my $reader = getObject('Slash::DB', { db_type => 'reader' }); + my $form = getCurrentForm(); + my $constants = getCurrentStatic(); + my $user = getCurrentUser(); + my($uid, $nickname); + + print createMenu("users", { + style => 'tabbed', + justify => 'right', + color => 'colored', + tab_selected => $hr->{tab_selected_1} || "", + }); + + if ($form->{uid} or $form->{nick}) { + $uid = $form->{uid} || $reader->getUserUID($form->{nick}); + $nickname = $reader->getUser($uid, 'nickname'); + } else { + $nickname = $user->{nickname}; + $uid = $user->{uid}; + } + + my $storycount = $reader->countStoriesBySubmitter($uid); + my $stories = $reader->getStoriesBySubmitter( + $uid, + $constants->{user_submitter_display_default} + ) unless !$storycount; + + slashDisplay('userSub', { + nick => $nickname, + uid => $uid, + nickmatch_flag => ($user->{uid} == $uid ? 1 : 0), + stories => $stories, + storycount => $storycount, + }); +} + +################################################################# +sub showComments { + my($hr) = @_; + my $reader = getObject('Slash::DB', { db_type => 'reader' }); + my $form = getCurrentForm(); + my $constants = getCurrentStatic(); + my $user = getCurrentUser(); + my $commentstruct = []; + my($uid, $nickname); + + my $user_edit; + if ($form->{uid} || $form->{nick}) { + $uid = $form->{uid} || $reader->getUserUID($form->{nick}); + $user_edit = $reader->getUser($uid); + } else { + $uid = $user->{uid}; + $user_edit = $user; + } + $nickname = $user_edit->{nickname}; + + print createMenu("users", { + style => 'tabbed', + justify => 'right', + color => 'colored', + tab_selected => $user_edit->{uid} == $user->{uid} ? 'me' : 'otheruser', + }); + + my $min_comment = $form->{min_comment} || 0; + $min_comment = 0 unless $user->{seclev} > $constants->{comments_more_seclev} + || $constants->{comments_more_seclev} == 2 && $user->{is_subscriber}; + my $comments_wanted = $user->{show_comments_num} + || $constants->{user_comment_display_default}; + my $commentcount = $reader->countCommentsByUID($uid); + my $comments = $reader->getCommentsByUID( + $uid, $comments_wanted, $min_comment + ) if $commentcount; + + if (ref($comments) eq 'ARRAY') { + my $kinds = $reader->getDescriptions('discussion_kinds'); + for my $comment (@$comments) { + # This works since $sid is numeric. + $comment->{replies} = $reader->countCommentsBySidPid($comment->{sid}, $comment->{cid}); + + # This is ok, since with all luck we will not be hitting the DB + # ...however, the "sid" parameter here must be the string + # based SID from either the "stories" table or from + # pollquestions. + my $discussion = $reader->getDiscussion($comment->{sid}); + + if ($kinds->{ $discussion->{dkid} } =~ /^journal(?:-story)?$/) { + $comment->{type} = 'journal'; + } elsif ($kinds->{ $discussion->{dkid} } eq 'poll') { + $comment->{type} = 'poll'; + } else { + $comment->{type} = 'story'; + } + $comment->{disc_title} = $discussion->{title}; + $comment->{url} = $discussion->{url}; + } + } + + my $mod_reader = getObject("Slash::$constants->{m1_pluginname}", { db_type => 'reader' }); + slashDisplay('userCom', { + nick => $nickname, + useredit => $user_edit, + nickmatch_flag => ($user->{uid} == $uid ? 1 : 0), + commentstruct => $comments, + commentcount => $commentcount, + min_comment => $min_comment, + reasons => $mod_reader->getReasons(), + karma_flag => 0, + admin_flag => $user->{is_admin}, + }); +} + +sub noUser { + print getData("no_user"); +} + +sub showFireHose { + my($hr) = @_; + my $user = getCurrentUser(); + my $form = getCurrentForm(); + my $reader = getObject('Slash::DB', { db_type => 'reader' }); + + my $uid = $form->{uid} || $user->{uid}; + my $user_edit = $reader->getUser($uid); + + $user->{state}{firehose_page} = "user"; + $user->{state}{firehose_user_uid} = $uid; + + my $firehose = getObject("Slash::FireHose"); + header(getMessage('userfirehose_header', { useredit => $user_edit })) or return; + print createMenu("users", { + style => 'tabbed', + justify => 'right', + color => 'colored', + tab_selected => $user_edit->{uid} == $user->{uid} ? 'me' : 'otheruser', + }); + + $form->{mode} = "full"; + $form->{color} = "black"; + $form->{orderby} = "createtime"; + $form->{orderdidr} = "DESC"; + $form->{skipmenu} = 1; + $form->{duration} = -1; + $form->{fhfilter} = "\"user:$user_edit->{nickname}\""; + $form->{pause} = 1; + + my $fhbox = $firehose->listView({ fh_page => 'users.pl'}); + slashDisplay("userFireHose", { firehosebox => $fhbox, uid => $uid, useredit => $user_edit }); +} + +################################################################# +# arhgghgh. I love torture. I love pain. This subroutine satisfies +# these needs of mine +sub showInfo { + my($hr) = @_; + my $id = $hr->{uid} || 0; + + my $reader = getObject('Slash::DB', { db_type => 'reader' }); + my $slashdb = getCurrentDB(); + my $form = getCurrentForm(); + my $constants = getCurrentStatic(); + my $user = getCurrentUser(); + + + my $admin_flag = ($user->{is_admin}) ? 1 : 0; + my($title, $admin_block, $fieldkey) = ('', '', ''); + my $comments = undef; + my $commentcount = 0; + my $commentcount_time = 0; + my $commentstruct = []; + my $requested_user = {}; + my $time_period = $constants->{admin_comment_display_days} || 30; + my $cid_for_time_period = $reader->getVar("min_cid_last_$time_period\_days",'value', 1) || 0; + my $admin_time_period_limit = $constants->{admin_daysback_commentlimit} || 100; + my $admin_non_time_limit = $constants->{admin_comment_subsequent_pagesize} || 24; + + my($points, $nickmatch_flag, $uid, $nick); + my($mod_flag, $karma_flag, $n) = (0, 0, 0); + + if ($admin_flag + && (defined($form->{show_m2s}) || defined($form->{show_m1s}) || defined($form->{m2_listing}))) + { + my $update_hr = {}; + $update_hr->{mod_with_comm} = $form->{show_m1s} + if defined $form->{show_m1s}; + $update_hr->{m2_with_mod} = ($constants->{m2} ? $form->{show_m2s} : undef) + if defined $form->{show_m2s}; + $update_hr->{show_m2_listing} = ($constants->{m2} ? $form->{m2_listing} : undef) + if defined $form->{m2_listing}; + $slashdb->setUser($user->{uid}, $update_hr); + } + + if (!$id && !$form->{userfield}) { + if ($form->{uid} && ! $id) { + $fieldkey = 'uid'; + ($uid, $id) = ($form->{uid}, $form->{uid}); + $requested_user = isAnon($uid) ? $user : $reader->getUser($id); + $nick = $requested_user->{nickname}; + $form->{userfield} = $nick if $admin_flag; + + } elsif ($form->{nick} && ! $id) { + $fieldkey = 'nickname'; + ($nick, $id) = ($form->{nick}, $form->{nick}); + $uid = $reader->getUserUID($id); + if (isAnon($uid)) { + $requested_user = $user; + ($nick, $uid, $id) = @{$user}{qw(nickname uid nickname)}; + } else { + $requested_user = $reader->getUser($uid); + } + $form->{userfield} = $uid if $admin_flag; + + } else { + $fieldkey = 'uid'; + ($id, $uid) = ($user->{uid}, $user->{uid}); + $requested_user = $reader->getUser($uid); + $form->{userfield} = $uid if $admin_flag; + } + + } elsif ($user->{is_admin}) { + $id ||= $form->{userfield} || $user->{uid}; + if ($id =~ /^[0-9a-f]{16}$/) { + $requested_user->{nonuid} = 1; + $fieldkey = "srcid"; + $requested_user->{$fieldkey} = $id; + } elsif ($id =~ /^\d+$/) { + # If it's longer than a uid could possibly be, it + # must be a srcid. The uid column right now is a + # MEDIUMINT (max 16M) but at most might someday + # be an INT (max 4G). + if (length($id) > 11) { + $requested_user->{nonuid} = 1; + $fieldkey = "srcid"; + $requested_user->{$fieldkey} = $id; + } else { + $fieldkey = 'uid'; + $requested_user = $reader->getUser($id); + $uid = $requested_user->{uid}; + $nick = $requested_user->{nickname}; + if ((my $conflict_id = $reader->getUserUID($id)) && $form->{userinfo}) { + #slashDisplay('showInfoConflict', { + #op => 'userinfo', + #id => $uid, + #nick => $nick, + #conflict_id => $conflict_id + #}); + return 1; + } + } + + } elsif (length($id) == 32) { + $requested_user->{nonuid} = 1; + if ($form->{fieldname} + && $form->{fieldname} =~ /^(ipid|subnetid)$/) { + $fieldkey = $form->{fieldname}; + } else { + $fieldkey = 'md5id'; + } + $requested_user->{$fieldkey} = $id; + } elsif ($id =~ /^(\d{1,3}\.\d{1,3}.\d{1,3}\.0)$/ + || $id =~ /^(\d{1,3}\.\d{1,3}\.\d{1,3})\.?$/) { + $fieldkey = 'subnetid'; + $requested_user->{subnetid} = $1; + $requested_user->{subnetid} .= '.0' if $requested_user->{subnetid} =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}$/; + $requested_user->{nonuid} = 1; + $requested_user->{subnetid} = md5_hex($requested_user->{subnetid}); + + } elsif ($id =~ /^([\d+\.]+)$/) { + $fieldkey = 'ipid'; + $requested_user->{nonuid} = 1; + $id ||= $1; + $requested_user->{ipid} = md5_hex($1); + + } elsif ($id =~ /^(.*@.*\..*?)$/) { + # check for email addy, but make it by uid + $fieldkey = 'uid'; + $id = $uid = $reader->getUserEmail($id); + $requested_user = $reader->getUser($uid); + $nick = $requested_user->{nickname}; + + } else { # go by nickname, but make it by uid + $fieldkey = 'uid'; + $id = $uid = $reader->getUserUID($id); + $requested_user = $reader->getUser($uid); + $nick = $requested_user->{nickname}; + } + + } else { + $fieldkey = 'uid'; + ($id, $uid) = ($user->{uid}, $user->{uid}); + $requested_user = $reader->getUser($uid); + } + + # Can't get user data for the anonymous user. + if ($fieldkey eq 'uid' && isAnon($uid)) { + header(getMessage('user_header')) or return; + return displayForm(); + } + + my $user_change = { }; + if ($fieldkey eq 'uid' && !$user->{is_anon} + && $uid != $user->{uid} && !isAnon($uid)) { + # Store the fact that this user last looked at that user. + # For maximal convenience in stalking. + $user_change->{lastlookuid} = $uid; + $user_change->{lastlooktime} = time; + $user->{lastlookuid} = $uid; + $user->{lastlooktime} = time; + $hr->{tab_selected_1} = 'otheruser'; + } + + # showInfo's header information is delayed until here, because + # the target user's info is not available until here. + vislenify($requested_user); + header(getMessage('user_header', { useredit => $requested_user, fieldkey => $fieldkey })) or return; + # This is a hardcoded position, bad idea and should be fixed -Brian + # Yeah, we should pull this into a template somewhere... + print getMessage('note', { note => $hr->{note} }) if defined $hr->{note}; + + print createMenu("users", { + style => 'tabbed', + justify => 'right', + color => 'colored', + tab_selected => $hr->{tab_selected_1} || "", + }); + + my $comments_wanted = $user->{show_comments_num} + || $constants->{user_comment_display_default}; + my $min_comment = $form->{min_comment} || 0; + $min_comment = 0 unless $user->{seclev} > $constants->{comments_more_seclev} + || $constants->{comments_more_seclev} == 2 && $user->{is_subscriber}; + + my($netid, $netid_vis) = ('', ''); + + my $comment_time; + my $non_admin_limit = $comments_wanted; + + if ($requested_user->{nonuid}) { + $requested_user->{fg} = $user->{fg}; + $requested_user->{bg} = $user->{bg}; + + if ($requested_user->{ipid}) { + $netid = $requested_user->{ipid} ; + + } elsif ($requested_user->{md5id}) { + $netid = $requested_user->{md5id} ; + + } elsif ($requested_user->{srcid}) { + $netid = $requested_user->{srcid} ; + } else { + $netid = $requested_user->{subnetid} ; + } + + my $data = { + id => $id, + md5id => $netid, + }; + vislenify($data); # add $data->{md5id_vis} + $netid_vis = $data->{md5id_vis}; + + $title = getTitle('user_netID_user_title', $data); + + $admin_block = getUserAdmin($netid, $fieldkey, 0) if $admin_flag; + + if ($form->{fieldname}) { + if ($form->{fieldname} eq 'ipid') { + $commentcount = $reader->countCommentsByIPID($netid); + $commentcount_time = $reader->countCommentsByIPID($netid, { cid_at_or_after => $cid_for_time_period }); + $comments = getCommentListing("ipid", $netid, + $min_comment, $time_period, $commentcount, $commentcount_time, $cid_for_time_period, + $non_admin_limit, $admin_time_period_limit, $admin_non_time_limit) + if $commentcount; + } elsif ($form->{fieldname} eq 'subnetid') { + $commentcount = $reader->countCommentsBySubnetID($netid); + $commentcount_time = $reader->countCommentsBySubnetID($netid, { cid_at_or_after => $cid_for_time_period }); + $comments = getCommentListing("subnetid", $netid, + $min_comment, $time_period, $commentcount, $commentcount_time, $cid_for_time_period, + $non_admin_limit, $admin_time_period_limit, $admin_non_time_limit) + if $commentcount; + + } else { + delete $form->{fieldname}; + } + } + if (!defined($comments)) { + # Last resort; here for backwards compatibility mostly. + my $type; + ($commentcount,$type) = $reader->countCommentsByIPIDOrSubnetID($netid); + $commentcount_time = $reader->countCommentsByIPIDOrSubnetID($netid, { cid_at_or_after => $cid_for_time_period }); + if ($type eq "ipid") { + $comments = getCommentListing("ipid", $netid, + $min_comment, $time_period, $commentcount, $commentcount_time, $cid_for_time_period, + $non_admin_limit, $admin_time_period_limit, $admin_non_time_limit) + if $commentcount; + } elsif ($type eq "subnetid") { + $comments = getCommentListing("subnetid", $netid, + $min_comment, $time_period, $commentcount, $commentcount_time, $cid_for_time_period, + $non_admin_limit, $admin_time_period_limit, $admin_non_time_limit) + if $commentcount; + } + } + } else { + $admin_block = getUserAdmin($id, $fieldkey, 1) if $admin_flag; + + $commentcount = $reader->countCommentsByUID($requested_user->{uid}); + $commentcount_time = $reader->countCommentsByUID($requested_user->{uid}, { cid_at_or_after => $cid_for_time_period }); + $comments = getCommentListing("uid", $requested_user->{uid}, + $min_comment, $time_period, $commentcount, $commentcount_time, $cid_for_time_period, + $non_admin_limit, $admin_time_period_limit, $admin_non_time_limit, + { use_uid_cid_cutoff => 1 }) + if $commentcount; + $netid = $requested_user->{uid}; + } + + # Grab the nicks of the uids we have, we're going to be adding them + # into the struct. + my @users_extra_cols_wanted = qw( nickname ); + my @discussions_extra_cols_wanted = qw( type ); + my $uid_hr = { }; + my $sid_hr = { }; + if ($comments && @$comments) { + my %uids = (); + my %sids = (); + for my $c (@$comments) { + $uids{$c->{uid}}++; + $sids{$c->{sid}}++; + } + my $uids = join(", ", sort { $a <=> $b } keys %uids); + my $sids = join(", ", sort { $a <=> $b } keys %sids); + $uid_hr = $reader->sqlSelectAllHashref( + "uid", + "uid, " . join(", ", @users_extra_cols_wanted), + "users", + "uid IN ($uids)" + ); + + $sid_hr = $reader->sqlSelectAllHashref( + "id", + "id, " . join(", ", @discussions_extra_cols_wanted), + "discussions", + "id IN ($sids)" + ); + + } + + my $cids_seen = {}; + my $kinds = $slashdb->getDescriptions('discussion_kinds'); + for my $comment (@$comments) { + $cids_seen->{$comment->{cid}}++; + my $type; + # This works since $sid is numeric. + my $replies = $reader->countCommentsBySidPid($comment->{sid}, $comment->{cid}); + + # This is cached. + my $discussion = $reader->getDiscussion($comment->{sid}); +#use Data::Dumper; if ($discussion && !$discussion->{dkid}) { print STDERR scalar(gmtime) . " users.pl discussion but no dkid: " . Dumper($discussion) } + if (!$discussion || !$discussion->{dkid}) { + # A comment with no accompanying discussion; + # basically we pretend it doesn't exist. + next; + } elsif ($kinds->{ $discussion->{dkid} } =~ /^journal(?:-story)?$/) { + $type = 'journal'; + } elsif ($kinds->{ $discussion->{dkid} } eq 'poll') { + $type = 'poll'; + } else { + $type = 'story'; + } + + $comment->{points} += $user->{karma_bonus} + if $user->{karma_bonus} && $comment->{karma_bonus} eq 'yes'; + $comment->{points} += $user->{subscriber_bonus} + if $user->{subscriber_bonus} && $comment->{subscriber_bonus} eq 'yes'; + + # fix points in case they are out of bounds + $comment->{points} = $constants->{comment_minscore} if $comment->{points} < $constants->{comment_minscore}; + $comment->{points} = $constants->{comment_maxscore} if $comment->{points} > $constants->{comment_maxscore}; + vislenify($comment); + my $data = { + pid => $comment->{pid}, + url => $discussion->{url}, + disc_type => $type, + disc_title => $discussion->{title}, + disc_time => $discussion->{ts}, + sid => $comment->{sid}, + cid => $comment->{cid}, + subj => $comment->{subject}, + cdate => $comment->{date}, + pts => $comment->{points}, + reason => $comment->{reason}, + uid => $comment->{uid}, + replies => $replies, + ipid => $comment->{ipid}, + ipid_vis => $comment->{ipid_vis}, + karma => $comment->{karma}, + tweak => $comment->{tweak}, + tweak_orig => $comment->{tweak_orig}, + + }; + #Karma bonus time + + for my $col (@users_extra_cols_wanted) { + $data->{$col} = $uid_hr->{$comment->{uid}}{$col} if defined $uid_hr->{$comment->{uid}}{$col}; + } + for my $col(@discussions_extra_cols_wanted) { + $data->{$col} = $sid_hr->{$comment->{sid}}{$col} if defined $sid_hr->{$comment->{sid}}{$col}; + } + push @$commentstruct, $data; + } +# if (grep { !defined($_->{disc_time}) || !defined($_->{sid}) } @$commentstruct) { use Data::Dumper; print STDERR "showInfo undef in commentstruct for id=$id: " . Dumper($commentstruct) } + # Sort so the chosen group of comments is sorted by discussion + @$commentstruct = sort { + $b->{disc_time} cmp $a->{disc_time} || $b->{sid} <=> $a->{sid} + } @$commentstruct + unless $user->{user_comment_sort_type} && $user->{user_comment_sort_type} == 1; + + my $cid_list = [ keys %$cids_seen ]; + my $cids_to_mods = {}; + my $mod_reader = getObject("Slash::$constants->{m1_pluginname}", { db_type => 'reader' }); + if ($constants->{m1} && $admin_flag && $constants->{show_mods_with_comments}) { + my $comment_mods = $mod_reader->getModeratorCommentLog("DESC", + $constants->{mod_limit_with_comments}, "cidin", $cid_list); + + # Loop through mods and group them by the sid they're attached to + while (my $mod = shift @$comment_mods) { + push @{$cids_to_mods->{$mod->{cid}}}, $mod; + } + } + + my $sub_limit = ((($admin_flag || $user->{uid} == $requested_user->{uid}) ? $constants->{submissions_all_page_size} : $constants->{submissions_accepted_only_page_size}) || ""); + + my $sub_options = { limit_days => 365 }; + $sub_options->{accepted_only} = 1 if !$admin_flag && $user->{uid} != $requested_user->{uid}; + + my $sub_field = $form->{fieldname}; + + my ($subcount, $ret_field) = $reader->countSubmissionsByNetID($netid, $sub_field) + if $requested_user->{nonuid}; + my $submissions = $reader->getSubmissionsByNetID($netid, $ret_field, $sub_limit, $sub_options) + if $requested_user->{nonuid}; + + my $ipid_hoursback = $constants->{istroll_ipid_hours} || 72; + my $uid_hoursback = $constants->{istroll_uid_hours} || 72; + + if ($requested_user->{nonuid}) { + #slashDisplay('netIDInfo', { + #title => $title, + #id => $id, + #useredit => $requested_user, + #commentstruct => $commentstruct || [], + #commentcount => $commentcount, + #min_comment => $min_comment, + #admin_flag => $admin_flag, + #admin_block => $admin_block, + #netid => $netid, + #netid_vis => $netid_vis, + #reasons => $mod_reader->getReasons(), + #subcount => $subcount, + #submissions => $submissions, + #hr_hours_back => $ipid_hoursback, + #cids_to_mods => $cids_to_mods, + #comment_time => $comment_time + #}); + + } else { + if (! $requested_user->{uid}) { + print getError('userinfo_idnf_err', { id => $id, fieldkey => $fieldkey}); + return 1; + } + + $karma_flag = 1 if $admin_flag; + $requested_user->{nick_plain} = $nick ||= $requested_user->{nickname}; + $nick = strip_literal($nick); + + if ($requested_user->{uid} == $user->{uid}) { + $karma_flag = 1; + $nickmatch_flag = 1; + $points = $requested_user->{points}; + + $mod_flag = 1 if $points > 0; + + $title = getTitle('userInfo_main_title', { nick => $nick, uid => $uid }); + + } else { + $title = getTitle('userInfo_user_title', { nick => $nick, uid => $uid }); + } + + my $lastjournal = _get_lastjournal($uid); + + my $subcount = $reader->countSubmissionsByUID($uid); + + my $submissions = $reader->getSubmissionsByUID($uid, $sub_limit, $sub_options); + my $metamods; + if ($constants->{m2} && $admin_flag) { + my $metamod_reader = getObject('Slash::Metamod', { db_type => 'reader' }); + $metamods = $metamod_reader->getMetamodlogForUser($uid, 30); + } + + my $tags_reader = getObject('Slash::Tags', { db_type => 'reader' }); + my $tagshist = []; + if ($tags_reader && $user->{is_admin}) { + $tagshist = $tags_reader->getAllTagsFromUser($requested_user->{uid}, { orderby => 'created_at', orderdir => 'DESC', limit => 30, include_private => 1 }); + } + + my $comment_blocks = $reader->sqlSelectAllHashref( + 'uid', 'bid, uid, block', 'user_event_blocks', "uid = $uid and code = 1"); + + my @block_ids = split(/,/, $comment_blocks->{$uid}->{block}); + + my %latest_comments; + foreach my $comment_block (@block_ids) { + ($latest_comments{$comment_block}->{sid}, $latest_comments{$comment_block}->{subject}) + = $reader->sqlSelect("sid, subject", "comments", "cid = $comment_block"); + #$latest_comments{$comment_block}->{text} = $reader->sqlSelect("comment", "comment_text", "cid = $comment_block"); + } + + my $journal_blocks = $reader->sqlSelectAllHashref( + 'uid', 'bid, uid, block', 'user_event_blocks', "uid = $uid and code = 2"); + + @block_ids = split(/,/, $journal_blocks->{$uid}->{block}); + my %latest_journals; + foreach my $journal_block (@block_ids) { + ($latest_journals{$journal_block}->{id}, $latest_journals{$journal_block}->{desc}) + = $reader->sqlSelect("id, description", "journals", "discussion = $journal_block"); + } + + slashDisplay('userInfo2', { + title => $title, + uid => $uid, + useredit => $requested_user, + points => $points, + commentstruct => $commentstruct || [], + commentcount => $commentcount, + min_comment => $min_comment, + nickmatch_flag => $nickmatch_flag, + mod_flag => $mod_flag, + karma_flag => $karma_flag, + admin_block => $admin_block, + admin_flag => $admin_flag, + reasons => $mod_reader->getReasons(), + lastjournal => $lastjournal, + hr_hours_back => $ipid_hoursback, + cids_to_mods => $cids_to_mods, + comment_time => $comment_time, + submissions => $submissions, + subcount => $subcount, + metamods => $metamods, + tagshist => $tagshist, + latest_comments => \%latest_comments, + latest_journals => \%latest_journals, + }, { Page => 'users', Skin => 'default'}); + } + + if ($user_change && %$user_change) { + $slashdb->setUser($user->{uid}, $user_change); + } + + return 1; +} + +sub _get_lastjournal { + my($uid) = @_; + my $user = getCurrentUser(); + my $constants = getCurrentStatic(); + my $reader = getObject('Slash::DB', { db_type => 'reader' }); + my $lastjournal = undef; + if (my $journal = getObject('Slash::Journal', { db_type => 'reader' })) { + my $j = $journal->getsByUid($uid, 0, 1); + if ($j && @$j) { + # Yep, there are 1 or more journals... get the first. + $j = $j->[0]; + } + if ($j && @$j) { + # Yep, that first journal exists and has entries... + # convert from stupid numeric array to a hashref. + my @field = qw( date article description id + posttype tid discussion ); + $lastjournal = { }; + for my $i (0..$#field) { + $lastjournal->{$field[$i]} = $j->[$i]; + } + } + } + + if ($lastjournal) { + + # Strip the article field for display. + $lastjournal->{article} = strip_mode($lastjournal->{article}, + $lastjournal->{posttype}); + + # For display, include a reduced-size version, where the + # size is based on the user's maxcomment size (which + # defaults to 4K) and can't have too many line-breaking + # tags. + my $art_shrunk = $lastjournal->{article}; + my $maxsize = int($user->{maxcommentsize} / 25); + $maxsize = 80 if $maxsize < 80; + $maxsize = 600 if $maxsize > 600; + $art_shrunk = chopEntity($art_shrunk, $maxsize); + + my $approvedtags_break = $constants->{approvedtags_break} || []; + my $break_tag = join '|', @$approvedtags_break; + if (scalar(() = $art_shrunk =~ /<(?:$break_tag)>/gi) > 2) { + $art_shrunk =~ s/\A + ( + (?: <(?:$break_tag)> )? + .*? <(?:$break_tag)> + .*? + ) <(?:$break_tag)>.* + /$1/six; + if (length($art_shrunk) < 15) { + # This journal entry has too much whitespace + # in its first few chars; scrap it. + undef $art_shrunk; + } + $art_shrunk = chopEntity($art_shrunk) if defined($art_shrunk); + } + + if (defined $art_shrunk) { + if (length($art_shrunk) < length($lastjournal->{article})) { + $art_shrunk .= " ..."; + } + $art_shrunk = strip_html($art_shrunk); + $art_shrunk = balanceTags($art_shrunk); + } + + $lastjournal->{article_shrunk} = $art_shrunk; + + if ($lastjournal->{discussion}) { + $lastjournal->{commentcount} = $reader->getDiscussion( + $lastjournal->{discussion}, 'commentcount'); + } + } + return $lastjournal; +} + +##################################################################### +sub validateUser { + my($hr) = @_; + my $user = getCurrentUser(); + my $form = getCurrentForm(); + my $slashdb = getCurrentDB(); + my $constants = getCurrentStatic(); + + # If we aren't expiring accounts in some way, we don't belong here. + if (! allowExpiry()) { + displayForm(); + return; + } + + print createMenu("users", { + style => 'tabbed', + justify => 'right', + color => 'colored', + tab_selected => $hr->{tab_selected_1} || "", + }); + + # Since we are here, if the minimum values for the comment trigger and + # the day trigger are -1, then they should be reset to 1. + $constants->{min_expiry_comm} = $constants->{min_expiry_days} = 1 + if $constants->{min_expiry_comm} <= 0 || + $constants->{min_expiry_days} <= 0; + + if ($user->{is_anon} || $user->{registered}) { + if ($user->{is_anon}) { + print getError('anon_validation_attempt'); + displayForm(); + return; + } else { + print getMessage('no_registration_needed') + if !$user->{reg_id}; + showInfo({ uid => $user->{uid} }); + return; + } + # Maybe this should be taken care of in a more centralized location? + } elsif ($user->{reg_id} eq $form->{id}) { + # We have a user and the registration IDs match. We are happy! + my($maxComm, $maxDays) = ($constants->{max_expiry_comm}, + $constants->{max_expiry_days}); + my($userComm, $userDays) = + ($user->{user_expiry_comm}, $user->{user_expiry_days}); + + # Ensure both $userComm and $userDays aren't -1 (expiry has + # just been turned on). + $userComm = $constants->{min_expiry_comm} + if $userComm < $constants->{min_expiry_comm}; + $userDays = $constants->{min_expiry_days} + if $userDays < $constants->{min_expiry_days}; + + my $exp = $constants->{expiry_exponent}; + + # Increment only the trigger that was used. + my $new_comment_expiry = ($maxComm > 0 && $userComm > $maxComm) + ? $maxComm + : $userComm * (($user->{expiry_comm} < 0) + ? $exp + : 1 + ); + my $new_days_expiry = ($maxDays > 0 && $userDays > $maxDays) + ? $maxDays + : $userDays * (($user->{expiry_days} < 0) + ? $exp + : 1 + ); + + # Reset re-registration triggers for user. + $slashdb->setUser($user->{uid}, { + 'expiry_comm' => $new_comment_expiry, + 'expiry_days' => $new_days_expiry, + 'user_expiry_comm' => $new_comment_expiry, + 'user_expiry_days' => $new_days_expiry, + }); + + # Handles rest of re-registration process. + setUserExpired($user->{uid}, 0); + } + + slashDisplay('regResult'); +} + +##################################################################### +sub editTags { + my($hr) = @_; + my $slashdb = getCurrentDB(); + my $user = getCurrentUser(); + my $constants = getCurrentStatic(); + my $note = $hr->{note} || ""; + + return if $user->{is_anon}; # shouldn't be, but can't hurt to check + + print createMenu("users", { + style => 'tabbed', + justify => 'right', + color => 'colored', + tab_selected => $hr->{tab_selected_1} || "", + }); + + my $user_edit = $slashdb->getUser($user->{uid}); + my $title = getTitle('editTags_title'); + + slashDisplay('editTags', { + user_edit => $user_edit, + title => $title, + note => $note, + }); +} + +sub saveTags { + my($hr) = @_; + my $slashdb = getCurrentDB(); + my $user = getCurrentUser(); + my $form = getCurrentForm(); + my $constants = getCurrentStatic(); + + return if $user->{is_anon}; # shouldn't be, but can't hurt to check + + $slashdb->setUser($user->{uid}, { + tags_turnedoff => $form->{showtags} ? '' : 1 }); + editTags({ note => getMessage('savetags_msg') }); +} + +##################################################################### +sub showTags { + my($hr) = @_; + my $user = getCurrentUser(); + my $form = getCurrentForm(); + my $slashdb = getCurrentDB(); + my $constants = getCurrentStatic(); + my $tags_reader = getObject('Slash::Tags', { db_type => 'reader' }); + + my($uid, $user_edit); + if ($form->{uid} || $form->{nick}) { + $uid = $form->{uid} || $tags_reader->getUserUID($form->{nick}); + $user_edit = $tags_reader->getUser($uid); + } + if (!$user_edit || $user_edit->{is_anon}) { + $uid = $user->{uid}; + $user_edit = $user; + } + my $nickname = $user_edit->{nickname}; + + if (!$constants->{plugin}{Tags}) { + print getError('bad_op', { op => $form->{op}}); + return; + } + + my $tags_ar = $tags_reader->getGroupedTagsFromUser($user_edit->{uid}); + slashDisplay('usertags', { + useredit => $user_edit, + tags_grouped => $tags_ar, + }); +} + +################################################################# +sub showBookmarks { + my($hr) = @_; + my $user = getCurrentUser(); + my $form = getCurrentForm(); + my $slashdb = getCurrentDB(); + my $constants = getCurrentStatic(); + my $tags_reader = getObject('Slash::Tags', { db_type => 'reader' }); + + my($uid, $user_edit); + if ($form->{uid} || $form->{nick}) { + $uid = $form->{uid} || $tags_reader->getUserUID($form->{nick}); + $user_edit = $tags_reader->getUser($uid); + } + if (!$user_edit || $user_edit->{is_anon}) { + $uid = $user->{uid}; + $user_edit = $user; + } + my $nickname = $user_edit->{nickname}; + + if (!$constants->{plugin}{Tags}) { + print getError('bad_op', { op => $form->{op}}); + return; + } + + my $tags_ar = $tags_reader->getGroupedTagsFromUser($user_edit->{uid}, { type => "urls", only_bookmarked => 1 }); + + slashDisplay('userbookmarks', { + useredit => $user_edit, + tags_grouped => $tags_ar, + }); +} + +################################################################# +sub editKey { + my($uid) = @_; + + my $slashdb = getCurrentDB(); + + my $pubkey = $slashdb->getUser($uid, 'pubkey'); + my $editkey = slashDisplay('editKey', { pubkey => $pubkey }, 1); + return $editkey; +} + +################################################################# +# We arrive here without header() having been called. Some of the +# functions we dispatch to call it, some do not. +sub adminDispatch { + my($hr) = @_; + my $form = getCurrentForm(); + my $op = $hr->{op} || $form->{op}; + + if ($op eq 'authoredit') { + # editUser() does not call header(), so we DO need to. + header(getMessage('user_header'), '', {}) or return; + editUser($hr); + + } elsif ($form->{saveuseradmin}) { + # saveUserAdmin() tail-calls showInfo(), which calls + # header(), so we need to NOT. + saveUserAdmin($hr); + + } elsif ($form->{userinfo}) { + # showInfo() calls header(), so we need to NOT. + showInfo($hr); + + } elsif ($form->{userfield}) { + # none of these calls header(), so we DO need to. + header(getMessage('user_header'), '', {}) or return; + if ($form->{edituser}) { + editUser($hr); + + } elsif ($form->{edithome}) { + editHome($hr); + + } elsif ($form->{editcomm}) { + editComm($hr); + + } elsif ($form->{changepasswd}) { + changePasswd($hr); + } + + } else { + # showInfo() calls header(), so we need to NOT. + showInfo($hr); + } +} + +################################################################# +sub tildeEd { + my($user_edit) = @_; + + my $reader = getObject('Slash::DB', { db_type => 'reader' }); + my $constants = getCurrentStatic(); + + my %story023_default = ( + author => { }, + nexus => { }, + topic => { }, + ); + + my %prefs = ( ); + for my $field (qw( + story_never_topic story_never_author story_never_nexus + story_always_topic story_always_author story_always_nexus story_brief_always_nexus + story_full_brief_nexus story_full_best_nexus story_brief_best_nexus + )) { + for my $id ( + grep /^\d+$/, + split /,/, + ($user_edit->{$field} || "") + ) { + $prefs{$field}{$id} = 1; + } + } +#print STDERR scalar(localtime) . " prefs: " . Dumper(\%prefs); + + # Set up $author_hr, @aid_order, and $story023_default{author}. + + my $author_hr = $reader->getDescriptions('authors'); + my @aid_order = sort { lc $author_hr->{$a} cmp lc $author_hr->{$b} } keys %$author_hr; + for my $aid (@aid_order) { + if ($prefs{story_never_author}{$aid}) { + $story023_default{author}{$aid} = 0; + } elsif ($prefs{story_always_author}{$aid}) { + $story023_default{author}{$aid} = 3; + } else { + $story023_default{author}{$aid} = 2; + } + } + + # Set up $topic_hr, @topictid_order, and $story023_default{topic}. + + my $topic_hr = $reader->getDescriptions('non_nexus_topics-storypickable'); + my @topictid_order = sort { lc $topic_hr->{$a} cmp lc $topic_hr->{$b} } keys %$topic_hr; + for my $tid (@topictid_order) { + if ($prefs{story_never_topic}{$tid}) { + $story023_default{topic}{$tid} = 0; + } elsif ($prefs{story_always_topic}{$tid}) { + $story023_default{topic}{$tid} = 3; + } else { + $story023_default{topic}{$tid} = 2; + } + } + + # Set up $nexus_hr, @nexustid_order, and $story023_default{nexus}. + my $topic_tree = $reader->getTopicTree(); + my $nexus_tids_ar = $reader->getStorypickableNexusChildren($constants->{mainpage_nexus_tid}, 1); + my $nexus_hr = { }; + + for my $tid (@$nexus_tids_ar) { + $nexus_hr->{$tid} = $topic_tree->{$tid}{textname}; + } + my @nexustid_order = sort {($b == $constants->{mainpage_nexus_tid}) <=> ($a == $constants->{mainpage_nexus_tid}) || + lc $nexus_hr->{$a} cmp lc $nexus_hr->{$b} } keys %$nexus_hr; + + my $mp_disp_nexuses = $reader->getMainpageDisplayableNexuses(); + my %mp_disp_nexus = ( map { ($_, 1) } @$mp_disp_nexuses ); + for my $tid (@nexustid_order) { + if ($prefs{story_never_nexus}{$tid}) { + $story023_default{nexus}{$tid} = 0; + } elsif ($prefs{story_always_nexus}{$tid}) { + $story023_default{nexus}{$tid} = 5; + } elsif ($prefs{story_full_brief_nexus}{$tid}) { + $story023_default{nexus}{$tid} = 4; + } elsif ($prefs{story_brief_always_nexus}{$tid}) { + $story023_default{nexus}{$tid} = 3; + } elsif ($prefs{story_full_best_nexus}{$tid}) { + $story023_default{nexus}{$tid} = 2; + } elsif ($prefs{story_brief_best_nexus}) { + $story023_default{nexus}{$tid} = 1; + } else { + # If brief_sectional_mainpage is set, then all + # nexuses in getMainpageDisplayableNexuses are, + # by default, shown as brief on the mainpage. + if ($constants->{brief_sectional_mainpage} + && $mp_disp_nexus{$tid} + ) { + $story023_default{nexus}{$tid} = 4; + } else { + $story023_default{nexus}{$tid} = 2; + } + } + } + + # Set up $section_descref and $box_order, used to decide which + # slashboxes appear. Really this doesn't seem to have anything + # to do with sections, so I'm not sure why it's called + # "section"_descref. + + my $section_descref = { }; + my $box_order; + my $sections_description = $reader->getSectionBlocks(); + + # the names of all the boxes in @{$skinBoxes->{$constants->{mainpage_skid}}} + # should be unioned into sections_description. whether the + # values are 0 or 1 is calculated correctly, but we're + # missing some 0's that should appear, I think, under + # some circumstances. ah heck, the whole concept of + # sectional slashboxes should be redone (why the heck + # do we have skinname_more instead of just a block + # called olderstories?) + + my $slashboxes_hr = { }; + my $slashboxes_textlist = $user_edit->{slashboxes}; + if (!$slashboxes_textlist) { + # Use the default. + my($boxes, $skinBoxes) = $reader->getPortalsCommon(); + $slashboxes_textlist = join ",", @{$skinBoxes->{$constants->{mainpage_skid}}}; + } + for my $bid ( + map { /^'?([^']+)'?$/; $1 } + split /,/, + $slashboxes_textlist + ) { + $slashboxes_hr->{$bid} = 1; + } + for my $ary (sort { lc $a->[1] cmp lc $b->[1]} @$sections_description) { + my($bid, $title, $boldflag) = @$ary; + push @$box_order, $bid; + $section_descref->{$bid}{checked} = + $slashboxes_hr->{$bid} + ? $constants->{markup_checked_attribute} + : ''; + $title =~ s/<(.*?)>//g; + $section_descref->{$bid}{title} = $title; + } + +#print STDERR scalar(localtime) . " tildeEd story023_default: " . Dumper(\%story023_default); + + # Userspace. + + my $userspace = $user_edit->{mylinks} || ""; + + # Titles of stuff. + + my $tildeEd_title = getTitle('tildeEd_title'); + my $criteria_msg = getMessage('tilded_criteria_msg'); + my $customize_title = getTitle('tildeEd_customize_title'); + my $tilded_customize_msg = getMessage('tilded_customize_msg', + { userspace => $userspace }); + my $tilded_box_msg = getMessage('tilded_box_msg'); + + my $tilde_ed = slashDisplay('tildeEd', { + user_edit => $user_edit, + title => $tildeEd_title, + criteria_msg => $criteria_msg, + customize_title => $customize_title, + tilded_customize_msg => $tilded_customize_msg, + tilded_box_msg => $tilded_box_msg, + + story023_default => \%story023_default, + authorref => $author_hr, + aid_order => \@aid_order, + topicref => $topic_hr, + topictid_order => \@topictid_order, + nexusref => $nexus_hr, + nexustid_order => \@nexustid_order, + + section_descref => $section_descref, + box_order => $box_order, + + userspace => $userspace, + }, 1); + + return $tilde_ed; +} + +################################################################# +sub changePasswd { + my($hr) = @_; + my $form = getCurrentForm(); + my $slashdb = getCurrentDB(); + my $user = getCurrentUser(); + my $constants = getCurrentStatic(); + + print createMenu("users", { + style => 'tabbed', + justify => 'right', + color => 'colored', + tab_selected => $hr->{tab_selected_1} || "", + }); + + my $user_edit = {}; + my $title; + my $suadmin_flag = ($user->{seclev} >= 10000) ? 1 : 0; + + my $admin_flag = ($user->{is_admin}) ? 1 : 0; + my $admin_block = ''; + + my $id = ''; + if ($admin_flag) { + if ($form->{userfield}) { + $id ||= $form->{userfield}; + if ($id =~ /^\d+$/) { + $user_edit = $slashdb->getUser($id); + } else { + $user_edit = $slashdb->getUser($slashdb->getUserUID($id)); + } + } else { + $user_edit = $id eq '' ? $user : $slashdb->getUser($id); + $id = $user_edit->{uid}; + } + } else { + $id = $user->{uid}; + $user_edit = $user; + } + + $admin_block = getUserAdmin($id, 'uid', 1) if $admin_flag; + + # print getMessage('note', { note => $form->{note}}) if $form->{note}; + + $title = getTitle('changePasswd_title', { user_edit => $user_edit }); + + my $session = $slashdb->getDescriptions('session_login'); + my $session_select = createSelect('session_login', $session, $user_edit->{session_login}, 1); + + my $clocation = $slashdb->getDescriptions('cookie_location'); + my @clocation_order = grep { exists $clocation->{$_} } qw(none classbid subnetid ipid); + my $clocation_select = createSelect('cookie_location', $clocation, + $user_edit->{cookie_location}, 1, 0, \@clocation_order + ); + + my $got_oldpass = 0; + if ($form->{oldpass}) { + my $return_uid = $slashdb->getUserAuthenticate($id, $form->{oldpass}, 1); + $got_oldpass = 1 if $return_uid && $id == $return_uid; + } + + slashDisplay('changePasswd', { + useredit => $user_edit, + admin_flag => $suadmin_flag, + title => $title, + session => $session_select, + clocation => $clocation_select, + admin_block => $admin_block, + got_oldpass => $got_oldpass + }); +} + +################################################################# +sub editUser { + my($hr) = @_; + my $id = $hr->{uid} || ''; + my $note = $hr->{note} || ''; + + print createMenu("users", { + style => 'tabbed', + justify => 'right', + color => 'colored', + tab_selected => $hr->{tab_selected_1} || "", + }); + + my $form = getCurrentForm(); + my $slashdb = getCurrentDB(); + my $user = getCurrentUser(); + my $constants = getCurrentStatic(); + my $plugins = $slashdb->getDescriptions('plugins'); + + my $user_edit = {}; + my($admin_block, $title); + my $admin_flag = ($user->{is_admin}) ? 1 : 0; + my $fieldkey; + + if ($admin_flag && $form->{userfield}) { + $id ||= $form->{userfield}; + if ($form->{userfield} =~ /^\d+$/) { + $user_edit = $slashdb->getUser($id); + $fieldkey = 'uid'; + } else { + $user_edit = $slashdb->getUser($slashdb->getUserUID($id)); + $fieldkey = 'nickname'; + } + } else { + $user_edit = $id eq '' ? $user : $slashdb->getUser($id); + $fieldkey = 'uid'; + $id = $user_edit->{uid}; + } + return if isAnon($user_edit->{uid}) && ! $admin_flag; + + $admin_block = getUserAdmin($id, $fieldkey, 1) if $admin_flag; + $user_edit->{homepage} ||= "http://"; + + # Remove domain tags, they'll be added back in, in saveUser. + for my $dat (@{$user_edit}{qw(sig bio)}) { + $dat = parseDomainTags($dat, 0, 1); + } + + $title = getTitle('editUser_title', { user_edit => $user_edit}); + + my $editkey = ""; + $editkey = editKey($user_edit->{uid}) if $fieldkey eq 'uid' && $plugins->{PubKey}; + + slashDisplay('editUser', { + useredit => $user_edit, + admin_flag => $admin_flag, + title => $title, + editkey => $editkey, + admin_block => $admin_block, + note => $note, + }); +} + +################################################################# +sub editHome { + my($hr) = @_; + my $id = $hr->{uid} || ''; + my $note = $hr->{note} || ''; + + my $slashdb = getCurrentDB(); + my $form = getCurrentForm(); + my $user = getCurrentUser(); + my $constants = getCurrentStatic(); + + print createMenu("users", { + style => 'tabbed', + justify => 'right', + color => 'colored', + tab_selected => $hr->{tab_selected_1} || "", + }); + + my($formats, $title, $tzformat_select); + my $user_edit = {}; + my $fieldkey; + + my $admin_flag = ($user->{is_admin}) ? 1 : 0; + my $admin_block = ''; + + if ($admin_flag && $form->{userfield}) { + $id ||= $form->{userfield}; + if ($form->{userfield} =~ /^\d+$/) { + $user_edit = $slashdb->getUser($id); + $fieldkey = 'uid'; + } else { + $user_edit = $slashdb->getUser($slashdb->getUserUID($id)); + $fieldkey = 'nickname'; + } + } else { + $user_edit = $id eq '' ? $user : $slashdb->getUser($id); + $fieldkey = 'uid'; + } +#use Data::Dumper; $Data::Dumper::Sortkeys = 1; print STDERR scalar(localtime) . " user_edit: " . Dumper($user_edit); + + return if isAnon($user_edit->{uid}) && ! $admin_flag; + $admin_block = getUserAdmin($id, $fieldkey, 1) if $admin_flag; + + $title = getTitle('editHome_title'); + + return if $user->{seclev} < 100 && isAnon($user_edit->{uid}); + + $formats = $slashdb->getDescriptions('dateformats'); + $tzformat_select = createSelect('tzformat', $formats, $user_edit->{dfid}, 1); + + my $lb_check = $user_edit->{lowbandwidth} ? $constants->{markup_checked_attribute} : ''; + my $sd_check = $user_edit->{simpledesign} ? $constants->{markup_checked_attribute} : ''; + my $i_check = $user_edit->{noicons} ? $constants->{markup_checked_attribute} : ''; + my $w_check = $user_edit->{willing} ? $constants->{markup_checked_attribute} : ''; + + my $tilde_ed = tildeEd($user_edit); + + slashDisplay('editHome', { + title => $title, + admin_block => $admin_block, + user_edit => $user_edit, + tzformat_select => $tzformat_select, + i_check => $i_check, + w_check => $w_check, + lb_check => $lb_check, + sd_check => $sd_check, + tilde_ed => $tilde_ed, + note => $note, + }); +} + +################################################################# +sub editComm { + my($hr) = @_; + my $id = $hr->{uid} || ''; + my $note = $hr->{note} || ''; + + my $slashdb = getCurrentDB(); + my $form = getCurrentForm(); + my $user = getCurrentUser(); + my $constants = getCurrentStatic(); + my $user_edit = {}; + my($formats, $commentmodes_select, $commentsort_select, $title, + $uthreshold_select, $highlightthresh_select, $posttype_select, + $bytelimit_select); + + my $admin_block = ''; + my $fieldkey; + + print createMenu("users", { + style => 'tabbed', + justify => 'right', + color => 'colored', + tab_selected => $hr->{tab_selected_1} || "", + }); + + my $admin_flag = $user->{is_admin} ? 1 : 0; + + if ($admin_flag && $form->{userfield}) { + $id ||= $form->{userfield}; + if ($form->{userfield} =~ /^\d+$/) { + $user_edit = $slashdb->getUser($id); + $fieldkey = 'uid'; + } else { + $user_edit = $slashdb->getUser($slashdb->getUserUID($id)); + $fieldkey = 'nickname'; + } + } else { + $user_edit = $id eq '' ? $user : $slashdb->getUser($id); + $fieldkey = 'uid'; + } + + my $hi = $constants->{comment_maxscore} - $constants->{comment_minscore}; + my $lo = -$hi; + my @range = map { $_ > 0 ? "+$_" : $_ } ($lo .. $hi); + + my @reasons = ( ); + my %reason_select = ( ); + if ($constants->{m1}) { + my $mod_reader = getObject("Slash::$constants->{m1_pluginname}", { db_type => 'reader' }); + my $reasons = $mod_reader->getReasons(); + for my $id (sort { $a <=> $b } keys %$reasons) { + push @reasons, $reasons->{$id}{name}; + } + # Reason modifiers + for my $reason_name (@reasons) { + my $key = "reason_alter_$reason_name"; + $reason_select{$reason_name} = createSelect( + $key, \@range, + $user_edit->{$key} || 0, 1, 1 + ); + } + } + + # Zoo relation modifiers + my %people_select; + my @people = qw(friend foe anonymous fof eof freak fan); + for (@people) { + my $key = "people_bonus_$_"; + $people_select{$_} = createSelect($key, \@range, + $user_edit->{$key} || 0, 1, 1 + ); + } + + # New-user modifier + my $new_user_bonus_select = createSelect('new_user_bonus', \@range, + $user_edit->{new_user_bonus} || 0, 1, 1); + my $new_user_percent_select = createSelect('new_user_percent', + [( 1..15, 20, 25, 30, 35, 40, 45, 50, 55, + 60, 65, 70, 75, 80, 85, 90, 95 )], + $user_edit->{new_user_percent} || 100, 1, 1); + # Karma modifier + my $karma_bonus = createSelect('karma_bonus', \@range, + $user_edit->{karma_bonus} || 0, 1, 1); + # Subscriber modifier + my $subscriber_bonus = createSelect('subscriber_bonus', \@range, + $user_edit->{subscriber_bonus} || 0, 1, 1); + + # Length modifier + my $small_length_bonus_select = createSelect('clsmall_bonus', \@range, + $user_edit->{clsmall_bonus} || 0, 1, 1); + my $long_length_bonus_select = createSelect('clbig_bonus', \@range, + $user_edit->{clbig_bonus} || 0, 1, 1); + + return if isAnon($user_edit->{uid}) && ! $admin_flag; + $admin_block = getUserAdmin($id, $fieldkey, 1) if $admin_flag; + + $title = getTitle('editComm_title'); + + $formats = $slashdb->getDescriptions('commentmodes'); + $commentmodes_select=createSelect('umode', $formats, $user_edit->{mode}, 1); + + $formats = $slashdb->getDescriptions('sortcodes'); + $commentsort_select = createSelect( + 'commentsort', $formats, $user_edit->{commentsort}, 1 + ); + + $formats = $slashdb->getDescriptions('threshcodes'); + $uthreshold_select = createSelect( + 'uthreshold', $formats, $user_edit->{threshold}, 1 + ); + + $formats = $slashdb->getDescriptions('threshcodes'); + $highlightthresh_select = createSelect( + 'highlightthresh', $formats, $user_edit->{highlightthresh}, 1 + ); + + $user_edit->{bytelimit} = $constants->{defaultbytelimit} + if $user_edit->{bytelimit} < 0 || $user_edit->{bytelimit} > 7; + my $bytelimit_desc = $user_edit->{is_subscriber} ? 'bytelimit' : 'bytelimit_sub'; + $formats = $slashdb->getDescriptions($bytelimit_desc); + $bytelimit_select = createSelect( + 'bytelimit', $formats, $user_edit->{bytelimit}, 1 + ); + + my $h_check = $user_edit->{hardthresh} ? $constants->{markup_checked_attribute} : ''; + my $r_check = $user_edit->{reparent} ? $constants->{markup_checked_attribute} : ''; + my $n_check = $user_edit->{noscores} ? $constants->{markup_checked_attribute} : ''; + my $s_check = $user_edit->{nosigs} ? $constants->{markup_checked_attribute} : ''; + my $b_check = $user_edit->{nobonus} ? $constants->{markup_checked_attribute} : ''; + my $sb_check = $user_edit->{nosubscriberbonus} ? $constants->{markup_checked_attribute} : ''; + my $p_check = $user_edit->{postanon} ? $constants->{markup_checked_attribute} : ''; + my $nospell_check = $user_edit->{no_spell} ? $constants->{markup_checked_attribute} : ''; + my $s_mod_check = $user_edit->{mod_with_comm} ? $constants->{markup_checked_attribute} : ''; + my $s_m2_check = $user_edit->{m2_with_mod} ? $constants->{markup_checked_attribute} : ''; + my $s_m2c_check = $user_edit->{m2_with_comm_mod} ? $constants->{markup_checked_attribute} : ''; + + $formats = $slashdb->getDescriptions('postmodes'); + $posttype_select = createSelect( + 'posttype', $formats, $user_edit->{posttype}, 1 + ); + + slashDisplay('editComm', { + title => $title, + admin_block => $admin_block, + user_edit => $user_edit, + h_check => $h_check, + r_check => $r_check, + n_check => $n_check, + s_check => $s_check, + b_check => $b_check, + sb_check => $sb_check, + p_check => $p_check, + s_mod_check => $s_mod_check, + s_m2_check => $s_m2_check, + s_m2c_check => $s_m2c_check, + nospell_check => $nospell_check, + commentmodes_select => $commentmodes_select, + commentsort_select => $commentsort_select, + highlightthresh_select => $highlightthresh_select, + uthreshold_select => $uthreshold_select, + posttype_select => $posttype_select, + reasons => \@reasons, + reason_select => \%reason_select, + people => \@people, + people_select => \%people_select, + new_user_percent_select => $new_user_percent_select, + new_user_bonus_select => $new_user_bonus_select, + note => $note, + karma_bonus => $karma_bonus, + subscriber_bonus => $subscriber_bonus, + small_length_bonus_select => $small_length_bonus_select, + long_length_bonus_select => $long_length_bonus_select, + bytelimit_select => $bytelimit_select, + }); +} + +################################################################# +sub saveUserAdmin { + my($hr) = @_; + my $slashdb = getCurrentDB(); + my $form = getCurrentForm(); + my $user = getCurrentUser(); + my $constants = getCurrentStatic(); + + my($user_edits_table, $user_edit) = ({}, {}); + my $author_flag; + my $note = ''; + my $srcid; + my $id; + my $user_editfield_flag; + my $banned = 0; + my $banref; + if ($form->{uid}) { + $user_editfield_flag = 'uid'; + $id = $form->{uid}; + $user_edit = $slashdb->getUser($id); + $srcid = $id; + + } elsif ($form->{subnetid}) { + $user_editfield_flag = 'subnetid'; + ($id, $user_edit->{subnetid}) = ($form->{subnetid}, $form->{subnetid}); + $user_edit->{nonuid} = 1; + $srcid = convert_srcid(subnetid => $id); + + } elsif ($form->{ipid}) { + $user_editfield_flag = 'ipid'; + ($id, $user_edit->{ipid}) = ($form->{ipid}, $form->{ipid}); + $user_edit->{nonuid} = 1; + $srcid = convert_srcid(ipid => $id); + + } elsif ($form->{md5id}) { + $user_editfield_flag = 'md5id'; + my $fieldname = $form->{fieldname} || 'md5id'; + ($id, $user_edit->{$fieldname}) + = ($form->{md5id}, $form->{md5id}); + warn "form field md5id specified, no srcid saving possible"; + + } elsif ($form->{srcid}) { + $user_editfield_flag = 'srcid'; + my $fieldname = $form->{fieldname} || 'srcid'; + ($id, $user_edit->{$fieldname}) + = ($form->{srcid}, $form->{srcid}); + $srcid = $id; + + } else { + # If we were not fed valid data, don't do anything. + return ; + } + + my $reader = getObject('Slash::DB', { db_type => 'reader' }); + my $all_al2types = $reader->getAL2Types; + my $al2_change = { }; + + # First, get a hash of what aclams (AL2's and ACLs) this user + # had when the previous admin page was loaded. + # XXXSRCID Right now acl_old is just calculated for debugging + # printing purposes, not actually used. + my @al2_old = ( ); + @al2_old = + @{ $form->{al2_old_multiple} } if $form->{al2_old_multiple}; + my %al2_old = ( map { ($_, 1) } @al2_old ); + my @acl_old = ( ); + @acl_old = + @{ $form->{acl_old_multiple} } if $form->{acl_old_multiple}; + my %acl_old = ( map { ($_, 1) } @acl_old ); + + # Next, get the list of the new data submitted. Separate + # it out into AL2's which are legitimate. Anything left + # over is an ACL. + my @al2_new_formfields = ( ); + @al2_new_formfields = @{ $form->{aclams_new_multiple} } if $form->{aclams_new_multiple}; + my @al2_new_submitted = map { s/^aclam_//; $_ } @al2_new_formfields; + my @al2_new = grep { exists $all_al2types->{$_} } @al2_new_submitted; + my %al2_new = ( map { ($_, 1) } @al2_new ); + my @acl_new = grep { !$al2_new{$_} } @al2_new_submitted; + my %acl_new = ( map { ($_, 1) } @acl_new ); + + # Find out what changed for AL2's. + for my $al2 (@al2_old, @al2_new) { + next if defined($al2_old{$al2}) && defined($al2_new{$al2}) + && $al2_old{$al2} == $al2_new{$al2}; + $al2_change->{$al2} = $al2_new{$al2} ? 1 : 0; + } +#print STDERR "al2_change for '$srcid': " . Dumper($al2_change); + # If there's a comment, throw that in. + if ($form->{al2_new_comment}) { + $al2_change->{comment} = $form->{al2_new_comment}; + } + $al2_change = undef if !keys %$al2_change; + + # Find out what changed for ACL's. + my $acl_change = { }; + for my $acl (@acl_old, @acl_new) { + next if $acl_old{$acl} == $acl_new{$acl}; + $acl_change->{$acl} = $acl_new{$acl} ? 1 : 0; + } + $acl_change = undef if !keys %$acl_change; + + if ($user->{is_admin} && $srcid) { + $slashdb->setAL2($srcid, $al2_change); + } + if ($user->{is_admin} && ($user_editfield_flag eq 'uid' || + $user_editfield_flag eq 'nickname')) { + + # This admin user cannot assign a seclev higher than he/she + # already has. + my $seclev = $form->{seclev}; + $seclev = $user->{seclev} if $seclev > $user->{seclev}; + $user_edits_table->{seclev} = $seclev; + + $user_edits_table->{section} = $form->{section}; + $user_edits_table->{author} = $form->{author} ? 1 : 0 ; + $user_edits_table->{defaultpoints} = $form->{defaultpoints}; + $user_edits_table->{tokens} = $form->{tokens}; + $user_edits_table->{tag_clout} = $form->{tag_clout}; + $user_edits_table->{m2info} = $form->{m2info}; + $user_edits_table->{acl} = $acl_change if $acl_change; + + my $author = $slashdb->getAuthor($id); + my $was_author = ($author && $author->{author}) ? 1 : 0; + + $slashdb->setUser($id, $user_edits_table); + + $note .= getMessage('saveuseradmin_saveduser', { field => $user_editfield_flag, id => $id }); + + if ($was_author xor $user_edits_table->{author}) { + # A frequently-asked question for new Slash admins is + # why their authors aren't showing up immediately. + # Give them some help here with an informative message. + $note .= getMessage('saveuseradmin_authorchg', { + basedir => $slashdb->getDescriptions("site_info") + ->{base_install_directory}, + virtuser => $slashdb->{virtual_user}, + }); + + } + } + + if (!$user_edit->{nonuid}) { + if ($form->{expired} && $form->{expired} eq 'on') { +# $slashdb->setExpired($user_edit->{uid}); + + } else { +# $slashdb->setUnexpired($user_edit->{uid}); + } + } + + my $data = { uid => $id }; + $data->{note} = $note if defined $note; + showInfo($data); +} + +################################################################# +sub savePasswd { + my($hr) = @_; + my $note = $hr->{noteref} || undef; + + my $slashdb = getCurrentDB(); + my $form = getCurrentForm(); + my $user = getCurrentUser(); + my $constants = getCurrentStatic(); + + my $error_flag = 0; + my $user_edit = {}; + my $uid; + + my $user_edits_table = {}; + + if ($user->{is_admin}) { + $uid = $form->{uid} || $user->{uid}; + } else { + $uid = ($user->{uid} == $form->{uid}) ? $form->{uid} : $user->{uid}; + } + + $user_edit = $slashdb->getUser($uid); + + if (!$user_edit->{nickname}) { + $$note .= getError('cookie_err', { titlebar => 0 }, 0, 1) + if $note; + $error_flag++; + } + + if ($form->{pass1} ne $form->{pass2}) { + $$note .= getError('saveuser_passnomatch_err', { titlebar => 0 }, 0, 1) + if $note; + $error_flag++; + } + + if (!$form->{pass1} || length $form->{pass1} < 6) { + $$note .= getError('saveuser_passtooshort_err', { titlebar => 0 }, 0, 1) + if $note; + $error_flag++; + } + + if (!$user->{is_admin}){ + # not an admin -- check old password before changing passwd + my $return_uid = $slashdb->getUserAuthenticate($uid, $form->{oldpass}, 1); + if (!$return_uid || $return_uid != $uid) { + $$note .= getError('saveuser_badoldpass_err', { titlebar => 0 }, 0, 1) + if $note; + $error_flag++; + + } + } + + if (! $error_flag) { + $user_edits_table->{passwd} = $form->{pass1} if $form->{pass1}; + $user_edits_table->{session_login} = $form->{session_login}; + $user_edits_table->{cookie_location} = $form->{cookie_location}; + + # changed pass, so delete all logtokens + $slashdb->deleteLogToken($form->{uid}, 1); + + if ($user->{admin_clearpass} + && !$user->{state}{admin_clearpass_thisclick}) { + # User is an admin who sent their password in the clear + # some time ago; now that it's been changed, we'll forget + # about that incident, unless this click was sent in the + # clear as well. + $user_edits_table->{admin_clearpass} = ''; + } + + getOtherUserParams($user_edits_table); + $slashdb->setUser($uid, $user_edits_table) ; + $$note .= getMessage('saveuser_passchanged_msg', + { nick => $user_edit->{nickname}, uid => $user_edit->{uid} }, + 0, 1) if $note; + + # only set cookie if user is current user + if ($form->{uid} eq $user->{uid}) { + $user->{logtoken} = bakeUserCookie($uid, $slashdb->getLogToken($form->{uid}, 1)); + setCookie('user', $user->{logtoken}, $user_edits_table->{session_login}); + } + } + + return $error_flag; +} + +################################################################# +sub saveUser { + my($hr) = @_; + my $slashdb = getCurrentDB(); + my $form = getCurrentForm(); + my $user = getCurrentUser(); + my $constants = getCurrentStatic(); + my $gSkin = getCurrentSkin(); + my $plugins = $slashdb->getDescriptions('plugins'); + my $uid; + my $user_editfield_flag; + + $uid = $user->{is_admin} && $form->{uid} ? $form->{uid} : $user->{uid}; + my $user_edit = $slashdb->getUser($uid); + + my($note, $formname); + + $note .= getMessage('savenickname_msg', { + nickname => $user_edit->{nickname}, + }, 1); + + if (!$user_edit->{nickname}) { + $note .= getError('cookie_err', 0, 1); + } + + # Check to ensure that if a user is changing his email address, that + # it doesn't already exist in the userbase. + if ($user_edit->{realemail} ne $form->{realemail}) { + if ($slashdb->existsEmail($form->{realemail})) { + $note .= getError('emailexists_err', 0, 1); + $form->{realemail} = $user_edit->{realemail}; # can't change! + } + } + + my(%extr, $err_message, %limit); + $limit{sig} = 120; # schema is 200, give an extra buffer for domain tags + $limit{bio} = $constants->{users_bio_length} || 1024; # can be up to 2^16 + + for my $key (keys %limit) { + my $dat = chopEntity($form->{$key}, $limit{$key}); + $dat = strip_html($dat); + $dat = balanceTags($dat, { deep_nesting => 2, length => $limit{$key} }); + $dat = addDomainTags($dat) if $dat; + + # If the sig becomes too long to fit (domain tagging causes + # string expansion and tag balancing can too), warn the user to + # use shorter domain names and don't save their change. + if ($key eq 'sig' && defined($dat) && length($dat) > 200) { + print getError('sig_too_long_err'); + $extr{sig} = undef; + } + + # really, comment filters should ignore short length IMO ... oh well. + if (length($dat) > 1 && ! filterOk('comments', 'postersubj', $dat, \$err_message)) { + print getError('filter message', { + err_message => $err_message, + item => $key, + }); + $extr{$key} = undef; + } elsif (! compressOk('comments', 'postersubj', $dat)) { + print getError('compress filter', { + ratio => 'postersubj', + item => $key, + }); + $extr{$key} = undef; + } else { + $extr{$key} = $dat; + } + } + + # We should do some conformance checking on a user's pubkey, + # make sure it looks like one of the known types of public + # key. Until then, just make sure it doesn't have HTML. + $form->{pubkey} = $plugins->{'PubKey'} ? strip_nohtml($form->{pubkey}, 1) : ''; + + my $homepage = $form->{homepage}; + $homepage = '' if $homepage eq 'http://'; + $homepage = fudgeurl($homepage); + $homepage = URI->new_abs($homepage, $gSkin->{absolutedir}) + ->canonical + ->as_string if $homepage ne ''; + $homepage = substr($homepage, 0, 100) if $homepage ne ''; + + my $calendar_url = $form->{calendar_url}; + if (length $calendar_url) { + # fudgeurl() doesn't like webcal; will remove later anyway + $calendar_url =~ s/^webcal/http/i; + $calendar_url = fudgeurl($calendar_url); + $calendar_url = URI->new_abs($calendar_url, $gSkin->{absolutedir}) + ->canonical + ->as_string if $calendar_url ne ''; + + $calendar_url =~ s|^http://||i; + $calendar_url = substr($calendar_url, 0, 200) if $calendar_url ne ''; + } + + # for the users table + my $user_edits_table = { + homepage => $homepage, + realname => $form->{realname}, + pubkey => $form->{pubkey}, + copy => $form->{copy}, + quote => $form->{quote}, + calendar_url => $calendar_url, + yahoo => $form->{yahoo}, + jabber => $form->{jabber}, + aim => $form->{aim}, + aimdisplay => $form->{aimdisplay}, + icq => $form->{icq}, + playing => $form->{playing}, + mobile_text_address => $form->{mobile_text_address}, + }; + + for (keys %extr) { + $user_edits_table->{$_} = $extr{$_} if defined $extr{$_}; + } + + # don't want undef, want to be empty string so they + # will overwrite the existing record + for (keys %$user_edits_table) { + $user_edits_table->{$_} = '' unless defined $user_edits_table->{$_}; + } + + if ($user_edit->{realemail} ne $form->{realemail}) { + $user_edits_table->{realemail} = + chopEntity($form->{realemail}, 50); + my $new_fakeemail = ''; # at emaildisplay 0, don't show any email address + if ($user->{emaildisplay}) { + $new_fakeemail = getArmoredEmail($uid, $user_edits_table->{realemail}) + if $user->{emaildisplay} == 1; + $new_fakeemail = $user_edits_table->{realemail} + if $user->{emaildisplay} == 2; + } + $user_edits_table->{fakeemail} = $new_fakeemail; + + $note .= getMessage('changeemail_msg', { + realemail => $user_edit->{realemail} + }, 1); + + my $saveuser_emailtitle = getTitle('saveUser_email_title', { + nickname => $user_edit->{nickname}, + realemail => $form->{realemail} + }, 1); + my $saveuser_email_msg = getMessage('saveuser_email_msg', { + nickname => $user_edit->{nickname}, + realemail => $form->{realemail} + }, 1); + + sendEmail($form->{realemail}, $saveuser_emailtitle, $saveuser_email_msg); + doEmail($uid, $saveuser_emailtitle, $saveuser_email_msg); + } + + getOtherUserParams($user_edits_table); + $slashdb->setUser($uid, $user_edits_table); + + editUser({ uid => $uid, note => $note }); +} + + +################################################################# +sub saveComm { + my($hr) = @_; + my $slashdb = getCurrentDB(); + my $user = getCurrentUser(); + my $form = getCurrentForm(); + my $constants = getCurrentStatic(); + my($uid, $user_fakeemail); + + if ($user->{is_admin}) { + $uid = $form->{uid} || $user->{uid}; + } else { + $uid = ($user->{uid} == $form->{uid}) ? + $form->{uid} : $user->{uid}; + } + + # Do the right thing with respect to the chosen email display mode + # and the options that can be displayed. + my $user_edit = $slashdb->getUser($uid); + my $new_fakeemail = ''; # at emaildisplay 0, don't show any email address + if ($form->{emaildisplay}) { + $new_fakeemail = getArmoredEmail($uid) if $form->{emaildisplay} == 1; + $new_fakeemail = $user_edit->{realemail} if $form->{emaildisplay} == 2; + } + + my $name = $user->{seclev} && $form->{name} ? + $form->{name} : $user->{nickname}; + + my $note = getMessage('savenickname_msg', + { nickname => $name }); + + print getError('cookie_err') if isAnon($uid) || !$name; + + # Take care of the lists + # Enforce Ranges for variables that need it + $form->{commentlimit} = 0 if $form->{commentlimit} < 1; + my $cl_max = $constants->{comment_commentlimit} || 0; + $form->{commentlimit} = $cl_max if $cl_max > 0 && $form->{commentlimit} > $cl_max; + $form->{commentspill} = 0 if $form->{commentspill} < 1; + + # For some of these values, namely the ones that we happen to + # know get stored in users_param, we change them to 'undef' + # if they are the default value. This deletes them from the + # users_param table, which has the same effect as storing the + # default except it's faster all around. If we ever change + # the schema to promote these fields from params into a + # proper users_* table, then this will no longer be correct. + # See prepareUser(). + my $max = $constants->{comment_maxscore} - $constants->{comment_minscore}; + my $min = -$max; + my $karma_bonus = ($form->{karma_bonus} !~ /^[\-+]?\d+$/) ? "+1" : $form->{karma_bonus}; + my $subscriber_bonus = ($form->{subscriber_bonus} !~ /^[\-+]?\d+$/) ? "+1" : $form->{subscriber_bonus}; + my $new_user_bonus = ($form->{new_user_bonus} !~ /^[\-+]?\d+$/) ? 0 : $form->{new_user_bonus}; + my $new_user_percent = (($form->{new_user_percent} <= 100 && $form->{new_user_percent} >= 0) + ? $form->{new_user_percent} + : 100); + my $clsmall_bonus = ($form->{clsmall_bonus} !~ /^[\-+]?\d+$/) ? 0 : $form->{clsmall_bonus}; + my $clbig_bonus = ($form->{clbig_bonus} !~ /^[\-+]?\d+$/) ? 0 : $form->{clbig_bonus}; + + my $user_edits_table = { + discussion2 => $form->{discussion2} || undef, + d2_comment_q => $form->{d2_comment_q} || undef, + d2_comment_order => $form->{d2_comment_order} || undef, + clsmall => $form->{clsmall}, + clsmall_bonus => ($clsmall_bonus || undef), + clbig => $form->{clbig}, + clbig_bonus => ($clbig_bonus || undef), + commentlimit => $form->{commentlimit}, + bytelimit => $form->{bytelimit}, + commentsort => $form->{commentsort}, + commentspill => $form->{commentspill}, + domaintags => ($form->{domaintags} != 2 ? $form->{domaintags} : undef), + emaildisplay => $form->{emaildisplay} || undef, + fakeemail => $new_fakeemail, + highlightthresh => $form->{highlightthresh}, + maxcommentsize => $form->{maxcommentsize}, + mode => $form->{umode}, + posttype => $form->{posttype}, + threshold => $form->{uthreshold}, + nosigs => ($form->{nosigs} ? 1 : 0), + reparent => ($form->{reparent} ? 1 : 0), + noscores => ($form->{noscores} ? 1 : 0), + hardthresh => ($form->{hardthresh} ? 1 : 0), + no_spell => ($form->{no_spell} ? 1 : undef), + nobonus => ($form->{nobonus} ? 1 : undef), + nosubscriberbonus => ($form->{nosubscriberbonus} ? 1 : undef), + postanon => ($form->{postanon} ? 1 : undef), + new_user_percent => ($new_user_percent && $new_user_percent != 100 + ? $new_user_percent : undef), + new_user_bonus => ($new_user_bonus || undef), + karma_bonus => ($karma_bonus ne '+1' ? $karma_bonus : undef), + subscriber_bonus => ($subscriber_bonus || undef), + textarea_rows => ($form->{textarea_rows} != $constants->{textarea_rows} + ? $form->{textarea_rows} : undef), + textarea_cols => ($form->{textarea_cols} != $constants->{textarea_cols} + ? $form->{textarea_cols} : undef), + user_comment_sort_type => ($form->{user_comment_sort_type} != 2 + ? $form->{user_comment_sort_type} : undef ), + mod_with_comm => ($form->{mod_with_comm} ? 1 : undef), + m2_with_mod => ($form->{m2_with_mod} ? 1 : undef), + m2_with_comm_mod => ($form->{m2_with_mod_on_comm} ? 1 : undef), + + }; + + # set our default values for the items where an empty-string won't do + my $defaults = { + posttype => 2, + highlightthresh => 4, + maxcommentsize => 4096, + reparent => 1, + commentlimit => 100, + commentspill => 50, + mode => 'thread' + }; + + my $mod_reader = getObject("Slash::$constants->{m1_pluginname}", { db_type => 'reader' }); + my @reasons = ( ); + my $reasons = $mod_reader->getReasons(); + for my $id (sort { $a <=> $b } keys %$reasons) { + push @reasons, $reasons->{$id}{name}; + } + + for my $reason_name (@reasons) { + my $key = "reason_alter_$reason_name"; + my $answer = $form->{$key} || 0; + $answer = 0 if !$answer || $answer !~ /^[\-+]?\d+$/; + $user_edits_table->{$key} = ($answer == 0) ? '' : $answer; + } + + for (qw| friend foe anonymous fof eof freak fan |) { + my $answer = $form->{"people_bonus_$_"}; + $answer = 0 if $answer !~ /^[\-+]?\d+$/; + $user_edits_table->{"people_bonus_$_"} = ($answer == 0) ? '' : $answer; + } + getOtherUserParams($user_edits_table); + setToDefaults($user_edits_table, {}, $defaults) if $form->{restore_defaults}; + $slashdb->setUser($uid, $user_edits_table); + + editComm({ uid => $uid, note => $note }); +} + +################################################################# +sub saveHome { + my($hr) = @_; + my $slashdb = getCurrentDB(); + my $user = getCurrentUser(); + my $form = getCurrentForm(); + my $constants = getCurrentStatic(); + my($uid, $error); + + if ($user->{is_admin}) { + $uid = $form->{uid} || $user->{uid} ; + } else { + $uid = ($user->{uid} == $form->{uid}) ? + $form->{uid} : $user->{uid}; + } + my $edit_user = $slashdb->getUser($uid); + + my $name = $user->{seclev} && $form->{name} ? + $form->{name} : $user->{nickname}; + $name = substr($name, 0, 20); + + my $note = getMessage('savenickname_msg', + { nickname => $name }); + + if (isAnon($uid) || !$name) { + my $cookiemsg = getError('cookie_err'); + print $cookiemsg; + } + + # Using the existing list of slashboxes and the set of + # what's checked and not, build up the new list. + # (New arrivals go at the end.) + my $slashboxes = $edit_user->{slashboxes}; + # Only go through all this if the user clicked save, + # not "Restore Slashbox Defaults"! + my($boxes, $skinBoxes) = $slashdb->getPortalsCommon(); + my $default_slashboxes_textlist = join ",", + @{$skinBoxes->{$constants->{mainpage_skid}}}; + if (!$form->{restore_slashbox_defaults}) { + $slashboxes = $default_slashboxes_textlist if !$slashboxes; + my @slashboxes = split /,/, $slashboxes; + my %slashboxes = ( ); + for my $i (0..$#slashboxes) { + $slashboxes{$slashboxes[$i]} = $i; + } + # Add new boxes in. + for my $key (sort grep /^showbox_/, keys %$form) { + my($bid) = $key =~ /^showbox_(\w+)$/; + next if length($bid) < 1 || length($bid) > 30 || $bid !~ /^\w+$/; + if (! exists $slashboxes{$bid}) { + $slashboxes{$bid} = 999; # put it at the end + } + } + # Remove any boxes that weren't checked. + for my $bid (@slashboxes) { + delete $slashboxes{$bid} unless $form->{"showbox_$bid"}; + } + @slashboxes = sort { + $slashboxes{$a} <=> $slashboxes{$b} + || + $a cmp $b + } keys %slashboxes; + # This probably should be a var (and appear in tilded_customize_msg) + $#slashboxes = 19 if $#slashboxes > 19; + $slashboxes = join ",", @slashboxes; + } + # If we're right back to the default, that means the + # empty string. + if ($slashboxes eq $default_slashboxes_textlist) { + $slashboxes = ""; + } + + # Set the story_never and story_always fields. + my $author_hr = $slashdb->getDescriptions('authors'); + my $tree = $slashdb->getTopicTree(); + my(@story_never_topic, @story_never_author, @story_never_nexus); + my(@story_always_topic, @story_always_author); + my(@story_always_nexus, @story_full_brief_nexus, @story_brief_always_nexus, @story_full_best_nexus, @story_brief_best_nexus); + my($story_topic_all, $story_author_all, $story_nexus_all) = (0, 0, 0); + + # Topics are either present (value=2) or absent (value=0). If absent, + # push them onto the never list. Otherwise, do nothing. (There's no + # way to have an "always" topic, at the moment.) If the hidden + # field topictids_present is false, then there are no topic tids, + # skip this. + if ($form->{topictids_present}) { + for my $tid ( + sort { $a <=> $b } + grep { !$tree->{$_}{nexus} } + keys %$tree + ) { + my $key = "topictid$tid"; + $story_topic_all++; + if (!$form->{$key}) { push @story_never_topic, $tid } + } + } + # Authors are either present (value=2) or absent (value=0). If + # absent, push them onto the never list. Otherwise, do nothing. + # (There's no way to have an "always" author, at the moment.) + for my $aid (sort { $a <=> $b } keys %$author_hr) { + my $key = "aid$aid"; + $story_author_all++; + if (!$form->{$key}) { push @story_never_author, $aid } + } + # Nexuses can have value 0, 1, 2, 3, 4, 5. + # 0 means the never list, + # 1 means brief view of mainpage articles only + # 2 means full view of mainpage articles only + # 3 means brief view of all content + # 4 means full view of mainpage content, brief view of sectional + # 5 means full view of all content + for my $tid ( + sort { $a <=> $b } + map { /^nexustid(\d+)$/; $1 } + grep { /^nexustid\d+$/ } + keys %$form + ) { + my $key = "nexustid$tid"; + next unless $tid && $tree->{$tid} && $tree->{$tid}{nexus}; + $story_nexus_all++; + if (!$form->{$key}) { push @story_never_nexus, $tid } + elsif ($form->{$key} == 5 ) { push @story_always_nexus, $tid } + elsif ($form->{$key} == 4 ) { push @story_full_brief_nexus, $tid } + elsif ($form->{$key} == 3 ) { push @story_brief_always_nexus, $tid } + elsif ($form->{$key} == 2 ) { push @story_full_best_nexus, $tid } + elsif ($form->{$key} == 1 ) { push @story_brief_best_nexus, $tid } + + + } +#use Data::Dumper; $Data::Dumper::Sortkeys = 1; print STDERR scalar(localtime) . " s_n_t '@story_never_topic' s_n_a '@story_never_author' s_n_n '@story_never_nexus' s_a_n '@story_always_nexus' form: " . Dumper($form); + # Sanity check. + $#story_never_topic = 299 if $#story_never_topic > 299; + $#story_never_author = 299 if $#story_never_author > 299; + $#story_never_nexus = 299 if $#story_never_nexus > 299; + $#story_always_topic = 299 if $#story_always_topic > 299; + $#story_always_author = 299 if $#story_always_author > 299; + $#story_always_nexus = 299 if $#story_always_nexus > 299; + $#story_full_brief_nexus = 299 if $#story_full_brief_nexus > 299; + $#story_brief_always_nexus = 299 if $#story_brief_always_nexus > 299; + $#story_brief_best_nexus = 299 if $#story_brief_best_nexus > 299; + $#story_full_best_nexus = 299 if $#story_full_best_nexus > 299; + + my $story_never_topic = join ",", @story_never_topic; + $story_never_topic = ($constants->{subscribe} && $user->{is_subscriber}) + ? checkList($story_never_topic, 1024) + : checkList($story_never_topic); + my $story_never_author = checkList(join ",", @story_never_author); + my $story_never_nexus = checkList(join ",", @story_never_nexus); + my $story_always_topic = checkList(join ",", @story_always_topic); + $story_always_topic = ($constants->{subscribe} && $user->{is_subscriber}) + ? checkList($story_always_topic, 1024) + : checkList($story_always_topic); + my $story_always_author = checkList(join ",", @story_always_author); + + my $story_always_nexus = checkList(join ",", @story_always_nexus); + my $story_full_brief_nexus = checkList(join ",", @story_full_brief_nexus); + my $story_brief_always_nexus = checkList(join ",", @story_brief_always_nexus); + my $story_brief_best_nexus = checkList(join ",", @story_brief_best_nexus); + my $story_full_best_nexus = checkList(join ",", @story_full_best_nexus); + + + my $user_edits_table = { + story_never_topic => $story_never_topic, + story_never_author => $story_never_author, + story_never_nexus => $story_never_nexus, + story_always_topic => $story_always_topic, + story_always_author => $story_always_author, + story_always_nexus => $story_always_nexus, + story_brief_always_nexus => $story_brief_always_nexus, + story_full_brief_nexus => $story_full_brief_nexus, + story_full_best_nexus => $story_full_best_nexus, + story_brief_best_nexus => $story_brief_best_nexus, + + slashboxes => checkList($slashboxes, 1024), + + maxstories => 30, # XXXSKIN fix this later + noboxes => ($form->{useslashboxes} ? 0 : 1), + lowbandwidth => ($form->{lowbandwidth} ? 1 : 0), + simpledesign => ($form->{simpledesign} ? 1 : 0), + noicons => ($form->{noicons} ? 1 : 0), + willing => ($form->{willing} ? 1 : 0), + }; + + if (defined $form->{tzcode} && defined $form->{tzformat}) { + $user_edits_table->{tzcode} = $form->{tzcode}; + $user_edits_table->{dfid} = $form->{tzformat}; + $user_edits_table->{dst} = $form->{dst}; + } + + # Force the User Space area to contain only known-good HTML tags. + # Unfortunately the cookie login model makes it just too risky + # to allow scripts in here; CSS's steal passwords. There are + # no known vulnerabilities at this time, but a combination of the + # social engineering taking place (inviting users to put Javascript + # from websites in here, and making available script URLs for that + # purpose), plus the fact that this could be used to amplify the + # seriousness of any future vulnerabilities, means it's way past + # time to shut this feature down. - Jamie 2002/03/06 + + # it's a VARCHAR ... + my $mylinks_limit = 255; + $user_edits_table->{mylinks} = balanceTags(strip_html( + chopEntity($form->{mylinks} || '', $mylinks_limit) + ), { deep_nesting => 2, length => $mylinks_limit }); + + $user_edits_table->{mylinks} = '' unless defined $user_edits_table->{mylinks}; + + $error = 1; + # must select at least 1/4 of nexuses, topics, authors + if ( scalar(@story_never_author) > ($story_author_all * 3/4) ) { + $note = getError('editHome_too_many_disabled'); + } elsif ( scalar(@story_never_nexus) > ($story_nexus_all * 3/4) ) { + $note = getError('editHome_too_many_disabled'); + } elsif ( scalar(@story_never_topic) > ($story_topic_all * 3/4) ) { + $note = getError('editHome_too_many_disabled'); + } else { + $error = 0; + } + + unless ($error) { + # If a user is unwilling to moderate, we should cancel all points, lest + # they be preserved when they shouldn't be. + if (!isAnon($uid) && !$form->{willing}) { + $slashdb->setUser($uid, { points => 0 }); + } + + getOtherUserParams($user_edits_table); + if ($form->{restore_defaults}) { + setToDefaults($user_edits_table, {}, { + maxstories => 30, + tzcode => "EST", + # XXX shouldn't this reset ALL the defaults, + # not just these two? + }); + } + if ($form->{restore_slashbox_defaults}) { + setToDefaults($user_edits_table, { + 'story_never_topic' => 1, + 'story_never_author' => 1, + 'story_never_nexus' => 1, + 'story_always_topic' => 1, + 'story_always_author' => 1, + 'story_always_nexus' => 1, + 'story_full_brief_nexus' => 1, + 'story_brief_always_nexus' => 1, + 'story_full_best_nexus' => 1, + 'story_brief_best_nexus' => 1, + 'maxstories' => 1, + 'noboxes' => 1, + 'light' => 1, + 'noicons' => 1, + 'willing' => 1 + }, { slashboxes => "" }); + } + +#print scalar(localtime) . " uet: " . Dumper($user_edits_table); + $slashdb->setUser($uid, $user_edits_table); + } + + editHome({ uid => $uid, note => $note }); +} + +################################################################# +# A generic way for a site to allow users to edit data about themselves. +# Most useful when your plugin or theme wants to let the user change +# minor settings but you don't want to write a whole new version +# of users.pl to provide a user interface. The user can save any +# param of the format "opt_foo", as long as "foo" shows up in +# getMiscUserOpts which lists all the misc opts that this user can edit. +# This is *not* protected by formkeys (yet), so assume attackers can make +# users click and accidentally edit their own settings: no really important +# data should be stored in this way. +sub editMiscOpts { + my($hr) = @_; + my $slashdb = getCurrentDB(); + my $user = getCurrentUser(); + my $constants = getCurrentStatic(); + my $note = $hr->{note} || ""; + + return if $user->{is_anon}; # shouldn't be, but can't hurt to check + + print createMenu("users", { + style => 'tabbed', + justify => 'right', + color => 'colored', + tab_selected => $hr->{tab_selected_1} || "", + }); + + my $edit_user = $slashdb->getUser($user->{uid}); + my $title = getTitle('editMiscOpts_title'); + + my $opts = $slashdb->getMiscUserOpts(); + for my $opt (@$opts) { + my $opt_name = "opt_" . $opt->{name}; + $opt->{checked} = $edit_user->{$opt_name} ? 1 : 0; + } + + slashDisplay('editMiscOpts', { +# useredit => $user_edit, + title => $title, + opts => $opts, + note => $note, + }); +} + +################################################################# +# +sub saveMiscOpts { + my($hr) = @_; + my $slashdb = getCurrentDB(); + my $user = getCurrentUser(); + my $form = getCurrentForm(); + my $constants = getCurrentStatic(); + + return if $user->{is_anon}; # shouldn't be, but can't hurt to check + + my $edit_user = $slashdb->getUser($user->{uid}); + my %opts_ok_hash = ( ); + my $opts = $slashdb->getMiscUserOpts(); + for my $opt (@$opts) { + $opts_ok_hash{"opt_$opt->{name}"} = 1; + } + + my $update = { }; + for my $opt (grep /^opt_/, keys %$form) { + next unless $opts_ok_hash{$opt}; + $update->{$opt} = $form->{$opt} ? 1 : 0; + } + + # Make the changes. + $slashdb->setUser($edit_user->{uid}, $update); + + # Inform the user the change was made. Since we don't + # require formkeys, we always want to print a message to + # make sure the user sees what s/he did. This is done + # by passing in a note which ends up passed to the + # editMiscOpts template, which displays it. + editMiscOpts({ note => getMessage('savemiscopts_msg') }); +} + +################################################################# +sub listReadOnly { + my $reader = getObject('Slash::DB', { db_type => 'reader' }); + + my $readonlylist = $reader->getAL2List('nopost'); + + slashDisplay('listReadOnly', { + readonlylist => $readonlylist, + }); + +} + +################################################################# +sub listBanned { + my $reader = getObject('Slash::DB', { db_type => 'reader' }); + + my $bannedlist = $reader->getAL2List('ban'); + + slashDisplay('listBanned', { + bannedlist => $bannedlist, + }); + +} + +################################################################# +sub topAbusers { + my $reader = getObject('Slash::DB', { db_type => 'reader' }); + + my $topabusers = $reader->getTopAbusers(); + + slashDisplay('topAbusers', { + topabusers => $topabusers, + }); +} + +################################################################# +sub listAbuses { + my $user = getCurrentUser(); + my $form = getCurrentForm(); + my $reader = getObject('Slash::DB', { db_type => 'reader' }); + my $constants = getCurrentStatic(); + + my $abuses = $reader->getAbuses($form->{key}, $form->{abuseid}); + + slashDisplay('listAbuses', { + abuseid => $form->{abuseid}, + abuses => $abuses, + }); +} + +################################################################# +sub forceAccountVerify { + my $user = getCurrentUser(); + my $form = getCurrentForm(); + my $slashdb = getCurrentDB(); + my $constants = getCurrentStatic(); + + my $uid = $form->{uid}; + my $useredit = $slashdb->getUser($uid); + + if ($useredit->{uid}) { + my $newpasswd = $slashdb->resetUserAccount($uid); + $slashdb->deleteLogToken($uid, 1); + my $emailtitle = getTitle('reset_acct_email_title', { + nickname => $useredit->{nickname} + }, 1); + + my $msg = getMessage('reset_acct_msg', { + newpasswd => $newpasswd, + tempnick => $useredit->{nickname}, + }, 1); + + $slashdb->setUser($useredit->{uid}, { + waiting_for_account_verify => 1, + account_verify_request_time => $slashdb->getTime() + }); + + doEmail($useredit->{uid}, $emailtitle, $msg) if $useredit->{uid}; + } + + print getMessage("reset_acct_complete", { useredit => $useredit }, 1); +} + +################################################################# +sub displayForm { + my($hr) = @_; + + my $user = getCurrentUser(); + my $form = getCurrentForm(); + my $slashdb = getCurrentDB(); + my $constants = getCurrentStatic(); + + my $suadmin_flag = $user->{seclev} >= 10000 ? 1 : 0; + + print createMenu("users", { + style => 'tabbed', + justify => 'right', + color => 'colored', + tab_selected => $hr->{tab_selected_1} || "", + }); + + my $op = $hr->{op} || $form->{op} || 'displayform'; + + my $ops = { + displayform => 'loginForm', + edithome => 'loginForm', + editcomm => 'loginForm', + edituser => 'loginForm', +# mailpasswdform => 'sendPasswdForm', +# newuserform => 'newUserForm', + userclose => 'loginForm', + userlogin => 'loginForm', + editmiscopts => 'loginForm', + savemiscopts => 'loginForm', + default => 'loginForm' + }; + + $op = 'default' if !defined($ops->{$op}); + + my($title, $title2, $msg1, $msg2) = ('', '', '', ''); + + if ($op eq 'userclose') { + $title = getMessage('userclose'); + + } elsif ($op eq 'displayForm') { + $title = $form->{unickname} + ? getTitle('displayForm_err_title') + : getTitle('displayForm_title'); + } elsif ($op eq 'mailpasswdform') { + $title = getTitle('mailPasswdForm_title'); + } elsif ($op eq 'newuserform') { + $title = getTitle('newUserForm_title'); + } else { + $title = getTitle('displayForm_title'); + } + + $form->{unickname} ||= $form->{newusernick}; + + if ($form->{newusernick}) { + $title2 = getTitle('displayForm_dup_title'); + } else { + $title2 = getTitle('displayForm_new_title'); + } + + $msg1 = getMessage('dispform_new_msg_1'); + if (! $form->{newusernick} && $op eq 'newuserform') { + $msg2 = getMessage('dispform_new_msg_2'); + } elsif ($op eq 'displayform' || $op eq 'userlogin') { + $msg2 = getMessage('newuserform_msg'); + } + + slashDisplay($ops->{$op}, { + newnick => nickFix($form->{newusernick}), + suadmin_flag => $suadmin_flag, + title => $title, + title2 => $title2, + logged_in => $user->{is_anon} ? 0 : 1, + msg1 => $msg1, + msg2 => $msg2 + }); +} + +################################################################# +# this groups all the messages together in +# one template, called "messages;users;default" +sub getMessage { + my($value, $hashref, $nocomm) = @_; + $hashref ||= {}; + $hashref->{value} = $value; + return slashDisplay('messages', $hashref, + { Return => 1, Nocomm => $nocomm }); +} + +################################################################# +# this groups all the errors together in +# one template, called "errors;users;default" +sub getError { + my($value, $hashref, $nocomm) = @_; + $hashref ||= {}; + $hashref->{value} = $value; + return slashDisplay('errors', $hashref, + { Return => 1, Nocomm => $nocomm }); +} + +################################################################# +# this groups all the titles together in +# one template, called "users-titles" +sub getTitle { + my($value, $hashref, $nocomm) = @_; + $hashref ||= {}; + $hashref->{value} = $value; + return slashDisplay('titles', $hashref, + { Return => 1, Nocomm => $nocomm }); +} + +################################################################# +# getUserAdmin - returns a block of HTML text that provides +# information and editing capabilities for admin users. +# Most of this data is already in the getUserAdmin template, +# but really, we should try to get more of this logic into +# that template. +sub getUserAdmin { + my($id, $field, $seclev_field) = @_; + my $reader = getObject('Slash::DB', { db_type => 'reader' }); + my $logdb = getObject('Slash::DB', { db_type => 'log_slave' }); + + + my $user = getCurrentUser(); + my $form = getCurrentForm(); + my $constants = getCurrentStatic(); + my $slashdb = getCurrentDB(); + $id ||= $user->{uid}; + + my($expired, $uidstruct, $readonly); + my($user_edit, $user_editfield, $ipstruct, $ipstruct_order, $authors, $author_flag, $topabusers, $thresh_select,$section_select); + my $srcid; + my $proxy_check = {}; + my @accesshits; + my $user_editinfo_flag = (!$form->{op} || $form->{op} eq 'userinfo' + || $form->{userinfo} || $form->{saveuseradmin} + ) ? 1 : 0; + my $authoredit_flag = ($user->{seclev} >= 10000) ? 1 : 0; + my $sectionref = $reader->getDescriptions('skins'); + $sectionref->{''} = getData('all_sections'); + + $field ||= 'uid'; + if ($field eq 'uid') { + $user_edit = $slashdb->getUser($id); + $user_editfield = $user_edit->{uid}; + $srcid = convert_srcid( uid => $id ); + #$expired = $slashdb->checkExpired($user_edit->{uid}) ? $constants->{markup_checked_attribute} : ''; + $ipstruct = $slashdb->getNetIDStruct($user_edit->{uid}); + @accesshits = $logdb->countAccessLogHitsInLastX($field, $user_edit->{uid}) if defined($logdb); + $section_select = createSelect('section', $sectionref, $user_edit->{section}, 1); + + } elsif ($field eq 'nickname') { + $user_edit = $slashdb->getUser($slashdb->getUserUID($id)); + $user_editfield = $user_edit->{nickname}; + #$expired = $slashdb->checkExpired($user_edit->{uid}) ? $constants->{markup_checked_attribute} : ''; + $ipstruct = $slashdb->getNetIDStruct($user_edit->{uid}); + @accesshits = $logdb->countAccessLogHitsInLastX('uid', $user_edit->{uid}) if defined($logdb); + $section_select = createSelect('section', $sectionref, $user_edit->{section}, 1); + + } elsif ($field eq 'md5id') { + $user_edit->{nonuid} = 1; + $user_edit->{md5id} = $id; + if ($form->{fieldname} && $form->{fieldname} =~ /^(ipid|subnetid)$/) { + $uidstruct = $slashdb->getUIDStruct($form->{fieldname}, $user_edit->{md5id}); + @accesshits = $logdb->countAccessLogHitsInLastX($form->{fieldname}, $user_edit->{md5id}) if defined($logdb); + } else { + $uidstruct = $slashdb->getUIDStruct('md5id', $user_edit->{md5id}); + @accesshits = $logdb->countAccessLogHitsInLastX($field, $user_edit->{md5id}) if defined($logdb); + } + + } elsif ($field eq 'ipid') { + $user_edit->{nonuid} = 1; + $user_edit->{ipid} = $id; + $srcid = convert_srcid( ipid => $id ); + $user_editfield = $id; + $uidstruct = $slashdb->getUIDStruct('ipid', $user_edit->{ipid}); + @accesshits = $logdb->countAccessLogHitsInLastX('host_addr', $user_edit->{ipid}) if defined($logdb); + + if ($form->{userfield} =~/^\d+\.\d+\.\d+\.(\d+)$/) { + if ($1 ne "0"){ + $proxy_check->{available} = 1; + $proxy_check->{results} = $slashdb->checkForOpenProxy($form->{userfield}) if $form->{check_proxy}; + } + } + + } elsif ($field eq 'subnetid') { + $user_edit->{nonuid} = 1; + $srcid = convert_srcid( ipid => $id ); + if ($id =~ /^(\d+\.\d+\.\d+)(?:\.\d)?/) { + $id = $1 . ".0"; + $user_edit->{subnetid} = $id; + } else { + $user_edit->{subnetid} = $id; + } + + $user_editfield = $id; + $uidstruct = $slashdb->getUIDStruct('subnetid', $user_edit->{subnetid}); + @accesshits = $logdb->countAccessLogHitsInLastX($field, $user_edit->{subnetid}) if defined($logdb); + + } elsif ($field eq "srcid") { + $user_edit->{nonuid} = 1; + $user_edit->{srcid} = $id; + $srcid = $id; + + } else { + $user_edit = $id ? $slashdb->getUser($id) : $user; + $user_editfield = $user_edit->{uid}; + $ipstruct = $slashdb->getNetIDStruct($user_edit->{uid}); + @accesshits = $logdb->countAccessLogHitsInLastX('uid', $user_edit->{uid}) if defined($logdb); + } + + ########## + # Put together the array and hashref that the template will need + # to construct the list for display to the admin. + # Note that currently a srcid which is not a uid (i.e. which + # represents an IP address or masked IP network) cannot have + # any ACLs assigned to it. This may change in the future. + # The term "aclam" is used because it has a field set for both + # every ACL and every access modifier (i.e. AL2 bit) that is set + # for this user or srcid. + # For now, ACLs will be listed for IPs as well. + # First get the list of ACLs that can be used. + my $all_acls_ar = $reader->getAllACLNames(); + my $all_acls_hr = { map { ( $_, 1 ) } @$all_acls_ar }; + # Add in any ACLs selected for this user (just in case + # getAllACLNames is cached and stale). + for my $acl (keys %{$user_edit->{acl}}) { + $all_acls_hr->{$acl} = 1; + } + # Start creating the $all_aclam_hr data, in which the keys are + # the HTML selection names that all begin with aclam_ and the + # the values are their names/descriptions shown to the admin. + # First put all the ACLs into the hash, if we're editing a user. + my $all_aclam_hr = { }; + if (!$user_edit->{nonuid}) { + $all_aclam_hr = { map { ( "aclam_$_", "ACL: $_" ) } keys %$all_acls_hr }; + } + # Next put in all the al2 types. + my $all_al2types = $reader->getAL2Types; + for my $key (keys %$all_al2types) { + next if $key eq 'comment'; # skip the 'comment' type + $all_aclam_hr->{"aclam_$key"} = $all_al2types->{$key}{title}; + } + # Finally, sort the keys of the hash into the order that we + # want them displayed to the admin (ACLs first). + my $all_acls_longkeys_hr = { map { ( "aclam_$_", 1 ) } keys %$all_acls_hr }; + my $all_aclam_ar = [ + sort { + (exists($all_acls_longkeys_hr->{$a}) ? -1 : 1) <=> (exists($all_acls_longkeys_hr->{$b}) ? -1 : 1) + || + $all_aclam_hr->{$a} cmp $all_aclam_hr->{$b} + } keys %$all_aclam_hr + ]; + # Now put together the hashref that identifies which of those + # items are selected for this user. + my $user_aclam_hr = { }; + for my $acl (keys %{ $user_edit->{acl} }) { + $user_aclam_hr->{"aclam_$acl"} = 1; + } + my $al2_tid_comment = $all_al2types->{comment}{al2tid} || 0; + my $al2_log_ar = [ ]; + my $al2_hr = { }; + # XXXSRCID Once we get rid of the silly 'md5id' field and all the + # other bizarre backward-compatibility code paths early in this + # function, this won't be necessary, but until then we need this + # sanity check... + if ($srcid) { + # getAL2 works with either a srcids hashref or a single srcid + $al2_hr = $slashdb->getAL2($srcid); + for my $al2 (keys %{ $al2_hr }) { + $user_aclam_hr->{"aclam_$al2"} = 1; + } + $al2_log_ar = $slashdb->getAL2Log($srcid); + } + # Generate al2_nick_hr, which will be populated with keys of all + # the (presumably) admin uids who have logged rows for this al2, + # and values of their nicks. + my $al2_nick_hr = { }; + for my $al2_log (@$al2_log_ar) { + my $uid = $al2_log->{adminuid}; + next if !$uid; # odd error, might want to flag this + $al2_nick_hr->{$uid} ||= $slashdb->getUser($uid, 'nickname'); + } + ########## + + $user_edit->{author} = ($user_edit->{author} && $user_edit->{author} == 1) + ? $constants->{markup_checked_attribute} : ''; + if (! $user->{nonuid}) { + my $threshcodes = $reader->getDescriptions('threshcode_values','',1); + $thresh_select = createSelect('defaultpoints', $threshcodes, $user_edit->{defaultpoints}, 1); + } + + if (!ref $ipstruct) { + undef $ipstruct; + } else { + @$ipstruct_order = sort { $ipstruct->{$b}{dmin} cmp $ipstruct->{$a}{dmin} } keys %$ipstruct; + } + + my $m2total = ($user_edit->{m2fair} || 0) + ($user_edit->{m2unfair} || 0); + if ($m2total) { + $user_edit->{m2unfairpercent} = sprintf("%.2f", + $user_edit->{m2unfair}*100/$m2total); + } + my $mod_total = ($user_edit->{totalmods} || 0) + ($user_edit->{stirred} || 0); + if ($mod_total) { + $user_edit->{stirredpercent} = sprintf("%.2f", + $user_edit->{stirred}*100/$mod_total); + } + if ($constants->{subscribe} and my $subscribe = getObject('Slash::Subscribe')) { + $user_edit->{subscribe_payments} = + $subscribe->getSubscriptionsForUser($user_edit->{uid}); + $user_edit->{subscribe_purchases} = + $subscribe->getSubscriptionsPurchasedByUser($user_edit->{uid},{ only_types => [ "grant", "gift" ] }); + } + my $ipid = $user_edit->{ipid}; + my $subnetid = $user_edit->{subnetid}; + my $post_restrictions = {}; + my ($subnet_karma, $ipid_karma); + + if ($ipid && !$subnetid) { + $ipid = md5_hex($ipid) if length($ipid) != 32; + $proxy_check->{ipid} = $ipid; + $proxy_check->{currently} = $slashdb->getKnownOpenProxy($ipid, "ipid"); + # This next call is very slow. + $subnetid = $reader->getSubnetFromIPIDBasedOnComments($ipid); + } + + if ($subnetid) { + $subnetid = md5_hex($subnetid) if length($subnetid) != 32; + # These next three calls can be very slow. In fact, getNetIDKarma + # is actually called twice on the same subnetid; if we can cache + # that data somehow that wouldn't be a bad idea. + $post_restrictions = $reader->getNetIDPostingRestrictions("subnetid", $subnetid); + $subnet_karma = $reader->getNetIDKarma("subnetid", $subnetid); + $ipid_karma = $reader->getNetIDKarma("ipid", $ipid) if $ipid; + } + + return slashDisplay('getUserAdmin', { + field => $field, + useredit => $user_edit, + srcid => $srcid, + all_aclam_ar => $all_aclam_ar, + all_aclam_hr => $all_aclam_hr, + user_aclam_hr => $user_aclam_hr, + al2_old => $al2_hr, + al2_log => $al2_log_ar, + al2_tid_comment => $al2_tid_comment, + al2_nick => $al2_nick_hr, + + userinfo_flag => $user_editinfo_flag, + userfield => $user_editfield, + ipstruct => $ipstruct, + ipstruct_order => $ipstruct_order, + uidstruct => $uidstruct, + accesshits => \@accesshits, + seclev_field => $seclev_field, + expired => $expired, + topabusers => $topabusers, + readonly => $readonly, + thresh_select => $thresh_select, + authoredit_flag => $authoredit_flag, + section_select => $section_select, + all_acls => $all_acls_hr, + proxy_check => $proxy_check, + subnet_karma => $subnet_karma, + ipid_karma => $ipid_karma, + post_restrictions => $post_restrictions + }, 1); +} + +################################################################# +# this is to allow alternate parameters to be specified. pass in +# your hash reference to be passed to setUser(), and this will +# add in those extra parameters. add the parameters to string_param, +# type = otherusersparam, code = name of the param. they will +# be checked for the main user prefs editing screens, and on +# user creation -- pudge +sub getOtherUserParams { + my($data) = @_; + my $reader = getObject('Slash::DB', { db_type => 'reader' }); + + my $user = getCurrentUser(); + my $form = getCurrentForm(); + my $params = $reader->getDescriptions('otherusersparam'); + + for my $param (keys %$params) { + if (exists $form->{$param}) { + # set user too for output in this request + $data->{$param} = $user->{$param} = $form->{$param} || undef; + } + } +} + +############################################################### +# This modifies a hashref to default values -- if nothing +# else we assume the empty string which clears items in the +# user_param table +# +# takes 3 hashrefs currently +# $data - hashref to change to defaults +# $skip - hashref of keys to skip modifying +# $defaults - hashref of defaults to set to something other +# than the empty string +sub setToDefaults { + my($data, $skip, $defaults) = @_; + foreach my $key (keys %$data) { + next if $skip->{$key}; + $data->{$key} = exists $defaults->{$key} ? $defaults->{$key} : ""; + } +} + +################################################################# +sub getCommentListing { + my ($type, $value, + $min_comment, $time_period, $cc_all, $cc_time_period, $cid_for_time_period, + $non_admin_limit, $admin_time_limit, $admin_non_time_limit, + $options) = @_; + my $reader = getObject('Slash::DB', { db_type => 'reader' }); + my $slashdb = getCurrentDB(); + my $constants = getCurrentStatic(); + my $user = getCurrentUser(); + my $store_cutoff = $options->{use_uid_cid_cutoff} ? $constants->{store_com_page1_min_cid_for_user_com_cnt} : 0; + + my $s_opt = {}; + my $num_wanted = 0; + if ($min_comment) { + if ($user->{is_admin}) { + $num_wanted = $admin_non_time_limit; + } else { + $num_wanted = $non_admin_limit; + } + } else { + + if ($user->{is_admin}) { + if ($cc_time_period >= $admin_non_time_limit) { + $s_opt->{cid_at_or_after} = $cid_for_time_period; + $num_wanted = $admin_time_limit; + } else { + $num_wanted = $admin_non_time_limit; + if($store_cutoff){ + my $min_cid = $reader->getUser($value, + "com_num_".$num_wanted."_at_or_after_cid"); + $s_opt->{cid_at_or_after} = $min_cid + if $min_cid && $min_cid =~ /^\d+$/; + } + } + } else { + if ($cc_time_period >= $non_admin_limit ) { + $s_opt->{cid_at_or_after} = $cid_for_time_period; + $num_wanted = $non_admin_limit; + } else { + $num_wanted = $non_admin_limit; + if($store_cutoff){ + my $min_cid = $reader->getUser($value, + "com_num_".$num_wanted."_at_or_after_cid"); + $s_opt->{cid_at_or_after} = $min_cid + if $min_cid && $min_cid =~ /^\d+$/; + } + } + } + } + if ($type eq "uid") { + + my $comments = $reader->getCommentsByUID($value, $num_wanted, $min_comment, $s_opt) if $cc_all; + if ($store_cutoff + && $comments && $cc_all >= $store_cutoff && $min_comment == 0 + && scalar(@$comments) == $num_wanted) { + my $min_cid = 0; + for my $comment (@$comments) { + $min_cid = $comment->{cid} + if !$min_cid || ($comment->{cid} < $min_cid); + } + if ($min_cid && $min_cid =~/^\d+$/) { + $slashdb->setUser($value, { + "com_num_".$num_wanted."_at_or_after_cid" => $min_cid + }); + } + + } + return $comments; + } elsif ($type eq "ipid"){ + return $reader->getCommentsByIPID($value, $num_wanted, $min_comment, $s_opt) if $cc_all; + } elsif ($type eq "subnetid"){ + return $reader->getCommentsBySubnetID($value, $num_wanted, $min_comment, $s_opt) if $cc_all; + } else { + return $reader->getCommentsByIPIDOrSubnetID($value, $num_wanted, $min_comment, $s_opt) if $cc_all; + } +} +createEnvironment(); +main(); + +1; Modified: slashjp/branches/upstream/current/themes/slashcode/templates/dispComment;misc;default =================================================================== --- slashjp/branches/upstream/current/themes/slashcode/templates/dispComment;misc;default 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/themes/slashcode/templates/dispComment;misc;default 2008-04-06 23:11:14 UTC (rev 569) @@ -23,7 +23,7 @@ dispComment __template__ [% IF !options.noshow_show %] -
  • +
  • [% END; IF !options.noshow %] @@ -34,7 +34,7 @@ [% ELSE %]

    [% subject %] [%- END %] - [% UNLESS user.noscores %]([% IF constants.modal_prefs_active && !user.is_anon %][% END %]Score:[% points.length ? points : "?" %][% IF constants.modal_prefs_active && !user.is_anon %][% END %][% IF reasons && reason %], [% reasons.$reason.name %][% END %])[% END %]

    + [% UNLESS user.noscores %]([% IF constants.modal_prefs_active %][% END %]Score:[% points.length ? points : "?" %][% IF constants.modal_prefs_active %][% END %][% IF reasons && reason %], [% reasons.$reason.name %][% END %])[% END %]
    by @@ -81,4 +81,4 @@ __seclev__ 10000 __version__ -$Id: dispComment;misc;default,v 1.66 2008/03/19 08:25:31 pudge Exp $ +$Id: dispComment;misc;default,v 1.69 2008/04/01 20:06:29 pudge Exp $ Modified: slashjp/branches/upstream/current/themes/slashcode/templates/dispLinkComment;misc;default =================================================================== --- slashjp/branches/upstream/current/themes/slashcode/templates/dispLinkComment;misc;default 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/themes/slashcode/templates/dispLinkComment;misc;default 2008-04-06 23:11:14 UTC (rev 569) @@ -13,38 +13,32 @@ __name__ dispLinkComment __template__ -[% IF user.mode != 'metamod' %] +[% IF user.mode != 'metamod' && user.mode != 'archive' %] [% IF user.is_admin || original_pid || !user.state.discussion_archived %] [% do_parent = ( original_pid ); #&& !(discussion2 && (!form.cid || form.cid != cid)) ); can_del = ( (constants.authors_unlimited && user.seclev >= constants.authors_unlimited) || user.acl.candelcomments_always ) %] [% IF !options.show_pieces %]
    [% END; IF !options.pieces %] - [ - [% IF !user.state.discussion_archived && !user.state.discussion_future_nopost %] - [% Slash.linkComment({ +

    [% Slash.linkComment({ sid => sid, pid => cid, op => 'Reply', subject => 'Reply to This', subject_only => 1, - onclick => ((discussion2 && (!constants.subscribe || user.is_subscriber)) ? "replyTo($cid); return false;" : '') - }) %] + onclick => ((discussion2 && !user.is_anon) ? "replyTo($cid); return false;" : '') + }) %]

    [% END %] - [% IF !(user.state.discussion_archived) && ( do_parent || can_mod || can_del ) %] | [% END %] - - [% IF do_parent %][% Slash.linkComment({ + [% IF do_parent %]

    [% Slash.linkComment({ sid => sid, cid => original_pid, pid => original_pid, subject => 'Parent', subject_only => 1, onclick => (discussion2 ? "return selectParent($original_pid)" : '') - }, 1) %][% END %] + }, 1) %]

    [% END %] - [% IF do_parent && ( can_mod || can_del ) %] | [% END %] - [% IF can_mod %]
    [% Slash.createSelect("reason_$cid", reasons, { 'return' => 1, @@ -52,14 +46,10 @@ onchange => (discussion2 ? 'return doModerate(this)' : '') }) %]
    [% END %] - [% IF can_mod && can_del %] | [% END %] - [% IF can_del %] [% END %] - ] - [% END; IF !options.show_pieces %]
    [% END; END %] @@ -68,4 +58,4 @@ __seclev__ 10000 __version__ -$Id: dispLinkComment;misc;default,v 1.43 2008/03/19 21:09:47 pudge Exp $ +$Id: dispLinkComment;misc;default,v 1.46 2008/03/27 19:02:43 lancelot Exp $ Modified: slashjp/branches/upstream/current/themes/slashcode/templates/editComm;users;default =================================================================== --- slashjp/branches/upstream/current/themes/slashcode/templates/editComm;users;default 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/themes/slashcode/templates/editComm;users;default 2008-04-06 23:11:14 UTC (rev 569) @@ -54,10 +54,7 @@

    Discussion Style

    - Slashdot Classic Discussion System
    - [% IF user.is_admin || user.acl.discussion2_uofm %] - University of Michigan Testing
    - [% END %] + Slashdot Classic Discussion System
    Slashdot Interactive Discussion System (a.k.a. D2)
    @@ -302,4 +299,4 @@ __seclev__ 500 __version__ -$Id: editComm;users;default,v 1.67 2008/02/07 00:51:23 pudge Exp $ +$Id: editComm;users;default,v 1.68 2008/03/25 18:43:56 pudge Exp $ Modified: slashjp/branches/upstream/current/themes/slashcode/templates/printCommComments;misc;default =================================================================== --- slashjp/branches/upstream/current/themes/slashcode/templates/printCommComments;misc;default 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/themes/slashcode/templates/printCommComments;misc;default 2008-04-06 23:11:14 UTC (rev 569) @@ -47,7 +47,7 @@ [% END %] -[% IF cid %] +[% IF cid && !discussion2 %]
      [% Slash.dispComment(comment) %]
    [% END %] - [% IF lvl %] - [% END %] + [% IF cid && !discussion2 %][% END %] + [% IF lvl; END %] [% lcp %] -[% IF discussion2 && !cid %] +[% IF discussion2 %]
    Check for more [% UNLESS user.state.discussion_archived || user.state.discussion_future_nopost %] @@ -112,7 +111,7 @@ op => 'reply', subject => 'Reply', subject_only => 1, - onclick => ((discussion2 && (!constants.subscribe || user.is_subscriber)) ? "replyTo(0); return false;" : '') + onclick => ((discussion2 && !user.is_anon) ? "replyTo(0); return false;" : '') }); END %]
    @@ -150,8 +149,7 @@ pieces_comments = [[% user.state.comments.pieces.join(',') %]]; init_hiddens = [[% user.state.comments.hiddens.join(',') %]]; - [% IF discussion2 == "slashdot" %]d2act(); - [% END -%]finishLoading(); + finishLoading(); //--> [% END %] @@ -159,4 +157,4 @@ __seclev__ 10000 __version__ -$Id: printCommComments;misc;default,v 1.68 2008/03/19 21:09:47 pudge Exp $ +$Id: printCommComments;misc;default,v 1.72 2008/04/02 18:27:30 pudge Exp $ Modified: slashjp/branches/upstream/current/themes/slashcode/templates/printCommentsMain;misc;default =================================================================== --- slashjp/branches/upstream/current/themes/slashcode/templates/printCommentsMain;misc;default 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/themes/slashcode/templates/printCommentsMain;misc;default 2008-04-06 23:11:14 UTC (rev 569) @@ -44,7 +44,7 @@
    -[% IF (!user.is_anon && !user.acl.discussion2_uofm) || user.is_admin %] +[% IF !user.is_anon %]
    @@ -62,10 +62,6 @@
    -[% END; IF (user.acl.discussion2_uofm_signup && !user.acl.discussion2_uofm && (user.is_admin || !user.is_subscriber)) && constants.uofm_key && constants.uofm_iv && env.http_user_agent.search('Firefox/1\.5') %] - [% END %] [% UNLESS discussion2 %] @@ -183,7 +179,7 @@ }) %] [% END %] - [% IF discussion2 && !cid && !pid %] + [% IF discussion2 %] More | [% END; IF user.is_admin && user.d2prefs_debug %] Prefs @@ -202,7 +198,7 @@ op => 'reply', subject => 'Reply', subject_only => 1, - onclick => ((discussion2 && (!constants.subscribe || user.is_subscriber)) ? "replyTo(0); return false;" : '') + onclick => ((discussion2 && !user.is_anon) ? "replyTo(0); return false;" : '') }) %] [% END %] @@ -218,6 +214,7 @@ init: function() { gCommentControlWidget = new YAHOO.slashdot.ThresholdWidget([% "'X'" IF horiz %]); gCommentControlWidget.setTHT(user_threshold, user_highlightthresh); + updateTotals(); } }; }(); @@ -269,7 +266,7 @@
    - [% IF discussion2 && !cid && !pid %] + [% IF discussion2 %] More | [% END; IF user.is_admin && user.d2prefs_debug %] Prefs @@ -287,7 +284,7 @@ op => 'reply', subject => 'Reply', subject_only => 1, - onclick => ((discussion2 && (!constants.subscribe || user.is_subscriber)) ? "replyTo(0); return false;" : '') + onclick => ((discussion2 && !user.is_anon) ? "replyTo(0); return false;" : '') }) %] [% END %]
    Keybindings Beta
    @@ -296,10 +293,16 @@ E
    A S -D +D
    +R +P +M
    +T +G +V
    -
    Loading ... Please wait.
    +
    Loading... please wait.
  • @@ -310,4 +313,4 @@ __seclev__ 10000 __version__ -$Id: printCommentsMain;misc;default,v 1.106 2008/03/19 21:09:47 pudge Exp $ +$Id: printCommentsMain;misc;default,v 1.110 2008/04/02 18:27:30 pudge Exp $ Added: slashjp/branches/upstream/current/themes/slashcode/templates/userInfo2;users;default =================================================================== --- slashjp/branches/upstream/current/themes/slashcode/templates/userInfo2;users;default (rev 0) +++ slashjp/branches/upstream/current/themes/slashcode/templates/userInfo2;users;default 2008-04-06 23:11:14 UTC (rev 569) @@ -0,0 +1,44 @@ +__section__ +default +__description__ +Display user's info + +* title = passed to titlebar +* useredit = hashref of info of the user being viewed +* points = available moderation points +* commentstruct = arrayref of comments +* nickmatch_flag = current user is same as viewed user +* mod_flag = is moderator + (no need for this anymore) +* karma_flag = boolean for display karma +* admin_block = admin stuff +* admin_flag = boolean for whether to display admin stuff + (no real need for this, could just use user.is_admin) +* fieldkey = the field key used to decide what we're looking at +* reasons = hashref from $moddb->getReasons() +* lastjournal = last journal posted +* hr_hours_back = number of hours back to show a
    for +* cids_to_mods = hashref keyed by cid containing arrays of moderations done to that cid +* comment_time = number of days back we are limiting the comments shown to. If 0 or undefined we're showing comments sequentially w/o time limits + +__title__ + +__page__ +users +__lang__ +en_US +__name__ +userInfo2 +__template__ +[% orig_title = title %] + +
    +[% PROCESS userboxes2 %] +
    + +[% title = orig_title %] + +__seclev__ +500 +__version__ +$Id: userInfo2;users;default,v 1.1 2008/04/02 14:42:24 entweichen Exp $ Added: slashjp/branches/upstream/current/themes/slashcode/templates/userboxes2;misc;default =================================================================== --- slashjp/branches/upstream/current/themes/slashcode/templates/userboxes2;misc;default (rev 0) +++ slashjp/branches/upstream/current/themes/slashcode/templates/userboxes2;misc;default 2008-04-06 23:11:14 UTC (rev 569) @@ -0,0 +1,147 @@ +__section__ +default +__description__ +Displays the three user boxes (fancybox's). + +* useredit = user being viewed ("edit" is for historical reasons) + (if not given, the standard "user" will be used) + +__title__ + +__page__ +misc +__lang__ +en_US +__name__ +userboxes2 +__template__ +[% + +IF !useredit; useredit = user; END; + +IF !useredit.is_anon; + + # First box: general user info + + title = 'User Bio'; + contents = BLOCK; + ''; + useredit.nickname | strip_literal; ' '; + PROCESS zoo_icons person=useredit.uid implied=""; + IF user.uid == useredit.uid OR user.is_admin; + # Looking at ourselves; show our real name and email info. + '
    '; IF useredit.realname; useredit.realname | strip_literal; ELSE; '(no real name given)'; END; + '
    '; + Slash.ellipsify(Slash.strip_literal(useredit.realemail)); ''; + '
      '; + IF useredit.fakeemail; + IF useredit.fakeemail == useredit.realemail; + '(shown without obfuscation)'; + ELSE; + 'shown as '; + Slash.ellipsify(Slash.strip_literal(useredit.fakeemail)); ''; + END; + ELSE; + '(email not shown publicly)'; + END; + ELSE; + # Looking at someone else; show fake email info. + '
      '; + IF useredit.fakeemail; + ''; + Slash.ellipsify(Slash.strip_literal(useredit.fakeemail)); ''; + ELSE; + '(email not shown publicly)'; + END; + END; + + IF useredit.homepage; + '
    '; + Slash.ellipsify(Slash.strip_literal(useredit.homepage)); ''; + END; + + IF user.uid == useredit.uid OR user.is_admin; + '
    Karma: '; + PROCESS karma karma=useredit.karma admin_flag=user.is_admin; + END; + + IF useredit.aim && !useredit.aimdisplay; + '
    AOL IM: '; + useredit.aim | strip_literal; + ' (Add Buddy, '; + 'Send Message)'; + END; + + IF useredit.yahoo; + '
    Yahoo! ID: '; + ''; + useredit.yahoo | strip_literal; + ' (Add User, '; + 'Send Message)'; + END; + + IF useredit.jabber; + '
    Jabber: '; + useredit.jabber | strip_literal; + END; + + IF useredit.calendar_url; + '
    Public Calendar: '; + 'Subscribe, Download'; + END; + + IF useredit.bio; + '

    '; + Slash.parseDomainTags(useredit.bio); + END; + + END; + Slash.sidebox(title, contents, "user-info", 1); + + # Latest comments box + contents = ''; + FOREACH cid = latest_comments.keys.sort; + contents = contents _ '' _ latest_comments.$cid.subject _ '
    '; + END; + title = 'Latest Comments'; + Slash.sidebox(title, contents, "user-info", 1); + + # Latest journals box + contents = ''; + FOREACH jid = latest_journals.keys.sort; + contents = contents _ '' _ latest_journals.$jid.desc _ '
    '; + END; + title = 'Latest Journal Entries'; + Slash.sidebox(title, contents, "user-info", 1); + +END %] + +__seclev__ +1000 +__version__ +$Id: userboxes2;misc;default,v 1.1 2008/04/02 14:41:12 entweichen Exp $ Modified: slashjp/branches/upstream/current/utils/createTestTags =================================================================== --- slashjp/branches/upstream/current/utils/createTestTags 2008-04-04 06:46:16 UTC (rev 568) +++ slashjp/branches/upstream/current/utils/createTestTags 2008-04-06 23:11:14 UTC (rev 569) @@ -2,7 +2,7 @@ # This code is a part of Slash, and is released under the GPL. # Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: createTestTags,v 1.6 2007/07/31 17:04:05 jamiemccarthy Exp $ +# $Id: createTestTags,v 1.7 2008/03/24 19:03:14 jamiemccarthy Exp $ BEGIN { { @@ -22,7 +22,7 @@ use vars qw( $slashdb $werder $constants $junk $tagsdb ); -(my $VERSION) = ' $Revision: 1.6 $ ' =~ /\$Revision:\s+([^\s]+)/; +(my $VERSION) = ' $Revision: 1.7 $ ' =~ /\$Revision:\s+([^\s]+)/; my $PROGNAME = basename($0); my %opts; @@ -63,7 +63,7 @@ my $stories = $slashdb->getStoriesEssentials({ future_secs => 0, limit => 10, limit_extra => 0, sectioncollapse => (rand(1) < 0.3) ? 1 : 0 }); - + my $priv_tagnames = $tagsdb->getPrivateTagnames(); my $firehose = getObject('Slash::FireHose'); my $minfhcolor = (rand(1) < 0.4 ? 5 : 7); my($firehose_items, $firehose_results) = @@ -88,11 +88,14 @@ $uid = _get_uid($tagsdb, $stoid); $tagnameid = _get_tagnameid($tagsdb, $tagnameid, $stoid, $uid); + my $tagname = $tagsdb->getTagnameDataFromId($tagnameid)->{tagname}; + my $is_private = $priv_tagnames->{$tagname}; my $tagid = $tagsdb->createTag({ uid => $uid, tagnameid => $tagnameid, table => 'stories', id => $stoid, + private => $is_private, }); print "tagid=$tagid tagnameid=$tagnameid uid=$uid stoid=$stoid\n"; } else { @@ -103,10 +106,13 @@ "karma BETWEEN $kmin AND $kmax", 'ORDER BY RAND() LIMIT 1') if !$uid || rand(1) > 0.2; $tagnameid = _get_tagnameid($tagsdb, $tagnameid, $globjid, $uid); + my $tagname = $tagsdb->getTagnameDataFromId($tagnameid)->{tagname}; + my $is_private = $priv_tagnames->{$tagname}; my $tagid = $tagsdb->createTag({ uid => $uid, tagnameid => $tagnameid, globjid => $globjid, + private => $is_private, }); print "tagid=$tagid tagnameid=$tagnameid uid=$uid globjid=$globjid\n"; } From svnnotify ¡÷ sourceforge.jp Mon Apr 7 08:13:54 2008 From: svnnotify ¡÷ sourceforge.jp (svnnotify ¡÷ sourceforge.jp) Date: Mon, 07 Apr 2008 08:13:54 +0900 Subject: [Slashdotjp-dev 1043] [570] cont. Message-ID: <1207523634.108076.14617.nullmailer@users.sourceforge.jp> Revision: 570 http://svn.sourceforge.jp/cgi-bin/viewcvs.cgi?root=slashdotjp&view=rev&rev=570 Author: tach Date: 2008-04-07 08:13:54 +0900 (Mon, 07 Apr 2008) Log Message: ----------- cont. merged from upstream T_2_5_0_198 (add some images) Added Paths: ----------- slashjp/branches/upstream/current/themes/slashcode/htdocs/images/corner_w_bl.png slashjp/branches/upstream/current/themes/slashcode/htdocs/images/corner_w_br.png slashjp/branches/upstream/current/themes/slashcode/htdocs/images/corner_w_tl.png slashjp/branches/upstream/current/themes/slashcode/htdocs/images/corner_w_tr.png -------------- next part -------------- Added: slashjp/branches/upstream/current/themes/slashcode/htdocs/images/corner_w_bl.png =================================================================== (Binary files differ) Property changes on: slashjp/branches/upstream/current/themes/slashcode/htdocs/images/corner_w_bl.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: slashjp/branches/upstream/current/themes/slashcode/htdocs/images/corner_w_br.png =================================================================== (Binary files differ) Property changes on: slashjp/branches/upstream/current/themes/slashcode/htdocs/images/corner_w_br.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: slashjp/branches/upstream/current/themes/slashcode/htdocs/images/corner_w_tl.png =================================================================== (Binary files differ) Property changes on: slashjp/branches/upstream/current/themes/slashcode/htdocs/images/corner_w_tl.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: slashjp/branches/upstream/current/themes/slashcode/htdocs/images/corner_w_tr.png =================================================================== (Binary files differ) Property changes on: slashjp/branches/upstream/current/themes/slashcode/htdocs/images/corner_w_tr.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream From svnnotify ¡÷ sourceforge.jp Mon Apr 7 08:20:44 2008 From: svnnotify ¡÷ sourceforge.jp (svnnotify ¡÷ sourceforge.jp) Date: Mon, 07 Apr 2008 08:20:44 +0900 Subject: [Slashdotjp-dev 1044] [571] add upstream 2.5.0.200 branch Message-ID: <1207524044.292254.20781.nullmailer@users.sourceforge.jp> Revision: 571 http://svn.sourceforge.jp/cgi-bin/viewcvs.cgi?root=slashdotjp&view=rev&rev=571 Author: tach Date: 2008-04-07 08:20:44 +0900 (Mon, 07 Apr 2008) Log Message: ----------- add upstream 2.5.0.200 branch Added Paths: ----------- slashjp/branches/upstream/2.5.0.200/ -------------- next part -------------- Copied: slashjp/branches/upstream/2.5.0.200 (from rev 570, slashjp/branches/upstream/current) From svnnotify ¡÷ sourceforge.jp Mon Apr 7 09:26:30 2008 From: svnnotify ¡÷ sourceforge.jp (svnnotify ¡÷ sourceforge.jp) Date: Mon, 07 Apr 2008 09:26:30 +0900 Subject: [Slashdotjp-dev 1045] [572] merged from upstream/2.5.0.200 branch Message-ID: <1207527990.562875.19996.nullmailer@users.sourceforge.jp> Revision: 572 http://svn.sourceforge.jp/cgi-bin/viewcvs.cgi?root=slashdotjp&view=rev&rev=572 Author: tach Date: 2008-04-07 09:26:30 +0900 (Mon, 07 Apr 2008) Log Message: ----------- merged from upstream/2.5.0.200 branch Modified Paths: -------------- slashjp/trunk/Slash/Apache/User/User.pm slashjp/trunk/Slash/DB/MySQL/MySQL.pm slashjp/trunk/Slash/Utility/Comments/Comments.pm slashjp/trunk/Slash/Utility/Environment/Environment.pm slashjp/trunk/debian/changelog slashjp/trunk/plugins/Ajax/PLUGIN slashjp/trunk/plugins/Ajax/htdocs/ajax.pl slashjp/trunk/plugins/Ajax/htdocs/images/admin.js slashjp/trunk/plugins/Ajax/htdocs/images/common.js slashjp/trunk/plugins/Ajax/htdocs/images/nodnix.js slashjp/trunk/plugins/Ajax/htdocs/images/sd_autocomplete.js slashjp/trunk/plugins/Ajax/htdocs/images/sd_calendar.js slashjp/trunk/plugins/Ajax/htdocs/images/slashbox.js slashjp/trunk/plugins/Ajax/templates/data;ajax;default slashjp/trunk/plugins/Ajax/templates/edit_comment;ajax;default slashjp/trunk/plugins/Console/console.pl slashjp/trunk/plugins/FireHose/FireHose.pm slashjp/trunk/plugins/FireHose/templates/data;firehose;default slashjp/trunk/plugins/FireHose/templates/dispTopicFireHose;misc;default slashjp/trunk/plugins/FireHose/templates/fireHoseForm;misc;default slashjp/trunk/plugins/FireHose/templates/firehose_pages;misc;default slashjp/trunk/plugins/FireHose/templates/list;firehose;default slashjp/trunk/plugins/HumanConf/HumanConf.pm slashjp/trunk/plugins/Journal/journal.pl slashjp/trunk/plugins/Moderation/Moderation.pm slashjp/trunk/plugins/ResKey/MANIFEST slashjp/trunk/plugins/ResKey/ResKey/Checks/Duration.pm slashjp/trunk/plugins/ResKey/ResKey/Key.pm slashjp/trunk/plugins/ResKey/example.plx slashjp/trunk/plugins/ResKey/mysql_dump.sql slashjp/trunk/plugins/ResKey/templates/data;reskey;default slashjp/trunk/plugins/TagDataView/TagDataView.pm slashjp/trunk/plugins/TagModeration/TagModeration.pm slashjp/trunk/plugins/Tags/Clout/Describe.pm slashjp/trunk/plugins/Tags/Clout/Vote.pm slashjp/trunk/plugins/Tags/PLUGIN slashjp/trunk/plugins/Tags/Tags.pm slashjp/trunk/plugins/Tags/mysql_dump.sql slashjp/trunk/plugins/Tags/tags.pl slashjp/trunk/plugins/Tags/templates/usertaghistory;users;default slashjp/trunk/plugins/Tags/templates/usertags;users;default slashjp/trunk/sql/mysql/defaults.sql slashjp/trunk/sql/mysql/upgrades slashjp/trunk/tagboxes/FHEditorPop/FHEditorPop.pm slashjp/trunk/tagboxes/FHEditorPop/mysql_dump.sql slashjp/trunk/tagboxes/Top/Top.pm slashjp/trunk/themes/slashcode/THEME slashjp/trunk/themes/slashcode/htdocs/comments.css slashjp/trunk/themes/slashcode/htdocs/comments.pl slashjp/trunk/themes/slashcode/htdocs/images/comments.js slashjp/trunk/themes/slashcode/htdocs/slashcode_lite.css slashjp/trunk/themes/slashcode/htdocs/users.pl slashjp/trunk/themes/slashcode/templates/dispComment;misc;default slashjp/trunk/themes/slashcode/templates/dispLinkComment;misc;default slashjp/trunk/themes/slashcode/templates/editComm;users;default slashjp/trunk/themes/slashcode/templates/printCommComments;misc;default slashjp/trunk/themes/slashcode/templates/printCommentsMain;misc;default slashjp/trunk/utils/createTestTags Added Paths: ----------- slashjp/trunk/plugins/Ajax/templates/hc_comment;ajax;default slashjp/trunk/plugins/ResKey/ResKey/Checks/HumanConf.pm slashjp/trunk/plugins/Tags/templates/usertagnames;users;default slashjp/trunk/plugins/Tags/templates/usertagsforname;users;default slashjp/trunk/tagboxes/RecentTags/ slashjp/trunk/themes/slashcode/htdocs/images/corner_w_bl.png slashjp/trunk/themes/slashcode/htdocs/images/corner_w_br.png slashjp/trunk/themes/slashcode/htdocs/images/corner_w_tl.png slashjp/trunk/themes/slashcode/htdocs/images/corner_w_tr.png slashjp/trunk/themes/slashcode/htdocs/users2.pl slashjp/trunk/themes/slashcode/templates/userInfo2;users;default slashjp/trunk/themes/slashcode/templates/userboxes2;misc;default -------------- next part -------------- Modified: slashjp/trunk/Slash/Apache/User/User.pm =================================================================== --- slashjp/trunk/Slash/Apache/User/User.pm 2008-04-06 23:20:44 UTC (rev 571) +++ slashjp/trunk/Slash/Apache/User/User.pm 2008-04-07 00:26:30 UTC (rev 572) @@ -597,7 +597,14 @@ $r->filename($constants->{basedir} . '/help.pl'); return OK; } - + + # This is a temporary addition! + if ($uri =~ m[^/(?:%5[eE]|\^)]) { + $r->uri('/users2.pl'); + $r->filename($constants->{basedir} . '/users2.pl'); + return OK; + } + # for self-references (/~/ and /my/) if (($saveuri =~ m[^/(?:%7[eE]|~)] && $uri =~ m[^/~ (?: /(.*) | /? ) $]x) # /my/ or /my can match, but not /mything @@ -612,6 +619,7 @@ } my($op, $extra) = split /\//, $string, 2; + $extra ||= ''; my $logged_in = $r->header_in('Cookie') =~ $USER_MATCH; my $try_login = !$logged_in && $logtoken; @@ -634,9 +642,9 @@ $found_the_op = 1; if ($op eq 'journal') { my $args; - if ($extra && $extra =~ /^\d+$/) { + if ($extra =~ /^\d+$/) { $args = "id=$extra&op=edit"; - } elsif ($extra && $extra eq 'friends') { + } elsif ($extra eq 'friends') { $args = "op=friendview"; } else { $args = "op=list"; @@ -703,7 +711,10 @@ $r->filename($constants->{basedir} . '/journal.pl'); } elsif ($op eq 'tags') { - $r->args("op=showtags"); + my $args = 'op=showtags'; + # XXX "!" is a 'reserved' char in URI, escape it here? + $args .= "&tagname=$extra" if $extra; + $r->args($args); $r->uri('/users.pl'); $r->filename($constants->{basedir} . '/users.pl'); @@ -861,7 +872,10 @@ $r->filename($constants->{basedir} . '/journal.pl'); } elsif ($op eq 'tags') { - $r->args("op=showtags&nick=$nick&uid=$uid"); + my $args = "op=showtags&nick=$nick&uid=$uid"; + # XXX "!" is a 'reserved' char in URI, escape it here? + $args .= "&tagname=$extra" if $extra; + $r->args($args); $r->uri('/users.pl'); $r->filename($constants->{basedir} . '/users.pl'); Modified: slashjp/trunk/Slash/DB/MySQL/MySQL.pm =================================================================== --- slashjp/trunk/Slash/DB/MySQL/MySQL.pm 2008-04-06 23:20:44 UTC (rev 571) +++ slashjp/trunk/Slash/DB/MySQL/MySQL.pm 2008-04-07 00:26:30 UTC (rev 572) @@ -3491,6 +3491,7 @@ # Of course, markStoryClean and -Dirty work too my($dirty_change, $dirty_newval); + if ($change_hr->{writestatus}) { $dirty_change = 1; $dirty_newval = $change_hr->{writestatus} eq 'dirty' ? 1 : 0; @@ -3504,6 +3505,11 @@ delete $change_hr->{is_dirty} } + if ($change_hr->{introtext} && $change_hr->{introtext} =~ /href=\"SELF\"/) { + my $link_url = $self->_getStorySelfLink($stoid, $change_hr); + $change_hr->{introtext} =~ s/href=\"SELF\"/href="$link_url"/; + } + $change_hr->{is_archived} = $change_hr->{is_archived} ? 'yes' : 'no' if defined $change_hr->{is_archived}; $change_hr->{in_trash} = $change_hr->{in_trash} ? 'yes' : 'no' @@ -7923,6 +7929,7 @@ $signoff_type ||= ''; $self->sqlInsert("signoff", { stoid => $stoid, uid => $uid, signoff_type => $signoff_type }); + $self->setStory($stoid, { thumb_signoff_needed => 0 }); if ($constants->{plugin}{FireHose}) { my $firehose = getObject("Slash::FireHose"); @@ -7993,6 +8000,19 @@ ); } +sub deleteSignoffsForStory { + my($self, $stoid) = @_; + my $constants = getCurrentStatic(); + my $stoid_q = $self->sqlQuote($stoid); + $self->sqlDelete("signoff", "stoid=$stoid_q"); + if ($constants->{plugin}{FireHose}) { + my $firehose = getObject("Slash::FireHose"); + my ($id) = $self->sqlSelect("id", "firehose", "type='story' and srcid=$stoid_q"); + $firehose->setFireHose($id, { signoffs => '' }); + + } +} + sub getSignoffsInLastMinutes { my ($self, $mins) = @_; $mins ||= getCurrentStatic("admin_timeout"); @@ -12629,6 +12649,23 @@ return $answer; } +sub _getStorySelfLink { + my($self, $stoid, $change_hr) = @_; + my $story = $self->getStory($stoid); + my $data = {}; + my $link = $change_hr->{title} || $story->{title}; + my $tid = $change_hr->{tid} || $story->{tid}; + my $skin = $change_hr->{primaryskid} || $story->{primary_skid}; + + my $story_link_ar = linkStory({ + sid => $story->{sid}, + link => $link, + tid => $tid, + skin => $skin + }); + return $story_link_ar->[0]; +} + ######################################################## sub DESTROY { my($self) = @_; Modified: slashjp/trunk/Slash/Utility/Comments/Comments.pm =================================================================== --- slashjp/trunk/Slash/Utility/Comments/Comments.pm 2008-04-06 23:20:44 UTC (rev 571) +++ slashjp/trunk/Slash/Utility/Comments/Comments.pm 2008-04-07 00:26:30 UTC (rev 572) @@ -38,7 +38,7 @@ @EXPORT = qw( constrain_score dispComment displayThread printComments jsSelectComments commentCountThreshold commentThresholds discussion2 - tempUofmLinkGenerate tempUofmCipherObj selectComments preProcessReplyForm + selectComments preProcessReplyForm getPoints preProcessComment postProcessComment prevComment saveComment ); @@ -156,8 +156,7 @@ #slashProf("sC main sort", "sC setup"); my($oldComment, %old_comments); - # XXXd2 disable for sub-threads for now ($cid) - if ($discussion2 && !$cid && !$options->{no_d2}) { + if ($discussion2 && !$options->{no_d2}) { my $limits = $slashdb->getDescriptions('d2_comment_limits'); my $max = $d2_comment_q ? $limits->{ $d2_comment_q } : 0; $max = int($max/2) if $shtml; @@ -165,6 +164,19 @@ $options->{existing} ||= {}; @$thisComment = sort { $a->{cid} <=> $b->{cid} } @$thisComment; + # we need to filter which comments are descendants of $cid + my %cid_seen; + if ($cid) { + # for display later + $user->{state}{d2_defaultclass}{$cid} = 'full'; + # this only works because we are already in cid order + for my $C (@$thisComment) { + if ($cid == $C->{cid} || $cid_seen{$C->{pid}}) { + $cid_seen{$C->{cid}} = 1; + } + } + } + my $sort_comments; if (!$user->{d2_comment_order}) { # score $sort_comments = [ sort { @@ -176,16 +188,21 @@ $sort_comments = $thisComment; } + for my $C (@$sort_comments) { next if $options->{existing}{$C->{cid}}; if ($max && @new_comments >= $max) { if ($cid) { + # still include $cid even if it would + # otherwise be excluded (should only + # matter if not sorting by date push @new_comments, $C if $cid == $C->{cid}; } else { last; } } else { + next if $cid && !$cid_seen{$C->{cid}}; push @new_comments, $C; } } @@ -193,9 +210,9 @@ my @seen; my $lastcid = 0; my %check = (%{$options->{existing}}, map { $_->{cid} => 1 } @new_comments); - for my $cid (sort { $a <=> $b } keys(%check)) { - push @seen, $lastcid ? $cid - $lastcid : $cid; - $lastcid = $cid; + for my $this_cid (sort { $a <=> $b } keys(%check)) { + push @seen, $lastcid ? $this_cid - $lastcid : $this_cid; + $lastcid = $this_cid; } $comments->{0}{d2_seen} = join ',', @seen; @@ -285,32 +302,38 @@ } # get the total visible kids for each comment --Pater - countTotalVisibleKids($comments); + countTotalVisibleKids($comments) unless $discussion2; - _print_cchp($discussion, $count, $comments->{0}{totals}); - -##slashProf("sC reparenting", "sC counting"); -#slashProf("sC reparenting"); - reparentComments($comments, $reader, $options); - -##slashProf("sC d2 fudging", "sC reparenting"); -#slashProf("", "sC reparenting"); +##slashProf("sC d2 fudging", "sC counting"); if ($oldComment) { - for my $cid (sort { $a <=> $b } keys %$comments) { - my $C = $comments->{$cid}; + my @new_seen; + for my $this_cid (sort { $a <=> $b } keys %$comments) { + next unless $this_cid; + my $C = $comments->{$this_cid}; # && !$options->{existing}{ $C->{pid} } while ($C->{pid}) { my $parent = $comments->{ $C->{pid} } || {}; + if (!$parent || !$parent->{kids} || !$parent->{cid} || !defined($parent->{pid}) || !defined($parent->{points})) { - $parent = $comments->{ $C->{pid} } = { - cid => $C->{pid}, - pid => ($old_comments{ $C->{pid} } && $old_comments{ $C->{pid} }{ pid }) || 0, - kids => [ ], - points => -2, - dummy => 1, - %$parent, - }; + # parents of our main cid, so spend time + # finding it ... + if ($cid && $C->{pid} < $cid) { + $user->{state}{d2_defaultclass}{$C->{pid}} = 'oneline'; + $parent = $old_comments{ $C->{pid} }; + push @new_seen, $C->{pid}; + $count++; + } else { + $parent = { + cid => $C->{pid}, + pid => ($old_comments{ $C->{pid} } && $old_comments{ $C->{pid} }{ pid }) || 0, + kids => [ ], + points => -2, + dummy => 1, + %$parent, + }; + } + $comments->{ $C->{pid} } = $parent; } unless (grep { $_ == $C->{cid} } @{$parent->{kids}}) { @@ -325,10 +348,29 @@ $C = $parent; } } + + # fix d2_seen + my @seen; + my $lastcid = 0; + for my $this_cid (sort { $a <=> $b } @new_seen) { + push @seen, $lastcid ? $this_cid - $lastcid : $this_cid; + $lastcid = $this_cid; + } + my @old_seen = split /,/, $comments->{0}{d2_seen}; + if (@seen && @old_seen) { + $old_seen[0] = $old_seen[0] - $lastcid; + } + $comments->{0}{d2_seen} = join ',', @seen, @old_seen; } ##slashProf("", "sC d2 fudging"); + _print_cchp($discussion, $count, $comments->{0}{totals}); + +#slashProf("sC reparenting"); + reparentComments($comments, $reader, $options); +#slashProf("", "sC reparenting"); + return($comments, $count); } @@ -344,7 +386,6 @@ $gSkin ||= getCurrentSkin(); my $id = $form->{sid}; - my $pid = $form->{cid} || 0; return unless $id; my $threshold = defined $user->{d2_threshold} ? $user->{d2_threshold} : $user->{threshold}; @@ -360,12 +401,8 @@ my($comments) = $user->{state}{selectComments}{comments}; my $d2_seen_0 = $comments->{0}{d2_seen} || ''; - #delete $comments->{0}; # non-comment data - if ($pid && exists $comments->{$pid}) { - $comments = _get_thread($comments, $pid); - } - my @roots = $pid ? $pid : @{$comments->{$pid}{kids}}; + my @roots = @{$comments->{0}{kids} || []}; my %roots_hash = ( map { $_ => 1 } @roots ); my $thresh_totals; @@ -392,7 +429,7 @@ } } - $thresh_totals = commentCountThreshold($comments, $pid, \%roots_hash); + $thresh_totals = commentCountThreshold($comments, 0, \%roots_hash); $comments = $comments_new; } @@ -408,6 +445,7 @@ $user->{is_anon} ||= 0; $user->{is_admin} ||= 0; $user->{is_subscriber} ||= 0; + my $root_comment = $user->{state}{selectComments}{cidorpid} || 0; my $extra = ''; if ($d2_seen_0) { @@ -435,7 +473,7 @@ thresh_totals = $anon_thresh; -root_comment = $pid; +root_comment = $root_comment; root_comments = $anon_roots; root_comments_hash = $anon_rootsh; max_cid = $max_cid; @@ -723,6 +761,7 @@ my $max_depth_allowed = $user->{state}{max_depth} || $constants->{max_depth} || 7; + # even if !reparent, we still want to be here so we can set comments at max depth return if $user->{state}{noreparent} || (!$max_depth_allowed && !$user->{reparent}); # Adjust the max_depth_allowed for the root pid or cid. @@ -731,7 +770,7 @@ # when $form->{cid|pid} is set. And besides, max depth we # display is for display, so it should be based on how much # we're displaying, not on absolute depth of this thread. - my $root_cid_or_pid = $form->{cid} || $form->{pid} || 0; + my $root_cid_or_pid = discussion2($user) ? 0 : ($form->{cid} || $form->{pid} || 0); if ($root_cid_or_pid) { my $tmpcid = $root_cid_or_pid; while ($tmpcid) { @@ -965,8 +1004,9 @@ #slashProf("", "selectComments"); if ($discussion2) { $user->{state}{selectComments} = { - comments => $comments, - count => $count + cidorpid => $cidorpid, + comments => $comments, + count => $count }; } @@ -1026,7 +1066,7 @@ return if $user->{state}{nocomment} || $user->{mode} eq 'nocomment'; my($comment, $next, $previous); - if ($cid) { + if ($cid && !$discussion2) { my($next, $previous); $comment = $comments->{$cid}; if (my $sibs = $comments->{$comment->{pid}}{kids}) { @@ -1241,6 +1281,9 @@ my $highlight = ($comment->{points} >= $highlightthresh && $class ne 'hidden') ? 1 : 0; $class = 'full' if $highlight; + if ($discussion2 && $user->{state}{d2_defaultclass}{$cid}) { + $class = $user->{state}{d2_defaultclass}{$cid}; + } $comment->{class} = $class; $user->{state}{comments}{totals}{$class}++ unless $comment->{dummy}; @@ -1902,8 +1945,10 @@ $score_to_display .= "Score:"; if (length $comment->{points}) { $score_to_display .= $comment->{points}; - $score_to_display = qq[$score_to_display] - if $constants->{modal_prefs_active} && !$user->{is_anon}; + if ($constants->{modal_prefs_active}) { + my $func = "getModalPrefs('modcommentlog', 'Moderation Comment Log', $comment->{cid})"; + $score_to_display = qq[$score_to_display]; + } } else { $score_to_display .= '?'; } @@ -1991,25 +2036,23 @@ && $comment->{nickname} ne "-") { # this last test probably useless my @link = ( ); - push @link, (qq'' . linkComment({ + push @link, (qq'

    ' . linkComment({ sid => $comment->{sid}, pid => $comment->{cid}, op => 'Reply', subject => 'Reply to This', subject_only => 1, - onclick => (($discussion2 && (!$constants->{subscribe} || $user->{is_subscriber})) ? "replyTo($comment->{cid}); return false;" : '') - }) . '') unless $user->{state}{discussion_archived}; + onclick => (($discussion2 && !$user->{is_anon}) ? "replyTo($comment->{cid}); return false;" : '') + }) . '

    ') unless $user->{state}{discussion_archived}; - push @link, linkComment({ + push @link, (qq'

    ' . linkComment({ sid => $comment->{sid}, cid => $comment->{original_pid}, pid => $comment->{original_pid}, subject => 'Parent', subject_only => 1, onclick => ($discussion2 ? "return selectParent($comment->{original_pid})" : '') - }, 1) if $comment->{original_pid};# && !($discussion2 && -# (!$form->{cid} || $form->{cid} != $comment->{cid}) -# ); + }, 1) . '

    ') if $comment->{original_pid}; #use Data::Dumper; print STDERR "_hard_dispComment createSelect can_mod='$can_mod' disc_arch='$user->{state}{discussion_archived}' modd_arch='$constants->{comments_moddable_archived}' cid='$comment->{cid}' reasons: " . Dumper($reasons); @@ -2025,10 +2068,10 @@ push @link, qq|| if $user->{is_admin}; - my $link = join(" | ", @link); + my $link = join(" ", @link); if (@link) { - $commentsub = "[ $link ]"; + $commentsub = $link; } } @@ -2084,6 +2127,7 @@ my $class = $comment->{class}; my $classattr = $discussion2 ? qq[ class="$class"] : ''; + my $contain = $class eq 'full' ? ' contain' : ''; my $head = $discussion2 ? <$comment->{subject} @@ -2093,7 +2137,7 @@ my $return = ''; $return = <{noshow_show}; -
  • +
  • EOT @@ -2506,43 +2550,11 @@ if (getCurrentStatic('no_d2')) { return 0; } - return $user->{discussion2} =~ /^(?:slashdot|uofm)$/ + return $user->{discussion2} eq 'slashdot' ? $user->{discussion2} : 0; } -sub tempUofmLinkGenerate { - require URI::Escape; - - my $constants = getCurrentStatic(); - my $user = getCurrentUser(); - - my $cipher = tempUofmCipherObj() or return; - - my $encrypted = $cipher->encrypt($user->{uid} . '|' . $user->{nickname}); - return sprintf($constants->{uofm_address}, URI::Escape::uri_escape($encrypted)); -} - -sub tempUofmCipherObj { - my $constants = getCurrentStatic(); - return unless $constants->{uofm_key} && $constants->{uofm_iv}; - - require Crypt::CBC; - - my $cipher = Crypt::CBC->new({ - key => $constants->{uofm_key}, - iv => $constants->{uofm_iv}, - cipher => 'Blowfish', - regenerate_key => 0, - padding => 'null', - prepend_iv => 0 - }); - - return $cipher; -} - - - 1; __END__ Modified: slashjp/trunk/Slash/Utility/Environment/Environment.pm =================================================================== --- slashjp/trunk/Slash/Utility/Environment/Environment.pm 2008-04-06 23:20:44 UTC (rev 571) +++ slashjp/trunk/Slash/Utility/Environment/Environment.pm 2008-04-07 00:26:30 UTC (rev 572) @@ -1884,10 +1884,12 @@ colorblock => sub { $_[0] =~ s|[^\w#,]+||g }, # What I actually want to do for userfield is allow it to match # [\w.]+, or pass emailValid(), or be changed to the return value -# from nickFix(). For technical reasons I'm putting that off -# until probably next week. Until then this breaks some very -# minor functionality. - Jamie 2008-01-09 +# from nickFix(). But nickFix() uses constants, which might not +# be set up at this point. - Jamie 2008-01-09 userfield => sub { $_[0] =~ s|[^\w.@ -]||g }, +# Ditto here, really - Jamie 2008-03-24 + tagname => sub { $_[0] = '' unless + $_[0] =~ /^\!?[a-z][a-z0-9]{0,62}$/ }, ); Modified: slashjp/trunk/debian/changelog =================================================================== --- slashjp/trunk/debian/changelog 2008-04-06 23:20:44 UTC (rev 571) +++ slashjp/trunk/debian/changelog 2008-04-07 00:26:30 UTC (rev 572) @@ -1,3 +1,9 @@ +slash (2.5.0.200-1) unstable; urgency=low + + * New upstream CVS release + + -- Taku YASUI Mon, 07 Apr 2008 09:26:13 +0900 + slash (2.5.0.198-1) unstable; urgency=low * New upstream CVS release Modified: slashjp/trunk/plugins/Ajax/PLUGIN =================================================================== --- slashjp/trunk/plugins/Ajax/PLUGIN 2008-04-06 23:20:44 UTC (rev 571) +++ slashjp/trunk/plugins/Ajax/PLUGIN 2008-04-07 00:26:30 UTC (rev 572) @@ -36,6 +36,7 @@ template=templates/data;ajax;default template=templates/datewidget;misc;default template=templates/edit_comment;ajax;default +template=templates/hc_comment;ajax;default template=templates/modal_footer;misc;default template=templates/prefs_d2;ajax;default template=templates/prefs_d2_posting;ajax;default Modified: slashjp/trunk/plugins/Ajax/htdocs/ajax.pl =================================================================== --- slashjp/trunk/plugins/Ajax/htdocs/ajax.pl 2008-04-06 23:20:44 UTC (rev 571) +++ slashjp/trunk/plugins/Ajax/htdocs/ajax.pl 2008-04-07 00:26:30 UTC (rev 572) @@ -40,8 +40,6 @@ ); # print STDERR "AJAX3 $$: $user->{uid}, $op\n"; -#$Slash::ResKey::DEBUG = 2; - $ops->{$op}{function} ||= loadCoderef($ops->{$op}{class}, $ops->{$op}{subroutine}); $op = 'default' unless $ops->{$op}{function}; @@ -58,7 +56,7 @@ if ($reskey_name ne 'NA') { my $reskey = getObject('Slash::ResKey'); - my $rkey = $reskey->key($reskey_name); + my $rkey = $reskey->key($reskey_name); #, { debug => 1 }); if (!$rkey) { print STDERR scalar(localtime) . " ajax.pl main no rkey for op='$op' name='$reskey_name'\n"; return; @@ -72,17 +70,17 @@ $rkey->use; } if (!$rkey->success) { + # feel free to send msgdiv => 'thisdivhere' to the ajax call, + # and any reskey error messages will be sent to it if ($form->{msgdiv}) { header_ajax({ content_type => 'application/json' }); (my $msgdiv = $form->{msgdiv}) =~ s/[^\w-]+//g; print Data::JavaScript::Anon->anon_dump({ - html => { $msgdiv => $rkey->errstr }, + html => { $msgdiv => $rkey->errstr }, + eval_last => "\$('#$msgdiv').show()" }); } - printf STDERR "AJAXE %d: UID:%d, op:%s: %s (%s:%s:%s:%s:%s:%s:%s)\n", - $$, $user->{uid}, $op, $rkey->errstr, $rkey->reskey, - $rkey->type, $rkey->resname, $rkey->rkrid, $rkey->code, $rkey->static, - $user->{srcids}{ 24 }; + $rkey->ERROR($op); return; } } @@ -281,12 +279,21 @@ my $discussion = $slashdb->getDiscussion($sid); my $comment = preProcessComment($form, $user, $discussion, \$error_message); if (!$error_message) { - $options->{rkey}->use or $error_message = $options->{rkey}->errstr; + unless ($options->{rkey}->use) { + $error_message = $options->{rkey}->errstr; + } } $saved_comment = saveComment($form, $comment, $user, $discussion, \$error_message) unless $error_message; my $cid = $saved_comment && $saved_comment ne '-1' ? $saved_comment->{cid} : 0; + if ($error_message) { + $error_message = getData('inline preview warning') . $error_message + unless $options->{rkey}->death; + # go back to HumanConf if we still have errors left to display + $error_message .= slashDisplay('hc_comment', { pid => $pid }, { Return => 1 }); + } + $options->{content_type} = 'application/json'; my %to_dump = ( cid => $cid, error => $error_message ); #use Data::Dumper; print STDERR Dumper \%to_dump; @@ -301,15 +308,18 @@ $user->{state}{ajax_accesslog_op} = 'comments_preview_reply'; - my($error_message, $preview, $html); + my $html = my $error_message = ''; my $discussion = $slashdb->getDiscussion($sid); my $comment = preProcessComment($form, $user, $discussion, \$error_message); if ($comment && $comment ne '-1') { - $preview = postProcessComment({ %$comment, %$form, %$user }, 0, $discussion); + my $preview = postProcessComment({ %$comment, %$form, %$user }, 0, $discussion); $html = prevComment($preview, $user); } - $error_message ||= 'This comment will not be saved until you click the Submit button below.'; + if ($html) { + $error_message = getData('inline preview warning') . $error_message; + $error_message .= slashDisplay('hc_comment', { pid => $pid }, { Return => 1 }); + } $options->{content_type} = 'application/json'; my %to_dump = ( error => $error_message, @@ -339,7 +349,7 @@ preProcessReplyForm($form, $reply); my $reskey = getObject('Slash::ResKey'); - my $rkey = $reskey->key('comments', { nostate => 1 }); + my $rkey = $reskey->key('comments', { nostate => 1 }); #, debug => 1 }); $rkey->create; my %to_dump; @@ -386,15 +396,14 @@ sub fetchComments { my($slashdb, $constants, $user, $form, $options) = @_; - my $cids = [ grep /^\d+$/, split /,/, ($form->{cids} || '') ]; + my $cids = [ grep { defined && /^\d+$/ } ($form->{_multi}{cids} ? @{$form->{_multi}{cids}} : $form->{cids}) ]; my $id = $form->{discussion_id} || 0; my $cid = $form->{cid} || 0; # root id my $d2_seen = $form->{d2_seen}; - my $placeholders = $form->{placeholders}; - my @placeholders; + my $placeholders = [ grep { defined && /^\d+$/ } ($form->{_multi}{placeholders} ? @{$form->{_multi}{placeholders}} : $form->{placeholders}) ]; $user->{state}{ajax_accesslog_op} = "ajax_comments_fetch"; -#use Data::Dumper; print STDERR Dumper [ $cids, $id, $cid, $d2_seen ]; +#use Data::Dumper; print STDERR Dumper [ $form, $cids, $id, $cid, $d2_seen ]; # XXX error? return unless $id && (@$cids || $d2_seen); @@ -439,17 +448,16 @@ #delete $comments->{0}; # non-comment data my %data; - if ($d2_seen || $placeholders) { + if ($d2_seen || @$placeholders) { my $special_cids; if ($d2_seen) { $special_cids = $cids = [ sort { $a <=> $b } grep { $_ && !$seen{$_} } keys %$comments ]; - } elsif ($placeholders) { - @placeholders = split /[,;]/, $placeholders; - $special_cids = [ sort { $a <=> $b } @placeholders ]; + } elsif (@$placeholders) { + $special_cids = [ sort { $a <=> $b } @$placeholders ]; if ($form->{d2_seen_ex}) { my @seen; my $lastcid = 0; - my %check = (%seen, map { $_ => 1 } @placeholders); + my %check = (%seen, map { $_ => 1 } @$placeholders); for my $cid (sort { $a <=> $b } keys(%check)) { push @seen, $lastcid ? $cid - $lastcid : $cid; $lastcid = $cid; @@ -587,9 +595,9 @@ $to_dump{eval_first} ||= ''; $to_dump{eval_first} .= "d2_seen = '$d2_seen_0'; updateMoreNum($total);"; } - if ($placeholders) { + if (@$placeholders) { $to_dump{eval_first} ||= ''; - $to_dump{eval_first} .= "placeholder_no_update = " . Data::JavaScript::Anon->anon_dump({ map { $_ => 1 } @placeholders }) . ';'; + $to_dump{eval_first} .= "placeholder_no_update = " . Data::JavaScript::Anon->anon_dump({ map { $_ => 1 } @$placeholders }) . ';'; } writeLog($id); return Data::JavaScript::Anon->anon_dump(\%to_dump); @@ -746,7 +754,7 @@ my $moddb = getObject("Slash::$constants->{m1_pluginname}"); if ($moddb) { # we hijack "tabbed" as our cid -- pudge - return $moddb->dispModCommentLog('cid', $form->{'tabbed'}, { + my $return = $moddb->dispModCommentLog('cid', $form->{'tabbed'}, { show_m2s => ($constants->{m2} ? (defined($form->{show_m2s}) ? $form->{show_m2s} @@ -756,6 +764,8 @@ need_m2_button => $constants->{m2}, title => " " }); + $return ||= getData('no modcommentlog'); + return $return; } } else { Modified: slashjp/trunk/plugins/Ajax/htdocs/images/admin.js =================================================================== --- slashjp/trunk/plugins/Ajax/htdocs/images/admin.js 2008-04-06 23:20:44 UTC (rev 571) +++ slashjp/trunk/plugins/Ajax/htdocs/images/admin.js 2008-04-07 00:26:30 UTC (rev 572) @@ -200,7 +200,7 @@ if(use_fh_interval) { interval = getFirehoseUpdateInterval(); } - setTimeout("console_update(" + use_fh_interval + "," + fh_is_timed_out +")", interval); + setTimeout("console_update(" + use_fh_interval + "," + fh_is_timed_out +")", interval * 2); } function firehose_usage() { Modified: slashjp/trunk/plugins/Ajax/htdocs/images/common.js =================================================================== --- slashjp/trunk/plugins/Ajax/htdocs/images/common.js 2008-04-06 23:20:44 UTC (rev 571) +++ slashjp/trunk/plugins/Ajax/htdocs/images/common.js 2008-04-07 00:26:30 UTC (rev 572) @@ -5,6 +5,42 @@ return document.getElementById(id); } +jQuery.fn.extend({ + + mapClass: function( map ) { + map['?'] = map['?'] || []; + return this.each(function() { + var unique = {}; + var cl = []; + $.each($.map(this.className.split(/\s+/), function(k){ + return k in map ? map[k] : ('*' in map ? map['*'] : k) + }).concat(map['+']), function(i, k) { + if ( k && !(k in unique) ) { + unique[k] = true; + cl.push(k); + } + }); + this.className = (cl.length ? cl : map['?']).join(' '); + }); + }, + + setClass: function( c1 ) { + return this.each(function() { + this.className = c1 + }); + }, + + toggleClasses: function( c1, c2, force ) { + var map = { '?': force }; + map[c1]=c2; + map[c2]=c1; + return this.mapClass(map); + } + +}); + +var reskey_static = ''; + // global settings, but a firehose might use a local settings object instead var firehose_settings = {}; firehose_settings.startdate = ''; @@ -18,8 +54,10 @@ firehose_settings.is_embedded = 0; firehose_settings.not_id = 0; firehose_settings.section = 0; + firehose_settings.more_num = 0; // Settings to port out of settings object + firehose_item_count = 0; firehose_updates = Array(0); firehose_updates_size = 0; firehose_ordered = Array(0); @@ -78,23 +116,11 @@ } function createPopupButtons() { - var buttons = ""; - if (arguments.length > 0) { - buttons = ''; - } - for (var i=0; i" + arguments[i] + ""; - } - - buttons = buttons + ""; - return buttons; + return '' + $.makeArray(arguments).join('') + ''; } function closePopup(id, refresh) { - var el = $dom(id); - if (el) { - el.parentNode.removeChild(el); - } + $('#'+id).remove(); if (refresh) { window.location.reload(); } @@ -134,87 +160,44 @@ } function getXYForId(id, addWidth, addHeight) { - var div = $dom(id); - var offset = jQuery(div).offset(); - var xy = [ offset.left, offset.top ]; - if (addWidth) { - xy[0] = xy[0] + div.offsetWidth; - } - if (addHeight) { - xy[1] = xy[1] + div.offsetHeight; - } - return xy; + var div = $('#'+id); + var offset = div.offset(); + if (addWidth) offset.left += div.attr('offsetWidth'); + if (addHeight) offset.top += div.attr('offsetHeight'); + return [ offset.left, offset.top ]; } function firehose_toggle_advpref() { - var obj = $dom('fh_advprefs'); - if (obj.className == 'hide') { - obj.className = ""; - } else { - obj.className = "hide"; - } + $('#fh_advprefs').toggleClass('hide'); } function firehose_open_prefs() { - var obj = $dom('fh_advprefs'); - obj.className = ""; + $('#fh_advprefs').removeClass(); } -function toggleId(id, first, second) { - var obj = $dom(id); - if (obj.className == first) { - obj.className = second; - } else if (obj.className == second) { - obj.className = first; - } else { - obj.className = first; - } +function toggleId(id, c1, c2) { + $('#'+id).toggleClasses(c1, c2, c1); } function toggleIntro(id, toggleid) { - var obj = $dom(id); - var toggle = $dom(toggleid); - if (obj.className == 'introhide') { - obj.className = "intro" - toggle.innerHTML = "[-]"; - toggle.className = "expanded"; - } else { - obj.className = "introhide" - toggle.innerHTML = "[+]"; - toggle.className = "condensed"; + var new_class = 'condensed'; + var new_html = '[+]'; + if ( $('#'+id).toggleClasses('introhide', 'intro').hasClass('intro') ) { + new_class = 'expanded'; + new_html = '[-]'; } + $('#'+toggleid).setClass(new_class).html(new_html); } function tagsToggleStoryDiv(id, is_admin, type) { - var bodyid = 'toggletags-body-' + id; - var tagsbody = $dom(bodyid); - if (tagsbody.className == 'tagshide') { - tagsShowBody(id, is_admin, '', type); - } else { - tagsHideBody(id); - } + ($('#toggletags-body-'+id).hasClass('tagshide') ? tagsShowBody : tagsHideBody)(id, is_admin, '', type); } function tagsHideBody(id) { - // Make the body of the tagbox vanish - var tagsbodyid = 'toggletags-body-' + id; - var tagsbody = $dom(tagsbodyid); - tagsbody.className = "tagshide" - - // Make the title of the tagbox change back to regular - var titleid = 'tagbox-title-' + id; - var title = $dom(titleid); - title.className = "tagtitleclosed"; - - // Make the tagbox change back to regular. - var tagboxid = 'tagbox-' + id; - var tagbox = $dom(tagboxid); - tagbox.className = "tags"; - - // Toggle the button back. - var tagsbuttonid = 'toggletags-button-' + id; - var tagsbutton = $dom(tagsbuttonid); - tagsbutton.innerHTML = "[+]"; + $('#toggletags-body-'+id).setClass('tagshide'); // Make the body of the tagbox vanish + $('#tagbox-title-'+id).setClass('tagtitleclosed'); // Make the title of the tagbox change back to regular + $('#tagbox-'+id).setClass('tags'); // Make the tagbox change back to regular. + $('#toggletags-button-'+id).html('[+]'); // Toggle the button back. } function tagsShowBody(id, is_admin, newtagspreloadtext, type) { @@ -229,37 +212,19 @@ } //alert("Tags show body / Type: " + type ); + $('#toggletags-button-'+id).html("[-]"); // Toggle the button to show the click was received + $('#tagbox-'+id).setClass("tags"); // Make the tagbox change to the slashbox class + $('#tagbox-title-'+id).setClass("tagtitleopen"); // Make the title of the tagbox change to white-on-green + $('#toggletags-body-'+id).setClass("tagbody"); // Make the body of the tagbox visible - // Toggle the button to show the click was received - var tagsbuttonid = 'toggletags-button-' + id; - var tagsbutton = $dom(tagsbuttonid); - tagsbutton.innerHTML = "[-]"; - - // Make the tagbox change to the slashbox class - var tagboxid = 'tagbox-' + id; - var tagbox = $dom(tagboxid); - tagbox.className = "tags"; - - // Make the title of the tagbox change to white-on-green - var titleid = 'tagbox-title-' + id; - var title = $dom(titleid); - title.className = "tagtitleopen"; - - // Make the body of the tagbox visible - var tagsbodyid = 'toggletags-body-' + id; - var tagsbody = $dom(tagsbodyid); - - tagsbody.className = "tagbody"; - // If the tags-user div hasn't been filled, fill it. - var tagsuserid = 'tags-user-' + id; - var tagsuser = $dom(tagsuserid); - if (tagsuser.innerHTML == "") { + var tagsuser = $('#tags-user-' + id); + if (tagsuser.html() == "") { // The tags-user-123 div is empty, and needs to be // filled with the tags this user has already // specified for this story, and a reskey to allow // the user to enter more tags. - tagsuser.innerHTML = "Retrieving..."; + tagsuser.html("Retrieving..."); var params = {}; if (type == "stories") { params['op'] = 'tags_get_user_story'; @@ -275,12 +240,10 @@ params['newtagspreloadtext'] = newtagspreloadtext; var handlers = { onComplete: function() { - var textid = 'newtags-' + id; - var input = $dom(textid); - input.focus(); + $dom('newtags-'+id).focus(); } } - ajax_update(params, tagsuserid, handlers); + ajax_update(params, 'tags-user-' + id, handlers); //alert('after ajax_update ' + tagsuserid); // Also fill the admin div. Note that if the user @@ -311,9 +274,8 @@ // that we append some text to the user text. // We can't do that by passing it in, so do it // manually now. - var textinputid = 'newtags-' + id; - var textinput = $dom(textinputid); - textinput.value = textinput.value + ' ' + newtagspreloadtext; + var textinput = $dom('newtags-'+id); + textinput.value += ' ' + newtagspreloadtext; textinput.focus(); } } @@ -391,7 +353,7 @@ params['type'] = type; if ( fh_is_admin && ("_#)^*".indexOf(tag[0]) != -1) ) { params['op'] = 'tags_admin_commands'; - params['reskey'] = $dom('admin_commands-reskey-' + id).value; + params['reskey'] = $('#admin_commands-reskey-' + id).val(); params['command'] = tag; } else { params['op'] = 'tags_create_tag'; @@ -405,68 +367,53 @@ } function tagsCreateForStory(id) { - var toggletags_message_id = 'toggletags-message-' + id; - var toggletags_message_el = $dom(toggletags_message_id); - toggletags_message_el.innerHTML = 'Saving tags...'; + var status = $('#toggletags-message-'+id).html('Saving tags...'); - var params = {}; - params['op'] = 'tags_create_for_story'; - params['sidenc'] = id; - var newtagsel = $dom('newtags-' + id); - params['tags'] = newtagsel.value; - var reskeyel = $dom('newtags-reskey-' + id); - params['reskey'] = reskeyel.value; + ajax_update({ + op: 'tags_create_for_story', + sidenc: id, + tags: $('#newtags-'+id).val(), + reskey: $('#newtags-reskey-'+id).val() + }, 'tags-user-' + id); - ajax_update(params, 'tags-user-' + id); - // XXX How to determine failure here? - toggletags_message_el.innerHTML = 'Tags saved.'; + status.html('Tags saved.'); } function tagsCreateForUrl(id) { - var toggletags_message_id = 'toggletags-message-' + id; - var toggletags_message_el = $dom(toggletags_message_id); - toggletags_message_el.innerHTML = 'Saving tags...'; + var status = $('#toggletags-message-'+id).html('Saving tags...'); - var params = {}; - params['op'] = 'tags_create_for_url'; - params['id'] = id; - var newtagsel = $dom('newtags-' + id); - params['tags'] = newtagsel.value; - var reskeyel = $dom('newtags-reskey-' + id); - params['reskey'] = reskeyel.value; + ajax_update({ + op: 'tags_create_for_url', + id: id, + tags: $('#newtags-'+id).val(), + reskey: $('#newtags-reskey-'+id).val() + }, 'tags-user-' + id); - ajax_update(params, 'tags-user-' + id); - // XXX How to determine failure here? - toggletags_message_el.innerHTML = 'Tags saved.'; + status.html('Tags saved.'); } //Firehose functions begin function setOneTopTagForFirehose(id, newtag) { - var params = {}; - params['op'] = 'firehose_update_one_tag'; - params['id'] = id; - params['tags'] = newtag; - // params['reskey'] = reskeyel.value; - ajax_update(params, ''); + ajax_update({ + op: 'firehose_update_one_tag', + id: id, + tags: newtag + }); } function tagsCreateForFirehose(id) { - var toggletags_message_id = 'toggletags-message-' + id; - var toggletags_message_el = $dom(toggletags_message_id); - toggletags_message_el.innerHTML = 'Saving tags...'; + var status = $('#toggletags-message-'+id).html('Saving tags...'); - var params = {}; - params['op'] = 'tags_create_for_firehose'; - params['id'] = id; - var newtagsel = $dom('newtags-' + id); - params['tags'] = newtagsel.value; - var reskeyel = $dom('newtags-reskey-' + id); - params['reskey'] = reskeyel.value; + ajax_update({ + op: 'tags_create_for_firehose', + id: id, + tags: $('#newtags-'+id).val(), + reskey: $('#newtags-reskey-'+id).val() + }, 'tags-user-'+id); - ajax_update(params, 'tags-user-' + id); - toggletags_message_el.innerHTML = 'Tags saved.'; + status.html('Tags saved.'); } function toggle_firehose_body(id, is_admin) { @@ -487,11 +434,7 @@ } }; params['reskey'] = reskey_static; - if (is_admin) { - ajax_update(params, 'fhbody-'+id, handlers); - } else { - ajax_update(params, 'fhbody-'+id); - } + ajax_update(params, 'fhbody-'+id, is_admin ? handlers : null); fhbody.className = "body"; fh.className = "article" + usertype; if (is_admin) @@ -510,12 +453,7 @@ } function toggleFirehoseTagbox(id) { - var fhtb = $dom('fhtagbox-'+id); - if (fhtb.className == "hide") { - fhtb.className = "tagbox"; - } else { - fhtb.className = "hide"; - } + $('#fhtagbox-'+id).toggleClasses('tagbox', 'hide'); } function firehose_set_options(name, value) { @@ -555,14 +493,7 @@ } if (classname) { - var els = document.getElementsByClassName(classname, $dom('firehoselist')); - var classval = classname; - if (value) { - classval = classval + " hide"; - } - for (i = 0; i< els.length; i++) { - els[i].className = classval; - } + $('#firehoselist .'+classname).setClass(classname + value ? ' hide' : ''); } } @@ -573,6 +504,7 @@ } } firehose_settings.page = 0; + firehose_settings.more_num = 0; } if (name != "color") { for (i=0; i< pairs.length; i++) { @@ -628,20 +560,19 @@ firehose_settings.startdate = value; firehose_settings.duration = 1; firehose_settings.page = 0; + firehose_settings.more_num = 0; var issuedate = firehose_settings.issue.substr(5,2) + "/" + firehose_settings.issue.substr(8,2) + "/" + firehose_settings.issue.substr(10,2); - if ($dom('fhcalendar')) { - $dom('fhcalendar')._widget.setDate(issuedate, "day"); - } - if ($dom('fhcalendar_pag')) { - $dom('fhcalendar_pag')._widget.setDate(issuedate, "day"); - } + $('#fhcalendar, #fhcalendar_pag').each(function(){ + this._widget.setDate(issuedate, "day"); + }); } if (name == "color") { firehose_settings.color = value; } if (name == "pagesize") { firehose_settings.page = 0; + firehose_settings.more_num = 0; } } @@ -669,14 +600,7 @@ } function firehose_remove_all_items() { - var fhl = $dom('firehoselist'); - var children = fhl.childNodes; - for (var i = children.length -1 ; i >= 0; i--) { - var el = children[i]; - if (el.id) { - el.parentNode.removeChild(el); - } - } + $('#firehoselist').children().remove(); } @@ -684,24 +608,15 @@ if (!check_logged_in()) return; setFirehoseAction(); - var params = {}; - var handlers = { - onComplete: json_handler - }; - params['op'] = 'firehose_up_down'; - params['id'] = id; - params['reskey'] = reskey_static; - params['dir'] = dir; - var updown = $dom('updown-' + id); - ajax_update(params, '', handlers); - if (updown) { - if (dir == "+") { - updown.className = "votedup"; - } else if (dir == "-") { - updown.className = "voteddown"; - } - } + ajax_update({ + op: 'firehose_up_down', + id: id, + reskey: reskey_static, + dir: dir + }, '', { onComplete: json_handler }); + $('#updown-'+id).setClass(dir=='+' ? 'votedup' : 'voteddown'); + if (dir == "-" && fh_is_admin) { firehose_collapse_entry(id); } @@ -709,15 +624,12 @@ function firehose_remove_tab(tabid) { setFirehoseAction(); - var params = {}; - var handlers = { - onComplete: json_handler - }; - params['op'] = 'firehose_remove_tab'; - params['tabid'] = tabid; - params['reskey'] = reskey_static; - params['section'] = firehose_settings.section; - ajax_update(params, '', handlers); + ajax_update({ + op: 'firehose_remove_tab', + tabid: tabid, + reskey: reskey_static, + section: firehose_settings.section + }, '', { onComplete: json_handler }); } @@ -733,12 +645,12 @@ url: request_url || '/ajax.pl', data: request_params, type: 'POST', - contentType: 'application/x-www-form-urlencoded', + contentType: 'application/x-www-form-urlencoded' }; if ( id ) { opts['success'] = function(html){ - jQuery('#'+id).html(html); + $('#'+id).html(html); } } @@ -782,37 +694,34 @@ if (response.html) { for (el in response.html) { - if ($dom(el)) - $dom(el).innerHTML = response.html[el]; + $('#'+el).html(response.html[el]); } } if (response.value) { for (el in response.value) { - if ($dom(el)) - $dom(el).value = response.value[el]; + $('#'+el).val(response.value[el]); } } if (response.html_append) { for (el in response.html_append) { - if ($dom(el)) - $dom(el).innerHTML = $dom(el).innerHTML + response.html_append[el]; + $('#'+el).each(function(){ + this.innerHTML += response.html_append[el]; + }); } } if (response.html_append_substr) { for (el in response.html_append_substr) { - if ($dom(el)) { - var this_html = $dom(el).innerHTML; - var i = $dom(el).innerHTML.search(/ ?<\/span>[\s\S]*$/i); - if (i == -1) { - $dom(el).innerHTML += response.html_append_substr[el]; - } else { - $dom(el).innerHTML = $dom(el).innerHTML.substr(0, i) + - response.html_append_substr[el]; - } + var found = $('#'+el); + if (found.size()) { + var this_html = found.html(); + var pos = this_html.search(/ ?<\/span>[\s\S]*$/i); + if ( pos != -1 ) + this_html = this_html.substr(0, pos); + found.html(this_html + response.html_append_substr[el]); } } } @@ -833,14 +742,14 @@ var fh = 'firehose-' + el[1]; var wait_interval = 800; if(el[0] == "add") { - if (firehose_before[el[1]] && jQuery('#firehose-' + firehose_before[el[1]]).size()) { - jQuery('#firehose-' + firehose_before[el[1]]).after(el[2]); - } else if (firehose_after[el[1]] && jQuery('#firehose-' + firehose_after[el[1]]).size()) { - jQuery('#firehose-' + firehose_after[el[1]]).before(el[2]); + if (firehose_before[el[1]] && $('#firehose-' + firehose_before[el[1]]).size()) { + $('#firehose-' + firehose_before[el[1]]).after(el[2]); + } else if (firehose_after[el[1]] && $('#firehose-' + firehose_after[el[1]]).size()) { + $('#firehose-' + firehose_after[el[1]]).before(el[2]); } else if (insert_new_at == "bottom") { - jQuery('#firehoselist').append(el[2]); + $('#firehoselist').append(el[2]); } else { - jQuery('#firehoselist').prepend(el[2]); + $('#firehoselist').prepend(el[2]); } var toheight = 50; @@ -937,28 +846,21 @@ function firehose_reorder() { if (firehose_ordered) { - var fhlist = $dom('firehoselist'); + var fhlist = $('#firehoselist'); if (fhlist) { - var item_count = 0; - for (i = 0; i < firehose_ordered.length; i++) { - if (/^\d+$/.test(firehose_ordered[i])) { - item_count++; + firehose_item_count = firehose_ordered.length; + for (i = 0; i < firehose_ordered.length; ++i) { + if (!/^\d+$/.test(firehose_ordered[i])) { + --firehose_item_count; } - var fhel = $dom('firehose-' + firehose_ordered[i]); - if (fhlist && fhel) { - fhlist.appendChild(fhel); - } + $('#firehose-'+firehose_ordered[i]).appendTo(fhlist); if ( firehose_future[firehose_ordered[i]] ) { - if ($dom("ttype-" + firehose_ordered[i])) { - $dom("ttype-" + firehose_ordered[i]).className = "future"; - } + $('#ttype-'+firehose_ordered[i]).setClass('future'); } else { - if ($dom("ttype-" + firehose_ordered[i]) && $dom("ttype-" + firehose_ordered[i]).className == "future") { - $dom("ttype-" + firehose_ordered[i]).className = "story"; - } + $('#ttype-'+firehose_ordered[i]+'.future').setClass('story'); } } - document.title = "[% sitename %] - " + (console_updating ? "Console" : "Firehose") + " (" + item_count + ")"; + document.title = "[% sitename %] - " + (console_updating ? "Console" : "Firehose") + " (" + firehose_item_count + ")"; } } @@ -973,9 +875,7 @@ function firehose_get_updates_handler(transport) { - if ($dom('busy')) { - $dom('busy').className = "hide"; - } + $('#busy').setClass('hide'); var response = eval_response(transport); var processed = 0; firehose_removals = response.update_data.removals; @@ -1005,24 +905,9 @@ } function firehose_get_item_idstring() { - var fhl = $dom('firehoselist'); - var str = ""; - var children; - if (fhl) { - var id; - children = fhl.childNodes; - if (children) { - for (var i = 0; i < children.length; i++) { - if (children[i].id) { - id = children[i].id; - id = id.replace(/^firehose-/g, ""); - id = id.replace(/^\s+|\s+$/g, ""); - str = str + id + ","; - } - } - } - } - return str; + return $('#firehoselist > [id]').map(function(){ + return this.id.replace(/firehose-(\S+)/, '$1'); + }).get().join(','); } @@ -1039,26 +924,20 @@ while(id = fh_update_timerids.pop()) { clearTimeout(id) }; } fh_is_updating = 1 - var params = {}; - var handlers = { - onComplete: firehose_get_updates_handler + var params = { + op: 'firehose_get_updates', + ids: firehose_get_item_idstring(), + updatetime: update_time, + fh_pageval: firehose_settings.pageval, + embed: firehose_settings.is_embedded }; - params['op'] = 'firehose_get_updates'; - params['ids'] = firehose_get_item_idstring(); - params['updatetime'] = update_time; for (i in firehose_settings) { params[i] = firehose_settings[i]; } - if ( firehose_settings.is_embedded ) { - params['embed'] = 1; - } - params['fh_pageval'] = firehose_settings.pageval; - if ($dom('busy')) { - $dom('busy').className = ""; - } - ajax_update(params, '', handlers); + $('#busy').removeClass(); + ajax_update(params, '', { onComplete: firehose_get_updates_handler }); } @@ -1100,8 +979,7 @@ var secs = getSecsSinceLastFirehoseAction(); if (secs > inactivity_timeout) { fh_is_timed_out = 1; - if ($dom('message_area')) - $dom('message_area').innerHTML = "¥µ¡¼¥Ð¤ÎÈ¿±þ¤¬Îɤ¯¤Ê¤¤¤Î¤Ç¼«Æ°¹¹¿·¤ÏÃÙ¤ì¤Þ¤¹"; + $('#message_area').html("Automatic updates have been slowed due to inactivity") //firehose_pause(); } } @@ -1110,36 +988,21 @@ fh_play = 1; setFirehoseAction(); firehose_set_options('pause', '0'); - var pausepanel = $dom('pauseorplay'); - if ($dom('message_area')) - $dom('message_area').innerHTML = ""; - if (pausepanel) { - pausepanel.innerHTML = "¹¹¿·"; - } - var pause = $dom('pause'); - - var play_div = $dom('play'); - if (play_div) { - play_div.className = "hide"; - } - if (pause) { - pause.className = "show"; - } + $('#message_area').html(''); + $('#pauseorplay').html('Updated'); + $('#play').setClass('hide'); + $('#pause').setClass('show'); } function is_firehose_playing() { - return YAHOO.util.Dom.hasClass('play', 'hide'); + return fh_play==1; } function firehose_pause() { fh_play = 0; - var pause = $dom('pause'); - var play_div = $dom('play'); - pause.className = "hide"; - play_div.className = "show"; - if ($dom('pauseorplay')) { - $dom('pauseorplay').innerHTML = "Ää»ß"; - } + $('#pause').setClass('hide'); + $('#play').setClass('show'); + $('#pauseorplay').html('Paused'); firehose_set_options('pause', '1'); } @@ -1148,14 +1011,8 @@ } function firehose_collapse_entry(id) { - var fhbody = $dom('fhbody-'+id); - var fh = $dom('firehose-'+id); - if (fhbody && fhbody.className == "body") { - fhbody.className = "hide"; - } - if (fh) { - fh.className = "briefarticle"; - } + $('#fhbody-'+id+'.body').setClass('hide'); + $('#firehose-'+id).setClass('briefarticle'); tagsHideBody(id) } @@ -1275,38 +1132,25 @@ } function logToDiv(id, message) { - var div = $dom(id); - if (div) { - div.innerHTML = div.innerHTML + message + "
    "; - } + $('#'+id).append(message + '
    '); } function firehose_open_tab(id) { - var tf = $dom('tab-form-'+id); - var tt = $dom('tab-text-'+id); - var ti = $dom('tab-input-'+id); - tf.className=""; - ti.focus(); - tt.className="hide"; + $('#tab-form-'+id).removeClass(); + $dom('tab-input-'+id).focus(); + $('#tab-text-'+id).setClass('hide'); } function firehose_save_tab(id) { - var tf = $dom('tab-form-'+id); - var tt = $dom('tab-text-'+id); - var ti = $dom('tab-input-'+id); - var params = {}; - var handlers = { - onComplete: json_handler - }; - params['op'] = 'firehose_save_tab'; - params['tabname'] = ti.value; - params['section'] = firehose_settings.section; - - params['tabid'] = id; - ajax_update(params, '', handlers); - tf.className = "hide"; - tt.className = ""; + ajax_update({ + op: 'firehose_save_tab', + tabname: $('#tab-input-'+id).val(), + section: firehose_settings.section, + tabid: id + }, '', { onComplete: json_handler }); + $('#tab-form-'+id).setClass('hide'); + $('#tab-text-'+id).removeClass(); } @@ -1424,6 +1268,8 @@ } function getModalPrefs(section, title, tabbed) { + if (!reskey_static) + return show_login_box(); document.getElementById('preference_title').innerHTML = title; var params = {}; params['op'] = 'getModalPrefs'; @@ -1464,28 +1310,17 @@ } function ajaxSaveSlashboxes() { - var wrapper = document.getElementById('slashboxes'); - var titles = YAHOO.util.Dom.getElementsByClassName('title', 'div', wrapper); - var sep = ""; - var all = ""; - for ( i=0; i #'+id).remove().size() ) { ajaxSaveSlashboxes(); } } @@ -1517,7 +1352,7 @@ } function admin_signoff(stoid, type, id) { - var params = []; + var params = {}; params['op'] = 'admin_signoff'; params['stoid'] = stoid; params['reskey'] = reskey_static; @@ -1530,7 +1365,6 @@ function scrollWindowToFirehose(fhid) { var firehose_y = getOffsetTop($('firehose-' + fhid)); - console.log(firehose_y); scroll(viewWindowLeft(), firehose_y); } @@ -1621,6 +1455,7 @@ var pos = firehose_get_pos_of_id(cur); if (pos < (firehose_ordered.length - 1)) { pos++; + } else { } firehose_set_cur(firehose_ordered[pos]); scrollWindowToFirehose(firehose_cur); @@ -1637,4 +1472,14 @@ } +function firehose_more() { + var increment_by = 10; + firehose_settings.more_num = firehose_settings.more_num + increment_by; + + if (((firehose_item_count + increment_by) >= 200) && !fh_is_admin) { + $('#firehose_more').hide(); + } + firehose_set_options('more_num', firehose_settings.more_num); +} + Modified: slashjp/trunk/plugins/Ajax/htdocs/images/nodnix.js =================================================================== --- slashjp/trunk/plugins/Ajax/htdocs/images/nodnix.js 2008-04-06 23:20:44 UTC (rev 571) +++ slashjp/trunk/plugins/Ajax/htdocs/images/nodnix.js 2008-04-07 00:26:30 UTC (rev 572) @@ -17,16 +17,17 @@ } function get_predefined_nodnix_tags() { - var tags = []; - var query = _get_nodnix('input').getAttribute("updown"); - var listEl = query=="+" ? document.getElementById('static-nod-completions') - : document.getElementById('static-nix-completions'); - if ( listEl ) { - var itemEls = listEl.getElementsByTagName('li'); - for ( var i=0; i! x
  • '; function handle_completer_key( type, args ) { - var key = args[0]; - var event = args[1]; - var stay_open = false; - switch ( key ) { - case YAHOO.util.KeyListener.KEY.ESCAPE: - hide_nodnix_menu(); - break; - case YAHOO.util.KeyListener.KEY.SPACE: - YAHOO.util.Event.stopEvent(event); - stay_open = true; - // fall through - case YAHOO.util.KeyListener.KEY.ENTER: - handle_nodnix_select("", [null, null, _get_nodnix('input').value], stay_open); - break; - } + var key = args[0]; + var event = args[1]; + var stay_open = false; + switch ( key ) { + case YAHOO.util.KeyListener.KEY.ESCAPE: + hide_nodnix_menu(); + break; + case YAHOO.util.KeyListener.KEY.SPACE: + YAHOO.util.Event.stopEvent(event); + stay_open = true; + // fall through + case YAHOO.util.KeyListener.KEY.ENTER: + handle_nodnix_select("", [null, null, _get_nodnix('input').value], stay_open); + break; + } } Modified: slashjp/trunk/plugins/Ajax/htdocs/images/sd_autocomplete.js =================================================================== --- slashjp/trunk/plugins/Ajax/htdocs/images/sd_autocomplete.js 2008-04-06 23:20:44 UTC (rev 571) +++ slashjp/trunk/plugins/Ajax/htdocs/images/sd_autocomplete.js 2008-04-07 00:26:30 UTC (rev 572) @@ -3,67 +3,66 @@ YAHOO.namespace("slashdot"); -YAHOO.slashdot.DS_JSArray = function(aData, oConfigs) - { - if ( typeof oConfigs == "object" ) - for ( var sConfig in oConfigs ) - this[sConfig] = oConfigs[sConfig]; +YAHOO.slashdot.DS_JSArray = function(aData, oConfigs) { + if ( typeof oConfigs == "object" ) + for ( var sConfig in oConfigs ) + this[sConfig] = oConfigs[sConfig]; - if ( !aData || (aData.constructor != Array) ) - return + if ( !aData || (aData.constructor != Array) ) + return - this.data = aData; - this._init(); - } + this.data = aData; + this._init(); +} YAHOO.slashdot.DS_JSArray.prototype = new YAHOO.widget.DataSource(); YAHOO.slashdot.DS_JSArray.prototype.data = null; YAHOO.slashdot.DS_JSArray.prototype.doQuery = function(oCallbackFn, sQuery, oParent) { - var aData = this.data; // the array - var aResults = []; // container for results - var bMatchFound = false; - var bMatchContains = this.queryMatchContains; + var aData = this.data; // the array + var aResults = []; // container for results + var bMatchFound = false; + var bMatchContains = this.queryMatchContains; - if(sQuery && !this.queryMatchCase) { - sQuery = sQuery.toLowerCase(); - } + if(sQuery && !this.queryMatchCase) { + sQuery = sQuery.toLowerCase(); + } - // Loop through each element of the array... - // which can be a string or an array of strings - for(var i = aData.length-1; i >= 0; i--) { - var aDataset = []; + // Loop through each element of the array... + // which can be a string or an array of strings + for(var i = aData.length-1; i >= 0; i--) { + var aDataset = []; - if(aData[i]) { - if(aData[i].constructor == String) { - aDataset[0] = aData[i]; - } - else if(aData[i].constructor == Array) { - aDataset = aData[i]; - } - } + if(aData[i]) { + if(aData[i].constructor == String) { + aDataset[0] = aData[i]; + } + else if(aData[i].constructor == Array) { + aDataset = aData[i]; + } + } - if(aDataset[0] && (aDataset[0].constructor == String)) { - var sKeyIndex = 0; - if (sQuery) { - sKeyIndex = (this.queryMatchCase) ? - encodeURIComponent(aDataset[0]).indexOf(sQuery): - encodeURIComponent(aDataset[0]).toLowerCase().indexOf(sQuery); - } + if(aDataset[0] && (aDataset[0].constructor == String)) { + var sKeyIndex = 0; + if (sQuery) { + sKeyIndex = (this.queryMatchCase) ? + encodeURIComponent(aDataset[0]).indexOf(sQuery): + encodeURIComponent(aDataset[0]).toLowerCase().indexOf(sQuery); + } - // A STARTSWITH match is when the query is found at the beginning of the key string... - if((!bMatchContains && (sKeyIndex === 0)) || - // A CONTAINS match is when the query is found anywhere within the key string... - (bMatchContains && (sKeyIndex > -1))) { - // Stash a match into aResults[]. - aResults.unshift(aDataset); - } - } - } + // A STARTSWITH match is when the query is found at the beginning of the key string... + if((!bMatchContains && (sKeyIndex === 0)) || + // A CONTAINS match is when the query is found anywhere within the key string... + (bMatchContains && (sKeyIndex > -1))) { + // Stash a match into aResults[]. + aResults.unshift(aDataset); + } + } + } - this.getResultsEvent.fire(this, oParent, sQuery, aResults); - oCallbackFn(sQuery, aResults, oParent); + this.getResultsEvent.fire(this, oParent, sQuery, aResults); + oCallbackFn(sQuery, aResults, oParent); }; @@ -282,242 +281,219 @@ "neverdisplay" ]; - var feedbackDS = new YAHOO.slashdot.DS_JSArray(YAHOO.slashdot.feedbackTags); - var actionsDS = new YAHOO.slashdot.DS_JSArray(YAHOO.slashdot.actionTags); - var sectionsDS = new YAHOO.slashdot.DS_JSArray(YAHOO.slashdot.sectionTags); - var topicsDS = new YAHOO.slashdot.DS_JSArray(YAHOO.slashdot.topicTags); - var fhitemDS = new YAHOO.slashdot.DS_JSArray(YAHOO.slashdot.fhitemOpts); - var storyDS = new YAHOO.slashdot.DS_JSArray(YAHOO.slashdot.storyOpts); +var feedbackDS = new YAHOO.slashdot.DS_JSArray(YAHOO.slashdot.feedbackTags); +var actionsDS = new YAHOO.slashdot.DS_JSArray(YAHOO.slashdot.actionTags); +var sectionsDS = new YAHOO.slashdot.DS_JSArray(YAHOO.slashdot.sectionTags); +var topicsDS = new YAHOO.slashdot.DS_JSArray(YAHOO.slashdot.topicTags); +var fhitemDS = new YAHOO.slashdot.DS_JSArray(YAHOO.slashdot.fhitemOpts); +var storyDS = new YAHOO.slashdot.DS_JSArray(YAHOO.slashdot.storyOpts); - var tagsDS = new YAHOO.widget.DS_XHR("./ajax.pl", ["\n", "\t"]); - // tagsDS.maxCacheEntries = 0; // turn off local cacheing, because Jamie says the query is fast - tagsDS.queryMatchSubset = false; - tagsDS.responseType = YAHOO.widget.DS_XHR.TYPE_FLAT; - tagsDS.scriptQueryParam = "prefix"; - tagsDS.scriptQueryAppend = "op=tags_list_tagnames"; - tagsDS.queryMethod = "POST"; +var tagsDS = new YAHOO.widget.DS_XHR("./ajax.pl", ["\n", "\t"]); +// tagsDS.maxCacheEntries = 0; // turn off local cacheing, because Jamie says the query is fast +tagsDS.queryMatchSubset = false; +tagsDS.responseType = YAHOO.widget.DS_XHR.TYPE_FLAT; +tagsDS.scriptQueryParam = "prefix"; +tagsDS.scriptQueryAppend = "op=tags_list_tagnames"; +tagsDS.queryMethod = "POST"; - var fhtabsDS = new YAHOO.widget.DS_XHR("./ajax.pl", ["\n", "\t"]); - fhtabsDS.queryMatchSubset = false; - fhtabsDS.responseType = YAHOO.widget.DS_XHR.TYPE_FLAT; - fhtabsDS.scriptQueryParam = "prefix"; - fhtabsDS.scriptQueryAppend = "op=firehose_list_tabs"; - fhtabsDS.queryMethod = "POST"; +var fhtabsDS = new YAHOO.widget.DS_XHR("./ajax.pl", ["\n", "\t"]); +fhtabsDS.queryMatchSubset = false; +fhtabsDS.responseType = YAHOO.widget.DS_XHR.TYPE_FLAT; +fhtabsDS.scriptQueryParam = "prefix"; +fhtabsDS.scriptQueryAppend = "op=firehose_list_tabs"; +fhtabsDS.queryMethod = "POST"; YAHOO.slashdot.dataSources = [tagsDS, actionsDS, sectionsDS, topicsDS, feedbackDS, storyDS, fhitemDS, fhtabsDS ]; -YAHOO.slashdot.AutoCompleteWidget = function() - { - this._widget = document.getElementById("ac-select-widget"); - this._spareInput = document.getElementById("ac-select-input"); +YAHOO.slashdot.AutoCompleteWidget = function() { + this._widget = document.getElementById("ac-select-widget"); + this._spareInput = document.getElementById("ac-select-input"); - this._sourceEl = null; - this._denyNextAttachTo = null; + this._sourceEl = null; + this._denyNextAttachTo = null; - YAHOO.util.Event.addListener(document.body, "click", this._onSdClick, this, true); - // add body/window blur to detect changing windows? - } + YAHOO.util.Event.addListener(document.body, "click", this._onSdClick, this, true); + // add body/window blur to detect changing windows? +} -YAHOO.slashdot.AutoCompleteWidget.prototype._textField = function() - { - if ( this._sourceEl==null || this._sourceEl.type=='text' || this._sourceEl.type=='textarea' ) - return this._sourceEl; +YAHOO.slashdot.AutoCompleteWidget.prototype._textField = function() { + if ( this._sourceEl==null || this._sourceEl.type=='text' || this._sourceEl.type=='textarea' ) + return this._sourceEl; - return this._spareInput; - } + return this._spareInput; +} -YAHOO.slashdot.AutoCompleteWidget.prototype._needsSpareInput = function() - { - // return this._textField() == this._spareInput; - return this._sourceEl && (this._sourceEl.type != "text") && (this._sourceEl.type != "textarea"); - } +YAHOO.slashdot.AutoCompleteWidget.prototype._needsSpareInput = function() { + // return this._textField() == this._spareInput; + return this._sourceEl && (this._sourceEl.type != "text") && (this._sourceEl.type != "textarea"); +} -YAHOO.slashdot.AutoCompleteWidget.prototype._newCompleter = function( tagDomain ) - { - var c = null; - if ( this._needsSpareInput() ) - { - c = new YAHOO.widget.AutoComplete("ac-select-input", "ac-choices", YAHOO.slashdot.dataSources[tagDomain]); - c.minQueryLength = 0; +YAHOO.slashdot.AutoCompleteWidget.prototype._newCompleter = function( tagDomain ) { + var c = null; + if ( this._needsSpareInput() ) { + c = new YAHOO.widget.AutoComplete("ac-select-input", "ac-choices", YAHOO.slashdot.dataSources[tagDomain]); + c.minQueryLength = 0; - // hack? -- override YUI's private member function so that for top tags auto-complete, right arrow means select - c._jumpSelection = function() { if ( this._oCurItem ) this._selectItem(this._oCurItem); }; - } - else - { - c = new YAHOO.widget.AutoComplete(this._sourceEl, "ac-choices", YAHOO.slashdot.dataSources[tagDomain]); - c.delimChar = " "; - c.minQueryLength = 3; - } - c.typeAhead = false; - c.forceSelection = false; - c.allowBrowserAutocomplete = false; - c.maxResultsDisplayed = 25; - c.animVert = false; + // hack? -- override YUI's private member function so that for top tags auto-complete, right arrow means select + c._jumpSelection = function() { if ( this._oCurItem ) this._selectItem(this._oCurItem); }; + } else { + c = new YAHOO.widget.AutoComplete(this._sourceEl, "ac-choices", YAHOO.slashdot.dataSources[tagDomain]); + c.delimChar = " "; + c.minQueryLength = 3; + } + c.typeAhead = false; + c.forceSelection = false; + c.allowBrowserAutocomplete = false; + c.maxResultsDisplayed = 25; + c.animVert = false; - return c; - } + return c; +} -YAHOO.slashdot.AutoCompleteWidget.prototype._show = function( obj, callbackParams, tagDomain ) - { - // onTextboxBlur should have already hidden the previous instance (if any), but if events - // come out of order, we must hide now to prevent broken listeners - if ( this._sourceEl ) - this._hide(); +YAHOO.slashdot.AutoCompleteWidget.prototype._show = function( obj, callbackParams, tagDomain ) { + // onTextboxBlur should have already hidden the previous instance (if any), but if events + // come out of order, we must hide now to prevent broken listeners + if ( this._sourceEl ) + this._hide(); - this._sourceEl = obj; + this._sourceEl = obj; - if ( this._sourceEl ) - { - this._callbackParams = callbackParams; - this._callbackParams._tagDomain = tagDomain; - this._completer = this._newCompleter(tagDomain); - - if ( typeof callbackParams.yui == "object" ) - for ( var field in callbackParams.yui ) - this._completer[field] = callbackParams.yui[field]; + if ( this._sourceEl ) { + this._callbackParams = callbackParams; + this._callbackParams._tagDomain = tagDomain; + this._completer = this._newCompleter(tagDomain); - if ( callbackParams.delayAutoHighlight ) - this._completer.autoHighlight = false; - + if ( typeof callbackParams.yui == "object" ) + for ( var field in callbackParams.yui ) + this._completer[field] = callbackParams.yui[field]; - // widget must be visible to move - YAHOO.util.Dom.removeClass(this._widget, "hidden"); - // move widget to be near the 'source' - var pos = YAHOO.util.Dom.getXY(this._sourceEl); - pos[1] += this._sourceEl.offsetHeight; - YAHOO.util.Dom.setXY(this._widget, pos); + if ( callbackParams.delayAutoHighlight ) + this._completer.autoHighlight = false; - YAHOO.util.Dom.addClass(this._sourceEl, "ac-source"); + // widget must be visible to move + YAHOO.util.Dom.removeClass(this._widget, "hidden"); + // move widget to be near the 'source' + var pos = YAHOO.util.Dom.getXY(this._sourceEl); + pos[1] += this._sourceEl.offsetHeight; + YAHOO.util.Dom.setXY(this._widget, pos); - if ( this._needsSpareInput() ) - { - YAHOO.util.Dom.removeClass(this._spareInput, "hidden"); - this._spareInput.value = ""; - this._spareInput.focus(); - this._pending_hide = setTimeout(YAHOO.slashdot.gCompleterWidget._hide, 15000); - } - else - YAHOO.util.Dom.addClass(this._spareInput, "hidden"); + YAHOO.util.Dom.addClass(this._sourceEl, "ac-source"); - this._completer.itemSelectEvent.subscribe(this._onSdItemSelectEvent, this); - this._completer.unmatchedItemSelectEvent.subscribe(this._onSdItemSelectEvent, this); - this._completer.textboxBlurEvent.subscribe(this._onSdTextboxBlurEvent, this); + if ( this._needsSpareInput() ) { + YAHOO.util.Dom.removeClass(this._spareInput, "hidden"); + this._spareInput.value = ""; + this._spareInput.focus(); + this._pending_hide = setTimeout(YAHOO.slashdot.gCompleterWidget._hide, 15000); + } else + YAHOO.util.Dom.addClass(this._spareInput, "hidden"); - YAHOO.util.Event.addListener(this._textField(), "keydown", this._onSdTextboxKeyDown, this, true); - } - } + this._completer.itemSelectEvent.subscribe(this._onSdItemSelectEvent, this); + this._completer.unmatchedItemSelectEvent.subscribe(this._onSdItemSelectEvent, this); + this._completer.textboxBlurEvent.subscribe(this._onSdTextboxBlurEvent, this); -YAHOO.slashdot.AutoCompleteWidget.prototype._hide = function() - { - if ( this._pending_hide ) - { - clearTimeout(this._pending_hide); - this._pending_hide = null; - } + YAHOO.util.Event.addListener(this._textField(), "keydown", this._onSdTextboxKeyDown, this, true); + } +} - YAHOO.util.Dom.addClass(this._widget, "hidden"); - YAHOO.util.Dom.addClass(this._spareInput, "hidden"); - if ( this._sourceEl ) - { - YAHOO.util.Dom.removeClass(this._sourceEl, "ac-source"); +YAHOO.slashdot.AutoCompleteWidget.prototype._hide = function() { + if ( this._pending_hide ) { + clearTimeout(this._pending_hide); + this._pending_hide = null; + } - YAHOO.util.Event.removeListener(this._textField(), "keydown", this._onSdTextboxKeyDown, this, true); - this._completer.itemSelectEvent.unsubscribe(this._onSdItemSelectEvent, this); - this._completer.unmatchedItemSelectEvent.unsubscribe(this._onSdItemSelectEvent, this); - this._completer.textboxBlurEvent.unsubscribe(this._onSdTextboxBlurEvent, this); + YAHOO.util.Dom.addClass(this._widget, "hidden"); + YAHOO.util.Dom.addClass(this._spareInput, "hidden"); + if ( this._sourceEl ) { + YAHOO.util.Dom.removeClass(this._sourceEl, "ac-source"); - this._sourceEl = null; - this._callbackParams = null; - this._completer = null; - } + YAHOO.util.Event.removeListener(this._textField(), "keydown", this._onSdTextboxKeyDown, this, true); + this._completer.itemSelectEvent.unsubscribe(this._onSdItemSelectEvent, this); + this._completer.unmatchedItemSelectEvent.unsubscribe(this._onSdItemSelectEvent, this); + this._completer.textboxBlurEvent.unsubscribe(this._onSdTextboxBlurEvent, this); - this._denyNextAttachTo = null; - } + this._sourceEl = null; + this._callbackParams = null; + this._completer = null; + } -YAHOO.slashdot.AutoCompleteWidget.prototype.attach = function( obj, callbackParams, tagDomain ) - { - var newSourceEl = obj; - if ( typeof obj == "string" ) - newSourceEl = document.getElementById(obj); + this._denyNextAttachTo = null; +} - // act like a menu: if we click on the same trigger while visible, hide - var denyThisAttach = this._denyNextAttachTo == newSourceEl; - this._denyNextAttachTo = null; - if ( denyThisAttach ) - return; +YAHOO.slashdot.AutoCompleteWidget.prototype.attach = function( obj, callbackParams, tagDomain ) { + var newSourceEl = obj; + if ( typeof obj == "string" ) + newSourceEl = document.getElementById(obj); - if ( newSourceEl && newSourceEl !== this._sourceEl ) - { - callbackParams._sourceEl = newSourceEl; - this._show(newSourceEl, callbackParams, tagDomain); + // act like a menu: if we click on the same trigger while visible, hide + var denyThisAttach = this._denyNextAttachTo == newSourceEl; + this._denyNextAttachTo = null; + if ( denyThisAttach ) + return; - var q = callbackParams.queryOnAttach; - if ( q ) - this._completer.sendQuery((typeof q == "string") ? q : ""); - } - } + if ( newSourceEl && newSourceEl !== this._sourceEl ) { + callbackParams._sourceEl = newSourceEl; + this._show(newSourceEl, callbackParams, tagDomain); -YAHOO.slashdot.AutoCompleteWidget.prototype._onSdClick = function( e, me ) - { - // if the user re-clicked the item to which I'm attached, then they mean to hide me - // I'm going to hide automatically, because a click outside the text will blur, and that makes me go away - // but I need to remember _not_ to let the current click re-show me - var reclicked = me._sourceEl && YAHOO.util.Event.getTarget(e, true) == me._sourceEl; - me._denyNextAttachTo = reclicked ? me._sourceEl : null; - } + var q = callbackParams.queryOnAttach; + if ( q ) + this._completer.sendQuery((typeof q == "string") ? q : ""); + } +} -YAHOO.slashdot.AutoCompleteWidget.prototype._onSdItemSelectEvent = function( type, args, me ) - { - var tagname = args[2]; - if ( tagname !== undefined && tagname !== null ) { - if ( typeof tagname != 'string' ) - tagname = tagname[0]; +YAHOO.slashdot.AutoCompleteWidget.prototype._onSdClick = function( e, me ) { + // if the user re-clicked the item to which I'm attached, then they mean to hide me + // I'm going to hide automatically, because a click outside the text will blur, and that makes me go away + // but I need to remember _not_ to let the current click re-show me + var reclicked = me._sourceEl && YAHOO.util.Event.getTarget(e, true) == me._sourceEl; + me._denyNextAttachTo = reclicked ? me._sourceEl : null; +} - var p = me._callbackParams; - if ( p.action0 !== undefined ) - p.action0(tagname, p); - me._hide(); - if ( p.action1 !== undefined ) - p.action1(tagname, p); +YAHOO.slashdot.AutoCompleteWidget.prototype._onSdItemSelectEvent = function( type, args, me ) { + var tagname = args[2]; + if ( tagname !== undefined && tagname !== null ) { + if ( typeof tagname != 'string' ) + tagname = tagname[0]; - } else { - me._hide(); - } - } + var p = me._callbackParams; + if ( p.action0 !== undefined ) + p.action0(tagname, p); + me._hide(); + if ( p.action1 !== undefined ) + p.action1(tagname, p); -YAHOO.slashdot.AutoCompleteWidget.prototype._onSdTextboxBlurEvent = function( type, args, me ) - { - var o = me._denyNextAttachTo; - me._hide(); - me._denyNextAttachTo = o; - } + } else { + me._hide(); + } +} -YAHOO.slashdot.AutoCompleteWidget.prototype._onSdTextboxKeyDown = function( e, me ) - { - if ( me._callbackParams && me._callbackParams.delayAutoHighlight ) - { - me._callbackParams.delayAutoHighlight = false; - me._completer.autoHighlight = true; - } +YAHOO.slashdot.AutoCompleteWidget.prototype._onSdTextboxBlurEvent = function( type, args, me ) { + var o = me._denyNextAttachTo; + me._hide(); + me._denyNextAttachTo = o; +} - switch ( e.keyCode ) - { - case 27: // esc - // any other keys?... - me._hide(); - break; - case 13: - // I'm sorry to say we have to test first, something somehow somewhere can still - // leave this listener dangling; want to look deeper into this, as this would _still_ - // leave the listener dangling - if ( me._completer ) - me._completer.unmatchedItemSelectEvent.fire(me._completer, me, me._completer._sCurQuery); - break; - default: - if ( me._pending_hide ) - clearTimeout(me._pending_hide); - if ( me._needsSpareInput() ) - me._pending_hide = setTimeout(YAHOO.slashdot.gCompleterWidget._hide, 15000); - } - } +YAHOO.slashdot.AutoCompleteWidget.prototype._onSdTextboxKeyDown = function( e, me ) { + if ( me._callbackParams && me._callbackParams.delayAutoHighlight ) { + me._callbackParams.delayAutoHighlight = false; + me._completer.autoHighlight = true; + } + + switch ( e.keyCode ) { + case 27: // esc + // any other keys?... + me._hide(); + break; + case 13: + // I'm sorry to say we have to test first, something somehow somewhere can still + // leave this listener dangling; want to look deeper into this, as this would _still_ + // leave the listener dangling + if ( me._completer ) + me._completer.unmatchedItemSelectEvent.fire(me._completer, me, me._completer._sCurQuery); + break; + default: + if ( me._pending_hide ) + clearTimeout(me._pending_hide); + if ( me._needsSpareInput() ) + me._pending_hide = setTimeout(YAHOO.slashdot.gCompleterWidget._hide, 15000); + } +} Modified: slashjp/trunk/plugins/Ajax/htdocs/images/sd_calendar.js =================================================================== --- slashjp/trunk/plugins/Ajax/htdocs/images/sd_calendar.js 2008-04-06 23:20:44 UTC (rev 571) +++ slashjp/trunk/plugins/Ajax/htdocs/images/sd_calendar.js 2008-04-07 00:26:30 UTC (rev 572) @@ -1,275 +1,275 @@ // _*_ Mode: JavaScript; tab-width: 8; indent-tabs-mode: true _*_ -// $Id: sd_calendar.js,v 1.7 2007/06/05 19:04:12 scc Exp $ +// $Id: sd_calendar.js,v 1.9 2008/03/28 20:53:43 pudge Exp $ YAHOO.namespace("slashdot"); function _datesToSelector( selectorFormat, dates ) { - function format( d ) { - return selectorFormat(d.getFullYear(), d.getMonth()+1, d.getDate(), d.getDay()); - } + function format( d ) { + return selectorFormat(d.getFullYear(), d.getMonth()+1, d.getDate(), d.getDay()); + } - var s = format(dates[0]); - if ( dates[1] !== undefined ) - s += "-" + format(dates[1]); - return s; + var s = format(dates[0]); + if ( dates[1] !== undefined ) + s += "-" + format(dates[1]); + return s; } function _bundleDates( date1, date2 ) { - if ( date1 instanceof Array ) - return date1; - else if ( date2 === undefined ) - return [ date1 ]; - else - return [ date1, date2 ]; + if ( date1 instanceof Array ) + return date1; + else if ( date2 === undefined ) + return [ date1 ]; + else + return [ date1, date2 ]; } function datesToHumanReadable( date1, date2 ) { - var day_name = ["ÆüÍËÆü", "·îÍËÆü", "²ÐÍËÆü", "¿åÍËÆü", "ÌÚÍËÆü", "¶âÍËÆü", "ÅÚÍËÆü"]; + var day_name = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; - function day_ordinal( d ) { - switch ( d ) { - case 1: case 21: case 31: return d+"st"; - case 2: case 22: return d+"nd"; - case 3: case 23: return d+"rd"; - default: return d+"th"; - } - } + function day_ordinal( d ) { + switch ( d ) { + case 1: case 21: case 31: return d+"st"; + case 2: case 22: return d+"nd"; + case 3: case 23: return d+"rd"; + default: return d+"th"; + } + } - var month_name = ["1·î", "2·î", "3·î", "4·î", "5·î", "6·î", "7·î", "8·î", "9·î", "10·î", "11·î", "12·î"]; + var month_name = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; - function minimalHumanReadable( y, m, d, wd ) { - var now = new Date(); - if ( now.getFullYear() == y ) { - if ( now.getMonth()+1 == m ) { - } - } - } + function minimalHumanReadable( y, m, d, wd ) { + var now = new Date(); + if ( now.getFullYear() == y ) { + if ( now.getMonth()+1 == m ) { + } + } + } - - return _datesToSelector(function(y,m,d){return ""+y+"ǯ"+month_name[m-1]+d+"Æü";}, _bundleDates(date1, date2)); + + return _datesToSelector(function(y,m,d){return ""+d+" "+month_name[m-1]+" "+y;}, _bundleDates(date1, date2)); } function datesToYUISelector( date1, date2 ) { - return _datesToSelector(function(y,m,d){return ""+m+"/"+d+"/"+y;}, _bundleDates(date1, date2)); + return _datesToSelector(function(y,m,d){return ""+m+"/"+d+"/"+y;}, _bundleDates(date1, date2)); } function datesToKinoSelector( date1, date2 ) { - function formatter( y, m, d ) { - if ( m < 10 ) m = "0" + m; - if ( d < 10 ) d = "0" + d; - return "" + y + m + d; - } - return _datesToSelector(formatter, _bundleDates(date1, date2)); + function formatter( y, m, d ) { + if ( m < 10 ) m = "0" + m; + if ( d < 10 ) d = "0" + d; + return "" + y + m + d; + } + return _datesToSelector(formatter, _bundleDates(date1, date2)); } // Kino format to YUI format: "20070428".replace(/(....)(..)(..)/, "$2/$3/$1") function weekOf( date ) { - var dayStart = new Date(datesToYUISelector(date)); - var dayCount = Math.round(dayStart.getTime() / 86400000); - var weekStart = dayCount - dayStart.getDay() + 1; - var weekStop = weekStart + 6; - var startDate = new Date(weekStart * 86400000); - var endDate = new Date(weekStop * 86400000); - return [startDate, endDate]; + var dayStart = new Date(datesToYUISelector(date)); + var dayCount = Math.round(dayStart.getTime() / 86400000); + var weekStart = dayCount - dayStart.getDay() + 1; + var weekStop = weekStart + 6; + var startDate = new Date(weekStart * 86400000); + var endDate = new Date(weekStop * 86400000); + return [startDate, endDate]; } var gOpenCalendarPane = null; YAHOO.slashdot.DateWidget = function( params ) { - this.init(params); + this.init(params); } YAHOO.slashdot.DateWidget.prototype.init = function( params ) { // id, mode, date, initCallback - var peer = null; - if ( params.peer !== undefined ) { - peer = document.getElementById(params.peer); - params.mode = peer._widget._mode; - params.date = peer._widget.getDate(); + var peer = null; + if ( params.peer !== undefined ) { + peer = document.getElementById(params.peer); + params.mode = peer._widget._mode; + params.date = peer._widget.getDate(); - this.subscribeToPeer(peer); - this._peer = peer; - } + this.subscribeToPeer(peer); + this._peer = peer; + } - this._mode = (params.mode !== undefined) ? params.mode : "now"; + this._mode = (params.mode !== undefined) ? params.mode : "now"; - var root = document.getElementById(params.id); - var find1st = function(name, kind) { - return YAHOO.util.Dom.getElementsByClassName(name, kind, root)[0]; - } + var root = document.getElementById(params.id); + var find1st = function(name, kind) { + return YAHOO.util.Dom.getElementsByClassName(name, kind, root)[0]; + } - var widget = this; + var widget = this; - this._element = root; - this._dateTab = find1st('date-tab', 'span'); - this._dateTab._widget = this; - this._label = find1st('day-label', 'option'); - this._calendarPane = find1st('calendar-pane', 'div'); - this.toggleCalendarPane(false); + this._element = root; + this._dateTab = find1st('date-tab', 'span'); + this._dateTab._widget = this; + this._label = find1st('day-label', 'option'); + this._calendarPane = find1st('calendar-pane', 'div'); + this.toggleCalendarPane(false); - this._popup = find1st('date-span-popup', 'select'); - this._popup._widget = this; + this._popup = find1st('date-span-popup', 'select'); + this._popup._widget = this; - this._calendar = new YAHOO.widget.Calendar(params.id+'-calendar-table', this._calendarPane.id, {maxdate:datesToYUISelector(new Date())}); - this._calendar.selectEvent.subscribe(this.handleCalendarSelect, this, true); + this._calendar = new YAHOO.widget.Calendar(params.id+'-calendar-table', this._calendarPane.id, {maxdate:datesToYUISelector(new Date())}); + this._calendar.selectEvent.subscribe(this.handleCalendarSelect, this, true); - root._widget = this; - root.setDate = function(d, m) { widget.setDate(d, m); } - root.getDateRange = function() { return widget.getDateRange(); } - root.changeEvent = new YAHOO.util.CustomEvent("change"); + root._widget = this; + root.setDate = function(d, m) { widget.setDate(d, m); } + root.getDateRange = function() { return widget.getDateRange(); } + root.changeEvent = new YAHOO.util.CustomEvent("change"); - this._muteEvents = 0; + this._muteEvents = 0; - this.setDate(params.date); + this.setDate(params.date); - if ( peer ) - peer._widget.subscribeToPeer(this._element); + if ( peer ) + peer._widget.subscribeToPeer(this._element); - if ( params.init !== undefined ) - params.init(root); + if ( params.init !== undefined ) + params.init(root); } function attachDateWidgetTo( params ) { - return new YAHOO.slashdot.DateWidget(params); + return new YAHOO.slashdot.DateWidget(params); } YAHOO.slashdot.DateWidget.prototype.muteEvents = function() { - ++this._muteEvents; + ++this._muteEvents; } YAHOO.slashdot.DateWidget.prototype.unmuteEvents = function() { - --this._muteEvents; + --this._muteEvents; } YAHOO.slashdot.DateWidget.prototype._reportChanged = function() { - if ( ! this._muteEvents ) - this._element.changeEvent.fire(this.getDateRange(), this._mode, this.getDate()); + if ( ! this._muteEvents ) + this._element.changeEvent.fire(this.getDateRange(), this._mode, this.getDate()); } YAHOO.slashdot.DateWidget.prototype.severPeer = function() { - if ( this._peer !== undefined ) { - this._peer._widget.unsubscribeFromPeer(this); - this.unsubscribeFromPeer(this._peer); - delete this._peer; - } + if ( this._peer !== undefined ) { + this._peer._widget.unsubscribeFromPeer(this); + this.unsubscribeFromPeer(this._peer); + delete this._peer; + } } YAHOO.slashdot.DateWidget.prototype.subscribeToPeer = function( peer ) { - peer.changeEvent.subscribe(this.handlePeerChange, this, true); + peer.changeEvent.subscribe(this.handlePeerChange, this, true); } YAHOO.slashdot.DateWidget.prototype.unsubscribeFromPeer = function( peer ) { - peer.changeEvent.unsubscribe(this.handlePeerChange, this); + peer.changeEvent.unsubscribe(this.handlePeerChange, this); } YAHOO.slashdot.DateWidget.prototype.setMode = function( newMode ) { - var oldMode = this._mode; - var modeChanged = (newMode !== undefined) && (newMode != oldMode); - if ( modeChanged ) { - if ( newMode == "all" ) - this.toggleCalendarPane(false); - YAHOO.util.Dom.replaceClass(this._element, oldMode, newMode); - this._mode = newMode; - this._popup.value = newMode; - } + var oldMode = this._mode; + var modeChanged = (newMode !== undefined) && (newMode != oldMode); + if ( modeChanged ) { + if ( newMode == "all" ) + this.toggleCalendarPane(false); + YAHOO.util.Dom.replaceClass(this._element, oldMode, newMode); + this._mode = newMode; + this._popup.value = newMode; + } - if ( modeChanged ) - this._reportChanged(); + if ( modeChanged ) + this._reportChanged(); - return modeChanged; + return modeChanged; } YAHOO.slashdot.DateWidget.prototype.setDate = function( date, mode ) { - this.muteEvents(); - if ( date === undefined ) - date = new Date(); - this._calendar.select(date); - this._calendar.render(); - var dateChanged = this._setDateFromSelection(date); + this.muteEvents(); + if ( date === undefined ) + date = new Date(); + this._calendar.select(date); + this._calendar.render(); + var dateChanged = this._setDateFromSelection(date); - var modeChanged = false; - if ( mode !== undefined ) - modeChanged = this.setMode(mode); - this.unmuteEvents(); + var modeChanged = false; + if ( mode !== undefined ) + modeChanged = this.setMode(mode); + this.unmuteEvents(); - if ( dateChanged || modeChanged ) - this._reportChanged(); + if ( dateChanged || modeChanged ) + this._reportChanged(); } YAHOO.slashdot.DateWidget.prototype._setDateFromSelection = function( date, allowModeChange ) { - var oldLabel = this._label.innerHTML; - var newLabel = "" + datesToHumanReadable(date); - var labelChanged = oldLabel != newLabel; - if ( labelChanged ) - this._label.innerHTML = newLabel; + var oldLabel = this._label.innerHTML; + var newLabel = "Day of " + datesToHumanReadable(date); + var labelChanged = oldLabel != newLabel; + if ( labelChanged ) + this._label.innerHTML = newLabel; - var modeChanged = false; - if ( allowModeChange==true ) { - var today = new Date(); - var newMode = ( date.getFullYear() == today.getFullYear() - && date.getMonth() == today.getMonth() - && date.getDate() == today.getDate() ) ? "now" : "day"; + var modeChanged = false; + if ( allowModeChange==true ) { + var today = new Date(); + var newMode = ( date.getFullYear() == today.getFullYear() + && date.getMonth() == today.getMonth() + && date.getDate() == today.getDate() ) ? "now" : "day"; - this.muteEvents(); - modeChanged = this.setMode(newMode); - this.unmuteEvents(); - } + this.muteEvents(); + modeChanged = this.setMode(newMode); + this.unmuteEvents(); + } - if ( labelChanged || modeChanged ) - this._reportChanged(); + if ( labelChanged || modeChanged ) + this._reportChanged(); - return labelChanged || modeChanged; + return labelChanged || modeChanged; } YAHOO.slashdot.DateWidget.prototype.getDate = function() { - return this._calendar.getSelectedDates()[0]; + return this._calendar.getSelectedDates()[0]; } YAHOO.slashdot.DateWidget.prototype.getDateRange = function() { - var range = { duration: -1 }; + var range = { duration: -1 }; - var start = null; - if ( this._mode == "day" ) { - start = this.getDate(); - range.duration = 1; - } else if ( this._mode == "now" ) { - range.duration = 7; - } + var start = null; + if ( this._mode == "day" ) { + start = this.getDate(); + range.duration = 1; + } else if ( this._mode == "now" ) { + range.duration = 7; + } - if ( start !== null ) - range.startdate = datesToKinoSelector(start); + if ( start !== null ) + range.startdate = datesToKinoSelector(start); - return range; + return range; } YAHOO.slashdot.DateWidget.prototype.toggleCalendarPane = function( show ) { - if ( gOpenCalendarPane !== null && gOpenCalendarPane !== this ) { - gOpenCalendarPane.toggleCalendarPane(false); - } - this._calendarPane.style.display = show ? 'block' : 'none'; - YAHOO.util.Dom[ show ? 'addClass' : 'removeClass' ](this._dateTab, 'active'); - gOpenCalendarPane = show ? this : null; + if ( gOpenCalendarPane !== null && gOpenCalendarPane !== this ) { + gOpenCalendarPane.toggleCalendarPane(false); + } + this._calendarPane.style.display = show ? 'block' : 'none'; + YAHOO.util.Dom[ show ? 'addClass' : 'removeClass' ](this._dateTab, 'active'); + gOpenCalendarPane = show ? this : null; } YAHOO.slashdot.DateWidget.prototype.handleDateTabClick = function() { - this.toggleCalendarPane( ! YAHOO.util.Dom.hasClass(this._dateTab, 'active') ); + this.toggleCalendarPane( ! YAHOO.util.Dom.hasClass(this._dateTab, 'active') ); } YAHOO.slashdot.DateWidget.prototype.handleCalendarSelect = function( type, args, obj ) { - this._setDateFromSelection(this._calendar._toDate(args[0][0]), true); - this.toggleCalendarPane(false); + this._setDateFromSelection(this._calendar._toDate(args[0][0]), true); + this.toggleCalendarPane(false); } YAHOO.slashdot.DateWidget.prototype.handleRangePopupSelect = function( obj ) { - this.setMode(obj.value); + this.setMode(obj.value); } YAHOO.slashdot.DateWidget.prototype.handlePeerChange = function( type, args, obj ) { - this.muteEvents(); - this.setDate(args[2], args[1]); - this.unmuteEvents(); + this.muteEvents(); + this.setDate(args[2], args[1]); + this.unmuteEvents(); } Modified: slashjp/trunk/plugins/Ajax/htdocs/images/slashbox.js =================================================================== --- slashjp/trunk/plugins/Ajax/htdocs/images/slashbox.js 2008-04-06 23:20:44 UTC (rev 571) +++ slashjp/trunk/plugins/Ajax/htdocs/images/slashbox.js 2008-04-07 00:26:30 UTC (rev 572) @@ -1,101 +1,90 @@ YAHOO.namespace("slashdot"); -YAHOO.slashdot.SlashBox = function( id, sGroup, config ) - { - if ( id ) - { - this.init(id, sGroup, config); - this.initFrame(); - this.logger = this.logger || YAHOO; - } +YAHOO.slashdot.SlashBox = function( id, sGroup, config ) { + if ( id ) { + this.init(id, sGroup, config); + this.initFrame(); + this.logger = this.logger || YAHOO; + } - this.deleteBoundaryId = sGroup; - } + this.deleteBoundaryId = sGroup; +} YAHOO.extend(YAHOO.slashdot.SlashBox, YAHOO.util.DDProxy); -YAHOO.slashdot.SlashBox.prototype.createFrame() - { - // ... - } +YAHOO.slashdot.SlashBox.prototype.createFrame = function() { + // ... +} -YAHOO.slashdot.SlashBox.prototype.startDrag = function(x, y) - { - var dragEl = this.getDragEl(); - var clickEl = this.getEl(); +YAHOO.slashdot.SlashBox.prototype.startDrag = function(x, y) { + var dragEl = this.getDragEl(); + var clickEl = this.getEl(); - dragEl.innerHTML = clickEl.innerHTML; - dragEl.className = clickEl.className; + dragEl.innerHTML = clickEl.innerHTML; + dragEl.className = clickEl.className; - YAHOO.util.Dom.addClass(clickEl, "to-be-moved"); - // so we can style the object-to-be-moved in CSS - } + YAHOO.util.Dom.addClass(clickEl, "to-be-moved"); + // so we can style the object-to-be-moved in CSS +} -YAHOO.slashdot.SlashBox.prototype.endDrag = function(e) - { - YAHOO.util.Dom.removeClass(this.getEl(), "to-be-moved"); - // done moving, back to your regularly scheduled CSS (see this.startDrag) - } +YAHOO.slashdot.SlashBox.prototype.endDrag = function(e) { + YAHOO.util.Dom.removeClass(this.getEl(), "to-be-moved"); + // done moving, back to your regularly scheduled CSS (see this.startDrag) +} -YAHOO.slashdot.SlashBox.prototype.onDragOver = function(e, id) - { - if ( id == this.deleteBoundaryId ) - return; +YAHOO.slashdot.SlashBox.prototype.onDragOver = function(e, id) { + if ( id == this.deleteBoundaryId ) + return; - var pointer_y = YAHOO.util.Event.getPageY(e); - var dragged_box = this.getEl(); - var fixed_box; - - if ("string" == typeof id) - fixed_box = YAHOO.util.DDM.getElement(id); - else - fixed_box = YAHOO.util.DDM.getBestMatch(id).getEl(); + var pointer_y = YAHOO.util.Event.getPageY(e); + var dragged_box = this.getEl(); + var fixed_box; - var parent = fixed_box.parentNode; + if ("string" == typeof id) + fixed_box = YAHOO.util.DDM.getElement(id); + else + fixed_box = YAHOO.util.DDM.getBestMatch(id).getEl(); - var dragged_top = YAHOO.util.DDM.getPosY(dragged_box); - var fixed_top = YAHOO.util.DDM.getPosY(fixed_box); - - var fixed_mid = fixed_top + ( Math.floor(fixed_box.offsetHeight / 2)); + var parent = fixed_box.parentNode; - var dragging_down = dragged_top < fixed_top; + var dragged_top = YAHOO.util.DDM.getPosY(dragged_box); + var fixed_top = YAHOO.util.DDM.getPosY(fixed_box); + + var fixed_mid = fixed_top + ( Math.floor(fixed_box.offsetHeight / 2)); + var dragging_down = dragged_top < fixed_top; - if ( dragging_down && pointer_y > fixed_mid ) - parent.insertBefore(fixed_box, dragged_box); - else if ( !dragging_down && pointer_y < fixed_mid ) - parent.insertBefore(dragged_box, fixed_box); - else - return; - } -YAHOO.slashdot.SlashBox.prototype.onDragEnter = function(e, id) - { - if ( id == this.deleteBoundaryId ) - { - var dragEl = this.getDragEl(); - var clickEl = this.getEl(); - YAHOO.util.Dom.removeClass(dragEl, "to-be-deleted"); - YAHOO.util.Dom.removeClass(clickEl, "to-be-deleted"); - // so we can style the object-to-be-moved in CSS - } - } + if ( dragging_down && pointer_y > fixed_mid ) + parent.insertBefore(fixed_box, dragged_box); + else if ( !dragging_down && pointer_y < fixed_mid ) + parent.insertBefore(dragged_box, fixed_box); + else + return; +} -YAHOO.slashdot.SlashBox.prototype.onDragOut = function(e, id) - { - if ( id == this.deleteBoundaryId ) - { - var dragEl = this.getDragEl(); - var clickEl = this.getEl(); - YAHOO.util.Dom.addClass(dragEl, "to-be-deleted"); - YAHOO.util.Dom.addClass(clickEl, "to-be-deleted"); - // so we can style the object-to-be-moved in CSS - } - } +YAHOO.slashdot.SlashBox.prototype.onDragEnter = function(e, id) { + if ( id == this.deleteBoundaryId ) { + var dragEl = this.getDragEl(); + var clickEl = this.getEl(); + YAHOO.util.Dom.removeClass(dragEl, "to-be-deleted"); + YAHOO.util.Dom.removeClass(clickEl, "to-be-deleted"); + // so we can style the object-to-be-moved in CSS + } +} -YAHOO.slashdot.SlashBox.prototype.onDragDrop = function(e, id) - { - ajaxSaveSlashboxes(); - } +YAHOO.slashdot.SlashBox.prototype.onDragOut = function(e, id) { + if ( id == this.deleteBoundaryId ) { + var dragEl = this.getDragEl(); + var clickEl = this.getEl(); + YAHOO.util.Dom.addClass(dragEl, "to-be-deleted"); + YAHOO.util.Dom.addClass(clickEl, "to-be-deleted"); + // so we can style the object-to-be-moved in CSS + } +} + +YAHOO.slashdot.SlashBox.prototype.onDragDrop = function(e, id) { + ajaxSaveSlashboxes(); +} Modified: slashjp/trunk/plugins/Ajax/templates/data;ajax;default =================================================================== --- slashjp/trunk/plugins/Ajax/templates/data;ajax;default 2008-04-06 23:20:44 UTC (rev 571) +++ slashjp/trunk/plugins/Ajax/templates/data;ajax;default 2008-04-07 00:26:30 UTC (rev 572) @@ -10,11 +10,20 @@ en_US __name__ data -__seclev__ -10000 __template__ [% SWITCH value %] [% CASE 'set_section_prefs_success_msg' %] Close + +[% CASE 'inline preview warning' %] +

    This comment will not be saved until you click the Submit button below.

    + +[% CASE 'no modcommentlog' %] +

    No comment history available.

    + [% END %] +__seclev__ +1000 +__version__ +$Id$ Modified: slashjp/trunk/plugins/Ajax/templates/edit_comment;ajax;default =================================================================== --- slashjp/trunk/plugins/Ajax/templates/edit_comment;ajax;default 2008-04-06 23:20:44 UTC (rev 571) +++ slashjp/trunk/plugins/Ajax/templates/edit_comment;ajax;default 2008-04-07 00:26:30 UTC (rev 572) @@ -19,57 +19,67 @@ __name__ edit_comment __template__ -
    -[% this_title = pid ? reply.subject : discussion.title; - this_title = this_title | strip_html; - PROCESS titlebar title="Reply to: $this_title" %] +
    +[% IF user.is_anon %] +

    + [% IF constants.allow_anonymous %] + You are not logged in. You can log + in now, or Create an Account. + [% ELSE %] + You are not logged in. You can log + in now, Create an Account, + or post as [% user.nickname | strip_literal %]. + [% END %] +

    +[% END %] -

    If you have difficulty with this form, please use the old form.

    - -[% IF user.is_anon %]

    - [% IF constants.allow_anonymous %] -You are not logged in. You can log -in now, or Create an Account. - [% ELSE %] -You are not logged in. You can log -in now, Create an Account, -or post as [% user.nickname | strip_literal %]. - [% END %] -

    [% END %] - [% IF !user.is_anon || constants.allow_anonymous %] -
    -
    -
    - -[% IF pid %][% END %] - -[% reskey_label = "reskey_reply_$pid"; PROCESS reskey_tag %] -

    -[% UNLESS user.is_anon %][Options] -[%- IF constants.allow_anonymous && user.karma > -1 && (discussion.commentstatus == 'enabled' || discussion.commentstatus == 'logged_in') -%] - Post Anonymously -[%- END %]

    [% END %] -

    - -
    -
    -
    - - -[%- IF pid # not for root-level reply %] -[% END %] - - - -
    -
    +
    +
    +
    + + [% IF pid %][% END %] + + [% reskey_label = "reskey_reply_$pid"; PROCESS reskey_tag %] +
    +
    +

    + + [% UNLESS user.is_anon %] + [%- IF constants.allow_anonymous && user.karma > -1 && (discussion.commentstatus == 'enabled' || discussion.commentstatus == 'logged_in') -%] + Post Anonymously + [%- END %] + [% END %] +

    + [% UNLESS user.is_anon %]Preferences[% END %] +
    +
    +
    +

    If you have difficulty with this form, please use the old form.

    + +
    +
    + +
    + + + [%- IF pid # not for root-level reply %] + [% END %] + [%- UNLESS user.is_anon %] + [% END %] + + + + + +
    +
    [% END # IF !user.is_anon || constants.allow_anonymous %]
    - __seclev__ 1000 __version__ Copied: slashjp/trunk/plugins/Ajax/templates/hc_comment;ajax;default (from rev 571, slashjp/branches/upstream/current/plugins/Ajax/templates/hc_comment;ajax;default) =================================================================== --- slashjp/trunk/plugins/Ajax/templates/hc_comment;ajax;default (rev 0) +++ slashjp/trunk/plugins/Ajax/templates/hc_comment;ajax;default 2008-04-07 00:26:30 UTC (rev 572) @@ -0,0 +1,29 @@ +__section__ +default +__description__ +Template which renders the comment editor. + +* error_message = error message if there is an error +* preview = preview of comment, if applicable +* reply = hashref of comment replying to +* hide_name = hide name / log out link +* hide_email = hide email display +* extras = array of any extras associated with this comment + +__title__ + +__page__ +ajax +__lang__ +en_US +__name__ +hc_comment +__template__ +[% IF user.state.hc && !user.state.hcinvalid %] +

    [% user.state.hcquestion; user.state.hchtml %] + +[% END %] +__seclev__ +1000 +__version__ +$Id: hc_comment;ajax;default,v 1.1 2008/03/25 18:46:24 pudge Exp $ Modified: slashjp/trunk/plugins/Console/console.pl =================================================================== --- slashjp/trunk/plugins/Console/console.pl 2008-04-06 23:20:44 UTC (rev 571) +++ slashjp/trunk/plugins/Console/console.pl 2008-04-07 00:26:30 UTC (rev 572) @@ -65,8 +65,7 @@ my $tagnamesbox = ''; my $tags = getObject('Slash::Tags'); if ($tags) { - my $rtoi_ar = $tags->getRecentTagnamesOfInterest(); - $tagnamesbox = $tags->showRecentTagnamesBox(); + $tagnamesbox = $tags->showRecentTagnamesBox({ box_only => 1}); } slashDisplay('display', { Modified: slashjp/trunk/plugins/FireHose/FireHose.pm =================================================================== --- slashjp/trunk/plugins/FireHose/FireHose.pm 2008-04-06 23:20:44 UTC (rev 571) +++ slashjp/trunk/plugins/FireHose/FireHose.pm 2008-04-07 00:26:30 UTC (rev 572) @@ -380,6 +380,9 @@ $options ||= {}; $options->{limit} ||= 50; + my $ps = $options->{limit}; + + $options->{limit} += $options->{more_num} if $options->{more_num}; my $pop; $pop = $self->getMinPopularityForColorLevel($colors->{$options->{color}}) @@ -609,9 +612,10 @@ $other = 'GROUP BY firehose.id' if $options->{tagged_by_uid}; my $count_other = $other; + my $offset; if (1 || !$doublecheck) { # do always for now - my $offset = defined $options->{offset} ? $options->{offset} : ''; + $offset = defined $options->{offset} ? $options->{offset} : ''; $offset = '' if $offset !~ /^\d+$/; $offset = "$offset, " if length $offset; $limit_str = "LIMIT $offset $options->{limit}" unless $options->{nolimit}; @@ -630,10 +634,11 @@ } - my $page_size = $options->{limit} || 1; + my $page_size = $ps || 1; $results->{records_pages} ||= ceil($count / $page_size); $results->{records_page} ||= (int(($options->{offset} || 0) / $options->{limit}) + 1) || 1; + my $future_count = $count - $options->{limit} - ($options->{offset} || 0); if (keys %$filter_globjids) { for my $i (0 .. $#{$hr_ar}) { @@ -664,7 +669,7 @@ $items = $hr_ar; } - return($items, $results, $count); + return($items, $results, $count, $future_count); } # A single-globjid wrapper around getUserFireHoseVotesForGlobjs. @@ -1017,7 +1022,7 @@ } my $eval_first = ""; - for my $o (qw(startdate mode fhfilter orderdir orderby startdate duration color)) { + for my $o (qw(startdate mode fhfilter orderdir orderby startdate duration color more_num)) { my $value = $opts->{$o}; if ($o eq 'orderby' && $value eq 'editorpop') { $value = 'popularity'; @@ -1025,6 +1030,9 @@ if ($o eq 'startdate') { $value =~ s/-//g; } + if ($o eq 'more_num') { + $value ||= 0; + } $eval_first .= "firehose_settings.$o = " . Data::JavaScript::Anon->anon_dump("$value") . "; "; } @@ -1162,7 +1170,7 @@ my %ids = map { $_ => 1 } @ids; my %ids_orig = ( %ids ) ; my $opts = $firehose->getAndSetOptions({ no_set => 1 }); - my($items, $results) = $firehose_reader->getFireHoseEssentials($opts); + my($items, $results, $count, $future_count) = $firehose_reader->getFireHoseEssentials($opts); my $num_items = scalar @$items; my $future = {}; my $globjs = []; @@ -1304,6 +1312,7 @@ $html->{filter_text} = "Filtered to ".strip_literal($opts->{color})." '".strip_literal($opts->{fhfilter})."'"; $html->{gmt_update_time} = " (".timeCalc($slashdb->getTime(), "%H:%M", 0)." GMT) " if $user->{is_admin}; $html->{itemsreturned} = $num_items == 0 ? getData("noitems", { options => $opts }, 'firehose') : ""; + $html->{firehose_more} = getData("firehose_more_link", { options => $opts, future_count => $future_count, contentsonly => 1}, 'firehose'); my $data_dump = Data::JavaScript::Anon->anon_dump({ html => $html, @@ -2153,6 +2162,15 @@ if ($form->{not_id} && $form->{not_id} =~ /^\d+$/) { $options->{not_id} = $form->{not_id}; } + + + if ($form->{more_num} && $form->{more_num} =~ /^\d+$/) { + $options->{more_num} = $form->{more_num}; + if (!$user->{is_admin} && (($options->{limit} + $options->{more_num}) > 200)) { + $options->{more_num} = 200 - $options->{limit} ; + } + } + return $options; } @@ -2277,7 +2295,7 @@ if ($featured && $featured->{id}) { $options->{not_id} = $featured->{id}; } - my($items, $results) = $firehose_reader->getFireHoseEssentials($options); + my($items, $results, $count, $future_count) = $firehose_reader->getFireHoseEssentials($options); my $itemnum = scalar @$items; @@ -2346,6 +2364,8 @@ $section = $gSkin->{skid}; } + my $firehose_more = getData('firehose_more_link', { future_count => $future_count, options => $options }, 'firehose'); + slashDisplay("list", { itemstext => $itemstext, itemnum => $itemnum, @@ -2361,7 +2381,8 @@ fh_page => $base_page, search_results => $results, featured => $featured, - section => $section + section => $section, + firehose_more => $firehose_more }, { Page => "firehose", Return => 1 }); } Modified: slashjp/trunk/plugins/FireHose/templates/data;firehose;default =================================================================== --- slashjp/trunk/plugins/FireHose/templates/data;firehose;default 2008-04-06 23:20:44 UTC (rev 571) +++ slashjp/trunk/plugins/FireHose/templates/data;firehose;default 2008-04-07 00:26:30 UTC (rev 572) @@ -93,6 +93,24 @@ [% END %]

    +[% CASE 'firehose_more_link' %] + [% extra_onclick = '' %] + [% IF !contentsonly %] +

    + [% END %] + [% IF day_label && day_count; + label = day_count _ " more " _ $day_label _ "..."; + ELSIF future_count > 0; + label = future_count _ " more..."; + ELSIF future_count <= 0 && !options.startdate && options.duration != -1 && options.orderby == "createtime"; + label = "Get more..."; + extra_onclick = 'firehose_set_options(\'duration\', -1); '; + END; + %] + [% label %] + [% IF !contentsonly %] +
    + [% END %] [% CASE 'notavailable' %] The item you're trying to view either does not exist, or is not viewable to you. [% END %] Modified: slashjp/trunk/plugins/FireHose/templates/dispTopicFireHose;misc;default =================================================================== --- slashjp/trunk/plugins/FireHose/templates/dispTopicFireHose;misc;default 2008-04-06 23:20:44 UTC (rev 571) +++ slashjp/trunk/plugins/FireHose/templates/dispTopicFireHose;misc;default 2008-04-07 00:26:30 UTC (rev 572) @@ -14,12 +14,16 @@ 10000 __template__ [% topic = Slash.db.getTopic(item.tid) %] -[% IF (item.thumb && (item.type == "story" || (item.type == "submission" && adminmode))) %] +[% IF item.type == "story"; + story = Slash.db.getStory(item.srcid); + + END %] +[% IF item.thumb && ((item.type == "story" && (!story.thumb_signoff_needed || adminmode)) || (item.type == "submission" && adminmode)) %] [% file = Slash.db.getStaticFile(item.thumb); %] [% fh = Slash.getObject("Slash::FireHose"); link_url = fh.linkFireHose(item); %] - thumbnail
    [% IF item.media %][% END %]
    [% IF item.media %]
    Watch[% END %] + thumbnail
    [% IF item.media %][% END %]
    [% IF item.media %]
    Watch[% END %][% END %] [% ELSIF user.noicons || user.simpledesign || user.lowbandwidth %] [ [% topic.textname %] ] Modified: slashjp/trunk/plugins/FireHose/templates/fireHoseForm;misc;default =================================================================== --- slashjp/trunk/plugins/FireHose/templates/fireHoseForm;misc;default 2008-04-06 23:20:44 UTC (rev 571) +++ slashjp/trunk/plugins/FireHose/templates/fireHoseForm;misc;default 2008-04-07 00:26:30 UTC (rev 572) @@ -48,7 +48,7 @@ [% END %] [% IF needjssubmit %] [% END %] __version__ Modified: slashjp/trunk/plugins/FireHose/templates/firehose_pages;misc;default =================================================================== --- slashjp/trunk/plugins/FireHose/templates/firehose_pages;misc;default 2008-04-06 23:20:44 UTC (rev 571) +++ slashjp/trunk/plugins/FireHose/templates/firehose_pages;misc;default 2008-04-07 00:26:30 UTC (rev 572) @@ -66,7 +66,7 @@ IF i_page == start_page_num %] [% END; IF i_page == page_cur %][% i_page %][% ELSE; i_page; END; - IF i_page == end_page_num %] [% END %] + IF i_page == end_page_num %] [% END %] [% END; END; Modified: slashjp/trunk/plugins/FireHose/templates/list;firehose;default =================================================================== --- slashjp/trunk/plugins/FireHose/templates/list;firehose;default 2008-04-06 23:20:44 UTC (rev 571) +++ slashjp/trunk/plugins/FireHose/templates/list;firehose;default 2008-04-07 00:26:30 UTC (rev 572) @@ -153,6 +153,7 @@ [% IF itemnum == 0; Slash.getData('noitems', { options => options }, 'firehose'); END %] +[% firehose_more %] [% PROCESS paginate options = options ulid = "fh-paginate" divid = "fh-pag-div" num_items = itemnum fh_page = fh_page %] [% END %] -[% IF cid %] +[% IF cid && !discussion2 %]
      [% Slash.dispComment(comment) %]
    [% END %] - [% IF lvl %] - [% END %] + [% IF cid && !discussion2 %][% END %] + [% IF lvl; END %] [% lcp %] -[% IF discussion2 && !cid %] +[% IF discussion2 %]
    Check for more [% UNLESS user.state.discussion_archived || user.state.discussion_future_nopost %] @@ -112,7 +111,7 @@ op => 'reply', subject => 'Reply', subject_only => 1, - onclick => ((discussion2 && (!constants.subscribe || user.is_subscriber)) ? "replyTo(0); return false;" : '') + onclick => ((discussion2 && !user.is_anon) ? "replyTo(0); return false;" : '') }); END %]
    @@ -150,8 +149,7 @@ pieces_comments = [[% user.state.comments.pieces.join(',') %]]; init_hiddens = [[% user.state.comments.hiddens.join(',') %]]; - [% IF discussion2 == "slashdot" %]d2act(); - [% END -%]finishLoading(); + finishLoading(); //--> [% END %] Modified: slashjp/trunk/themes/slashcode/templates/printCommentsMain;misc;default =================================================================== --- slashjp/trunk/themes/slashcode/templates/printCommentsMain;misc;default 2008-04-06 23:20:44 UTC (rev 571) +++ slashjp/trunk/themes/slashcode/templates/printCommentsMain;misc;default 2008-04-07 00:26:30 UTC (rev 572) @@ -44,7 +44,7 @@
    -[% IF (!user.is_anon && !user.acl.discussion2_uofm) || user.is_admin %] +[% IF !user.is_anon %]
    @@ -62,10 +62,6 @@
    -[% END; IF (user.acl.discussion2_uofm_signup && !user.acl.discussion2_uofm && (user.is_admin || !user.is_subscriber)) && constants.uofm_key && constants.uofm_iv && env.http_user_agent.search('Firefox/1\.5') %] - [% END %] [% UNLESS discussion2 %] @@ -183,7 +179,7 @@ }) %] [% END %] - [% IF discussion2 && !cid && !pid %] + [% IF discussion2 %] More | [% END; IF user.is_admin && user.d2prefs_debug %] Prefs @@ -202,7 +198,7 @@ op => 'reply', subject => 'Reply', subject_only => 1, - onclick => ((discussion2 && (!constants.subscribe || user.is_subscriber)) ? "replyTo(0); return false;" : '') + onclick => ((discussion2 && !user.is_anon) ? "replyTo(0); return false;" : '') }) %] [% END %] @@ -218,6 +214,7 @@ init: function() { gCommentControlWidget = new YAHOO.slashdot.ThresholdWidget([% "'X'" IF horiz %]); gCommentControlWidget.setTHT(user_threshold, user_highlightthresh); + updateTotals(); } }; }(); @@ -269,7 +266,7 @@
    - [% IF discussion2 && !cid && !pid %] + [% IF discussion2 %] More | [% END; IF user.is_admin && user.d2prefs_debug %] Prefs @@ -287,7 +284,7 @@ op => 'reply', subject => 'Reply', subject_only => 1, - onclick => ((discussion2 && (!constants.subscribe || user.is_subscriber)) ? "replyTo(0); return false;" : '') + onclick => ((discussion2 && !user.is_anon) ? "replyTo(0); return false;" : '') }) %] [% END %]
    Keybindings Beta
    @@ -296,10 +293,16 @@ E
    A S -D +D
    +R +P +M
    +T +G +V
    -
    Loading ... Please wait.
    +
    Loading... please wait.
    Copied: slashjp/trunk/themes/slashcode/templates/userInfo2;users;default (from rev 571, slashjp/branches/upstream/current/themes/slashcode/templates/userInfo2;users;default) =================================================================== --- slashjp/trunk/themes/slashcode/templates/userInfo2;users;default (rev 0) +++ slashjp/trunk/themes/slashcode/templates/userInfo2;users;default 2008-04-07 00:26:30 UTC (rev 572) @@ -0,0 +1,44 @@ +__section__ +default +__description__ +Display user's info + +* title = passed to titlebar +* useredit = hashref of info of the user being viewed +* points = available moderation points +* commentstruct = arrayref of comments +* nickmatch_flag = current user is same as viewed user +* mod_flag = is moderator + (no need for this anymore) +* karma_flag = boolean for display karma +* admin_block = admin stuff +* admin_flag = boolean for whether to display admin stuff + (no real need for this, could just use user.is_admin) +* fieldkey = the field key used to decide what we're looking at +* reasons = hashref from $moddb->getReasons() +* lastjournal = last journal posted +* hr_hours_back = number of hours back to show a
    for +* cids_to_mods = hashref keyed by cid containing arrays of moderations done to that cid +* comment_time = number of days back we are limiting the comments shown to. If 0 or undefined we're showing comments sequentially w/o time limits + +__title__ + +__page__ +users +__lang__ +en_US +__name__ +userInfo2 +__template__ +[% orig_title = title %] + +
    +[% PROCESS userboxes2 %] +
    + +[% title = orig_title %] + +__seclev__ +500 +__version__ +$Id: userInfo2;users;default,v 1.1 2008/04/02 14:42:24 entweichen Exp $ Copied: slashjp/trunk/themes/slashcode/templates/userboxes2;misc;default (from rev 571, slashjp/branches/upstream/current/themes/slashcode/templates/userboxes2;misc;default) =================================================================== --- slashjp/trunk/themes/slashcode/templates/userboxes2;misc;default (rev 0) +++ slashjp/trunk/themes/slashcode/templates/userboxes2;misc;default 2008-04-07 00:26:30 UTC (rev 572) @@ -0,0 +1,147 @@ +__section__ +default +__description__ +Displays the three user boxes (fancybox's). + +* useredit = user being viewed ("edit" is for historical reasons) + (if not given, the standard "user" will be used) + +__title__ + +__page__ +misc +__lang__ +en_US +__name__ +userboxes2 +__template__ +[% + +IF !useredit; useredit = user; END; + +IF !useredit.is_anon; + + # First box: general user info + + title = 'User Bio'; + contents = BLOCK; + ''; + useredit.nickname | strip_literal; ' '; + PROCESS zoo_icons person=useredit.uid implied=""; + IF user.uid == useredit.uid OR user.is_admin; + # Looking at ourselves; show our real name and email info. + '
    '; IF useredit.realname; useredit.realname | strip_literal; ELSE; '(no real name given)'; END; + '
    '; + Slash.ellipsify(Slash.strip_literal(useredit.realemail)); ''; + '
      '; + IF useredit.fakeemail; + IF useredit.fakeemail == useredit.realemail; + '(shown without obfuscation)'; + ELSE; + 'shown as '; + Slash.ellipsify(Slash.strip_literal(useredit.fakeemail)); ''; + END; + ELSE; + '(email not shown publicly)'; + END; + ELSE; + # Looking at someone else; show fake email info. + '
      '; + IF useredit.fakeemail; + ''; + Slash.ellipsify(Slash.strip_literal(useredit.fakeemail)); ''; + ELSE; + '(email not shown publicly)'; + END; + END; + + IF useredit.homepage; + '
    '; + Slash.ellipsify(Slash.strip_literal(useredit.homepage)); ''; + END; + + IF user.uid == useredit.uid OR user.is_admin; + '
    Karma: '; + PROCESS karma karma=useredit.karma admin_flag=user.is_admin; + END; + + IF useredit.aim && !useredit.aimdisplay; + '
    AOL IM: '; + useredit.aim | strip_literal; + ' (Add Buddy, '; + 'Send Message)'; + END; + + IF useredit.yahoo; + '
    Yahoo! ID: '; + ''; + useredit.yahoo | strip_literal; + ' (Add User, '; + 'Send Message)'; + END; + + IF useredit.jabber; + '
    Jabber: '; + useredit.jabber | strip_literal; + END; + + IF useredit.calendar_url; + '
    Public Calendar: '; + 'Subscribe, Download'; + END; + + IF useredit.bio; + '

    '; + Slash.parseDomainTags(useredit.bio); + END; + + END; + Slash.sidebox(title, contents, "user-info", 1); + + # Latest comments box + contents = ''; + FOREACH cid = latest_comments.keys.sort; + contents = contents _ '' _ latest_comments.$cid.subject _ '
    '; + END; + title = 'Latest Comments'; + Slash.sidebox(title, contents, "user-info", 1); + + # Latest journals box + contents = ''; + FOREACH jid = latest_journals.keys.sort; + contents = contents _ '' _ latest_journals.$jid.desc _ '
    '; + END; + title = 'Latest Journal Entries'; + Slash.sidebox(title, contents, "user-info", 1); + +END %] + +__seclev__ +1000 +__version__ +$Id: userboxes2;misc;default,v 1.1 2008/04/02 14:41:12 entweichen Exp $ Modified: slashjp/trunk/utils/createTestTags =================================================================== --- slashjp/trunk/utils/createTestTags 2008-04-06 23:20:44 UTC (rev 571) +++ slashjp/trunk/utils/createTestTags 2008-04-07 00:26:30 UTC (rev 572) @@ -63,7 +63,7 @@ my $stories = $slashdb->getStoriesEssentials({ future_secs => 0, limit => 10, limit_extra => 0, sectioncollapse => (rand(1) < 0.3) ? 1 : 0 }); - + my $priv_tagnames = $tagsdb->getPrivateTagnames(); my $firehose = getObject('Slash::FireHose'); my $minfhcolor = (rand(1) < 0.4 ? 5 : 7); my($firehose_items, $firehose_results) = @@ -88,11 +88,14 @@ $uid = _get_uid($tagsdb, $stoid); $tagnameid = _get_tagnameid($tagsdb, $tagnameid, $stoid, $uid); + my $tagname = $tagsdb->getTagnameDataFromId($tagnameid)->{tagname}; + my $is_private = $priv_tagnames->{$tagname}; my $tagid = $tagsdb->createTag({ uid => $uid, tagnameid => $tagnameid, table => 'stories', id => $stoid, + private => $is_private, }); print "tagid=$tagid tagnameid=$tagnameid uid=$uid stoid=$stoid\n"; } else { @@ -103,10 +106,13 @@ "karma BETWEEN $kmin AND $kmax", 'ORDER BY RAND() LIMIT 1') if !$uid || rand(1) > 0.2; $tagnameid = _get_tagnameid($tagsdb, $tagnameid, $globjid, $uid); + my $tagname = $tagsdb->getTagnameDataFromId($tagnameid)->{tagname}; + my $is_private = $priv_tagnames->{$tagname}; my $tagid = $tagsdb->createTag({ uid => $uid, tagnameid => $tagnameid, globjid => $globjid, + private => $is_private, }); print "tagid=$tagid tagnameid=$tagnameid uid=$uid globjid=$globjid\n"; } From svnnotify ¡÷ sourceforge.jp Mon Apr 7 10:53:35 2008 From: svnnotify ¡÷ sourceforge.jp (svnnotify ¡÷ sourceforge.jp) Date: Mon, 07 Apr 2008 10:53:35 +0900 Subject: [Slashdotjp-dev 1046] [573] fix typo Message-ID: <1207533215.552469.23813.nullmailer@users.sourceforge.jp> Revision: 573 http://svn.sourceforge.jp/cgi-bin/viewcvs.cgi?root=slashdotjp&view=rev&rev=573 Author: tach Date: 2008-04-07 10:53:35 +0900 (Mon, 07 Apr 2008) Log Message: ----------- fix typo Modified Paths: -------------- images/Makefile -------------- next part -------------- Modified: images/Makefile =================================================================== --- images/Makefile 2008-04-07 00:26:30 UTC (rev 572) +++ images/Makefile 2008-04-07 01:53:35 UTC (rev 573) @@ -50,7 +50,7 @@ force: clean default clean: - rm -f css/*.css.orig *.js.orig image-stamp \ + rm -f css/*.css.orig *.js.orig images-stamp \ $(patsubst %,css/%.css, $(csses)) \ $(patsubst %,css/slashdot_%.css, $(sections)) \ $(patsubst %,%.js, $(jses)) From svnnotify ¡÷ sourceforge.jp Mon Apr 7 10:58:30 2008 From: svnnotify ¡÷ sourceforge.jp (svnnotify ¡÷ sourceforge.jp) Date: Mon, 07 Apr 2008 10:58:30 +0900 Subject: [Slashdotjp-dev 1047] [574] add new images Message-ID: <1207533510.650829.28450.nullmailer@users.sourceforge.jp> Revision: 574 http://svn.sourceforge.jp/cgi-bin/viewcvs.cgi?root=slashdotjp&view=rev&rev=574 Author: tach Date: 2008-04-07 10:58:30 +0900 (Mon, 07 Apr 2008) Log Message: ----------- add new images Added Paths: ----------- images/corner_w_bl.png images/corner_w_tl.png images/corner_w_tr.png images/dark_fade_30.png images/dark_fade_g.png images/s3a_controls.png -------------- next part -------------- Added: images/corner_w_bl.png =================================================================== (Binary files differ) Property changes on: images/corner_w_bl.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: images/corner_w_tl.png =================================================================== (Binary files differ) Property changes on: images/corner_w_tl.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: images/corner_w_tr.png =================================================================== (Binary files differ) Property changes on: images/corner_w_tr.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: images/dark_fade_30.png =================================================================== (Binary files differ) Property changes on: images/dark_fade_30.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: images/dark_fade_g.png =================================================================== (Binary files differ) Property changes on: images/dark_fade_g.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: images/s3a_controls.png =================================================================== (Binary files differ) Property changes on: images/s3a_controls.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream From svnnotify ¡÷ sourceforge.jp Mon Apr 7 12:21:05 2008 From: svnnotify ¡÷ sourceforge.jp (svnnotify ¡÷ sourceforge.jp) Date: Mon, 07 Apr 2008 12:21:05 +0900 Subject: [Slashdotjp-dev 1048] [575] add slash_2.5.0.200.orig.tar.gz Message-ID: <1207538465.941185.4008.nullmailer@users.sourceforge.jp> Revision: 575 http://svn.sourceforge.jp/cgi-bin/viewcvs.cgi?root=slashdotjp&view=rev&rev=575 Author: tach Date: 2008-04-07 12:21:05 +0900 (Mon, 07 Apr 2008) Log Message: ----------- add slash_2.5.0.200.orig.tar.gz Added Paths: ----------- slashjp/tarballs/slash_2.5.0.200.orig.tar.gz -------------- next part -------------- Added: slashjp/tarballs/slash_2.5.0.200.orig.tar.gz =================================================================== (Binary files differ) Property changes on: slashjp/tarballs/slash_2.5.0.200.orig.tar.gz ___________________________________________________________________ Name: svn:mime-type + application/octet-stream From svnnotify ¡÷ sourceforge.jp Mon Apr 7 14:09:04 2008 From: svnnotify ¡÷ sourceforge.jp (svnnotify ¡÷ sourceforge.jp) Date: Mon, 07 Apr 2008 14:09:04 +0900 Subject: [Slashdotjp-dev 1049] [576] Fix anonymous comment interval function Message-ID: <1207544944.414273.25109.nullmailer@users.sourceforge.jp> Revision: 576 http://svn.sourceforge.jp/cgi-bin/viewcvs.cgi?root=slashdotjp&view=rev&rev=576 Author: tach Date: 2008-04-07 14:09:04 +0900 (Mon, 07 Apr 2008) Log Message: ----------- Fix anonymous comment interval function Modified Paths: -------------- slashjp/trunk/Slash/Utility/Comments/Comments.pm -------------- next part -------------- Modified: slashjp/trunk/Slash/Utility/Comments/Comments.pm =================================================================== --- slashjp/trunk/Slash/Utility/Comments/Comments.pm 2008-04-07 03:21:05 UTC (rev 575) +++ slashjp/trunk/Slash/Utility/Comments/Comments.pm 2008-04-07 05:09:04 UTC (rev 576) @@ -1448,9 +1448,8 @@ AND date > SUBDATE(NOW(), INTERVAL $constants->{anonymous_comment_interval} MINUTE) AND ipid='$ipid'"); if ($ipid_count > 0) { - header('Comments', $discussion->{section}) or return; - editComment(@_, getError('anonymous_comment_interval')); - return 0; + $$error_message = getError('anonymous_comment_interval'); + return -1; } } From svnnotify ¡÷ sourceforge.jp Fri Apr 11 16:28:41 2008 From: svnnotify ¡÷ sourceforge.jp (svnnotify ¡÷ sourceforge.jp) Date: Fri, 11 Apr 2008 16:28:41 +0900 Subject: [Slashdotjp-dev 1050] [577] merged from upstream T_2_5_0_201 Message-ID: <1207898921.705717.27326.nullmailer@users.sourceforge.jp> Revision: 577 http://svn.sourceforge.jp/cgi-bin/viewcvs.cgi?root=slashdotjp&view=rev&rev=577 Author: tach Date: 2008-04-11 16:28:41 +0900 (Fri, 11 Apr 2008) Log Message: ----------- merged from upstream T_2_5_0_201 Modified Paths: -------------- slashjp/branches/upstream/current/Slash/DB/MySQL/MySQL.pm slashjp/branches/upstream/current/Slash/Utility/Anchor/Anchor.pm slashjp/branches/upstream/current/Slash/Utility/Comments/Comments.pm slashjp/branches/upstream/current/Slash/XML/RSS/RSS.pm slashjp/branches/upstream/current/plugins/Ajax/htdocs/ajax.pl slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/admin.js slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/common.js slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/slashbox.js slashjp/branches/upstream/current/plugins/Ajax/templates/edit_comment;ajax;default slashjp/branches/upstream/current/plugins/Ajax/templates/modal_footer;misc;default slashjp/branches/upstream/current/plugins/Ajax/templates/prefs_d2;ajax;default slashjp/branches/upstream/current/plugins/FAQSlashdot/faq/UI.shtml slashjp/branches/upstream/current/plugins/FAQSlashdot/faq/accounts.shtml slashjp/branches/upstream/current/plugins/FAQSlashdot/faq/advertising.shtml slashjp/branches/upstream/current/plugins/FAQSlashdot/faq/badges.shtml slashjp/branches/upstream/current/plugins/FAQSlashdot/faq/com-mod.shtml slashjp/branches/upstream/current/plugins/FAQSlashdot/faq/editorial.shtml slashjp/branches/upstream/current/plugins/FAQSlashdot/faq/faq-meta.shtml slashjp/branches/upstream/current/plugins/FAQSlashdot/faq/feeds.shtml slashjp/branches/upstream/current/plugins/FAQSlashdot/faq/firehose.shtml slashjp/branches/upstream/current/plugins/FAQSlashdot/faq/friends.shtml slashjp/branches/upstream/current/plugins/FAQSlashdot/faq/index.shtml slashjp/branches/upstream/current/plugins/FAQSlashdot/faq/interviews.shtml slashjp/branches/upstream/current/plugins/FAQSlashdot/faq/metamod.shtml slashjp/branches/upstream/current/plugins/FAQSlashdot/faq/slashmeta.shtml slashjp/branches/upstream/current/plugins/FAQSlashdot/faq/subscriptions.shtml slashjp/branches/upstream/current/plugins/FAQSlashdot/faq/suggestions.shtml slashjp/branches/upstream/current/plugins/FAQSlashdot/faq/tags.shtml slashjp/branches/upstream/current/plugins/FAQSlashdot/faq/tech.shtml slashjp/branches/upstream/current/plugins/FireHose/FireHose.pm slashjp/branches/upstream/current/plugins/FireHose/firehose.css slashjp/branches/upstream/current/plugins/FireHose/mysql_dump.sql slashjp/branches/upstream/current/plugins/FireHose/mysql_schema.sql slashjp/branches/upstream/current/plugins/FireHose/templates/data;firehose;default slashjp/branches/upstream/current/plugins/FireHose/templates/list;firehose;default slashjp/branches/upstream/current/plugins/FireHose/templates/paginate;firehose;default slashjp/branches/upstream/current/plugins/Journal/journal.pl slashjp/branches/upstream/current/plugins/ResKey/ResKey/Checks/Duration.pm slashjp/branches/upstream/current/plugins/ResKey/ResKey/Key.pm slashjp/branches/upstream/current/plugins/ResKey/example.plx slashjp/branches/upstream/current/plugins/ResKey/mysql_dump.sql slashjp/branches/upstream/current/plugins/Stats/Stats.pm slashjp/branches/upstream/current/sql/mysql/defaults.sql slashjp/branches/upstream/current/sql/mysql/upgrades slashjp/branches/upstream/current/tagboxes/Despam/Despam.pm slashjp/branches/upstream/current/themes/slashcode/THEME slashjp/branches/upstream/current/themes/slashcode/htdocs/comments.css slashjp/branches/upstream/current/themes/slashcode/htdocs/comments.pl slashjp/branches/upstream/current/themes/slashcode/htdocs/images/comments.js slashjp/branches/upstream/current/themes/slashcode/htdocs/users2.pl slashjp/branches/upstream/current/themes/slashcode/templates/dispLinkComment;misc;default slashjp/branches/upstream/current/themes/slashcode/templates/printCommComments;misc;default slashjp/branches/upstream/current/themes/slashcode/templates/printCommentsMain;misc;default slashjp/branches/upstream/current/themes/slashcode/templates/userInfo2;users;default Added Paths: ----------- slashjp/branches/upstream/current/themes/slashcode/templates/printCommentsLinks;misc;default Removed Paths: ------------- slashjp/branches/upstream/current/themes/slashcode/templates/d2prefs;misc;default -------------- next part -------------- Modified: slashjp/branches/upstream/current/Slash/DB/MySQL/MySQL.pm =================================================================== --- slashjp/branches/upstream/current/Slash/DB/MySQL/MySQL.pm 2008-04-07 05:09:04 UTC (rev 576) +++ slashjp/branches/upstream/current/Slash/DB/MySQL/MySQL.pm 2008-04-11 07:28:41 UTC (rev 577) @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. # Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: MySQL.pm,v 1.1012 2008/03/27 16:56:27 tvroom Exp $ +# $Id: MySQL.pm,v 1.1013 2008/04/09 22:01:06 jamiemccarthy Exp $ package Slash::DB::MySQL; use strict; @@ -20,7 +20,7 @@ use base 'Slash::DB::Utility'; use Slash::Constants ':messages'; -($VERSION) = ' $Revision: 1.1012 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.1013 $ ' =~ /\$Revision:\s+([^\s]+)/; # Fry: How can I live my life if I can't tell good from evil? @@ -1753,7 +1753,7 @@ $self->sqlUpdate('users', { passwd => $enc, newpasswd => $enc, - newpasswd_ts => undef, + newpasswd_ts => undef, # should this be NOW() ? }, 'uid=' . $self->sqlQuote($uid)); return $newpasswd; } @@ -5071,7 +5071,10 @@ my @aliases = grep { $_ } split /\s+/, $alias_text; for my $alias (@aliases) { my($src, $implied) = $alias =~ /^(\w+)->(\w+)$/; - $_al2_type_aliases->{$src} = $implied if $src && $implied; + if ($src && $implied) { + $_al2_type_aliases->{$src} ||= [ ]; + push @{ $_al2_type_aliases->{$src} }, $implied; + } } } sub getAL2TypeAliases { @@ -5295,8 +5298,10 @@ my $aliases = $self->getAL2TypeAliases(); for my $src (keys %$aliases) { if ($retval->{$src}) { - my $implied = $aliases->{$src}; - $retval->{$implied} = { implied_by => $src }; + my $implied_ar = $aliases->{$src}; + for my $imp (@$implied_ar) { + $retval->{$imp} ||= { implied_by => $src }; + } } } Modified: slashjp/branches/upstream/current/Slash/Utility/Anchor/Anchor.pm =================================================================== --- slashjp/branches/upstream/current/Slash/Utility/Anchor/Anchor.pm 2008-04-07 05:09:04 UTC (rev 576) +++ slashjp/branches/upstream/current/Slash/Utility/Anchor/Anchor.pm 2008-04-11 07:28:41 UTC (rev 577) @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. # Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Anchor.pm,v 1.89 2007/06/27 00:12:14 jamiemccarthy Exp $ +# $Id: Anchor.pm,v 1.91 2008/04/10 21:23:38 pudge Exp $ package Slash::Utility::Anchor; @@ -36,9 +36,10 @@ use base 'Exporter'; use vars qw($VERSION @EXPORT); -($VERSION) = ' $Revision: 1.89 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.91 $ ' =~ /\$Revision:\s+([^\s]+)/; @EXPORT = qw( http_send + get_etag header footer redirect @@ -268,7 +269,7 @@ if ($opt->{etag} || $opt->{do_etag}) { if ($opt->{do_etag} && $opt->{content}) { - $opt->{etag} = md5_hex($opt->{content}); + $opt->{etag} = get_etag($opt->{content}); } $r->header_out('ETag', $opt->{etag}); @@ -305,8 +306,11 @@ return 1; } +sub get_etag { + my($content) = @_; + return md5_hex($content); +} - #======================================================================== =head2 footer(OPTIONS) @@ -749,4 +753,4 @@ =head1 VERSION -$Id: Anchor.pm,v 1.89 2007/06/27 00:12:14 jamiemccarthy Exp $ +$Id: Anchor.pm,v 1.91 2008/04/10 21:23:38 pudge Exp $ Modified: slashjp/branches/upstream/current/Slash/Utility/Comments/Comments.pm =================================================================== --- slashjp/branches/upstream/current/Slash/Utility/Comments/Comments.pm 2008-04-07 05:09:04 UTC (rev 576) +++ slashjp/branches/upstream/current/Slash/Utility/Comments/Comments.pm 2008-04-11 07:28:41 UTC (rev 577) @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. # Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Comments.pm,v 1.19 2008/04/03 00:38:32 pudge Exp $ +# $Id: Comments.pm,v 1.20 2008/04/10 05:22:29 pudge Exp $ package Slash::Utility::Comments; @@ -34,7 +34,7 @@ use base 'Exporter'; use vars qw($VERSION @EXPORT); -($VERSION) = ' $Revision: 1.19 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.20 $ ' =~ /\$Revision:\s+([^\s]+)/; @EXPORT = qw( constrain_score dispComment displayThread printComments jsSelectComments commentCountThreshold commentThresholds discussion2 @@ -327,11 +327,13 @@ $parent = { cid => $C->{pid}, pid => ($old_comments{ $C->{pid} } && $old_comments{ $C->{pid} }{ pid }) || 0, + opid => ($old_comments{ $C->{pid} } && $old_comments{ $C->{pid} }{ original_pid }) || 0, kids => [ ], points => -2, dummy => 1, %$parent, }; + $parent->{opid} ||= $parent->{pid}; } $comments->{ $C->{pid} } = $parent; } @@ -419,6 +421,7 @@ my @keys = qw(pid points uid); for my $cid (grep $_, keys %$comments) { @{$comments_new->{$cid}}{@keys} = @{$comments->{$cid}}{@keys}; + $comments_new->{$cid}{opid} = $comments->{$cid}{original_pid}; $comments_new->{$cid}{kids} = [sort { $a <=> $b } @{$comments->{$cid}{kids}}]; # we only care about it if it is not original ... we could @@ -454,6 +457,9 @@ $total--; # off by one $extra .= "d2_seen = '$d2_seen_0';\nmore_comments_num = $total;\n"; } + if ($user->{d2_keybindings_switch}) { + $extra .= "d2_keybindings_off = 1;\n"; + } # maybe also check if this ad should be running with some other var? # from ads table? -- pudge @@ -2025,7 +2031,7 @@ op => 'Reply', subject => 'Reply to This', subject_only => 1, - onclick => (($discussion2 && !$user->{is_anon}) ? "replyTo($comment->{cid}); return false;" : '') + onclick => ($discussion2 ? "replyTo($comment->{cid}); return false;" : '') }) . '

    ') unless $user->{state}{discussion_archived}; push @link, (qq'

    ' . linkComment({ @@ -2546,4 +2552,4 @@ =head1 VERSION -$Id: Comments.pm,v 1.19 2008/04/03 00:38:32 pudge Exp $ +$Id: Comments.pm,v 1.20 2008/04/10 05:22:29 pudge Exp $ Modified: slashjp/branches/upstream/current/Slash/XML/RSS/RSS.pm =================================================================== --- slashjp/branches/upstream/current/Slash/XML/RSS/RSS.pm 2008-04-07 05:09:04 UTC (rev 576) +++ slashjp/branches/upstream/current/Slash/XML/RSS/RSS.pm 2008-04-11 07:28:41 UTC (rev 577) @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. # Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: RSS.pm,v 1.39 2007/10/04 19:38:34 pudge Exp $ +# $Id: RSS.pm,v 1.41 2008/04/10 17:01:52 scc Exp $ package Slash::XML::RSS; @@ -32,7 +32,7 @@ use base 'Slash::XML'; use vars qw($VERSION); -($VERSION) = ' $Revision: 1.39 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.41 $ ' =~ /\$Revision:\s+([^\s]+)/; #======================================================================== @@ -433,6 +433,7 @@ my $desc = $self->rss_item_description($item->{description} || $story->{introtext}); if ($desc) { $encoded_item->{description} = $desc; + $encoded_item->{description} .= qq{

    }; $encoded_item->{description} .= "

    Read more of this story at $constants->{sitename}.

    " if $action; # add poll if any $encoded_item->{description} .= pollbooth($story->{qid},1, 0, 1) if $story->{qid}; @@ -575,4 +576,4 @@ =head1 VERSION -$Id: RSS.pm,v 1.39 2007/10/04 19:38:34 pudge Exp $ +$Id: RSS.pm,v 1.41 2008/04/10 17:01:52 scc Exp $ Modified: slashjp/branches/upstream/current/plugins/Ajax/htdocs/ajax.pl =================================================================== --- slashjp/branches/upstream/current/plugins/Ajax/htdocs/ajax.pl 2008-04-07 05:09:04 UTC (rev 576) +++ slashjp/branches/upstream/current/plugins/Ajax/htdocs/ajax.pl 2008-04-11 07:28:41 UTC (rev 577) @@ -2,7 +2,7 @@ # This code is a part of Slash, and is released under the GPL. # Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: ajax.pl,v 1.84 2008/03/31 21:43:56 pudge Exp $ +# $Id: ajax.pl,v 1.87 2008/04/11 01:12:38 pudge Exp $ use strict; use warnings; @@ -14,7 +14,7 @@ use Slash::Utility; use vars qw($VERSION); -($VERSION) = ' $Revision: 1.84 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.87 $ ' =~ /\$Revision:\s+([^\s]+)/; ################################################################## sub main { @@ -287,15 +287,23 @@ unless $error_message; my $cid = $saved_comment && $saved_comment ne '-1' ? $saved_comment->{cid} : 0; + $options->{content_type} = 'application/json'; + my %to_dump = ( cid => $cid ); + if ($error_message) { $error_message = getData('inline preview warning') . $error_message unless $options->{rkey}->death; # go back to HumanConf if we still have errors left to display $error_message .= slashDisplay('hc_comment', { pid => $pid }, { Return => 1 }); + $to_dump{error} = $error_message; + + my $max_duration = $options->{rkey}->max_duration; + if (defined($max_duration) && length($max_duration)) { + $max_duration = 0 if $max_duration > 60; + $to_dump{eval_last} = "submitCountdown($pid,$max_duration);" + } } - $options->{content_type} = 'application/json'; - my %to_dump = ( cid => $cid, error => $error_message ); #use Data::Dumper; print STDERR Dumper \%to_dump; return Data::JavaScript::Anon->anon_dump(\%to_dump); @@ -312,7 +320,7 @@ my $discussion = $slashdb->getDiscussion($sid); my $comment = preProcessComment($form, $user, $discussion, \$error_message); if ($comment && $comment ne '-1') { - my $preview = postProcessComment({ %$comment, %$form, %$user }, 0, $discussion); + my $preview = postProcessComment({ %$user, %$form, %$comment }, 0, $discussion); $html = prevComment($preview, $user); } @@ -329,6 +337,13 @@ if $form->{gotmodwarning} || ($error_message && $error_message eq Slash::Utility::Comments::getError("moderations to be lost") ); + + my $max_duration = $options->{rkey}->max_duration; + if (defined($max_duration) && length($max_duration)) { + $max_duration = 0 if $max_duration > 60; + $to_dump{eval_last} = "submitCountdown($pid,$max_duration);" + } + #use Data::Dumper; print STDERR Dumper \%to_dump; return Data::JavaScript::Anon->anon_dump(\%to_dump); @@ -368,6 +383,7 @@ $options->{content_type} = 'application/json'; $to_dump{eval_first} = "comment_body_reply[$pid] = '$pid_reply';" if $pid_reply; + #use Data::Dumper; print STDERR Dumper \%to_dump; return Data::JavaScript::Anon->anon_dump(\%to_dump); @@ -792,12 +808,17 @@ my $user_edits_table; if ($params{'formname'} eq 'd2_display') { $user_edits_table = { - discussion2 => ($params{'discussion2'}) ? 'slashdot' : 'none', - d2_comment_q => $params{'d2_comment_q'} || undef, - d2_comment_order => $params{'d2_comment_order'} || undef, - nosigs => ($params{'nosigs'} ? 1 : 0), - noscores => ($params{'noscores'} ? 1 : 0), - domaintags => ($params{'domaintags'} != 2 ? $params{'domaintags'} : undef), + discussion2 => ($params{'discussion2'}) ? 'slashdot' : 'none', + # i know the logic here is backward, but it still makes the most sense to me! + # we only want to save the pref for people who turn it off, but the checkbox + # is on by default, so if the value is true then it is on, and if false, + # it is off -- pudge + d2_keybindings_switch => $params{'d2_keybindings_switch'} ? undef : 1, + d2_comment_q => $params{'d2_comment_q'} || undef, + d2_comment_order => $params{'d2_comment_order'} || undef, + nosigs => ($params{'nosigs'} ? 1 : 0), + noscores => ($params{'noscores'} ? 1 : 0), + domaintags => ($params{'domaintags'} != 2 ? $params{'domaintags'} : undef), }; } Modified: slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/admin.js =================================================================== --- slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/admin.js 2008-04-07 05:09:04 UTC (rev 576) +++ slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/admin.js 2008-04-11 07:28:41 UTC (rev 577) @@ -1,34 +1,32 @@ -// $Id: admin.js,v 1.49 2008/03/27 20:12:17 tvroom Exp $ +// $Id: admin.js,v 1.50 2008/04/08 17:52:30 scc Exp $ function um_ajax(the_behaviors, the_events) { - var params = {}; - params['op'] = 'um_ajax'; - params['behaviors'] = the_behaviors; - params['events'] = the_events; - ajax_update(params, 'links-vendors-content'); + ajax_update({ + op: 'um_ajax', + behaviors: the_behaviors, + events: the_events + }, 'links-vendors-content'); } function um_fetch_settings() { - var params = {}; - params['op'] = 'um_fetch_settings'; - ajax_update(params, 'links-vendors-content'); + ajax_update({ op: 'um_fetch_settings' }, 'links-vendors-content'); } function um_set_settings(behavior) { - var params = {}; - params['op'] = 'um_set_settings'; - params['behavior'] = behavior; - ajax_update(params, 'links-vendors-content'); + ajax_update({ + op: 'um_set_settings', + behavior: behavior + }, 'links-vendors-content'); } function admin_neverdisplay(stoid, type, fhid) { - var params = {}; - params['op'] = 'admin_neverdisplay'; - params['reskey'] = reskey_static; - params['stoid'] = stoid; - params['fhid'] = fhid; if (confirm("Set story to neverdisplay?")) { - ajax_update(params, 'nvd-' + stoid); + ajax_update({ + op: 'admin_neverdisplay', + reskey: reskey_static, + stoid: stoid, + fhid: fhid + }, 'nvd-' + stoid); if (type == "firehose") { firehose_remove_entry(fhid); } @@ -36,12 +34,12 @@ } function admin_submit_memory(fhid) { - var params = {}; - params['op'] = 'admin_submit_memory'; - params['reskey'] = reskey_static; - params['submatch'] = $dom('submatch-'+fhid).value; - params['subnote'] = $dom('subnote-'+fhid).value; - ajax_update(params, 'sub_mem_message-'+fhid); + ajax_update({ + op: 'admin_submit_memory', + reskey: reskey_static, + submatch: $('#submatch-'+fhid).val(), + subnote: $('#subnote-'+fhid).val() + }, 'sub_mem_message-'+fhid); } function adminTagsCommands(id, type) { @@ -154,33 +152,23 @@ } function admin_slashdbox_fetch(secs) { - var params = {}; - params['op'] = 'admin_slashdbox'; - ajax_periodic_update(secs, params, "slashdbox-content"); + ajax_periodic_update(secs, { op: 'admin_slashdbox' }, "slashdbox-content"); } function admin_perfbox_fetch(secs) { - var params = {}; - params['op'] = 'admin_perfbox'; - ajax_periodic_update(secs, params, "performancebox-content"); + ajax_periodic_update(secs, { op: 'admin_perfbox' }, "performancebox-content"); } function admin_authorbox_fetch(secs) { - var params = {}; - params['op'] = 'admin_authorbox'; - ajax_periodic_update(secs, params, "authoractivity-content"); + ajax_periodic_update(secs, { op: 'admin_authorbox' }, "authoractivity-content"); } function admin_storyadminbox_fetch(secs) { - var params = {}; - params['op'] = 'admin_storyadminbox'; - ajax_periodic_update(secs, params, "storyadmin-content"); + ajax_periodic_update(secs, { op: 'admin_storyadminbox' }, "storyadmin-content"); } function admin_recenttagnamesbox_fetch(secs) { - var params = {}; - params['op'] = 'admin_recenttagnamesbox'; - ajax_periodic_update(secs, params, "recenttagnames-content"); + ajax_periodic_update(secs, { op: 'admin_recenttagnamesbox' }, "recenttagnames-content"); } function console_update(use_fh_interval, require_fh_timeout) { @@ -190,24 +178,17 @@ return; } - var params = {}; - params['op'] = 'console_update' - var handlers = { - onComplete: json_handler - }; - ajax_update(params, '', handlers); + ajax_update({ op: 'console_update' }, '', { onComplete: json_handler }); var interval = 30000; if(use_fh_interval) { interval = getFirehoseUpdateInterval(); } - setTimeout("console_update(" + use_fh_interval + "," + fh_is_timed_out +")", interval * 2); + setTimeout(function(){console_update(use_fh_interval, fh_is_timed_out)}, interval * 2); } function firehose_usage() { - var params = {}; - params['op'] = 'firehose_usage' var interval = 300000; - ajax_update(params, 'firehose_usage-content'); + ajax_update({ op: 'firehose_usage' }, 'firehose_usage-content'); setTimeout(firehose_usage, interval); } @@ -253,69 +234,60 @@ } function firehose_reject (el) { - var params = {}; - var fh = $dom('firehose-' + el.value); - params['op'] = 'firehose_reject'; - params['id'] = el.value; - params['reskey'] = reskey_static; - ajax_update(params, 'reject_' + el.value); + ajax_update({ + op: 'firehose_reject', + id: el.value, + reskey: reskey_static + }, 'reject_' + el.value); firehose_remove_entry(el.value); } function firehose_open_note(id) { - var nf = $dom('note-form-'+id); - var nt = $dom('note-text-'+id); - var ni = $dom('note-input-'+id); - nf.className=""; - ni.focus(); - nt.className="hide"; + $('#note-form-'+id).removeClass(); + $('#note-input-'+id).each(function(){this.focus()}); + $('#note-text-'+id).setClass("hide"); } function firehose_save_note(id) { - var nf = $dom('note-form-'+id); - var nt = $dom('note-text-'+id); - var ni = $dom('note-input-'+id); - var params = {}; - params['op'] = 'firehose_save_note'; - params['note'] = ni.value; - params['id'] = id; - ajax_update(params, 'note-text-'+id); - nf.className = "hide"; - nt.className = ""; + ajax_update({ + op: 'firehose_save_note', + note: $('#note-input-'+id).val(), + id: id + }, 'note-text-'+id); + $('#note-form-'+id).setClass("hide"); + $('#note-text-'+id).removeClass(); } function firehose_get_admin_extras(id) { - var params = {}; - params['id'] = id; - params['op'] = 'firehose_get_admin_extras'; - var handlers = { + ajax_update({ + op: 'firehose_get_admin_extras', + id: id + }, '', { onComplete: function(transport) { json_handler(transport); if (firehoseIsInWindow(id)) { scrollToWindowFirehose(id); } } - }; - ajax_update(params, '', handlers); + }); } function firehose_get_and_post(id) { - var params = {}; - params['id'] = id; - params['op'] = 'firehose_get_form'; - firehose_collapse_entry(id); - var handlers = { - onComplete: function() { $dom('postform-'+id).submit();} - }; - ajax_update(params, 'postform-'+id, handlers); + ajax_update({ + op: 'firehose_get_form', + id: id + }, 'postform-'+id, { + onComplete: function() { + $dom('postform-'+id).submit() + } + }); } function appendToBodytext(text) { - var obj = $dom('admin-bodytext'); - if (obj) { - obj.className = "show"; - obj.value = obj.value + text; - } + $('#admin-bodytext').each(function(){ + this.className = "show"; + this.value += text; + }) } function appendToMedia(text) { Modified: slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/common.js =================================================================== --- slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/common.js 2008-04-07 05:09:04 UTC (rev 576) +++ slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/common.js 2008-04-11 07:28:41 UTC (rev 577) @@ -1,5 +1,5 @@ // _*_ Mode: JavaScript; tab-width: 8; indent-tabs-mode: true _*_ -// $Id: common.js,v 1.194 2008/04/03 19:14:51 tvroom Exp $ +// $Id: common.js,v 1.195 2008/04/08 17:52:30 scc Exp $ function $dom( id ) { return document.getElementById(id); @@ -1160,8 +1160,8 @@ var login_inst = 0; function init_login_divs() { - login_cover = document.getElementById('login_cover'); - login_box = document.getElementById('login_box'); + login_cover = $dom('login_cover'); + login_box = $dom('login_box'); } function install_login() { @@ -1270,28 +1270,23 @@ function getModalPrefs(section, title, tabbed) { if (!reskey_static) return show_login_box(); - document.getElementById('preference_title').innerHTML = title; - var params = {}; - params['op'] = 'getModalPrefs'; - params['section'] = section; - params['reskey'] = reskey_static; - params['tabbed'] = tabbed; - var handlers = {onComplete:show_modal_box}; - ajax_update(params, 'modal_box_content', handlers); - - return; + $('#preference_title').html(title); + ajax_update({ + op: 'getModalPrefs', + section: section, + reskey: reskey_static, + tabbed: tabbed + }, 'modal_box_content', { onComplete: show_modal_box }); } function firehose_get_media_popup(id) { - if ($dom('preference_title')) { - $dom('preference_title').innerHTML = "Media"; - } - var params = {}; - params['op'] = 'firehose_get_media'; - params['id'] = id; + $('#preference_title').html('Media'); show_modal_box(); - $dom('modal_box_content').innerHTML = "

    Loading...

    "; - ajax_update(params, 'modal_box_content'); + $('#modal_box_content').html("

    Loading...

    "); + ajax_update({ + op: 'firehose_get_media', + id: id + }, 'modal_box_content'); } function saveModalPrefs() { @@ -1325,10 +1320,9 @@ } } -function displayModalPrefHelp(element) { - var elem = document.getElementById(element); - var vis = elem.style; - vis.display = (!vis.display || vis.display == 'block') ? 'none' : 'block'; +function displayModalPrefHelp(id) { + var el = $('#'+id); + el.css('display', el.css('display')!='none' ? 'none' : 'block'); } function toggle_filter_prefs() { Modified: slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/slashbox.js =================================================================== --- slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/slashbox.js 2008-04-07 05:09:04 UTC (rev 576) +++ slashjp/branches/upstream/current/plugins/Ajax/htdocs/images/slashbox.js 2008-04-11 07:28:41 UTC (rev 577) @@ -13,25 +13,17 @@ YAHOO.extend(YAHOO.slashdot.SlashBox, YAHOO.util.DDProxy); -YAHOO.slashdot.SlashBox.prototype.createFrame = function() { - // ... -} - - YAHOO.slashdot.SlashBox.prototype.startDrag = function(x, y) { - var dragEl = this.getDragEl(); - var clickEl = this.getEl(); - - dragEl.innerHTML = clickEl.innerHTML; - dragEl.className = clickEl.className; - - YAHOO.util.Dom.addClass(clickEl, "to-be-moved"); - // so we can style the object-to-be-moved in CSS + var orig = $(this.getEl()); + var dragCopy = $(this.getDragEl()); + // dragging a copy, make sure it has the same contents and class as the original + dragCopy.html(orig.html()).setClass(orig.attr('className')); + orig.addClass("to-be-moved"); } YAHOO.slashdot.SlashBox.prototype.endDrag = function(e) { - YAHOO.util.Dom.removeClass(this.getEl(), "to-be-moved"); - // done moving, back to your regularly scheduled CSS (see this.startDrag) + $(this.getEl()).removeClass("to-be-moved"); + // done moving, back to your regularly scheduled CSS (see this.startDrag) } YAHOO.slashdot.SlashBox.prototype.onDragOver = function(e, id) { @@ -67,20 +59,14 @@ YAHOO.slashdot.SlashBox.prototype.onDragEnter = function(e, id) { if ( id == this.deleteBoundaryId ) { - var dragEl = this.getDragEl(); - var clickEl = this.getEl(); - YAHOO.util.Dom.removeClass(dragEl, "to-be-deleted"); - YAHOO.util.Dom.removeClass(clickEl, "to-be-deleted"); + $([this.getDragEl(), this.getEl()]).removeClass("to-be-deleted"); // so we can style the object-to-be-moved in CSS } } YAHOO.slashdot.SlashBox.prototype.onDragOut = function(e, id) { if ( id == this.deleteBoundaryId ) { - var dragEl = this.getDragEl(); - var clickEl = this.getEl(); - YAHOO.util.Dom.addClass(dragEl, "to-be-deleted"); - YAHOO.util.Dom.addClass(clickEl, "to-be-deleted"); + $([this.getDragEl(), this.getEl()]).addClass("to-be-deleted"); // so we can style the object-to-be-moved in CSS } } Modified: slashjp/branches/upstream/current/plugins/Ajax/templates/edit_comment;ajax;default =================================================================== --- slashjp/branches/upstream/current/plugins/Ajax/templates/edit_comment;ajax;default 2008-04-07 05:09:04 UTC (rev 576) +++ slashjp/branches/upstream/current/plugins/Ajax/templates/edit_comment;ajax;default 2008-04-11 07:28:41 UTC (rev 577) @@ -19,21 +19,21 @@ __name__ edit_comment __template__ -
    [% IF user.is_anon %] -

    - [% IF constants.allow_anonymous %] - You are not logged in. You can log - in now, or Create an Account. - [% ELSE %] - You are not logged in. You can log - in now, Create an Account, - or post as [% user.nickname | strip_literal %]. - [% END %] -

    +
    + [% IF constants.allow_anonymous %] +You are not logged in. You can log +in now, or Create an Account. + [% ELSE %] +You are not logged in. You can log +in now, Create an Account, +or post as [% user.nickname | strip_literal %]. + [% END %] +
    [% END %] [% IF !user.is_anon || constants.allow_anonymous %] +
    @@ -62,25 +62,25 @@
    - +

    Preview

    [%- IF pid # not for root-level reply %] - [% END %] +

    Quote Parent

    [% END %] [%- UNLESS user.is_anon %] - [% END %] +

    Options

    [% END %]
    - +

    Cancel

    +
    [% END # IF !user.is_anon || constants.allow_anonymous %] -
    __seclev__ 1000 __version__ -$Id: edit_comment;ajax;default,v 1.11 2008/04/03 04:38:36 pudge Exp $ +$Id: edit_comment;ajax;default,v 1.13 2008/04/10 18:43:44 pudge Exp $ Modified: slashjp/branches/upstream/current/plugins/Ajax/templates/modal_footer;misc;default =================================================================== --- slashjp/branches/upstream/current/plugins/Ajax/templates/modal_footer;misc;default 2008-04-07 05:09:04 UTC (rev 576) +++ slashjp/branches/upstream/current/plugins/Ajax/templates/modal_footer;misc;default 2008-04-11 07:28:41 UTC (rev 577) @@ -13,11 +13,11 @@ __seclev__ 500 __version__ -$Id: modal_footer;misc;default,v 1.2 2007/12/13 20:54:55 pudge Exp $ +$Id: modal_footer;misc;default,v 1.3 2008/04/07 22:31:29 pudge Exp $ Modified: slashjp/branches/upstream/current/plugins/Ajax/templates/prefs_d2;ajax;default =================================================================== --- slashjp/branches/upstream/current/plugins/Ajax/templates/prefs_d2;ajax;default 2008-04-07 05:09:04 UTC (rev 576) +++ slashjp/branches/upstream/current/plugins/Ajax/templates/prefs_d2;ajax;default 2008-04-11 07:28:41 UTC (rev 577) @@ -29,11 +29,7 @@
    - [% d2_check = ''; - IF user.discussion2 == 'slashdot'; - d2_check = constants.markup_checked_attribute; - END %] -  Enable Dynamic Discussions ? +  Enable Dynamic Discussions ?