svnno****@sourc*****
svnno****@sourc*****
2007年 12月 6日 (木) 18:17:48 JST
Revision: 272 http://svn.sourceforge.jp/cgi-bin/viewcvs.cgi?root=slashdotjp&view=rev&rev=272 Author: tach Date: 2007-12-06 18:17:47 +0900 (Thu, 06 Dec 2007) Log Message: ----------- merge from upstream 2.5.0.186 branch Modified Paths: -------------- slashjp/trunk/Slash/Apache/User/User.pm slashjp/trunk/Slash/DB/MySQL/MySQL.pm slashjp/trunk/plugins/Admin/Admin.pm slashjp/trunk/plugins/Admin/admin.pl slashjp/trunk/plugins/Admin/templates/editStory;admin;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/sectionprefs.js slashjp/trunk/plugins/Ajax/mysql_dump.sql slashjp/trunk/plugins/Ajax/templates/prefs_d2;ajax;default slashjp/trunk/plugins/Ajax/templates/prefs_d2_posting;ajax;default slashjp/trunk/plugins/Ajax/templates/prefs_messages;ajax;default slashjp/trunk/plugins/Console/Console.pm slashjp/trunk/plugins/Console/console.pl slashjp/trunk/plugins/Console/templates/display;console;default slashjp/trunk/plugins/FAQSlashdot/faq/tags.shtml slashjp/trunk/plugins/FireHose/FireHose.pm slashjp/trunk/plugins/FireHose/firehose.css slashjp/trunk/plugins/FireHose/firehose.pl slashjp/trunk/plugins/FireHose/templates/admin_extras;misc;default slashjp/trunk/plugins/FireHose/templates/list;firehose;default slashjp/trunk/plugins/FireHose/templates/nodnix_menus;firehose;default slashjp/trunk/plugins/Stats/Stats.pm slashjp/trunk/plugins/Stats/adminmail.pl slashjp/trunk/plugins/Stats/templates/display;adminmail;default slashjp/trunk/plugins/Tags/Clout/Describe.pm slashjp/trunk/plugins/Tags/Clout.pm slashjp/trunk/plugins/Tags/PLUGIN slashjp/trunk/plugins/Tags/Tagbox.pm slashjp/trunk/plugins/Tags/Tags.pm slashjp/trunk/plugins/Tags/templates/data;tags;default slashjp/trunk/sql/mysql/defaults.sql slashjp/trunk/sql/mysql/upgrades slashjp/trunk/tagboxes/Top/mysql_dump.sql slashjp/trunk/themes/slashcode/htdocs/base.css slashjp/trunk/themes/slashcode/htdocs/comments.css slashjp/trunk/themes/slashcode/htdocs/images/comments.js slashjp/trunk/themes/slashcode/htdocs/users.pl slashjp/trunk/themes/slashcode/tasks/freshenup.pl slashjp/trunk/themes/slashcode/templates/prefs_titlebar;misc;default slashjp/trunk/themes/slashcode/templates/printCommentsMain;misc;default Added Paths: ----------- slashjp/trunk/plugins/Ajax/templates/prefs_sectional;ajax;default slashjp/trunk/plugins/Ajax/templates/prefs_user;ajax;default slashjp/trunk/plugins/Tags/templates/recenttagnamesbox;misc;default -------------- next part -------------- Modified: slashjp/trunk/Slash/Apache/User/User.pm =================================================================== --- slashjp/trunk/Slash/Apache/User/User.pm 2007-12-06 09:12:31 UTC (rev 271) +++ slashjp/trunk/Slash/Apache/User/User.pm 2007-12-06 09:17:47 UTC (rev 272) @@ -961,6 +961,10 @@ Bender:Stop doing the right thing, you jerk! Bender:Are you familiar with the old robot saying "does not compute"? Bender:The sparks keep me warm. +Bender:Boy, were we suckers! +Bender:Whaddya say, folks? Hot or not? +Bender:Bender knows when to use finesse. +Bender:And I bet it's gonna get a lot more confusing. Fry:There's a lot about my face you don't know. Fry:These new hands are great. I'm gonna break them in tonight. Fry:I refuse to testify on the grounds that my organs will be chopped up into a patty. @@ -1007,6 +1011,9 @@ Fry:I have more important things to do today than laugh and clap my hands. Fry:I'll be whatever I wanna do. Fry:There's a political debate on. Quick, change the channel! +Fry:It's all there, in the macaroni. +Fry:Can I pull up my pants now? +Fry:Robots don't go to heaven. Leela:There's a political debate on. Quick, change the channel! Leela:You did the best you could, I guess, and some of these gorillas are okay. Leela:This wangs chung. @@ -1016,6 +1023,8 @@ Leela:I'm a millionaire! Suddenly I have an opinion about the capital gains tax. Leela:Do you have idiots on your planet? Leela:My old life wasn't as glamorous as my webpage made it look. +Leela:No, Leela will show you out. +Hermes:Without my body, I'm a nobody. EOT 1; Modified: slashjp/trunk/Slash/DB/MySQL/MySQL.pm =================================================================== --- slashjp/trunk/Slash/DB/MySQL/MySQL.pm 2007-12-06 09:12:31 UTC (rev 271) +++ slashjp/trunk/Slash/DB/MySQL/MySQL.pm 2007-12-06 09:17:47 UTC (rev 272) @@ -12423,20 +12423,12 @@ my $noid = $self->sqlSelect('noid','submissions_notes', 'submatch=' . $self->sqlQuote($submatch)); - if ($noid) { - $self->sqlUpdate('submissions_notes', { - subnote => $subnote, - uid => $user->{uid}, - '-time' => 'NOW()', - }, "noid=" . $noid); - } else { - $self->sqlInsert('submissions_notes', { - submatch => $submatch, - subnote => $subnote, - uid => $user->{uid}, - '-time' => 'NOW()', - }); - } + $self->sqlInsert('submissions_notes', { + submatch => $submatch, + subnote => $subnote, + uid => $user->{uid}, + '-time' => 'NOW()', + }); } sub getSubmissionMemory { Modified: slashjp/trunk/plugins/Admin/Admin.pm =================================================================== --- slashjp/trunk/plugins/Admin/Admin.pm 2007-12-06 09:12:31 UTC (rev 271) +++ slashjp/trunk/plugins/Admin/Admin.pm 2007-12-06 09:17:47 UTC (rev 272) @@ -455,10 +455,10 @@ tasks_next => \@tasks_next, tasks_inprogress => \@tasks_inprogress, tasks_last => \@tasks_last, - }, , { Return => 1 }); - + }, { Return => 1 }); + return $text if $options->{contents_only}; - + $updater = getData('slashdbox_js', {}, "admin") if $options->{updater}; slashDisplay('sidebox', { updater => $updater, @@ -479,7 +479,7 @@ my $updater; my $perf_box = slashDisplay('performance_box', {}, { Return => 1 }); return $perf_box if $options->{contents_only}; - $updater =getData('perfbox_js', {}, "admin") if $options->{updater}; + $updater = getData('perfbox_js', {}, "admin") if $options->{updater}; slashDisplay("sidebox", { updater => $updater, name => 'performancebox', Modified: slashjp/trunk/plugins/Admin/admin.pl =================================================================== --- slashjp/trunk/plugins/Admin/admin.pl 2007-12-06 09:12:31 UTC (rev 271) +++ slashjp/trunk/plugins/Admin/admin.pl 2007-12-06 09:17:47 UTC (rev 272) @@ -10,7 +10,6 @@ use Time::HiRes; use LWP::UserAgent; use URI; -use XML::Simple; use Slash; use Slash::Display; @@ -1448,34 +1447,6 @@ } } - my $yoogli_similar_stories = {}; - if ($constants->{yoogli_oai_search}) { - my $query = $constants->{yoogli_oai_query_base} .= '?verb=GetRecord&metadataPrefix=oai_dc&rescount='; - $query .= $constants->{yoogli_oai_result_count} . '&identifier=' . URI->new($storyref->{introtext}); - - my $ua = new LWP::UserAgent; - $ua->timeout($constants->{yoogli_oai_result_count} + 2); - my $req = new HTTP::Request GET => $query; - my $res = $ua->request($req); - if ($res->is_success) { - my $xml = new XML::Simple; - my $content = eval { $xml->XMLin($res->content) }; - unless ($@) { - my $sid_regex = regexSid(); - foreach my $metadata (@{$content->{'GetRecord'}{'record'}}) { - next if $metadata->{'metadata'}{'title'} eq $storyref->{title}; - my $key = $metadata->{'header'}{'identifier'}; - my($sid) = $metadata->{'metadata'}{'identifier'} =~ $sid_regex; - $yoogli_similar_stories->{$key}{'date'} = $reader->getStory($sid, 'time'); - $yoogli_similar_stories->{$key}{'url'} = $metadata->{'metadata'}{'identifier'}; - $yoogli_similar_stories->{$key}{'title'} = $metadata->{'metadata'}{'title'}; - $yoogli_similar_stories->{$key}{'relevance'} = $metadata->{'metadata'}{'relevance'}; - $yoogli_similar_stories->{$key}{'sid'} = $sid; - } - } - } - } - my $admindb = getObject('Slash::Admin'); my $authortext = $admindb->showStoryAdminBox($storyref); my $slashdtext = $admindb->showSlashdBox(); @@ -1556,7 +1527,6 @@ signofftext => $signofftext, user_signoff => $user_signoff, add_related_text => $add_related_text, - yoogli_similar_stories => $yoogli_similar_stories, pending_file_count => $pending_file_count, story_static_files => $story_static_files }); @@ -2094,6 +2064,12 @@ $data->{neverdisplay} = $form->{display} ? '' : 1; #print STDERR "admin.pl before updateStory data: " . Dumper($data); + if ($data->{neverdisplay}) { + print STDERR "Setting sid: $form->{sid} to neverdisplay\n"; + use Data::Dumper; + print STDERR Dumper($form); + print STDERR Dumper($data); + } if (!$slashdb->updateStory($form->{sid}, $data)) { titlebar('100%', getTitle('story_update_failed')); editStory(@_); Modified: slashjp/trunk/plugins/Admin/templates/editStory;admin;default =================================================================== --- slashjp/trunk/plugins/Admin/templates/editStory;admin;default 2007-12-06 09:12:31 UTC (rev 271) +++ slashjp/trunk/plugins/Admin/templates/editStory;admin;default 2007-12-06 09:17:47 UTC (rev 272) @@ -78,16 +78,6 @@ [% seen_related.${story.sid} = 1 %] </tr> [% END %] - [% FOREACH story = yoogli_similar_stories.keys.sort %] - <tr class="story_main"> - <td>Y=[% yoogli_similar_stories.$story.relevance.substr(0, 4) %]</td> - <td><a href="[% yoogli_similar_stories.$story.url %]">[% yoogli_similar_stories.$story.title.substr(0, 35) %]...</a></td> - <td>[% Slash.timeCalc(yoogli_similar_stories.$story.date) %]</td> - <td><input type="checkbox" name="related_story" value="[% yoogli_similar_stories.$story.sid | strip_attribute %]"[% IF storyref.related_sids_hr.${yoogli_similar_stories.$story.sid}; constants.markup_checked_attribute; END %]></td> - <td> </td> - [% seen_related.${yoogli_similar_stories.$story.sid} = 1 %] - </tr> - [% END %] [% FOREACH rel_sid = storyref.related_sids_hr.keys %] [% IF seen_related.$rel_sid; NEXT; END; %] Modified: slashjp/trunk/plugins/Ajax/PLUGIN =================================================================== --- slashjp/trunk/plugins/Ajax/PLUGIN 2007-12-06 09:12:31 UTC (rev 271) +++ slashjp/trunk/plugins/Ajax/PLUGIN 2007-12-06 09:17:47 UTC (rev 272) @@ -37,3 +37,5 @@ template=templates/prefs_d2_posting;ajax;default template=templates/prefs_messages;ajax;default template=templates/modal_footer;misc;default +template=templates/prefs_user;ajax;default +template=templates/prefs_sectional;ajax;default Modified: slashjp/trunk/plugins/Ajax/htdocs/ajax.pl =================================================================== --- slashjp/trunk/plugins/Ajax/htdocs/ajax.pl 2007-12-06 09:12:31 UTC (rev 271) +++ slashjp/trunk/plugins/Ajax/htdocs/ajax.pl 2007-12-06 09:17:47 UTC (rev 272) @@ -171,7 +171,7 @@ my $master_value = !$multiple_values ? $first_val : ""; - return slashDisplay("sectionpref", + return slashDisplay("prefs_sectional", { nexusref => $nexus_hr, nexustid_order => \@nexustid_order, @@ -183,7 +183,7 @@ ); } -sub setSectionNexusPrefs() { +sub setSectionNexusPrefs { my($slashdb, $constants, $user, $form) = @_; my $reader = getObject('Slash::DB', { db_type => 'reader' }); @@ -259,7 +259,7 @@ } ); - return getData('set_section_prefs_success_msg'); + #return getData('set_section_prefs_success_msg'); } ################### @@ -538,8 +538,10 @@ }, { Return => 1 } ); - } else { - return + } elsif ($form->{'section'} eq 'sectional') { + getSectionPrefsHTML($slashdb, $constants, $user, $form); + } else { + return slashDisplay('prefs_' . $form->{'section'}, { user => $user, }, @@ -571,14 +573,9 @@ } if ($params{'formname'} eq 'd2_posting') { - my $karma_bonus = ($params{'karma_bonus'} !~ /^[\-+]?\d+$/) ? "+1" : $params{'karma_bonus'}; - my $subscriber_bonus = ($params{'subscriber_bonus'} !~ /^[\-+]?\d+$/) ? "+1" : $params{'subscriber_bonus'}; - $user_edits_table = { emaildisplay => $params{'emaildisplay'} || undef, - karma_bonus => ($karma_bonus ne '+1' ? $karma_bonus : undef), nobonus => ($params{'nobonus'} ? 1 : undef), - subscriber_bonus => ($subscriber_bonus || undef), nosubscriberbonus => ($params{'nosubscriberbonus'} ? 1 : undef), posttype => $params{'posttype'}, textarea_rows => ($params{'textarea_rows'} != $constants->{'textarea_rows'} @@ -612,6 +609,109 @@ }; } + if ($params{'formname'} eq 'user') { + my $user_edit = $slashdb->getUser($params{uid}); + my $gSkin = getCurrentSkin(); + + # Real Email + if ($user_edit->{realemail} ne $params{realemail}) { + if ($slashdb->existsEmail($params{realemail})) { + $params{realemail} = $user_edit->{realemail}; + } + } + + # Homepage + my $homepage = $params{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 ''; + + # Calendar + my $calendar_url = $params{calendar_url}; + if (length $calendar_url) { + $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 ''; + } + + my(%extr, $err_message, %limit); + $limit{sig} = 120; + $limit{bio} = $constants->{users_bio_length} || 1024; + + for my $key (keys %limit) { + my $dat = chopEntity($params{$key}, $limit{$key}); + $dat = strip_html($dat); + $dat = balanceTags($dat, { deep_nesting => 2, length => $limit{$key} }); + $dat = addDomainTags($dat) if $dat; + + if ($key eq 'sig' && defined($dat) && length($dat) > 200) { + $extr{sig} = undef; + } + + if ((length($dat) > 1 && !filterOk('comments', 'postersubj', $dat, \$err_message)) || + (!compressOk('comments', 'postersubj', $dat))) { + $extr{$key} = undef; + } + else { + $extr{$key} = $dat; + } + } + + $user_edits_table = { + homepage => $homepage, + realname => $params{realname}, + calendar_url => $calendar_url, + yahoo => $params{yahoo}, + jabber => $params{jabber}, + aim => $params{aim}, + aimdisplay => $params{aimdisplay}, + icq => $params{icq}, + playing => $params{playing}, + mobile_text_address => $params{mobile_text_address}, + }; + + for (keys %extr) { + $user_edits_table->{$_} = $extr{$_} if defined $extr{$_}; + } + + for (keys %$user_edits_table) { + $user_edits_table->{$_} = '' unless defined $user_edits_table->{$_}; + } + + if ($user_edit->{realemail} ne $params{realemail}) { + $user_edits_table->{realemail} = chopEntity($params{realemail}, 50); + my $new_fakeemail = ''; + + if ($user->{emaildisplay}) { + $new_fakeemail = getArmoredEmail($params{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; + } + + my $reader = getObject('Slash::DB', { db_type => 'reader' }); + my $otherparams = $reader->getDescriptions('otherusersparam'); + for my $param (keys %$otherparams) { + if (exists $params{$param}) { + $user_edits_table->{$param} = $user->{$param} = $params{$param} || undef; + } + } + } + + if ($params{'formname'} eq "sectional") { + setSectionNexusPrefs($slashdb, $constants, $user, \%params); + } + else { + $slashdb->setUser($params{uid}, $user_edits_table); + } + $slashdb->setUser($params{uid}, $user_edits_table); } Modified: slashjp/trunk/plugins/Ajax/htdocs/images/admin.js =================================================================== --- slashjp/trunk/plugins/Ajax/htdocs/images/admin.js 2007-12-06 09:12:31 UTC (rev 271) +++ slashjp/trunk/plugins/Ajax/htdocs/images/admin.js 2007-12-06 09:17:47 UTC (rev 272) @@ -180,6 +180,12 @@ ajax_periodic_update(secs, params, "storyadmin-content"); } +function admin_recenttagnamesbox_fetch(secs) { + var params = []; + params['op'] = 'admin_recenttagnamesbox'; + ajax_periodic_update(secs, params, "recenttagnames-content"); +} + function console_update(use_fh_interval, require_fh_timeout) { use_fh_interval = use_fh_interval || 0; Modified: slashjp/trunk/plugins/Ajax/htdocs/images/common.js =================================================================== --- slashjp/trunk/plugins/Ajax/htdocs/images/common.js 2007-12-06 09:12:31 UTC (rev 271) +++ slashjp/trunk/plugins/Ajax/htdocs/images/common.js 2007-12-06 09:17:47 UTC (rev 272) @@ -1451,7 +1451,7 @@ onComplete: function() { hide_modal_box(); if (document.forms['modal_prefs'].refreshable.value) - document.location=document.forms['modal_prefs'].refreshable.value; + document.location=document.URL; } }; ajax_update(params, '', handlers); Modified: slashjp/trunk/plugins/Ajax/htdocs/images/sectionprefs.js =================================================================== --- slashjp/trunk/plugins/Ajax/htdocs/images/sectionprefs.js 2007-12-06 09:12:31 UTC (rev 271) +++ slashjp/trunk/plugins/Ajax/htdocs/images/sectionprefs.js 2007-12-06 09:17:47 UTC (rev 272) @@ -17,12 +17,12 @@ function masterChange(el) { swapClassColors('secpref_master','secpref_nexus_row'); updateNexusAllTidPrefs(el); - postSectionPrefChanges(el); + //postSectionPrefChanges(el); } function individualChange(el) { swapClassColors('secpref_nexus_row','secpref_master'); - postSectionPrefChanges(el); + //postSectionPrefChanges(el); } function postSectionPrefChanges(el) { @@ -50,7 +50,8 @@ } function updateNexusAllTidPrefs(el) { - theForm = document.forms["sectionprefs"]; + //theForm = document.forms["sectionprefs"]; + theForm = document.forms["modal_prefs"]; for(i=0; i<theForm.elements.length; i++){ var regex = /^nexustid\d+$/; if (regex.test(theForm.elements[i].name)) { Modified: slashjp/trunk/plugins/Ajax/mysql_dump.sql =================================================================== --- slashjp/trunk/plugins/Ajax/mysql_dump.sql 2007-12-06 09:12:31 UTC (rev 271) +++ slashjp/trunk/plugins/Ajax/mysql_dump.sql 2007-12-06 09:17:47 UTC (rev 272) @@ -162,6 +162,7 @@ INSERT INTO ajax_ops VALUES (NULL, 'admin_storyadminbox', 'Slash::Admin', 'ajax_storyadminbox', 'ajax_admin', 'createuse'); INSERT INTO ajax_ops VALUES (NULL, 'admin_authorbox', 'Slash::Admin', 'ajax_authorbox', 'ajax_admin', 'createuse'); INSERT INTO ajax_ops VALUES (NULL, 'admin_perfbox', 'Slash::Admin', 'ajax_perfbox', 'ajax_admin', 'createuse'); +INSERT INTO ajax_ops VALUES (NULL, 'admin_recenttagnamesbox', 'Slash::Tags', 'ajax_recenttagnamesbox', 'ajax_admin', 'createuse'); INSERT INTO ajax_ops VALUES (NULL, 'admin_learnword', 'Slash::Admin', 'admin_learnword', 'ajax_admin', 'createuse'); Modified: slashjp/trunk/plugins/Ajax/templates/prefs_d2;ajax;default =================================================================== --- slashjp/trunk/plugins/Ajax/templates/prefs_d2;ajax;default 2007-12-06 09:12:31 UTC (rev 271) +++ slashjp/trunk/plugins/Ajax/templates/prefs_d2;ajax;default 2007-12-06 09:17:47 UTC (rev 272) @@ -24,7 +24,7 @@ IF user.discussion2 == 'slashdot'; d2_check = constants.markup_checked_attribute; END %] - <label><input type="checkbox" name="discussion2"[% d2_check %] onclick="javascript:void(document.forms['modal_prefs'].refreshable.value=document.URL);"> Enable Dynamic Discussions</label> + <label><input type="checkbox" name="discussion2"[% d2_check %] onclick="javascript:void(document.forms['modal_prefs'].refreshable.value=1);"> Enable Dynamic Discussions</label> <p> Modified: slashjp/trunk/plugins/Ajax/templates/prefs_d2_posting;ajax;default =================================================================== --- slashjp/trunk/plugins/Ajax/templates/prefs_d2_posting;ajax;default 2007-12-06 09:12:31 UTC (rev 271) +++ slashjp/trunk/plugins/Ajax/templates/prefs_d2_posting;ajax;default 2007-12-06 09:17:47 UTC (rev 272) @@ -47,15 +47,6 @@ <input type="radio" name="emaildisplay" [% emaildisplay.2 %] value=2> Show your real email address without cowering behind childish anonymity or obfuscation. </div></blockquote> - <b><a name="karma_bonus">Karma Bonus</a></b> (modifier assigned to posts where the user has good karma)<br> - [% karma_bonus = 0; - IF user.karma_bonus; - karma_bonus = user.karma_bonus; - END %] - [% Slash.createSelect('karma_bonus', range, karma_bonus, 1, 1) %] - - <p> - [% IF user.karma > constants.goodkarma; b_check = ''; IF user.nobonus; @@ -63,19 +54,8 @@ END %] <input type="hidden" name="nobonus_present" value="1"> <label><input type="checkbox" name="nobonus"[% b_check %]> No Karma Bonus</label> - - <p> [% END %] - <b><a name="subscriber_bonus">Subscriber Bonus</a></b> (modifier assigned to posts where the user was a subscriber)<br> - [% subscriber_bonus = 0; - IF user.subscriber_bonus; - subscriber_bonus = user.subscriber_bonus; - END %] - [% Slash.createSelect('subscriber_bonus', range, subscriber_bonus, 1, 1) %] - - <p> - [% IF user.is_subscriber; sb_check = ''; IF user.nosubscriberbonus; Modified: slashjp/trunk/plugins/Ajax/templates/prefs_messages;ajax;default =================================================================== --- slashjp/trunk/plugins/Ajax/templates/prefs_messages;ajax;default 2007-12-06 09:12:31 UTC (rev 271) +++ slashjp/trunk/plugins/Ajax/templates/prefs_messages;ajax;default 2007-12-06 09:17:47 UTC (rev 272) @@ -12,8 +12,6 @@ __name__ prefs_messages __template__ -<div id="users-blocks"> - <div class="generalbody"> [% usernick = user.nickname | strip_literal; @@ -22,6 +20,8 @@ modeweb = Slash.MSG_MODE_WEB; %] + <br> + From this page you can configure various messages that [% constants.sitename %] can optionally send to you. The primary options are [% deliverymodes.$modenone %] (Disabled), [% deliverymodes.$modemail %], [% deliverymodes.$modeweb %], [% IF constants.im_screenname %]AIM,[% END %] and Mobile Text. Not all options are available for all message types. [% deliverymodes.$modeweb %] messages <b>will be deleted</b> after <b>[% constants.message_web_expire || 31 %] days</b>.[% IF constants.im_screenname %] If you plan on receiving AIM messages, please add [% constants.im_screenname %] to your buddylist.[% END %] <p> @@ -91,8 +91,6 @@ <input type="hidden" name="formname" value="messages"> <input type="button" value="Save" onclick="saveModalPrefs()"> </form> - </div> -</div> __seclev__ 500 __version__ Copied: slashjp/trunk/plugins/Ajax/templates/prefs_sectional;ajax;default (from rev 269, slashjp/branches/upstream/current/plugins/Ajax/templates/prefs_sectional;ajax;default) Copied: slashjp/trunk/plugins/Ajax/templates/prefs_user;ajax;default (from rev 269, slashjp/branches/upstream/current/plugins/Ajax/templates/prefs_user;ajax;default) Modified: slashjp/trunk/plugins/Console/Console.pm =================================================================== --- slashjp/trunk/plugins/Console/Console.pm 2007-12-06 09:12:31 UTC (rev 271) +++ slashjp/trunk/plugins/Console/Console.pm 2007-12-06 09:17:47 UTC (rev 272) @@ -46,6 +46,9 @@ $html->{'slashdbox-content'} = $admindb->showSlashdBox({ contents_only => 1}); $html->{'performancebox-content'} = $admindb->showPerformanceBox({ contents_only => 1}); $html->{'authoractivity-content'} = $admindb->showAuthorActivityBox({ contents_only => 1}); + if (my $tagsdb = getObject('Slash::Tags')) { + $html->{'recenttagnames-content'} = $tagsdb->showRecentTagnamesBox({ contents_only => 1 }); + } return Data::JavaScript::Anon->anon_dump({ html => $html }); Modified: slashjp/trunk/plugins/Console/console.pl =================================================================== --- slashjp/trunk/plugins/Console/console.pl 2007-12-06 09:12:31 UTC (rev 271) +++ slashjp/trunk/plugins/Console/console.pl 2007-12-06 09:17:47 UTC (rev 272) @@ -60,18 +60,24 @@ my $firehosebox = ""; if ($constants->{plugin}{FireHose}) { my $firehose = getObject("Slash::FireHose"); - $user->{state}{firehose_page} = "console"; + local $user->{state}{firehose_page} = 'console'; $firehosebox = $firehose->listView({ fh_page => 'console.pl'}); } + my $tagnamesbox = ''; + my $tags = getObject('Slash::Tags'); + if ($tags) { + my $rtoi_ar = $tags->getRecentTagnamesOfInterest(); + $tagnamesbox = $tags->showRecentTagnamesBox(); + } - slashDisplay('display', { remarks => $remarkstext, storyadmin => $storyadmin, slashdbox => $slashdbox, perfbox => $perfbox, authorbox => $authorbox, - firehosebox => $firehosebox + firehosebox => $firehosebox, + tagnamesbox => $tagnamesbox, }); } Modified: slashjp/trunk/plugins/Console/templates/display;console;default =================================================================== --- slashjp/trunk/plugins/Console/templates/display;console;default 2007-12-06 09:12:31 UTC (rev 271) +++ slashjp/trunk/plugins/Console/templates/display;console;default 2007-12-06 09:17:47 UTC (rev 272) @@ -17,6 +17,7 @@ [% perfbox %] [% Slash.sidebox("Firehose Usage", ' ', "firehose_usage", 1) %] [% slashdbox %] + [% tagnamesbox %] </div> <div id="console"> [% remarks %] Modified: slashjp/trunk/plugins/FAQSlashdot/faq/tags.shtml =================================================================== --- slashjp/trunk/plugins/FAQSlashdot/faq/tags.shtml 2007-12-06 09:12:31 UTC (rev 271) +++ slashjp/trunk/plugins/FAQSlashdot/faq/tags.shtml 2007-12-06 09:17:47 UTC (rev 272) @@ -40,7 +40,7 @@ multiple tags. Use "bigbrother", not "big brother". <li>For the <b>opposite</b> of a tag, prefix it with "!", e.g. "!funny" means "not funny."</li> -<li>Keep your tags brief.</li> +<li>Keep your tags brief. No full sentences. Tags are not comments.</li> <li>We provide a few example tags for you. Use them if you like.</li> <li>Don't forget to click 'Tag' to save your tags.</li> <li>After you save, your current list of tags is put back into the @@ -50,7 +50,8 @@ <li>Tags must be all-lowercase, no punctuation. Numbers can appear but can't be first. Smoosh them up: for "Web 2.0", tag "web20". Max 64 chars.</li> -<li>Avoid plurals when possible: "harddrive", not "harddrives".</li> +<li>Avoid plurals when possible: "harddrive", not "harddrives". +But sometimes singular would be silly: "starwars".</li> </ul> <p>We're excited about this, and see huge potential for this system. @@ -60,7 +61,7 @@ <p><i><font size=-1>Answered by: <a href="mailto:malda****@slash*****">CmdrTaco</a></font></i> -<br><i><font size=-1>Last Modified: 11/02/06</font></i> +<br><i><font size=-1>Last Modified: 11/22/07</font></i> @@ -115,11 +116,13 @@ grammatical errors, or bad HTML like a malformed link. Do not tag the story with the misspelled word in question.</p> -<p>These tags will alert us to problems immediately (but they won't show -up on the top tags list).</p> +<p>These tags will alert us to problems immediately, which we love! +But they won't show up on the top tags list. Trying to get around this +with similarly spelled (but system-meaningless) tags like "dupitydupe" +is discouraged.</p> <p><i><font size=-1>Answered by: <a href="mailto:malda****@slash*****">CmdrTaco</a></font></i> -<br><i><font size=-1>Last Modified: 11/02/06</font></i> +<br><i><font size=-1>Last Modified: 11/22/07</font></i> <br><a name="tags300" id="tags300"></a> Modified: slashjp/trunk/plugins/FireHose/FireHose.pm =================================================================== --- slashjp/trunk/plugins/FireHose/FireHose.pm 2007-12-06 09:12:31 UTC (rev 271) +++ slashjp/trunk/plugins/FireHose/FireHose.pm 2007-12-06 09:17:47 UTC (rev 272) @@ -36,7 +36,6 @@ use POSIX qw(ceil); use LWP::UserAgent; use URI; -use XML::Simple; use base 'Slash::DB::Utility'; use base 'Slash::DB::MySQL'; @@ -613,7 +612,15 @@ #print STDERR "[\nSELECT $columns\nFROM $tables\nWHERE $where\n$other\n]\n"; my $hr_ar = $self->sqlSelectAllHashrefArray($columns, $tables, $where, $other); - my $count = $self->sqlSelect("count(*)", $tables, $where, $count_other); + my $count; + if ($options->{tagged_by_uid}) { + my $rows = $self->sqlSelectAllHashrefArray("count(*)", $tables, $where, $count_other); + $count = @$rows; + } else { + $count = $self->sqlSelect("count(*)", $tables, $where, $count_other); + } + + my $page_size = $options->{limit} || 1; $results->{records_pages} ||= ceil($count / $page_size); $results->{records_page} ||= (int(($options->{offset} || 0) / $options->{limit}) + 1) || 1; @@ -648,7 +655,6 @@ $items = $hr_ar; } - return($items, $results, $count); } @@ -782,7 +788,7 @@ sub itemHasSpamURL { my($self, $item) = @_; - my @spamurlregexes = grep { $_ } split /\s+/, ($self->getBlock('spamurlregexes') || ''); + my @spamurlregexes = grep { $_ } split /\s+/, ($self->getBlock('spamurlregexes', 'block') || ''); return 0 unless @spamurlregexes; my @urls = $self->getURLsForItem($item); for my $url (@urls) { @@ -1392,9 +1398,6 @@ $accepted_from_ipid = $slashdb->countSubmissionsFromIPID($item->{ipid}, { del => 2}); } - my $yoogli_similar_stories = 0; - $yoogli_similar_stories = $firehose->getYoogliSimilarForItem($item) if $constants->{yoogli_oai_search}; - my $the_user = $slashdb->getUser($item->{uid}); my $byline = getData("byline", { @@ -1415,7 +1418,6 @@ item => $item, subnotes_ref => $subnotes_ref, similar_stories => $similar_stories, - yoogli_similar_stories => $yoogli_similar_stories, }, { Return => 1 }); return Data::JavaScript::Anon->anon_dump({ @@ -1590,43 +1592,6 @@ return $similar_stories; } -sub getYoogliSimilarForItem { - my($self, $item) = @_; - - my $user = getCurrentUser(); - my $constants = getCurrentStatic(); - return 0 unless $user->{is_admin} && $constants->{yoogli_oai_query_base} && $constants->{yoogli_oai_result_count}; - - my $query = $constants->{yoogli_oai_query_base} .= '?verb=GetRecord&metadataPrefix=oai_dc&rescount='; - $query .= $constants->{yoogli_oai_result_count} . '&identifier=' . URI->new($item->{introtext}); - my $yoogli_similar_stories = {}; - - my $ua = new LWP::UserAgent; - # Timeout is set to the number of responses we're expecting +1 for wiggle room. - $ua->timeout($constants->{yoogli_oai_result_count} + 2); - my $req = new HTTP::Request GET => $query; - my $res = $ua->request($req); - if ($res->is_success) { - my $xml = new XML::Simple; - my $content = eval { $xml->XMLin($res->content) }; - unless ($@) { - my $reader = getObject("Slash::DB", { db_type => "reader" }); - my $sid_regex = regexSid(); - foreach my $metadata (@{$content->{'GetRecord'}{'record'}}) { - next if $metadata->{'metadata'}{'title'} eq $item->{title}; - my $key = $metadata->{'header'}{'identifier'}; - my($sid) = $metadata->{'metadata'}{'identifier'} =~ $sid_regex; - $yoogli_similar_stories->{$key}{'date'} = $reader->getStory($sid, 'time'); - $yoogli_similar_stories->{$key}{'url'} = $metadata->{'metadata'}{'identifier'}; - $yoogli_similar_stories->{$key}{'title'} = $metadata->{'metadata'}{'title'}; - $yoogli_similar_stories->{$key}{'relevance'} = $metadata->{'metadata'}{'relevance'}; - } - } - } - - return $yoogli_similar_stories; -} - sub getAndSetOptions { my($self, $opts) = @_; my $user = getCurrentUser(); @@ -1670,7 +1635,6 @@ $self->setUser($user->{uid}, { firehose_paused => $options->{pause} }); } } - if (defined $form->{duration}) { if ($form->{duration} =~ /^-?\d+$/) { $options->{duration} = $form->{duration}; @@ -1700,7 +1664,6 @@ my $colors = $self->getFireHoseColors(); - if ($form->{color} && $colors->{$form->{color}}) { $options->{color} = $form->{color}; } @@ -1748,9 +1711,9 @@ # XXX my $user_tabs = $self->getUserTabs(); my %user_tab_names = map { $_->{tabname} => 1 } @$user_tabs; - my %firehose_tabs_given = map { $_ => 1 } split (/\|/, $user->{firehose_tabs_given}); + my $tabs_given = $user->{firehose_tabs_given} || ''; + my %firehose_tabs_given = map { $_ => 1 } split (/\|/, $tabs_given); my @tab_fields = qw(tabname filter mode color orderdir orderby); - my $tabs_given = $user->{firehose_tabs_given}; my $system_tabs = $self->getSystemDefaultTabs(); foreach my $tab (@$system_tabs) { @@ -1876,11 +1839,7 @@ # ...for which we'll have fewer items per page if ($force_smaller) { $options->{smalldevices} = 1; - if ($mode eq "full") { - $options->{limit} = $pagesize eq "large" ? 15 : 10; - } else { - $options->{limit} = $pagesize eq "large" ? 20 : 15; - } + $options->{limit} = 10; } if ($user->{is_admin} && $form->{setusermode}) { @@ -2060,7 +2019,6 @@ $options->{duration} = 1; } - return $options; } Modified: slashjp/trunk/plugins/FireHose/firehose.css =================================================================== --- slashjp/trunk/plugins/FireHose/firehose.css 2007-12-06 09:12:31 UTC (rev 271) +++ slashjp/trunk/plugins/FireHose/firehose.css 2007-12-06 09:17:47 UTC (rev 272) @@ -451,4 +451,4 @@ .briefarticle .storylinks .comments a:hover {background:transparent url('//images.slashdot.org/sic_icons.png') no-repeat scroll 0px -1498px; color: #fff !important} .briefarticle .storylinks .comments.nocomment, .briefarticle .storylinks .comments span {display: none} -.embed .paginate, .embed .firemenu, .embed + .copyright { display: none; } +.embed .paginate, .embed .firemenu, .embed a.skin, .copyright.embed { display: none; } Modified: slashjp/trunk/plugins/FireHose/firehose.pl =================================================================== --- slashjp/trunk/plugins/FireHose/firehose.pl 2007-12-06 09:12:31 UTC (rev 271) +++ slashjp/trunk/plugins/FireHose/firehose.pl 2007-12-06 09:17:47 UTC (rev 272) @@ -65,7 +65,8 @@ $redirect = 0; } if ($redirect) { - redirect("$gSkin->{rootdir}/firehose.shtml"); + my $prefix = $form->{embed} ? "embed_" : ""; + redirect("$gSkin->{rootdir}/${prefix}firehose.shtml"); return; } } Modified: slashjp/trunk/plugins/FireHose/templates/admin_extras;misc;default =================================================================== --- slashjp/trunk/plugins/FireHose/templates/admin_extras;misc;default 2007-12-06 09:12:31 UTC (rev 271) +++ slashjp/trunk/plugins/FireHose/templates/admin_extras;misc;default 2007-12-06 09:17:47 UTC (rev 272) @@ -40,7 +40,7 @@ </tr> </table> </form> -[% IF similar_stories.size > 0 or yoogli_similar_stories %] +[% IF similar_stories.size > 0 %] <table border="0" cellpadding="2" cellspacing="0" class="data"> <tr class="data_head"><td><b>Similar Stories</b></td></tr> [% FOREACH story = similar_stories %] @@ -64,16 +64,6 @@ </td> </tr> [% END %] - [% FOREACH story = yoogli_similar_stories.keys.sort %] - <tr> - <td> </td> - <td>Y=[% yoogli_similar_stories.$story.relevance.substr(0, 4) %]</td> - <td valign="TOP"><a href="[% yoogli_similar_stories.$story.url %]" title="[% yoogli_similar_stories.$story.title %]"> - [% yoogli_similar_stories.$story.title.substr(0, 35) %]...</a></td> - <td valign="TOP">[% Slash.timeCalc(yoogli_similar_stories.$story.date, "%Y-%m-%d") %]</td> - <td> </td> - </tr> - [% END %] </table> [% END %] __version__ Modified: slashjp/trunk/plugins/FireHose/templates/list;firehose;default =================================================================== --- slashjp/trunk/plugins/FireHose/templates/list;firehose;default 2007-12-06 09:12:31 UTC (rev 271) +++ slashjp/trunk/plugins/FireHose/templates/list;firehose;default 2007-12-06 09:17:47 UTC (rev 272) @@ -132,7 +132,7 @@ [% END %] </div> </div> -[% IF !user.is_admin || (user.is_admin && user.firehose_usermode ) %] +[% IF !form.embed && (!user.is_admin || (user.is_admin && user.firehose_usermode )) %] <p style="padding: 1em 1em 0 1em"> The Slashdot Firehose is a collaborative system designed to allow users to assist our editors in the story selection process. The hose Modified: slashjp/trunk/plugins/FireHose/templates/nodnix_menus;firehose;default =================================================================== --- slashjp/trunk/plugins/FireHose/templates/nodnix_menus;firehose;default 2007-12-06 09:12:31 UTC (rev 271) +++ slashjp/trunk/plugins/FireHose/templates/nodnix_menus;firehose;default 2007-12-06 09:17:47 UTC (rev 272) @@ -19,6 +19,7 @@ <div class="menu" onmouseover="dont_hide_nodnix_menu()" onmouseout="hide_nodnix_menu(750)" onmousedown="hide_nodnix_menu()"> <ul> <li title="Tag this item 'interesting', voting it up" onmousedown="nodnix_tag('interesting', '+')">interesting</li> + <li title="Tag this item 'fresh', voting it up" onmousedown="nodnix_tag('fresh', '+')">fresh</li> <li title="Tag this item 'funny', voting it up" onmousedown="nodnix_tag('funny', '+')">funny</li> <li title="Tag this item 'insightful', voting it up" onmousedown="nodnix_tag('insightful', '+')">insightful</li> </ul> @@ -33,6 +34,7 @@ <li title="Tag this item 'offtopic', voting it down" onmousedown="nodnix_tag('offtopic', '-')">offtopic</li> <li title="Tag this item 'stupid', voting it down" onmousedown="nodnix_tag('stupid', '-')">stupid</li> <li title="Tag this item 'slownewsday', voting it down" onmousedown="nodnix_tag('slownewsday', '-')">slownewsday</li> + <li title="Tag this item 'stale', voting it down" onmousedown="nodnix_tag('stale', '-')">stale</li> </ul> </div> </div> Modified: slashjp/trunk/plugins/Stats/Stats.pm =================================================================== --- slashjp/trunk/plugins/Stats/Stats.pm 2007-12-06 09:12:31 UTC (rev 271) +++ slashjp/trunk/plugins/Stats/Stats.pm 2007-12-06 09:17:47 UTC (rev 272) @@ -1670,11 +1670,54 @@ return $self->sqlSelectAll( "DISTINCT SUBSTRING_INDEX(referer,'/',3) AS referer, COUNT(id) AS c", "accesslog_temp", - "referer IS NOT NULL AND LENGTH(referer) > 0 AND referer LIKE 'http%' $where ", + "op != 'slashdot-it' + AND referer IS NOT NULL AND LENGTH(referer) > 0 AND referer LIKE 'http%' + $where", "GROUP BY referer ORDER BY c DESC, referer LIMIT $count" ); } +sub getTopBadgeURLs { + my($self, $options) = @_; + # This is Slashdot-specific. It won't make much sense for any + # other site to use it. + my $constants = getCurrentStatic(); + return [ ] unless $constants->{basedomain} eq 'slashdot.org'; + + my $count = $options->{count} || 10; + my $top_ar = $self->sqlSelectAll( + "query_string AS qs, COUNT(*) AS c", + "accesslog_temp", + "op='slashdot-it'", + "GROUP BY qs ORDER BY c DESC, qs LIMIT $count" + ); + for my $duple (@$top_ar) { + my($qs, $c) = @$duple; + $qs =~ s/^.*url=//; + $qs =~ s/\%[a-fA-F0-9]?$//; + $qs =~ s/%([a-fA-F0-9]{2})/pack('C', hex($1))/ge; + $duple = [$qs, $c]; + } + return $top_ar; +} + +sub getTopBadgeHosts { + my($self, $options) = @_; + my $count = $options->{count} || 10; + my $url_count = $count * 20; + my $top_ar = $self->getTopBadgeURLs({ count => $url_count }); + my %count = ( ); + for my $duple (@$top_ar) { + my($uri, $c) = @$duple; + my $host = URI->new($uri)->host(); + $count{$host} += $c; + } + my @top_hosts = (sort { $count{$b} <=> $count{$a} || $a <=> $b } keys %count); + $#top_hosts = $count-1 if scalar @top_hosts > $count; + my @top = ( map { [ $_, $count{$_} ] } @top_hosts ); + return \@top; +} + ######################################################## sub countSfNetIssues { my($self, $group_id) = @_; Modified: slashjp/trunk/plugins/Stats/adminmail.pl =================================================================== --- slashjp/trunk/plugins/Stats/adminmail.pl 2007-12-06 09:12:31 UTC (rev 271) +++ slashjp/trunk/plugins/Stats/adminmail.pl 2007-12-06 09:17:47 UTC (rev 272) @@ -819,6 +819,8 @@ } $data{top_referers} = $logdb->getTopReferers({count => 20}); + $data{top_badgehosts} = $logdb->getTopBadgeHosts({count => 20}); + $data{top_badgeurls} = $logdb->getTopBadgeURLs({count => 20}); my $new_users_yest = $slashdb->getNumNewUsersSinceDaysback(1) - $slashdb->getNumNewUsersSinceDaysback(0); Modified: slashjp/trunk/plugins/Stats/templates/display;adminmail;default =================================================================== --- slashjp/trunk/plugins/Stats/templates/display;adminmail;default 2007-12-06 09:12:31 UTC (rev 271) +++ slashjp/trunk/plugins/Stats/templates/display;adminmail;default 2007-12-06 09:17:47 UTC (rev 272) @@ -164,6 +164,24 @@ [% END %] [% END %] +[% IF top_badgehosts.size %] +----------------------- + +Top badge hosts: +[% FOREACH badgehost = top_badgehosts -%] +[% badgehost.1 %] [% badgehost.0 %] +[% END %] +[% END %] + +[% IF top_badgeurls.size %] +----------------------- + +Top badge URLs: +[% FOREACH badgeurl = top_badgeurls -%] +[% badgeurl.1 %] [% badgeurl.0 %] +[% END %] +[% END %] + [% IF errors.size -%] ----------------------- Error count by Page: Modified: slashjp/trunk/plugins/Tags/Clout/Describe.pm =================================================================== --- slashjp/trunk/plugins/Tags/Clout/Describe.pm 2007-12-06 09:12:31 UTC (rev 271) +++ slashjp/trunk/plugins/Tags/Clout/Describe.pm 2007-12-06 09:17:47 UTC (rev 272) @@ -62,7 +62,9 @@ sourcetag.tagnameid, sourcetag.globjid, gtid", - "tags AS sourcetag, globjs, tags_peerclout AS sourcetpc, users_info, + "tags AS sourcetag, + tagname_params AS tagparam, + globjs, tags_peerclout AS sourcetpc, users_info, tags AS newtag LEFT JOIN tags_peerclout AS newtpc USING (uid)", "sourcetag.inactivated IS NULL AND sourcetag.globjid=globjs.globjid @@ -70,7 +72,8 @@ AND sourcetpc.clid=$self->{clid} AND sourcetag.globjid=newtag.globjid AND sourcetag.tagnameid=newtag.tagnameid - AND sourcetag.tagnameid NOT IN ($self->{nodid}, $self->{nixid}) + AND sourcetag.tagnameid=tagparam.tagnameid + AND tagparam.name='descriptive' AND sourcetag.tagid != newtag.tagid AND newtag.created_at >= DATE_SUB(NOW(), INTERVAL $self->{months_back} MONTH) AND newtag.uid=users_info.uid @@ -271,10 +274,10 @@ my $total = $w_pos_mag+$w_neg_mag; if ($w_pos_mag > $total * 0.60) { my $neg_reduc_factor = $w_neg_mag*3/$w_pos_mag; - @ret = map { $_ < 0 ? $_*$neg_reduc_factor : $_ } @_; + @ret = map { $_ < 0 ? $_*$neg_reduc_factor : $_ } @w; } elsif ($w_neg_mag > $total * 0.60) { my $pos_reduc_factor = $w_pos_mag*3/$w_neg_mag; - @ret = map { $_ > 0 ? $_*$pos_reduc_factor : $_ } @_; + @ret = map { $_ > 0 ? $_*$pos_reduc_factor : $_ } @w; } else { # No change. @ret = @w; Modified: slashjp/trunk/plugins/Tags/Clout.pm =================================================================== --- slashjp/trunk/plugins/Tags/Clout.pm 2007-12-06 09:12:31 UTC (rev 271) +++ slashjp/trunk/plugins/Tags/Clout.pm 2007-12-06 09:17:47 UTC (rev 272) @@ -39,30 +39,5 @@ 1; } -#sub insert_nextgen { -# my($g, $insert_ar) = @_; -# my $slashdb = getCurrentDB(); -# for my $hr (@$insert_ar) { -# $hr->{gen} = $g; -# $slashdb->sqlInsert('tags_peerweight', $hr); -# } -#} -# -#sub update_tags_peerweight { -# my($insert_ar) = @_; -# for my $hr (@$insert_ar) { -# $tags_peerweight->{ $hr->{uid} } = $hr->{weight}; -# } -#} -# -#sub B_copy_peerweight_sql { -# my $slashdb = getCurrentDB(); -# $slashdb->sqlDo("SET AUTOCOMMIT=0"); -# $slashdb->sqlDo("DELETE FROM users_param WHERE name='tagpeerval2'"); -# $slashdb->sqlDo("INSERT INTO users_param SELECT NULL, uid, 'tagpeerval2', ROUND(weight,6)+0 FROM tags_peerweight"); -# $slashdb->sqlDo("COMMIT"); -# $slashdb->sqlDo("SET AUTOCOMMIT=1"); -#} - 1; Modified: slashjp/trunk/plugins/Tags/PLUGIN =================================================================== --- slashjp/trunk/plugins/Tags/PLUGIN 2007-12-06 09:12:31 UTC (rev 271) +++ slashjp/trunk/plugins/Tags/PLUGIN 2007-12-06 09:17:47 UTC (rev 272) @@ -10,6 +10,7 @@ task=tags_updateclouts.pl template=templates/data;tags;default template=templates/index;tags;default +template=templates/recenttagnamesbox;misc;default template=templates/tagsstorydivadmin;misc;default template=templates/tagsstorydivtagbox;misc;default template=templates/tagsurldivtagbox;misc;default Modified: slashjp/trunk/plugins/Tags/Tagbox.pm =================================================================== --- slashjp/trunk/plugins/Tags/Tagbox.pm 2007-12-06 09:12:31 UTC (rev 271) +++ slashjp/trunk/plugins/Tags/Tagbox.pm 2007-12-06 09:17:47 UTC (rev 272) @@ -287,6 +287,20 @@ return $self->sqlInsert('tagboxlog_feeder', $info_hr); } +sub forceFeederRecalc { + my($self, $tbid, $affected_id) = @_; + my $info_hr = { + -created_at => 'NOW()', + tbid => $tbid, + affected_id => $affected_id, + importance => 9999, + tagid => 0, + tdid => 0, + tuid => 0, + }; + return $self->sqlInsert('tagboxlog_feeder', $info_hr); +} + sub markTagboxLogged { my($self, $tbid, $update_hr) = @_; $self->sqlUpdate('tagboxes', $update_hr, "tbid=$tbid"); Modified: slashjp/trunk/plugins/Tags/Tags.pm =================================================================== --- slashjp/trunk/plugins/Tags/Tags.pm 2007-12-06 09:12:31 UTC (rev 271) +++ slashjp/trunk/plugins/Tags/Tags.pm 2007-12-06 09:17:47 UTC (rev 272) @@ -364,22 +364,41 @@ my($self, $id, $params) = @_; return 0 if !$id || !$params || !%$params; + my $tagboxdb = getObject("Slash::Tagbox"); + my @feeder = ( ); + my $tagboxes = $tagboxdb->getTagboxes(); + my($globjid, $uid) = $self->sqlSelect('globjid, uid', 'tags', "tagid=$id"); + my $changed = 0; for my $key (sort keys %$params) { next if $key =~ /^(tagid|tagname|tagnameid|globjid|uid|created_at|inactivated|private)$/; # don't get to override existing fields my $value = $params->{$key}; + my $this_changed = 0; if (defined($value) && length($value)) { - $changed = 1 if $self->sqlReplace('tag_params', { + $this_changed = 1 if $self->sqlReplace('tag_params', { tagid => $id, name => $key, value => $value, }); } else { my $key_q = $self->sqlQuote($key); - $changed = 1 if $self->sqlDelete('tag_params', + $this_changed = 1 if $self->sqlDelete('tag_params', "tagid = $id AND name = $key_q" ); } + if ($this_changed) { + for my $tagbox_hr (@$tagboxes) { + my $tbid = $tagbox_hr->{tbid}; + my $affected = $tagbox_hr->{affected_type} eq 'user' + ? $uid : $globjid; + $tagboxdb->addFeederInfo($tbid, { + affected_id => $affected, + importance => 1, + tagid => $id, + }); + } + } + $changed ||= $this_changed; } if ($changed) { @@ -1126,6 +1145,14 @@ $tags->processAdminCommand($c, $id, $table); } + my $globjid = $tags_reader->getGlobjidFromTargetIfExists($table, $id); + my $tagboxdb = getObject('Slash::Tagbox'); + my $tagboxes = $tagboxdb->getTagboxes(); + for my $tagbox_hr (@$tagboxes) { + next if $tagbox_hr->{affected_type} eq 'user'; + $tagboxdb->forceFeederRecalc($tagbox_hr->{tbid}, $globjid); + } + my $tags_admin_str = "Performed commands: '@commands'."; if ($type eq "stories") { return slashDisplay('tagsstorydivadmin', { @@ -1153,17 +1180,23 @@ $_adcmd_prefix{0} = '_'; for my $i (1..5) { $_adcmd_prefix{$i} = '#' x $i } } + my @new = ( ); my %count = ( ); for my $c (@commands) { my($type, $tagname) = $self->getTypeAndTagnameFromAdminCommand($c); next unless $type; + if ($type !~ /$(_|#+)/) { + push @new, $c; + next; + } my $count = $type =~ tr/#/#/; $count{$tagname} ||= 0; $count{$tagname} = $count if $count{$tagname} < $count; my $opp = $self->getOppositeTagname($tagname); $count{$opp} ||= 0; } - my @new = ( map { $_adcmd_prefix{$count{$_}} . $_ } sort keys %count ); + + push @new, ( map { $_adcmd_prefix{$count{$_}} . $_ } sort keys %count ); return @new; } } @@ -1291,8 +1324,17 @@ my $new_min_tagid = 0; -#print STDERR "type '$type' for c '$c' new_clout '$new_user_clout' for table $table id $id\n"; - if ($type eq '^') { +print STDERR "type '$type' for c '$c' new_clout '$new_user_clout' for table $table id $id\n"; + if ($type eq '+') { + # Plus sign means admin is saying this tagname is "OK", + # which (at least so far, 2007/12) means it is not + # malicious or stupid or pointless or etc. + $self->setTagname($tagnameid, { admin_ok => 1 }); + } elsif ($type eq ')') { + # Right-paren means admin is labelling this tagname as + # descriptive. Mnemonic: ")" looks like "D" + $self->setTagname($tagnameid, { descriptive => 1 }); + } elsif ($type eq '^') { # Set individual clouts to 0 for tags of this name on # this story that have already been applied. Future # tags of this name on this story will apply with @@ -1369,7 +1411,7 @@ sub getTypeAndTagnameFromAdminCommand { my($self, $c) = @_; - my($type, $tagname) = $c =~ /^(\^|\$?\_|\$?\#{1,5})(.+)$/; + my($type, $tagname) = $c =~ /^(\^|\+|\)|\$?\_|\$?\#{1,5})(.+)$/; #print STDERR scalar(gmtime) . " get c '$c' type='$type' tagname='$tagname'\n"; return (undef, undef) if !$type || !$self->tagnameSyntaxOK($tagname); return($type, $tagname); @@ -1407,7 +1449,7 @@ # are all the opposites of at least one of the inputs. sub getOppositeTagnameids { - my($self, $data) = @_; + my($self, $data, $create) = @_; my @tagnameids = ( ); $data = [ $data ] if !ref($data); @@ -1434,7 +1476,15 @@ # Type one: my @tagnames = map { $self->getTagnameDataFromId($_)->{tagname} } @tagnameids; my @opp_tagnames = map { $self->getOppositeTagname($_) } @tagnames; - my @opp_tagnameids_1 = map { $self->getTagnameidCreate($_) } @opp_tagnames; + my @opp_tagnameids_1 = ( ); + if ($create) { + @opp_tagnameids_1 = + map { $self->getTagnameidCreate($_) } @opp_tagnames; + } else { + @opp_tagnameids_1 = + grep { $_ } + map { $self->getTagnameidFromNameIfExists($_) } @opp_tagnames; + } # Type two: my $src_tnids_str = join(',', @tagnameids); my $opp_tagnameids_2_ar = $self->sqlSelectColArrayref( @@ -1685,6 +1735,161 @@ }, { ignore => 1, delayed => 1 }); } +sub getRecentTagnamesOfInterest { + my($self, $options) = @_; + my $max_num = $options->{max_num} || 10; + my $min_weight = $options->{min_weight} || 1; + + # First, collect the list of all tagnames used recently. + my $secsback = $options->{secsback} || 12 * 3600; + my $tagname_recent_ar = $self->listTagnamesRecent({ seconds => $secsback }); + # If none, short-circuit out. + return [ ] if !@$tagname_recent_ar; + + # Get their tagnameids. + my $tagname_str = join(',', map { $self->sqlQuote($_) } sort @$tagname_recent_ar); + my $tagnameid_to_name = $self->sqlSelectAllKeyValue( + 'tagnameid, tagname', + 'tagnames', + "tagname IN ($tagname_str)"); + my $tagnameid_str = join(',', map { $self->sqlQuote($_) } sort 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)"); + my %tagname_firstrecent = ( map { ($_, 1) } @$tagname_firstrecent_ar ); + + # Build a regex that will identify tagnames that begin with an + # author's name, and a hash matching recent tagnames. + my $author_names = join('|', map { "\Q\L$_\E" } @{ $self->getAuthorNames() }); + my $author_regex = qr{^($author_names)}; + my %tagname_startauthor = ( map { ($_, 1) } + grep { $_ =~ $author_regex } @$tagname_recent_ar ); + + # Build a hash identifying those tagnames which have been + # marked by an admin, at any time, as being "ok." + my $tagnameid_ok_ar = $self->sqlSelectColArrayref( + 'DISTINCT tagnameid', + 'tagcommand_adminlog', + "tagnameid IN ($tagnameid_str) + AND cmdtype='+'"); + my %tagname_adminok = ( map { ($tagnameid_to_name->{$_}, 1) } @$tagnameid_ok_ar ); + + # Build a hash identifying those tagnames which have been + # marked by an admin, at any time, as being bad (# etc.). + my $tagnameid_bad_ar = $self->sqlSelectColArrayref( + 'DISTINCT tagnameid', + 'tagcommand_adminlog', + "tagnameid IN ($tagnameid_str) + AND cmdtype REGEXP '#'"); + my %tagname_bad = ( map { ($tagnameid_to_name->{$_}, 1) } @$tagnameid_bad_ar ); + + # Using the hashes, build a list of all recent tagnames which + # are of interest. + my @tagnames_of_interest = grep { + $tagname_bad{$_} + || $tagname_startauthor{$_} + || ( $tagname_firstrecent{$_} && !$tagname_adminok{$_} ) + } @$tagname_recent_ar; +if (!@tagnames_of_interest) { use Data::Dumper; print STDERR "none interesting in '@$tagname_recent_ar', bad: " . Dumper(\%tagname_bad) . "startauthor: " . Dumper(\%tagname_startauthor) . "firstrecent: " . Dumper(\%tagname_firstrecent) . "adminok: " . Dumper(\%tagname_adminok); } + return [ ] if !@tagnames_of_interest; + my @tagnameids_of_interest = map { $tagname_to_id->{$_} } @tagnames_of_interest; + my $tagnameids_of_interest_str = join(',', map { $self->sqlQuote($_) } + sort @tagnameids_of_interest); + + # Now sort the tagnames in order of the sum of their current + # weights. Exclude those with sum weight 0, because there's + # no need for admins to evaluate those. + my $tags_ar = $self->sqlSelectAllHashrefArray( + '*', + 'tags', + "tagnameid IN ($tagnameids_of_interest_str) + AND created_at >= DATE_SUB(NOW(), INTERVAL $secsback SECOND)"); + $self->addCloutsToTagArrayref($tags_ar, 'describe'); + my %tagnameid_weightsum = ( ); + my %t_globjid_weightsum = ( ); + for my $tag_hr (@$tags_ar) { + my $tc = $tag_hr->{total_clout}; + next unless $tc; + my $tagnameid = $tag_hr->{tagnameid}; + my $globjid = $tag_hr->{globjid}; + $tagnameid_weightsum{ $tagnameid } ||= 0; + $tagnameid_weightsum{ $tagnameid } += $tc; + $t_globjid_weightsum{ $tagnameid }{ $globjid } ||= 0; + $t_globjid_weightsum{ $tagnameid }{ $globjid } += $tc; + } + my @tagnameids_top = + sort { $tagnameid_weightsum{$b} <=> $tagnameid_weightsum{$a} + || $b <=> $a } + grep { $tagnameid_weightsum{$_} >= $min_weight } + keys %tagnameid_weightsum; + $#tagnameids_top = $max_num-1 if $#tagnameids_top > $max_num; + + # Now we just have to construct the data structure to return. + my @rtoi = ( ); + my %globjid_linktext = ( ); + my $linktext_next = 'a'; # label the links simply 'a', 'b', etc. + for my $tagnameid (@tagnameids_top) { + my @globjids = + sort { $t_globjid_weightsum{$tagnameid}{$b} <=> $t_globjid_weightsum{$tagnameid}{$a} + || $b <=> $a } + keys %{$t_globjid_weightsum{$tagnameid}}; + $#globjids = $max_num-1 if $#globjids > $max_num; + my @globjid_data = ( ); + for my $globjid (@globjids) { + my $lt = $globjid_linktext{$globjid} || ''; + if (!$lt) { + $lt = $globjid_linktext{$globjid} = $linktext_next; + ++$linktext_next; + } + push @globjid_data, { + globjid => $globjid, + linktext => $lt, + }; + } + $self->addGlobjEssentialsToHashrefArray(\@globjid_data); + push @rtoi, { + tagname => $tagnameid_to_name->{$tagnameid}, + globjs => \@globjid_data, + }; + } +use Data::Dumper; print STDERR scalar(localtime) . " rtoi: " . Dumper(\@rtoi); + + return \@rtoi; +} + +sub showRecentTagnamesBox { + my($self, $options) = @_; + my $rtoi_ar = $self->getRecentTagnamesOfInterest($options); + + my $text = slashDisplay('recenttagnamesbox', { + rtoi => $rtoi_ar, + }, { Return => 1 }); + + return $text if $options->{contents_only}; + + my $updater = getData('recenttagnamesbox_js', { }, 'tags') if $options->{updater}; + slashDisplay('sidebox', { + updater => $updater, + title => 'Recent Tagnames', + contents => $text, + name => 'recenttagnames', + }, { Return => 1 }); +} + +sub ajax_recenttagnamesbox { + my $tagsdb = getObject("Slash::Tags"); + $tagsdb->showRecentTagnamesBox({ contents_only => 1}); +} + ################################################################# sub DESTROY { my($self) = @_; Modified: slashjp/trunk/plugins/Tags/templates/data;tags;default =================================================================== --- slashjp/trunk/plugins/Tags/templates/data;tags;default 2007-12-06 09:12:31 UTC (rev 271) +++ slashjp/trunk/plugins/Tags/templates/data;tags;default 2007-12-06 09:17:47 UTC (rev 272) @@ -42,6 +42,9 @@ <i>(none)</i> [% END %] +[% CASE 'recenttagnamesbox_js' %] + <script type="text/javascript">admin_recenttagnamesbox_fetch(60);</script> + [% CASE 'error' %] Sorry, an error occurred. [% returnme.data_constant = 1 %] Copied: slashjp/trunk/plugins/Tags/templates/recenttagnamesbox;misc;default (from rev 269, slashjp/branches/upstream/current/plugins/Tags/templates/recenttagnamesbox;misc;default) Modified: slashjp/trunk/sql/mysql/defaults.sql =================================================================== --- slashjp/trunk/sql/mysql/defaults.sql 2007-12-06 09:12:31 UTC (rev 271) +++ slashjp/trunk/sql/mysql/defaults.sql 2007-12-06 09:17:47 UTC (rev 272) @@ -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_184','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_186','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 2007-12-06 09:12:31 UTC (rev 271) +++ slashjp/trunk/sql/mysql/upgrades 2007-12-06 09:17:47 UTC (rev 272) @@ -4963,8 +4963,6 @@ # 2007-10-25 UPDATE vars SET value = 'T_2_5_0_181' WHERE name = 'cvs_tag_currentcode'; -# PUDGE LAST UPDATED HERE - # For plugins/FireHose # Install CPAN module File::Type for plugins/FireHose ALTER TABLE firehose_text ADD COLUMN media TEXT; @@ -5007,8 +5005,6 @@ # 18 = "Invalid HTML Input" (see the Messages dump to add back) DELETE FROM message_codes WHERE code = 18; -# SLASHCODE/USEPERL LAST UPDATED HERE - # Redundant for many sites, but this is here because an earlier error # in the upgrades file may have left your site without them if you # didn't have the FireHose plugin installed. @@ -5036,8 +5032,6 @@ # 2007-11-08 UPDATE vars SET value = 'T_2_5_0_183' WHERE name = 'cvs_tag_currentcode'; -# SLASHDOT LAST UPDATED HERE - INSERT INTO blocks (bid, block, seclev, type, description, skin, ordernum, title, portal, url, rdf, retrieve) VALUES ('spamurlregexes','',100,'static','Whitespace-delimited list of regexes which indicate a spammer URL.','mainpage',5,'Spam URL Regexes',0,NULL,NULL,0); INSERT IGNORE INTO vars (name, value, description) VALUES ('al2_type_aliases', 'spammer->nosubmit spammer->nopost nopost->nopostanon', 'List of AL2s that imply other AL2s, in a whitespace-delimited list of A->B format'); @@ -5047,8 +5041,29 @@ UPDATE code_param SET name = 'Oldest' WHERE type = 'd2_comment_order' AND name = 'Date'; UPDATE code_param SET name = 'Highest Rated' WHERE type = 'd2_comment_order' AND name = 'Score'; -UPDATE al2_types SET name='spammer',title='Binspammer' WHERE name='binspam'; +UPDATE al2_types SET name='spammer',title='Spammer' WHERE name='binspam'; # 2007-11-14 UPDATE vars SET value = 'T_2_5_0_184' WHERE name = 'cvs_tag_currentcode'; +# SLASHDOT LAST UPDATED HERE + +# 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'; + +# SLASHCODE/USEPERL LAST UPDATED HERE + +# for plugins/Tags +INSERT INTO ajax_ops VALUES (NULL, 'admin_recenttagnamesbox', 'Slash::Tags', 'ajax_recenttagnamesbox', 'ajax_admin', 'createuse'); + +# for plugins/FireHose +INSERT IGNORE INTO ajax_ops VALUES (NULL, 'firehose_usage', 'Slash::FireHose', 'ajaxFireHoseUsage', 'ajax_admin', 'createuse'); + +# 2007-12-05 +UPDATE vars SET value = 'T_2_5_0_186' WHERE name = 'cvs_tag_currentcode'; + Modified: slashjp/trunk/tagboxes/Top/mysql_dump.sql =================================================================== --- slashjp/trunk/tagboxes/Top/mysql_dump.sql 2007-12-06 09:12:31 UTC (rev 271) +++ slashjp/trunk/tagboxes/Top/mysql_dump.sql 2007-12-06 09:17:47 UTC (rev 272) @@ -4,7 +4,7 @@ INSERT IGNORE INTO vars (name, value, description) VALUES ('tagbox_top_minscore_stories', '2', 'Minimum score a tag must have to make it into the top tags for a story'); INSERT IGNORE INTO vars (name, value, description) VALUES ('tagbox_top_minscore_urls', '2', 'Minimum score a tag must have to make it into the top tags for a URL'); -INSERT IGNORE INTO vars (name, value, description) VALUES ('tagbox_top_excludetagnames', 'yes no binspam dupe notthebest offtopic stupid slownewsday interesting funny insightful', 'Minimum score a tag must have to make it into the top tags for a story or firehose item'); +INSERT IGNORE INTO vars (name, value, description) VALUES ('tagbox_top_excludetagnames', 'yes no binspam dupe notthebest offtopic stupid slownewsday stale interesting funny insightful fresh', 'Minimum score a tag must have to make it into the top tags for a story or firehose item'); INSERT INTO tagbox_userkeyregexes VALUES ('Top', '^tag_clout$'); Modified: slashjp/trunk/themes/slashcode/htdocs/base.css =================================================================== --- slashjp/trunk/themes/slashcode/htdocs/base.css 2007-12-06 09:12:31 UTC (rev 271) +++ slashjp/trunk/themes/slashcode/htdocs/base.css 2007-12-06 09:17:47 UTC (rev 272) @@ -755,7 +755,7 @@ #modal_cover {background-color: #222; height: 100%; opacity: 0.75; filter: alpha(opacity=75); position: fixed; width: 100%; z-index: 1000000;} #modal_box .generaltitle .title h3 {background: transparent; margin: 0; padding: .1em .3em 0 .3em;} #modal_box .generaltitle .title { margin: 0; border: none;} -#modal_box {position: fixed; margin: 15% 25%; width: 60%;z-index: 1000001;border: 4px solid #222;} +#modal_box {position: fixed; margin: 15% 25%; width: 50%;z-index: 1000001;border: 4px solid #222; overflow: auto; background: #fff; height: 65%;} #modal_box h3 a {position: absolute !important; right: .3em; top: .3em} #modal_box #modal_box_content legend {display: none;} #modal_box #modal_box_content fieldset {margin: 0;padding: 0;border: none;} Modified: slashjp/trunk/themes/slashcode/htdocs/comments.css =================================================================== --- slashjp/trunk/themes/slashcode/htdocs/comments.css 2007-12-06 09:12:31 UTC (rev 271) +++ slashjp/trunk/themes/slashcode/htdocs/comments.css 2007-12-06 09:17:47 UTC (rev 272) @@ -234,6 +234,9 @@ #commentlisting {clear: right;} #commentControlBoxStatus {border-bottom: 1px solid #444; border-top: 1px solid #ccc; text-align: center; padding: 3px; background: #666; color: #fff; } +#bindings-legend {display: none; position: relative; text-align: center; font-family: monospace} +.vertical #bindings-legend {display: block;} + .escape-link { position: absolute; left: 0.8em; } .horizontal .loki {display: block;} Modified: slashjp/trunk/themes/slashcode/htdocs/images/comments.js =================================================================== --- slashjp/trunk/themes/slashcode/htdocs/images/comments.js 2007-12-06 09:12:31 UTC (rev 271) +++ slashjp/trunk/themes/slashcode/htdocs/images/comments.js 2007-12-06 09:17:47 UTC (rev 272) @@ -14,7 +14,7 @@ var root_comments_hash = {}; var last_updated_comments = []; var last_updated_comments_index = 0; -var last_updated_comments_started = 0; +var comments_started = 0; var current_cid = 0; var more_comments_num; var behaviors = { @@ -45,6 +45,7 @@ var loaded = 0; var shift_down = 0; var alt_down = 0; +var ctrl_down = 0; var d2_seen = ''; var agt = navigator.userAgent.toLowerCase(); @@ -123,14 +124,14 @@ var kidhiddens = 0; if (comment && comment['kids'] && comment['kids'].length) { - if (!subexpand) { - if (shift_down && !alt_down && futuredisplaymode[cid] == 'full') { - subexpand = 1; - } else if (shift_down && !alt_down && futuredisplaymode[cid] == 'oneline') { - subexpand = 2; - threshold = user_threshold; - } - } +// if (!subexpand) { +// if (shift_down && !alt_down && futuredisplaymode[cid] == 'full') { +// subexpand = 1; +// } else if (shift_down && !alt_down && futuredisplaymode[cid] == 'oneline') { +// subexpand = 2; +// threshold = user_threshold; +// } +// } for (var kiddie = 0; kiddie < comment['kids'].length; kiddie++) { kidhiddens += updateCommentTree(comment['kids'][kiddie], threshold, subexpand); @@ -644,6 +645,8 @@ /*******************/ /* misc. functions */ /*******************/ +function numsort (a, b) { return (a - b) } + function toHash(thisobject) { return thisobject.map(function (pair) { return pair.map(encodeURIComponent).join(','); @@ -1027,7 +1030,7 @@ if (!noshow_comments_hash[cid]) last_updated_comments.push(cid); } - last_updated_comments = last_updated_comments.sort(function (a, b) { return (a - b) }); + last_updated_comments = last_updated_comments.sort(numsort); if (1 || user_is_admin) { if (window.addEventListener) // DOM method for binding an event @@ -1038,7 +1041,7 @@ document.body.onkeydown = keyHandler; } - setCurrentComment(last_updated_comments[i]); + setCurrentComment(last_updated_comments[last_updated_comments_index]); if (more_comments_num) updateMoreNum(more_comments_num); @@ -1065,12 +1068,12 @@ function resetModifiers () { shift_down = 0; alt_down = 0; + ctrl_down = 0; } function doModifiers (e) { e = e || window.event; - shift_down = 0; - alt_down = 0; + resetModifiers(); if (e) { if (e.modifiers) { @@ -1078,11 +1081,15 @@ shift_down = 1; if (e.modifiers & Event.ALT_MASK) alt_down = 1; + if (e.modifiers & Event.CTRL_MASK) + ctrl_down = 1; } else { if (e.shiftKey) shift_down = 1; if (e.altKey) alt_down = 1; + if (e.ctrlKey) + ctrl_down = 1; } } } @@ -1299,7 +1306,10 @@ } function commentIsInWindow(cid) { - return isInWindow(fetchEl('comment_' + cid)); + var in_window = isInWindow(fetchEl('comment_' + cid)); + if (in_window && fetchEl('comment_body_' + cid)) + in_window = isInWindow(fetchEl('comment_body_' + cid)); + return in_window; } function isInWindow(obj) { @@ -1690,62 +1700,220 @@ } -function keyHandler(e) { - e = e || window.event; +/* keys +prev comment: A, H +next comment: D, L +prev thread: W, J +next thread: S, K +prev comm chrono: Q +next comm chrono: E +*/ - if (e) { +var validkeys = { + A: { thread : 1, prev: 1, comment: 1 }, + D: { thread : 1, next: 1, comment: 1 }, + W: { thread : 1, prev: 1 }, + S: { thread : 1, next: 1 }, + Q: { chrono : 1, prev: 1, comment: 1 }, + E: { chrono : 1, next: 1, comment: 1 }, +}; + +validkeys['H'] = validkeys['A']; +validkeys['L'] = validkeys['D']; +validkeys['J'] = validkeys['W']; +validkeys['K'] = validkeys['S']; + +function keyHandler(e, k) { + if (!k) + e = e || window.event; + + if (k || e) { // don't handle for forms ... "type" should handle all our cases here - if (e.target && e.target.type) + if (!k && e.target && e.target.type) return; - var c = e.keyCode; - if (c) { - var key = String.fromCharCode(c); - if (key == 'J' || key == 'K' || key == 'W' || key == 'S') { + var c; + if (e) + c = e.keyCode; + if (k || c) { + if (!k) + doModifiers(e); + var collapseCurrent = shift_down; + var getNextUnread = ctrl_down; + if (!k) + resetModifiers(); + + var update = 0; + var next_cid = 0; + var key = k || String.fromCharCode(c); + var keyo = validkeys[key]; + // forward and back between comments, in order of how they were loaded + if (keyo && keyo['chrono']) { var i = last_updated_comments_index; var l = last_updated_comments.length - 1; - var update = 0; - if (key == 'J' || key == 'S') { - update = 1; + update = 1; + + if (keyo['prev']) { if (i <= 0) { // this did go back to end; nothing, for now //i = l; } else i = i - 1; - } else if (key == 'K' || key == 'W') { + } else if (keyo['next']) { if (i >= l) { if (ajaxCommentsWait()) return; update = 2; ajaxFetchComments(0, 1, '', 1); } else { - update = 1; - if (!i && !last_updated_comments_started && !commentIsInWindow(last_updated_comments[i])) - last_updated_comments_started = 1; // only come here once + if (!i && noSeeFirstComment(last_updated_comments[i])) + comments_started = 1; // only come here once else i = i + 1; } } - if (update) { - doModifiers(e); - var this_shift_down = shift_down; - resetModifiers(); - if (this_shift_down && current_cid) { // if shift, collapse previously selected - setFocusComment('-' + current_cid, 1); + if (update == 1) { + last_updated_comments_index = i; + next_cid = last_updated_comments[i]; + } + } + + // forward and back between threads, and comments within each thread + else if (keyo && keyo['thread']) { + update = 1; + if (keyo['next']) { + if (noSeeFirstComment(current_cid)) + next_cid = current_cid; + else { + if (keyo['comment']) + next_cid = commTreeNextComm(current_cid, 0, getNextUnread); + else + next_cid = commTreeNextComm(comments[current_cid].pid, current_cid, getNextUnread); } - if (update == 1) { - last_updated_comments_index = i; - setFocusComment(last_updated_comments[i], 1); - } } + + else if (keyo['prev'] && keyo['comment']) + next_cid = commTreePrevComm(current_cid); + + else if (keyo['prev']) + next_cid = commTreePrevComm(current_cid, 1); } + + if (update && next_cid) { + comments_started = 1; + if (collapseCurrent && current_cid) + setFocusComment('-' + current_cid, 1); + if (update == 1) + setFocusComment(next_cid, 1); + } } } +} +// at first comment, comment is not in window OR comment is not full +function noSeeFirstComment (cid) { + setDefaultDisplayMode(cid); + if (!comments_started && (!commentIsInWindow(cid) || (viewmodevalue[displaymode[cid]] < viewmodevalue['full']))) { + return 1; + } + return 0; } +// XXX somehow sync this with the prev/next by load order? might require +// a quick grep to find the position +function commTreeNextComm (cid, old_cid, getNextUnread) { + var kids; + if (cid) + kids = sortKids(cid); + else + kids = rootSort(); + for (var i = 0; i < kids.length; i++) { + var next_cid = kids[i]; + if (next_cid > old_cid) { + if (next_cid) + if (!getNextUnread || (next_cid = getNextUnreadCid(next_cid))) + return next_cid; + continue; + } + } + + if (!cid) + return 0; // at the end, stay where we are + + // we can't continue here, go back up a level + return commTreeNextComm(comments[cid].pid, cid, getNextUnread); +} + +function commTreePrevComm (cid, to_parent) { + var root_kids = root_comments.sort(numsort); + var comm = comments[cid]; + var pid = comm.pid; + + if (to_parent == 1) { + if (pid) + return pid; + else // if in roots, then just climb up roots + return commTreePrevComm(cid, 2); + } + + var kids; + if (pid) + kids = sortKids(pid); + else + kids = root_kids; + + for (var i = 0; i < kids.length; i++) { + if (cid == kids[i]) { + if (i == 0) // go up + return pid; + else if (to_parent) + return kids[i - 1]; + else + return getLastChild(kids[i - 1]); + } + } +} + +function rootSort() { // maybe cache later + return root_comments.sort(numsort); +} + +function sortKids(cid) { // maybe cache later + return comments[cid].kids.sort(numsort); +} + +function isUnread(cid) { + var this_id = fetchEl('comment_top_' + cid); + if (this_id) + if (this_id.className.match(' oldcomment')) + return 0; + else + return 1; +} + +function getNextUnreadCid(cid) { + if (isUnread(cid)) + return cid; + var kids = sortKids(cid); + for (var i = 0; i < kids.length; i++) { + var next_cid = getNextUnreadCid(kids[i]); + if (next_cid) + return next_cid; + } + return 0; +} + +function getLastChild(cid) { + var kids = sortKids(cid); + if (kids.length) + return getLastChild(kids[kids.length - 1]); + else + return cid; +} + + function dummyComment(cid) { var html = '<li id="tree_--CID--" class="comment">\ <div id="comment_status_--CID--" class="commentstatus"></div>\ Modified: slashjp/trunk/themes/slashcode/htdocs/users.pl =================================================================== --- slashjp/trunk/themes/slashcode/htdocs/users.pl 2007-12-06 09:12:31 UTC (rev 271) +++ slashjp/trunk/themes/slashcode/htdocs/users.pl 2007-12-06 09:17:47 UTC (rev 272) @@ -906,7 +906,7 @@ $form->{mode} = "full"; $form->{color} = "black"; $form->{orderby} = "createtime"; - $form->{orderdidr} = "DESC"; + $form->{orderdir} = "DESC"; $form->{skipmenu} = 1; $form->{duration} = -1; $form->{fhfilter} = "\"user:$user_edit->{nickname}\""; Modified: slashjp/trunk/themes/slashcode/tasks/freshenup.pl =================================================================== --- slashjp/trunk/themes/slashcode/tasks/freshenup.pl 2007-12-06 09:12:31 UTC (rev 271) +++ slashjp/trunk/themes/slashcode/tasks/freshenup.pl 2007-12-06 09:17:47 UTC (rev 272) @@ -409,8 +409,9 @@ }); if ($constants->{plugin}{FireHose}) { - gen_firehose_static($virtual_user, "index_firehose.shtml", $gSkin->{name}, "", { skipmenu => 1, skippop => 1, fhfilter=> "story", duration => "7", mode => 'fulltitle', mixedmode => '1', setfield => '1', color => "black", index => "1", nocolors => 1 }); + gen_firehose_static($virtual_user, "index_firehose.shtml", $gSkin->{name}, "", { skipmenu => 1, skippop => 1, fhfilter => "story", duration => "7", mode => 'fulltitle', mixedmode => '1', setfield => '1', color => "black", index => "1", nocolors => 1 }); gen_firehose_static($virtual_user, "firehose.shtml", $gSkin->{name}, "", { duration => "7", mode => 'fulltitle', mixedmode => '1', setfield => '1', color => "blue", nodates => '1' }); + gen_firehose_static($virtual_user, "embed_index.shtml", $gSkin->{name}, "", { embed => '1', smalldevices => '1', fhfilter => "story", duration => "7", mode => 'fulltitle', setfield => '1', color => "black", index => "1", nodates => '1', nocolors => 1 }); gen_firehose_static($virtual_user, "embed_firehose.shtml", $gSkin->{name}, "", { embed => '1', smalldevices => '1', duration => "7", mode => 'fulltitle', setfield => '1', color => "blue", nodates => '1' }); } $slashdb->markSkinClean($mp_skid); @@ -440,8 +441,9 @@ handle_err => 0 }); if ($constants->{plugin}{FireHose}) { - gen_firehose_static($virtual_user, "index_firehose.shtml", $skin->{name}, $skinname, { skipmenu => 1, skippop => 1, fhfilter=> "'story $skin->{name}'", duration => "7", mode => 'fulltitle', mixedmode => '1', setfield => '1', color => "black", index => "1", nocolors => "1" }); + gen_firehose_static($virtual_user, "index_firehose.shtml", $skin->{name}, $skinname, { skipmenu => 1, skippop => 1, fhfilter => "'story $skin->{name}'", duration => "7", mode => 'fulltitle', mixedmode => '1', setfield => '1', color => "black", index => "1", nocolors => "1" }); gen_firehose_static($virtual_user, "firehose.shtml", $skin->{name}, $skinname, { duration => "7", mode => 'fulltitle', mixedmode => '1', setfield => '1', color => "blue", nodates => '1', fhfilter => "'$skin->{name}'" }); + gen_firehose_static($virtual_user, "embed_index.shtml", $gSkin->{name}, "", { embed => '1', smalldevices => '1', fhfilter => "'story $skin->{name}'", duration => "7", mode => 'fulltitle', setfield => '1', color => "black", index => "1", nodates => '1', nocolors => 1 }); gen_firehose_static($virtual_user, "embed_firehose.shtml", $skin->{name}, $skinname, { embed => '1', smalldevices => '1', duration => "7", mode => 'fulltitle', setfield => '1', color => "blue", nodates => '1', fhfilter => "'$skin->{name}'" }); } Modified: slashjp/trunk/themes/slashcode/templates/prefs_titlebar;misc;default =================================================================== --- slashjp/trunk/themes/slashcode/templates/prefs_titlebar;misc;default 2007-12-06 09:12:31 UTC (rev 271) +++ slashjp/trunk/themes/slashcode/templates/prefs_titlebar;misc;default 2007-12-06 09:17:47 UTC (rev 272) @@ -18,8 +18,13 @@ PROCESS titlebar title=title; '<div id="usermenu">'; +user_link = '/users.pl?op=edituser'; +IF constants.modal_prefs_active; + user_link = user_link _ "\" onclick=\"getModalPrefs('user', 'User')\; return false"; +END; + tabs = [ - { link = "/users.pl?op=edituser", label = "User", sel_label = "user" }, + { link = user_link, label = "User", sel_label = "user" }, { link = "/users.pl?op=edithome", label = "Homepage", sel_label = "home" }, { link = "/users.pl?op=editcomm", label = "Comments", sel_label = "comments" } ]; Modified: slashjp/trunk/themes/slashcode/templates/printCommentsMain;misc;default =================================================================== --- slashjp/trunk/themes/slashcode/templates/printCommentsMain;misc;default 2007-12-06 09:12:31 UTC (rev 271) +++ slashjp/trunk/themes/slashcode/templates/printCommentsMain;misc;default 2007-12-06 09:17:47 UTC (rev 272) @@ -282,6 +282,14 @@ subject_only => 1 }) %] [% END %] + <div id="bindings-legend">Keybindings Beta<br> +<a href="#" onclick="keyHandler('','Q'); return false" title="previous comment by load order">Q</a> +<a href="#" onclick="keyHandler('','W'); return false" title="previous thread" >W</a> +<a href="#" onclick="keyHandler('','E'); return false" title="next comment by load order" >E</a><br> +<a href="#" onclick="keyHandler('','A'); return false" title="previous comment in thread" >A</a> +<a href="#" onclick="keyHandler('','S'); return false" title="next thread" >S</a> +<a href="#" onclick="keyHandler('','D'); return false" title="next comment in thread" >D</a> + </div> </div> <div id="commentControlBoxStatus" class="hide"><b>Loading ... Please wait.</b></div> </div>