Anne Rice (Unofficial Build 6)

All new Coranto Addons, updates and patches to addons, will be released here...also, get support for addons within!

Moderators: Spunkmeyer, Dale Ray, SrNupsen, Bluetooth, Jackanape

Anne Rice (Unofficial Build 6)

Postby Pirate Elf » Tue Jun 17, 2008 12:02 pm

Once again here is another unofficial update to a beloved addon. The changes in this addon are documented here

Basically this version makes it to where if you turn on Anne Rice after having a site up for a while it will do the add replaces without having to modify every single entry! ;-)

cra_annerice.zip
(Virus Scanned With Bit Defender 2008, but that doesn't mean you should EVER trust the interweb! Please virus scan everything and be sure to look through any code if you can attain source)

Code: Select all
#! CRADDON 1
#! NAME Anne Rice
#! DESCRIPTION Anne Rice is an advanced glossary with reverse-replacement in Modify News and other useful features.<br>Written by: plushpuffin<br>Modified By: faithless<br>Put Together By: PirateElf
#! VERSION Unofficial Build 6
#! HOMEPAGE mailto:plushpuffin@wwddfd.com">E-Mail Author</a>] [<a href="http://www.wwddfd.com/
#! DOC 1

#
# Provides advanced glossary functionality for Coranto.
# http://www.wwddfd.com/
#

# Will compile & work with the following:
#use strict;
#use vars qw(%Subs %in %CConfig @annerice @anne_re $ardbloaded );

my $addon = new Addon('Anne Rice');
$addon->registerAdminFunction('annericesave', 'AnneRiceSave');
$addon->registerAdminFunction('annerice', 'AnneRiceEdit');
$addon->registerAdminFunction('annericeupdate', 'AnneRiceUpdate');
$addon->addAdminFunction('Anne Rice', 'Edit the Anne Rice Advanced Glossary.' . '<br>' .
   PageLink( { action => 'admin', adminarea => 'annericeupdate' } ) . q~Click here to run Anne Rice on ALL NEWS.</a>~, 'annerice');
$addon->checkBuild(19);

my $ModifyNews_Edit_TopRow = << 'END_CODE';
   &AnneRiceLoadDB;
   &CRHTMLHead("annericetest");
   my @annefields = split( /\Q(delim)\E/, $CConfig{annefields} );
   for( my $i = 0; $i < @annerice; $i++ ) {
      my $flags = '';
      unless( $annerice[$i]->[3] ) {
         $flags .= 'g';
      }
      if( $annerice[$i]->[4] ) {
         $flags .= 'i';
      }
      my $code = '';
      if( $anne_re[$i] != undef ) {
         $code = q^$$fn =~ ^ . $anne_re[$i]->[1] . q~;~;
      }
      else {
            $code = q^$$fn =~ s/^;                     # start the regex
            if( $annerice[$i]->[2] ) {
               $code .= '([^\w\d\<]|\A)\Q';            # word break
               $code .= $annerice[$i]->[1];            # search for this
               $code .= '\E([^\w\d\>]|\Z)';            # another word break
               $code .= '/';                        # middle of regex
               $code .= '$1' . "((annerice$i))" . '$2';   # replace with this
            }
            else {
               $code .= '\Q';                        # no word break
               $code .= $annerice[$i]->[1];            # search for this
               $code .= '\E';                        # no word break
               $code .= '/';                        # middle of regex
               $code .= "((annerice$i))";               # replace with this
            }
            $code .= '/' . $flags;                     # end the regex
      }
      # print '<h4>' . HTMLescape("$code") . '</h4>';
      foreach my $fn (@annefields) {
         eval $code;
         if( $anne_re[$i] == undef ) {
            $$fn =~ s/\(\(annerice(\d+)\)\)/$annerice[$i]->[0]/g;
         }
      }
   }
END_CODE

my $AnneRice_SaveNews = << 'END_CODE';
   &AnneRiceLoadDB;
   my @annefields = split( /\Q(delim)\E/, $CConfig{annefields} );
   for( my $i = 0; $i < @annerice; $i++ ) {
      my $flags = '';
      unless( $annerice[$i]->[3] ) {
         $flags .= 'g';
      }
      if( $annerice[$i]->[4] ) {
         $flags .= 'i';
      }
      my $code = '';
      if( $anne_re[$i] != undef ) {
         $code = q^$$fn =~ ^ . $anne_re[$i]->[0] . q~;~;
      }
      else {
            $code = q^$$fn =~ s/^;                     # start the regex
            if( $annerice[$i]->[2] ) {
               $code .= '([^\w\d\<]|\A)\Q';            # word break
               $code .= $annerice[$i]->[0];            # search for this
               $code .= '\E([^\w\d\>]|\Z)';            # another word break
               $code .= '/';                        # middle of regex
               $code .= '$1' . "((annerice$i))" . '$2';   # replace with this
            }
            else {
               $code .= '\Q';                        # no word break
               $code .= $annerice[$i]->[0];            # search for this
               $code .= '\E';                        # no word break
               $code .= '/';                        # middle of regex
               $code .= "((annerice$i))";               # replace with this
            }
            $code .= '/' . $flags;                     # end the regex
      }
      # print '<h4>' . HTMLescape("$code") . '</h4>';
      foreach my $fn (@annefields) {
         eval $code;
         if( $anne_re[$i] == undef ) {
            $$fn =~ s/\(\(annerice(\d+)\)\)/$annerice[$i]->[1]/g;
         }
      }
   }
END_CODE

my $AdvSettings = << 'END_CODE';
   NeedCFG();
   my( $runselect, %runfields, $i, $numfields, $glossdat );
   foreach $i ( split(/\Q(delim)\E/, $CConfig{annefields}) ) {
      $runfields{$i} = ' selected';
   }
   foreach $i (@fieldDB) {
      $runselect .= qq~
      <option value="$i"$runfields{$i}>$fieldDB{$i}->{DisplayName}</option>~;
   }
   $numfields = @fieldDB > 10 ? 10 : @fieldDB;
   $CConfig{annericeglossary} ||= qq~$CConfig{htmlfile_path}/glossdat.txt~;
   $addon->addAdvancedSettingHeading('Anne Rice');
   $addon->addAdvancedSetting('annericeglossary', '<i>glossdat.txt</i> file location', "The exact pathname to, and name of, the Anne Rice glossdat.txt file.");
   $addon->addAdvancedSetting('annefields', 'Run Fields', "The fields to run the Anne Rice Glossary on.",
qq~
<select name="annefields" size="$numfields" multiple>
$runselect
</select>
~);
END_CODE

# EditGlossary: Display Edit Anne Rice Glossary page
$Subs{'AnneRiceEdit'} = << 'END_SUB';
sub AnneRiceEdit {
   my $addon = shift;
   &AnneRiceLoadDB;
   $addon->pageHeader('Edit Anne Rice Glossary', 1);
   print $addon->descParagraph(q~You may edit the following glossary entries. When submitting news, text
that matches the text you enter in the first field will be replaced with what you entered in the
second field.<br><br>
When modifying news, the reverse will occur; your news will appear
as it did in Submit News.<br><br>
To add a new entry, use the blank fields provided at the bottom.
(If you fill the available blank fields, click Submit Changes and then edit Anne Rice again. Four new
blank fields will be available.)<br><br>
To delete an entry, delete everything in both fields.~),
   $addon->form({'action' => 'admin', 'adminarea' => 'annericesave'}),
   q~<br><div align="center"><input type="submit" name="submit" value="Submit Changes"></div><table width="95%" border="0" align="center" cellpadding="2" cellspacing="0">~;
   my( $i, $findtext, $replacewith, $wholeword, $single, $nocase );
   for( $i = 0; $i < @annerice + 4; $i++ ) {
      if( $i < @annerice ) {
         ( $findtext, $replacewith, $wholeword, $single, $nocase ) = @{$annerice[$i]};
         $findtext = &HTMLescape( $findtext );
         $replacewith = &HTMLescape( $replacewith );
         $wholeword = $wholeword ? q~ checked~ : q~~;
         $single = $single ? q~ checked~ : q~~;
         $nocase = $nocase ? q~ checked~ : q~~;
      }
      else {
         ( $findtext, $replacewith, $wholeword, $single, $nocase ) = ( '', '', '', '' );
      }
      print qq~
<tr><td colspan="3"><br><input type="text" name="glosstext$i" value="$findtext" size="32" style="width:100%"></td></tr>
<tr><td colspan="3"><input type="text" name="glossreplace$i" value="$replacewith" size="32" style="width:100%"></td></tr>
<tr>
<td width="34%" align="right"><input type="checkbox" name="wholeword$i"$wholeword> Whole Words only?</td>
<td width="33%" align="middle"><input type="checkbox" name="single$i"$single> Replace First Instance only?</td>
<td width="33%" align="left"><input type="checkbox" name="nocase$i"$nocase> Case Insensitive?</td>
</tr>~;
   }
   print q~
   </table><br><div align="center"><input type="submit" name="submit" value="Submit Changes"></div>
   </form>
   ~;
   $addon->pageFooter;
}
END_SUB

# AnneRiceSave: Saves changes made in AnneRiceEdit
$Subs{'AnneRiceSave'} = << 'END_SUB';
sub AnneRiceSave {
   my $addon = shift;
   @annerice = ();
   for( my $i = 0; exists $in{"glosstext$i"} && exists $in{"glossreplace$i"}; $i++ ) {
      $in{"glosstext$i"} =~ s/\Q|x|\E//g;
      $in{"glosstext$i"} =~ s/\n//g;
      $in{"glossreplace$i"} =~ s/\Q|x|\E//g;
      $in{"glossreplace$i"} =~ s/\n//g;
      if( $in{"glosstext$i"} eq '' || $in{"glossreplace$i"} eq '' ) { next; }
      push(@annerice, [$in{"glosstext$i"}, $in{"glossreplace$i"}, $in{"wholeword$i"}, $in{"single$i"}, $in{"nocase$i"}]);
   }
   &AnneRiceStoreDB;
   $addon->simplePage('Anne Rice Glossary Saved', 'Your changes to Anne Rice Glossary have been saved. ' .
      $addon->link({'action' => 'admin', 'adminarea' => 'annerice'}) .
      'Back to Edit Anne Rice Glossary</a>.', 1);
}
END_SUB

# Load the Anne Rice Glossary from file
$Subs{'AnneRiceLoadDB'} = << 'END_SUB';

sub AnneRice_CreateRE ($) {
   my $untilthis = $_[0] || '\W';
   if( $untilthis eq ' ' ) { $untilthis = '\s'; }
   $untilthis =~ s~\A(\W)\Z~\\$1~;
   return q~[^~ . $untilthis . q~]+~;
}

sub AnneRiceLoadDB {
   if( $ardbloaded++ ) { return; }
   $CConfig{annericeglossary} ||= qq~$CConfig{htmlfile_path}/glossdat.txt~;
   &AnneRiceReadRayInfo( \@annerice, $CConfig{annericeglossary} );
   @anne_re = ();
   for( my $i = 0; $i < @annerice; ++$i ) {
      if( $annerice[$i]->[0] =~ m~\(##\)~ ) {
         my( $text, $newt ) = ( $annerice[$i]->[0], $annerice[$i]->[1] );

         my $butt = $newt;
            $butt =~ s~.*?(\(#\d+#\))~$1~g;
            $butt =~ s~\(#(\d+)#\)~$1\0~g;
            $butt =~ s~\0[^\0]*\Z~~;
            my( @butts ) = split( /\0/, $butt );
            my( @ind, @backs );
            for( my $i = 0; $i < @butts; ++$i ) {
               $ind[$i] = [ $i, $butts[$i] ];
            }
         @backs = map { $_->[0] + 1 } sort { $a->[1] <=> $b->[1] } @ind;
            # now we have the mapback to the original!

         my $backnew;
            my( @splitback ) = split( /\(##\)/, $text );
            for( my $i = 0; $i < @splitback; ++$i ) {
               $backnew .= quotemeta $splitback[$i];
               if( $i < $#splitback ) {
                  $backnew .= '$' . $backs[$i];
               }
            }
         my $backtex = $newt;
            $backtex =~ s~\(#\d+#\)~(##)~g;

         $text =~ s~(.*?)\(##\)(.)~$1 . '\E(' . AnneRice_CreateRE($2) . ')\Q' . $2~ge;
         $backtex =~ s~(.*?)\(##\)(.)~$1 . '\E(' . AnneRice_CreateRE($2) . ')\Q' . $2~ge;
         $text = '\Q' . $text . '\E';
         $backtex = '\Q' . $backtex . '\E';

         $newt = quotemeta $newt;
         $newt =~ s~\\\(\\#(\d+)\\#\\\)~\$$1~g;

         my $re = qq^s~$text~$newt~^;
         my $rre = qq^s~$backtex~$backnew~^;
         my $flags = '';
         unless( $annerice[$i]->[3] ) {
            $flags .= 'g';
         }
         if( $annerice[$i]->[4] ) {
            $flags .= 'i';
         }
         $re .= $flags;
         $rre .= $flags;
         push( @anne_re, [ $re, $rre ] );
      }
      else {
         push( @anne_re, undef );
      }
   }
}
END_SUB

# AnneRiceReadRayInfo: Reads from file into @$rayref
$Subs{'AnneRiceReadRayInfo'} = << 'END_SUB';
sub AnneRiceReadRayInfo {
   my ($rayref, $filename) = @_;
   @$rayref = ();
   unless( -e $filename ) {
      my $aff = CRopen(">$filename");
      print $aff '';
      close($aff);
      return;
   }
   my $aff = CRopen($filename);
   @$rayref = ();
   my $num = 0;
   while( my $i = <$aff> ) {
      $i =~ s/\n//g;
      @{$$rayref[$num]} = split(/\Q|x|\E/, $i);
      $num++;
   }
   close($aff);
}
END_SUB

$Subs{'AnneRiceStoreDB'} = << 'END_SUB';
sub AnneRiceStoreDB {
   $CConfig{annericeglossary} ||= qq~$CConfig{htmlfile_path}/glossdat.txt~;
   &AnneRiceWriteRayInfo( \@annerice, $CConfig{annericeglossary} );
}

# AbeWriteRayInfo: Saves @$rayref to file
sub AnneRiceWriteRayInfo {
   my ($rayref, $filename) = @_;
   my $aff = CRopen(">$filename");
   for( my $num = 0; $num < @$rayref; $num++ ) {
      if ($$rayref[$num][0] ne '' && $$rayref[$num][1] ne '') {
         print $aff join('|x|', @{$$rayref[$num]}) . qq~\n~;
      }
   }
   close($aff);
}
END_SUB

$Subs{'AnneRiceUpdate'} = << 'END_SUB';
sub AnneRiceUpdate {
   my $addon = shift;
   NeedCFG();


   &AnneRiceLoadDB;
   $addon->pageHeader('Anne Rice Running...', 1);
   print qq~Starting Anne Rice MegaRun!<br>\n\n\n~;

   my ($fh, $fh2) = EditNewsdat_Start();

   my $stoppermnow = 0;
   ARNDLOOP: while (<$fh>) {
      $stoppermnow = 0;
      $FileCount++;
      chomp $_;
      SplitDataFile($_);

      if ($up <= 1 && $User ne $CurrentUser) {
         # User doesn't have permission for this item
         next ARNDLOOP;
      }
      # Addons: please only hook in here if you're restricting access to items based
      # on permissions. If you're filtering/searching, your hook is later.
      # HOOK: ModifyNews_Permissions
      # if($Addons{'ModifyNews_Permissions'}){my $w;foreach $w (@{$Addons{'ModifyNews_Permissions'}}){my $addon=$w->[2];eval ${$w->[0]};AErr($addon,$@)if $@;};}

      # BUG FIX: NDLOOP label not accessible from outside crcore.pl
      if ($stoppermnow == 1){
         next ARNDLOOP;
      }

      # let's make all other addons think that we're in modify news
      # first we edit, then we save. taa-daa!
      #
      # note: I have no freaking clue what effect this will have on
      # any other addons that might hook into Edit_TopRow or EditSave_3
      # I hope it doesn't do anything super bad! ;)

      print qq~Running Anne Rice on # $FileCount, $Subject / $newsid<br>\n~;

      # HOOK: ModifyNews_Edit_TopRow
      # if($Addons{'ModifyNews_Edit_TopRow'}){my $w;foreach $w (@{$Addons{'ModifyNews_Edit_TopRow'}}){my $addon=$w->[2];eval ${$w->[0]};AErr($addon,$@)if $@;};}
      eval $ModifyNews_Edit_TopRow;

      # HOOK: ModifyNews_EditSave_3
      # if($Addons{'ModifyNews_EditSave_3'}){my $w;foreach $w (@{$Addons{'ModifyNews_EditSave_3'}}){my $addon=$w->[2];eval ${$w->[0]};AErr($addon,$@)if $@;};}
      eval $AnneRice_SaveNews;

      my $newsline = JoinDataFile();
      print $fh2 $newsline, "\n";
      $ItemCount++;
      $CConfig{'LastBuildOverride'} = ($newstime - 1) if ($newstime - 1) < $CConfig{'LastBuildOverride'};
   }

   close($fh);
   close($fh2);
   EditNewsdat_Finish();

   if ($CConfig{'AutoBuild_Modify'}) {
      BuildNews();
   }
   print qq~\n\n\n<br>DONE.<br>\n~;
   $addon->pageFooter();
   exit;
}
END_SUB

$addon->hook('ModifyNews_Edit_TopRow', \$ModifyNews_Edit_TopRow, 6);
$addon->hook('SaveNews_1', \$AnneRice_SaveNews, 6);
$addon->hook('ModifyNews_EditSave_3', \$AnneRice_SaveNews, 6);
$addon->hook('AdvSettings', \$AdvSettings, 10);
1;


__END__

=head1 Anne Rice

=head2 SETUP

After enabling the addon, go to the Administration page and click Advanced Settings. Under the settings heading "Anne Rice" you should choose the fields which you would like to run replacement on. You may also choose the location for the glossdat.txt file, if you want to put it in a directory other than your News Files directory. (ie if you want to share a glossdat.txt file with another installation of Coranto somewhere on the same server)

=head2 EDITING

Now that you have chosen the "run fields," you should go back to the Administration page and choose the "Anne Rice" option. You will be presented with a form containing groups of fields and checkboxes.

Each group contains a top text field, a bottom text field, and two checkboxes.

The top text field is the text to find, and the bottom text is the text to replace it with.

DO NOT USE DOLLAR SIGNS. Sorry, it just doesn't work, and I don't feel like investing the time to make it work. If someone wants to debug this and offer a fix, I'll gladly add it to Anne Rice.

The first checkbox determines whether or not Anne Rice should match all occurrences of the text, or only whole words.

The second checkbox tells Anne Rice whether it should replace all occurrences it finds, or just the first one. This feature could be useful if you want to have a special word link to its definition on another page, but only the first time it appears on the page.

The third checkbox allows Anne Rice to perform case-insensitive matches. So, it can match "HELLO", "Hello", and "hello" in one pattern.

=head2 USE

Anne Rice works by itself. You do not have to do anything special. Just use the correct text in one of your fields and Anne Rice will replace it. Anne Rice is case sensitive.

=head2 MODIFY NEWS

It may appear that Anne Rice is not working if you try to modify your news and discover that it hasn't changed at all. This is a special feature of Anne Rice: it performs its replacement in reverse when you modify news. Everything still looks nice and neat, but it is saved differently in the database and appears differently on your generated news pages.

Anne Rice will re-convert your news when you save the modifications.

=head2 EXPERIMENTAL FEATURE OF ANNE RICE 1.5

Anne Rice 1.5 includes an advanced form of replacement suitable for instituting UBBcode on your site. Here's an example:

replace: I like (##), it is a good food that is (##) and (##), and I feel (##) when I eat it.

with: I feel (#4#) when I eat (#1), because it is both (#3#) and (#2#). Yay!

Anne Rice will replace the original text with the replacement text, but will take the elements signified by (##) and rearrange them in the order you specify.

Here's another example:

replace: [img=(##)](##)[/img]

with: <img src="(#2#)" alt="(#1#)">

which will turn [img=http://img.gif]pumpkin![/img] into <img src="img.gif" alt="pumpkin!">

Please keep in mind that it's possible to break this feature by using multiple delimiters. Here's an example of a BAD replacement:

bad original: I say "(##)" to all nuns I see.

bad replacement: The word of the day is (##).

As you edit and save and edit and save, text matching this expression can become garbled like so:

I say "yes...." to all nuns I see. -> I say "yes" to all nuns I see.

Notice how the periods get dropped off, because Anne Rice thinks the period was a delimiter the next time you edit.

Also, please note that in the above IMG example, the alt="" text will NOT be HTML-escaped, so it's possible to really screw up your HTML code if you put something silly, like so:

[img=lalala"a]img.gif[/img]

Using this will work fine with Anne Rice, but your resulting HTML will be broken because of the quote inside the alt="" attribute.

Protip: just be smart about this kinda stuff. Try to use the same delimiters, or delimiters that will never appear in the actual ($$) item, and you shouldn't have a problem.

Do not use dollar signs in your patterns. I have not yet figured out how to make it work well. Sorry.

=head2 EXAMPLE

text to find: [ :) ]

replace with: [ <img src="happy_emoticon.gif"> ]

[X] Whole Words Only? [_] Replace First Instance Only? [_] Case Insensitive?

=head2 ABOUT THE AUTHOR

=over 4

=item *

name: Darya Misse

email: plushpuffin@wwddfd.com

=item *

site: http://www.wwddfd.com/

=back
Nichts ist für dich
Nichts war für dich
Nichts bleibt für dich
Für immer
Pirate Elf
 
Posts: 732
Joined: Wed Jan 31, 2007 9:45 pm

Return to Addon Release and Support

Who is online

Users browsing this forum: No registered users and 3 guests

cron