*/}}

3 Commits a9a82c210b ... 9baeae4687

Autor SHA1 Mensagem Data
  YimingWu 9baeae4687 notes há 3 semanas atrás
  YimingWu 3fc838d5dc subscription há 3 semanas atrás
  YimingWu a1f85c3a0c new title bar layout and fix number há 1 mês atrás
3 ficheiros alterados com 284 adições e 43 exclusões
  1. 108 43
      index.php
  2. 170 0
      mailsub.php
  3. 6 0
      translations.md

+ 108 - 43
index.php

@@ -42,6 +42,7 @@ class LA{
     protected $SpecialFooter;
     protected $SpecialFooter2;
     protected $SpecialPinned;
+    protected $SpecialPinnedNotes;
     protected $DefaultGallery;
     protected $SelfAuthPath;
     protected $HereHost;
@@ -83,6 +84,7 @@ class LA{
     protected $InExperimentalMode;
     protected $LanguageAppendix;
     protected $UseRemoteFont;
+    protected $NotesView;
     
     protected $Posts;
     protected $Threads; // [ keys: first last displayed count]
@@ -175,12 +177,13 @@ class LA{
             }
         }
         if(isset($LA_GLOBAL_LANG)){
-            if($LA_GLOBAL_LANG=='en'){ $this->LanguageAppendix = 'en'; setcookie('la_language','en',time()+3600*24*7); }
-            else if($LA_GLOBAL_LANG=='zh'){ $this->LanguageAppendix = 'zh'; setcookie('la_language','zh',time()+3600*24*7); }
+            if($LA_GLOBAL_LANG=='en'){ $this->LanguageAppendix = 'en'; setcookie('la_language','en',time()+3600*24*7,'/'); }
+            else if($LA_GLOBAL_LANG=='zh'){ $this->LanguageAppendix = 'zh'; setcookie('la_language','zh',time()+3600*24*7,'/'); }
         }
         if(isset($_COOKIE['la_font'])){
             $this->UseRemoteFont = ($_COOKIE['la_font']!='local');
         }
+        if($this->LoggedIn && isset($_COOKIE['la_notes_view'])){ $this->NotesView=$_COOKIE['la_notes_view']; }
     }
     function SwitchWayBackMode(){        
         if(isset($_COOKIE['la_wayback'])){
@@ -279,9 +282,11 @@ class LA{
         fwrite($conf,'- SpecialFooter = '.$this->SpecialFooter.PHP_EOL);
         fwrite($conf,'- SpecialFooter2 = '.$this->SpecialFooter2.PHP_EOL);
         fwrite($conf,'- SpecialPinned = '.$this->SpecialPinned.PHP_EOL);
+        fwrite($conf,'- SpecialPinnedNotes = '.$this->SpecialPinnedNotes.PHP_EOL);
         fwrite($conf,'- DefaultGallery = '.$this->DefaultGallery.PHP_EOL);
         fwrite($conf,'- SelfAuthPath = '.$this->SelfAuthPath.PHP_EOL);
         fwrite($conf,'- CommentEnabled = '.($this->CommentEnabled?"True":"False").PHP_EOL);
+        fwrite($conf,'- NewsletterEnabled = '.($this->NewsletterEnabled?"True":"False").PHP_EOL);
         fwrite($conf,'- HereHost = '.$this->HereHost.PHP_EOL);
         fwrite($conf,'- HereTitle = '.$this->HereTitle.PHP_EOL);
         fwrite($conf,'- HereShortTitle = '.$this->HereShortTitle.PHP_EOL);
@@ -448,7 +453,7 @@ class LA{
         $this->NULL_IMAGE_DUMMY = [];
         $this->NULL_IMAGE_DUMMY['name']=$this->NULL_IMAGE_DUMMY['file']=$this->NULL_IMAGE_DUMMY['thumb']="";
         
-        $this->Markers=['●', '○', '✓', '×', '!', 'P', 'E', 'S'];
+        $this->Markers=['●', '○', '✓', '×', '!', 'P', 'E', 'S', 'N'];
         
         $this->PostsPerPage = 40;
         $this->CommentsPerPage = 100;
@@ -473,13 +478,13 @@ class LA{
     function RecordToken($unset_current=false){
         if(isset($unset_current) && isset($_COOKIE['la_token'])){
             $t = $_COOKIE['la_token'];
-            setcookie('la_token', null, -1); unset($_COOKIE['la_token']);
+            setcookie('la_token', null, -1,'/'); unset($_COOKIE['la_token']);
             if (($key = array_search($t,$this->LoginTokens)) !== false) { unset($this->LoginTokens[$key]); }
             $this->WriteTokens();
             return null;
         }else{
             $t = uniqid('la_',true);
-            setcookie('la_token',$t,time()+3600*24*7); $_COOKIE['la_token'] = $t;
+            setcookie('la_token',$t,time()+3600*24*7,'/'); $_COOKIE['la_token'] = $t;
             $this->LoginTokens[] = $t;
             $this->WriteTokens();
             return $t;
@@ -492,7 +497,7 @@ class LA{
         if (($key = array_search($t,$this->LoginTokens)) !== false) {
             $_SESSION['user_id']=$this->Admin;
             $this->LoggedIn = true;
-            setcookie('la_token',$t,time()+3600*24*7);
+            setcookie('la_token',$t,time()+3600*24*7,'/');
             return true;
         }
         return false;
@@ -561,12 +566,12 @@ select{font-size:inherit;}
 a,button,::file-selector-button{text-decoration:underline;color:%black%;text-decoration-thickness:2px;text-underline-offset:0.15em;}
 a:hover,.button:hover,::file-selector-button:hover{text-decoration:none;color:%gray%;}
 .button:disabled{background-color:%gray%;pointer-events:none;}
-header{position:sticky;top:0;background-color:%white%;z-index:10;padding-top:0.5em;box-shadow: 0.5em 0px %white%;}
+header{position:fixed;top:0;width:calc(100% - 2em);background-color:%white%;z-index:10;padding-top:0.5em;box-shadow: 0.5em 0px %white%;}
 header::before{content:'';position:absolute;left:0;right:0;top:0;height:1.95em;box-shadow:-2em 0em 1em -1em inset %white%;pointer-events:none;}
 header>div{overflow:auto;white-space:nowrap;}
 .header_nav{display:inline;}
 header a,.left a,.footer a,.clean_a,.clean_a a{text-decoration:none;}
-header a:hover,.button:hover{color:%gray% !important;}
+header a:hover,.button:hover{color:%gray% !important;text-decoration:underline;text-decoration-thickness:2px;text-underline-offset:0.15em;}
 .exp_h_f{padding-top:0.3em !important;padding-bottom:0.3em !important;line-height:1.5em !important;height:2.1em !important;}
 .exp_f{text-align:center;}
 .toc_button{position:absolute;top:0.5em;right:0;text-shadow: 0px 0px 10px %white%;background-color:%white%88;}
@@ -575,12 +580,16 @@ header a:hover,.button:hover{color:%gray% !important;}
 .invert_a:hover,.invert_a a:hover{color:%black% !important;}
 .gray,.gray a{color:%gray%;}
 hr{border:1px solid %gray%;}
-header ul,.small_footer ul,.small_footer span,header li,.small_footer li{display:inline-block;}
+header ul,.small_footer ul,.small_footer span,header li,.small_footer li{display:inline-block;vertical-align:text-top;}
 header li::before,.small_footer li::before{content:' - '}
+header li ul{display:none;}
+header:hover li ul{display:inline;}
+header li ul li{display:block !important;margin-left:1em;}
+header li ul li a{font-size:0.9em;}
 //h1,h2,h3,h4,h5{font-size:1em;}
 //h1{text-decoration:underline;}
 header h1,header h2,header h3,header h4,header h5,header p{display:inline;font-size:1rem;}
-.main{position:relative;word-spacing:-1em;}
+.main{position:relative;word-spacing:-1em;top:2em;margin-bottom:2em;}
 .main *{word-spacing:initial;}
 pre{overflow:auto;display:block;line-break:anywhere;white-space:pre-wrap;}code{font-size:0.83em;}
 ul{display:block;}
@@ -749,10 +758,11 @@ margin-left:auto;margin-right:auto;max-width:100%;max-height:90vh;}
 .original_img img,.original_img video{max-height:90vh;max-width:100%;}
 .p_row .original_img{margin-bottom:0;}
 .post_ref .original_img{margin:unset;max-width:unset;max-height:min(70vh, 20rem);max-width:min(100%, 20rem);}
-.imbtn{display:block;contain:content;padding:0.25em;margin-bottom:0.5em;text-decoration:none;text-shadow:0px 0px 5px %white%;}
+.imbtn{color:rgba(0,0,0,0);display:block;contain:content;padding:0.25em;margin-bottom:0.5em;text-decoration:none;}
 .imbtn img{display:block;object-fit:cover;position:absolute;top:0;left:0;bottom:0;right:0;margin:auto;z-index:-1;
-min-width:100% !important;min-height:100% !important;filter:opacity(40%);}
-.imbtn:hover img{filter:opacity(20%) blur(0.1em);} .imbtn:hover{color:%black% !important;}
+min-width:100% !important;min-height:100% !important;filter:opacity(70%);transition:0.1s;}
+.imbtn:hover img{filter:opacity(20%) blur(0.2em);} .imbtn:hover{color:%black% !important;}
+.imbtn:hover {color:%black%;text-shadow:0px 0px 5px %white%;}
 header .imbtn{display:inherit;border:none;padding:0em;height:unset;height:unset;margin:0em;contain:unset;}
 header .imbtn:hover{border:none;color:%gray% !important;} header .imbtn img{display:none;}
 .b ul{font-size:1.4em;}
@@ -875,10 +885,12 @@ label{text-align:left;display:inline-block;}
 }
 
 @media screen and (max-width:666px){
+.main{top:unset;margin-bottom:unset;}
 html{font-size:16px;}
 pre{max-width:85vw;}
 #titlectrl:checked ~ header .mobile_fold{display:block !important;}
 #titlectrl:checked ~ .main .mobile_fold{display:block !important;}
+#titlectrl:checked ~ header li ul{display:inline;}
 .mobile_fold{display:none !important;}
 .hidden_m{display:none !important;}
 .block_m{display:block !important;}
@@ -952,7 +964,7 @@ border-radius:unset;box-shadow:unset;font-size:1.3rem;text-shadow:unset;}
 @media print{
 .small_footer .hidden_on_print{display:none}
 header b,.small_footer b{font-weight:normal;}
-header{display:table-header-group;box-shadow:none;} .main{display:table-row-group;} .small_footer{text-align:right;}
+header{display:table-header-group;box-shadow:none;} .main{display:table-row-group;top:unset;margin-bottom:unset;} .small_footer{text-align:right;}
 header::before{box-shadow:none;display:none;} header::after{display:block;height:1em;content:' ';}
 .small_footer::before{box-shadow:none;display:block;height:1em;position:relative;}
 body,footer,header,.small_footer,a,.clean_a,.invert_a,.clean_a a,.invert_a a{background:none;color:black;}
@@ -1518,7 +1530,7 @@ blockquote{border-left:2px solid black;}
                 }
                 if(preg_match('/NUM\s+([0-9]{1,})\s*;/u', $m[2], $n)){ $post['number']=$n[1]; $this->PNUMBER=max($post['number'],$this->PNUMBER); }
                 else{ $this->PNUMBER++; $post['number']=$this->PNUMBER; }
-                $post['number']=$this->PNUMBER; $this->PNUMBER++;
+                //$this->PNUMBER++; $post['number']=$this->PNUMBER;
                 if(isset($post['mark_value']) && $post['mark_value']==5){
                     $post['product']=[];
                 }
@@ -1633,7 +1645,8 @@ blockquote{border-left:2px solid black;}
         }
         if(isset($th['first']['mark_value'])){
             if($th['first']['mark_value']==6)      $th['exp'] = true;
-            else if($th['first']['mark_value']==7) $th['slf'] = true;
+            else if($th['first']['mark_value']>=7) $th['slf'] = true;
+            if($th['first']['mark_value']==8)      $th['sln'] = true;
         }
         if($th['first'] == $th['last']){ unset($post['tid']); return; }
         $this->Threads[] = &$th;
@@ -2175,6 +2188,7 @@ blockquote{border-left:2px solid black;}
             if($this->GetPost($id,true)!== $this->NULL_POST) return $this->NULL_POST;
             $post = []; $post['id'] = $id;
             $post['real_content'] = $content; $post['content'] = &$post['real_content'];
+            if(isset($mark_value) && $mark_value!==NULL) $post['mark_value'] = $mark_value;
             if(isset($reply_to) && ($rep = &$this->GetPost($reply_to,true))!== $this->NULL_POST){
                 while($rep !== $this->NULL_POST && isset($rep['next']) && $rep['next']){ $rep = &$this->GetPost($rep['next'],true); }
                 if($rep !== $this->NULL_POST){ $rep['next'] = $id; $post['prev'] = $rep['id']; }
@@ -2268,7 +2282,8 @@ blockquote{border-left:2px solid black;}
     function CanShowPost(&$p){
         if(!isset($p) || isset($p['comment_to'])) return false;
         $is_mark_exp = (isset($p['tid'])&&isset($p['tid']['exp'])&&$p['tid']['exp']) || (isset($p['mark_value'])&&$p['mark_value']==6);
-        $is_mark_slf = (isset($p['tid'])&&isset($p['tid']['slf'])&&$p['tid']['slf']) || (isset($p['mark_value'])&&$p['mark_value']==7);
+        $is_mark_slf = (isset($p['tid'])&&isset($p['tid']['slf'])&&$p['tid']['slf']) || (isset($p['mark_value'])&&$p['mark_value']>=7);
+        $is_mark_sln = (isset($p['tid'])&&isset($p['tid']['sln'])&&$p['tid']['sln']) || (isset($p['mark_value'])&&$p['mark_value']==8);
         if($is_mark_slf && !$this->LoggedIn){ return false; }
         if(isset($this->WayBack)){
             if(isset($p['version'])) { if ($p['version']>$this->WayBack) return false; }
@@ -2279,6 +2294,7 @@ blockquote{border-left:2px solid black;}
                 if($is_mark_exp) return false;
                 return true;
             }
+            if($this->NotesView && !$is_mark_sln){ return false; }
             return true;
         }else{
             if($is_mark_exp) return true;
@@ -2486,7 +2502,7 @@ blockquote{border-left:2px solid black;}
                 $th = &$p['tid']; if($p['tid']['count']==0) continue; }
             
             if(in_array($p['id'],
-                [$this->SpecialPinned,$this->SpecialFooter,$this->SpecialFooter2,$this->SpecialNavigation,$this->SpecialSidebar])) continue;
+                [$this->SpecialPinned,$this->SpecialPinnedNotes,$this->SpecialFooter,$this->SpecialFooter2,$this->SpecialNavigation,$this->SpecialSidebar])) continue;
             if(isset($p['tid'])){ if(isset($p['tid']['displayed'])) continue; $p['tid']['displayed'] = True; }
             
             
@@ -2562,7 +2578,7 @@ blockquote{border-left:2px solid black;}
             return 0;
         }
         if(isset($_GET['set_language'])){
-            setcookie('la_language',$_GET['set_language'],time()+3600*24*7); $_COOKIE['la_language'] = $_GET['set_language'];
+            setcookie('la_language',$_GET['set_language'],time()+3600*24*7,'/'); $_COOKIE['la_language'] = $_GET['set_language'];
             $redirect=$this->GetRedirect(); return 0;
         }
         if(isset($_GET['rss'])){
@@ -2571,7 +2587,7 @@ blockquote{border-left:2px solid black;}
         }
         if(isset($_GET['toggle_font'])){ $use_font='local';
             if(!isset($_COOKIE['la_font']) || $_COOKIE['la_font']!='remote') $use_font='remote';
-            setcookie('la_font',$use_font,time()+3600*24*7); $_COOKIE['la_font'] = $use_font;
+            setcookie('la_font',$use_font,time()+3600*24*7,'/'); $_COOKIE['la_font'] = $use_font;
             $redirect=$this->GetRedirect(); return 0;
         }
         if(isset($_GET['set_wayback'])){
@@ -2584,9 +2600,9 @@ blockquote{border-left:2px solid black;}
                     if(isset($_POST['wayback_hour'])) $wayback=substr_replace($wayback,str_pad($_POST['wayback_hour'],2,"0",STR_PAD_LEFT),8,2);
                     if(isset($_POST['wayback_minute'])) $wayback=substr_replace($wayback,str_pad($_POST['wayback_minute'],2,"0",STR_PAD_LEFT),10,2);
                 }else{ if(preg_match('/[0-9]{14}/u', $_GET['set_wayback'])) $wayback = $_GET['set_wayback']; }
-                setcookie('la_wayback',$wayback); $_COOKIE['la_wayback'] = $wayback;
+                setcookie('la_wayback',$wayback,'/'); $_COOKIE['la_wayback'] = $wayback;
             }else{
-                setcookie('la_wayback', null, -1); unset($_COOKIE['la_wayback']);
+                setcookie('la_wayback', null, -1,'/'); unset($_COOKIE['la_wayback']);
             }
             $redirect=$this->GetRedirect(); return 0;
         }
@@ -2639,7 +2655,7 @@ blockquote{border-left:2px solid black;}
             exit;
         }
         if(isset($_GET['confirm_enter']) && $_GET['confirm_enter']!=false){
-            setcookie('la_experimental','confirmed'); $_COOKIE['la_experimental'] = $_GET['confirmed'];
+            setcookie('la_experimental','confirmed','/'); $_COOKIE['la_experimental'] = $_GET['confirmed'];
             $redirect=$INDEXPHP.(isset($_GET['post'])?'?post='.$_GET['post']:"");return 0;
         }
         if(isset($_GET['apub_actor'])){
@@ -2658,6 +2674,10 @@ blockquote{border-left:2px solid black;}
             if(isset($_GET['TestAPubDeliver'])){
                 $this->APubTestDeliver();
             }
+            if(isset($_GET['set_notes_view'])){
+                setcookie('la_notes_view',$_GET['set_notes_view'],time()+3600*24*7,'/'); $_COOKIE['la_notes_view'] = $_GET['set_notes_view'];
+                $redirect=$this->GetRedirect(); return 0;
+            }
         
             $this->DoUpload();
             
@@ -2671,9 +2691,11 @@ blockquote{border-left:2px solid black;}
                 if(isset($_POST['settings_special_footer'])) $this->SpecialFooter=$_POST['settings_special_footer'];
                 if(isset($_POST['settings_special_footer2'])) $this->SpecialFooter2=$_POST['settings_special_footer2'];
                 if(isset($_POST['settings_special_pinned'])) $this->SpecialPinned=$_POST['settings_special_pinned'];
+                if(isset($_POST['settings_special_pinned_notes'])) $this->SpecialPinnedNotes=$_POST['settings_special_pinned_notes'];
                 if(isset($_POST['settings_default_gallery'])) $this->DefaultGallery=$_POST['settings_default_gallery'];
                 if(isset($_POST['settings_selfauth_path'])) $this->SelfAuthPath=$_POST['settings_selfauth_path'];
                 if(isset($_POST['settings_enable_comments'])) $this->CommentEnabled=True; else $this->CommentEnabled=False;
+                if(isset($_POST['settings_enable_newsletter'])) $this->NewsletterEnabled=True; else $this->NewsletterEnabled=False;
                 if(isset($_POST['settings_gallery_step'])) $this->GalleryStep=$_POST['settings_gallery_step'];
                 if(isset($_POST['settings_here_host'])) $this->HereHost=$_POST['settings_here_host'];
                 if(isset($_POST['settings_here_title'])) $this->HereTitle=$_POST['settings_here_title'];
@@ -2737,7 +2759,7 @@ blockquote{border-left:2px solid black;}
                 if(isset($_GET['post'])) $redirect='?post='.$_GET['target']; else $redirect=$this->GetRedirect();
                 return 0;
             }
-            if(isset($_POST['post_button']) && isset($_POST['post_content'])){
+            if((isset($_POST['post_button'])||isset($_POST['post_button_note'])) && isset($_POST['post_content'])){
                 $c = $_POST['post_content'];
                 if('有什么想说的' == $c){ return 0;}
                 if(preg_match('/\[LAMDWIKIPOST/u',$c))
@@ -2745,7 +2767,9 @@ blockquote{border-left:2px solid black;}
                 $reply_to = (isset($_POST['post_reply_to'])&&$_POST['post_reply_to']!="")?$_POST['post_reply_to']:NULL;
                 $edit_id = (isset($_POST['post_edit_target'])&&$_POST['post_edit_target']!="")?$_POST['post_edit_target']:NULL;
                 $push_history = (isset($edit_id) && isset($_POST['post_record_edit']));
-                if(($edited = $this->EditPost($edit_id, $c, NULL, $reply_to,NULL,NULL,NULL,$push_history,NULL,NULL))!=NULL){
+                $postmark=NULL;
+                if(isset($_POST['post_button_note'])){ $postmark=8; }
+                if(($edited = $this->EditPost($edit_id, $c, NULL, $reply_to,NULL,$postmark,NULL,$push_history,NULL,NULL))!=NULL){
                     $redirect='?post='.$edited['id']; return 0;
                 };
             }
@@ -2989,17 +3013,18 @@ blockquote{border-left:2px solid black;}
     }
     function GetPostTitle(&$post, $h1_only=false, $add_unamed=true){
         if($h1_only){
-            if(preg_match('/^#\s+(.*?)$/mu',$post['content'],$m)) return $m[1];
+            if(preg_match('/^#\s+(.*?)$/mu',$post['content'],$m)) return strip_tags($this->TranslatePostParts($m[1]));
             else return NULL;
         }
         if(!isset($post['title'])){
-            if(preg_match('/^#{1,6}\s+(.*?)$/mu',$post['content'],$m)){$post['title']=$m[1];}
+            if(preg_match('/^#{1,6}\s+(.*?)$/mu',$post['content'],$m)){$post['title']=$m[0];}
             else{ $post['title'] = $add_unamed?$this->T('未命名'):""; 
                 if(preg_match('/(.*)$/mu',$post['content'],$m)){
-                    $post['title'].=($add_unamed?' (':'').strip_tags($this->PDE->text($m[1])).($add_unamed?')':''); } 
+                    $post['title'].=($add_unamed?' (':'').$this->PDE->text($m[1]).($add_unamed?')':''); } 
             }
         }
-        return $this->ChoosePartsByLanguage($post['title']);
+        
+        return strip_tags($this->TranslatePostParts($this->PDE->text($post['title'])));
     }
     
     function DetectPageType(){
@@ -3162,6 +3187,7 @@ blockquote{border-left:2px solid black;}
                     <a id='mark_set_5' href='javascript:SetMark(5);'><?=$this->Markers[5]?></a>
                     <a id='mark_set_6' href='javascript:SetMark(6);'><?=$this->Markers[6]?></a>
                     <a id='mark_set_7' href='javascript:SetMark(7);'><?=$this->Markers[7]?></a>
+                    <a id='mark_set_8' href='javascript:SetMark(8);'><?=$this->Markers[8]?></a>
                 </b></li>
                 <li id='rename_details' style='display:none;text-align:left;' class='smaller'>
                     <form action="" method="post" style='display:none;' id='post_rename_form'></form>
@@ -3230,9 +3256,11 @@ blockquote{border-left:2px solid black;}
             <li class='hidden_m'><a href='?gallery=default' onclick='ShowWaitingBar()'><?=$this->T('画廊')?></a></li>
             <li class='hidden_on_desktop_force block_m smaller'>&nbsp;</li>
             <li class='hidden_on_desktop_force block_m bigger'>
-                <a href='<?=$INDEXPHP?>?part=recent' onclick='ShowWaitingBar()'><?=$this->T('最近')?></a>
+                <a href='<?=$INDEXPHP?>?part=recent' onclick='ShowWaitingBar()'><?=$this->NotesView?$this->T('笔记'):$this->T('最近')?></a>
                 <?php if($this->LoggedIn){ ?> | <span class='gray invert_a'>
-                    <a href='<?=$INDEXPHP?>?comments=all'>@</a> <a href='<?=$INDEXPHP?>?statistics=all'>%</a></span><?php } ?></li>
+                    <a href='<?=$INDEXPHP?>?set_notes_view=<?=$this->NotesView?'0':'1'?>'>N</a>
+                    <a href='<?=$INDEXPHP?>?comments=all'>@</a> <a href='<?=$INDEXPHP?>?statistics=all'>%</a>
+                </span><?php } ?></li>
             <li class='hidden_on_desktop_force block_m bigger'>
                 <a href='<?=$INDEXPHP?>?gallery=default' onclick='ShowWaitingBar()'><?=$this->T('画廊')?></a></li>
             <?php $this->SpecialNavigation;if(isset($this->SpecialNavigation) && ($p = &$this->GetPost($this->SpecialNavigation))!=NULL){
@@ -3301,6 +3329,8 @@ blockquote{border-left:2px solid black;}
                   oninput=\"la_auto_grow(this);\" onload=\"la_auto_grow(this);\">{$this->T('有什么想说的')}</textarea>
         <input class='button' form=\"post_form\" type=\"submit\" name='post_button' value='{$this->T('发送')}' 
             onclick='ShowWaitingBar();' />
+        <input class='button' form=\"post_form\" type=\"submit\" name='post_button_note' value='{$this->T('笔记')}' 
+            onclick='ShowWaitingBar();' />
         | <a class='gray smaller pointer' onclick='ShowSideUploader();'>{$this->T('图片')}</a>
         <div style='float:right;'>
             <a class='gray smaller pointer' onclick=\"t=document.querySelector('#post_content');t.value='';la_auto_grow(t);\">
@@ -3438,6 +3468,7 @@ blockquote{border-left:2px solid black;}
             $STR.="<div class='hidden_on_print'><br />{$this->MakePostingFieldsV2($is_thread?$th['last']['id']:$post['id'], true)}</div>";
             $this->TFill(2,$STR); $this->TRow();
         }
+        if($this->NewsletterEnabled){ $STR=$this->MakeSubscription(); $this->TFill(2,$STR); $this->TRow(); }
         //$this->MakeCommentSection($post);
         $STR="";
         if(isset($post['slides']) || ($is_thread&&isset($post['tid']['slides']))){
@@ -3496,19 +3527,38 @@ blockquote{border-left:2px solid black;}
         }
     }
 
+    function MakeSubscription($smaller=false){
+        $STR="";$STR.="<div".($smaller?" class='smaller hidden_on_print'":"").">
+        <form action='mailsub.php?subscribe=1' method='post' id='subscribe_form' style='display:none;'></form>
+        <br />
+        <h".($smaller?"3":"2").">{$this->T("订阅我的新闻")}</h".($smaller?"3":"2").">
+        <span class='gray'>{$this->T("输入您的邮件:")}</span>
+        <input type='text' id='email_subscribe_name' name='email_subscribe_name' form='subscribe_form' ".
+            ($smaller?"style='border-color:#f8ca9b88;background:rgba(0,0,0,0.2);max-width:16em;'":"").">
+        <input class='button' form='subscribe_form' type='submit' value={$this->T("订阅")}>
+        <br /></div>";
+        return $STR;
+    }
+
     function MakeRecentPostsV2($search_term=NULL, $category=NULL){ global $INDEXPHP;
-        $STR="";
+        $STR=""; $tmppinned=$this->SpecialPinned;
+        if($this->LoggedIn && $this->NotesView){ $this->SpecialPinned=$this->SpecialPinnedNotes; }
         if(!isset($search_term) && !isset($category) &&
             (isset($this->SpecialPinned) && ($p = &$this->GetPost($this->SpecialPinned))!=NULL && !$this->CurrentOffset) &&
             $this->CanShowPost($p)){
             $this->MakeSinglePostV2($p, true, false, "active_post", false, true, false, false, false, true, false);
         }
+        $this->SpecialPinned=$tmppinned;
+        if($this->NewsletterEnabled && !isset($category) && !isset($search_term) && !$this->NotesView){
+            $STR=$this->MakeSubscription(); $this->TFill(2,$STR); $this->TRow(); $STR='';
+        }
         $STR.="<br /><h2>".(isset($search_term)?$this->T('搜索'):
                                 (isset($category)?("<span class='gray'>".$this->T('分类')."</span> ".
-                                    ($category=='none'?$this->T('未分类'):$this->T($category))):($this->T('最近')).
-                                    " <span class='gray invert_a hidden_on_print'>".//"<a href='index.php?&set_wayback=true'>↶</a>".
-                                    ($this->LoggedIn?"<a href='".$INDEXPHP."?comments=all'>@</a> <a href='".$INDEXPHP."?statistics=all'>%</a>":"")."</span>")).
-                    "</h2>";
+                                    ($category=='none'?$this->T('未分类'):$this->T($category))):($this->NotesView?$this->T('笔记'):$this->T('最近')).
+                                    "<span class='gray invert_a hidden_on_print'>".//"<a href='index.php?&set_wayback=true'>↶</a>".
+                                    ($this->LoggedIn?" <a href='".$INDEXPHP."?set_notes_view=".($this->NotesView?'0':'1')."'>N</a> ".
+                                    "<a href='".$INDEXPHP."?comments=all'>@</a> <a href='".$INDEXPHP."?statistics=all'>%</a>":"")."</span>")).
+                    "</h2><br />";
         $this->TFill(2,$STR); $this->TRow();
         if(isset($search_term)){
             $STR.="<form action='".$INDEXPHP."' method='post' style='display:none;' id='search_form'></form>".
@@ -3540,7 +3590,7 @@ blockquote{border-left:2px solid black;}
                 if(isset($p['tid'])){ if(isset($p['tid']['displayed'])) continue; $p['tid']['displayed'] = True; }
             }else{
                 if(in_array($p['id'],
-                    [$this->SpecialPinned,$this->SpecialFooter,$this->SpecialFooter2,$this->SpecialNavigation,$this->SpecialSidebar])) continue;
+                    [$this->SpecialPinned,$this->SpecialPinnedNotes,$this->SpecialFooter,$this->SpecialFooter2,$this->SpecialNavigation,$this->SpecialSidebar])) continue;
                 if(isset($p['tid'])){ if(isset($p['tid']['displayed'])) continue; $p['tid']['displayed'] = True; }
             }
             if($i < $this->PostsPerPage * $this->CurrentOffset) {$i++; continue;}
@@ -3776,7 +3826,7 @@ blockquote{border-left:2px solid black;}
             }?>
             <h2><?=isset($search_term)?$this->T('搜索'):
                                 (isset($category)?("<span class='gray'>".$this->T('分类')."</span> ".
-                                    ($category=='none'?$this->T('未分类'):$this->T($category))):($this->T('最近')).
+                                    ($category=='none'?$this->T('未分类'):$this->T($category))):($this->NotesView?$this->T('笔记'):$this->T('最近')).
                                     " <span class='gray invert_a hidden_on_print'>".//"<a href='index.php?&set_wayback=true'>↶</a>".
                                     ($this->LoggedIn?"<a href='$INDEXPHP?comments=all'>@</a> <a href='$INDEXPHP?statistics=all'>%</a>":"")."</span>")?></h2><br />
             <?php if(isset($search_term)){ ?>
@@ -3809,7 +3859,7 @@ blockquote{border-left:2px solid black;}
                             if(isset($p['tid'])){ if(isset($p['tid']['displayed'])) continue; $p['tid']['displayed'] = True; }
                         }else{
                             if(in_array($p['id'],
-                                [$this->SpecialPinned,$this->SpecialFooter,$this->SpecialFooter2,$this->SpecialNavigation,$this->SpecialSidebar])) continue;
+                                [$this->SpecialPinned,$this->SpecialPinnedNotes,$this->SpecialFooter,$this->SpecialFooter2,$this->SpecialNavigation,$this->SpecialSidebar])) continue;
                             if(isset($p['tid'])){ if(isset($p['tid']['displayed'])) continue; $p['tid']['displayed'] = True; }
                         }
                         if($i < $this->PostsPerPage * $this->CurrentOffset) {$i++; continue;}
@@ -4148,7 +4198,8 @@ blockquote{border-left:2px solid black;}
     function MakeSidebar(){ ?>
         <div class='left mobile_fold'><?php if(isset($this->SpecialSidebar) && ($p = &$this->GetPost($this->SpecialSidebar))!=NULL){
             ?><span class='gray smaller'><br /></span><?php
-            echo $this->GenerateSinglePost($p, false, false, false, false); }?>
+            //echo $this->GenerateSinglePost($p, false, false, false, false);
+            }?>
         <div class='wayback_link clean_a smaller'><span class='gray'><br /><?=$this->T('工具')?></span><ul>
         <li><a href='?search=' onclick='ShowWaitingBar()' class='bigger'><?=$this->T('搜索')?></a></li>
         <li><?php if(!isset($this->WayBack)){ ?>
@@ -4159,6 +4210,7 @@ blockquote{border-left:2px solid black;}
         <li><a rel="alternate" type="application/rss+xml" href="?rss=<?=$this->LanguageAppendix;?>" />RSS/Atom<sup><?=$this->LanguageAppendix;?></sup></a></li>
         </ul>
         </div>
+        <?php  if($this->NewsletterEnabled){ $STR=$this->MakeSubscription(1); echo $STR; }?>
         <br />
         <hr class="hidden_on_desktop" />
         </div>
@@ -4951,6 +5003,9 @@ blockquote{border-left:2px solid black;}
                     <tr><td><?=$this->T('置顶文')?><?=isset($this->SpecialPinned)?"<a href='?post=".$this->SpecialPinned."'>→</a>":""?></td>
                         <td><input type="text" form="settings_form" id='settings_special_pinned' name='settings_special_pinned'
                         value='<?=$this->SpecialPinned?>'/></td></tr>
+                    <tr><td><?=$this->T('置顶笔记')?><?=isset($this->SpecialPinnedNotes)?"<a href='?post=".$this->SpecialPinnedNotes."'>→</a>":""?></td>
+                        <td><input type="text" form="settings_form" id='settings_special_pinned_notes' name='settings_special_pinned_notes'
+                        value='<?=$this->SpecialPinnedNotes?>'/></td></tr>
                     <tr><td><?=$this->T('默认相册')?></td>
                         <td><input type="text" form="settings_form" id='settings_default_gallery' name='settings_default_gallery'
                         value='<?=$this->DefaultGallery?>'/></td></tr>
@@ -4963,6 +5018,9 @@ blockquote{border-left:2px solid black;}
                     <tr><td><?=$this->T('启用评论')?></td>
                         <td><input type="checkbox" id="settings_enable_comments" name="settings_enable_comments"
                         form="settings_form" <?=$this->CommentEnabled?"checked":""?>/></td></tr>
+                    <tr><td><?=$this->T('启用新闻')?></td>
+                        <td><input type="checkbox" id="settings_enable_newsletter" name="settings_enable_newsletter"
+                        form="settings_form" <?=$this->NewsletterEnabled?"checked":""?>/></td></tr>
                     <tr><td><?=$this->T('附加操作')?></td><td><a class='gray' href='<?=$INDEXPHP?>?extras=true'><?=$this->T('进入')?></a></td></tr>
                         
                     <tr><td class='smaller gray'>&nbsp;</td></tr>
@@ -5079,7 +5137,7 @@ blockquote{border-left:2px solid black;}
                 <?=$this->T('P为帖子跳转,匹配REQUEST_URI跳到目标文章;S为站点跳转,可以重定向来源域名,例子:')?>
             <br /><pre>P discount:20001001010101;<br />S old_domain:www.new_domain.com:20001001010101;</pre></span>
             <form action="<?=$_SERVER['REQUEST_URI']?>" method="post" style='display:none;' id='settings_form2'></form>
-            <textarea id="settings_redirect" name="settings_redirect" rows="3" class='full_box' wrap="off"
+            <textarea id="settings_redirect" name="settings_redirect" rows="4" class='full_box' wrap="off"
                 form='settings_form2'><?=$this->DisplayRedirectConfig()?></textarea>
             <input class='button' form="settings_form2" type="submit" name='settings_save_redirect'
                 value='<?=$this->T('保存重定向设置')?>' />
@@ -5089,11 +5147,18 @@ blockquote{border-left:2px solid black;}
                 <?=$this->T('填写格式:')?>
             <br /><pre>- 语言 | Language</pre></span>
             <form action="<?=$_SERVER['REQUEST_URI']?>" method="post" style='display:none;' id='settings_form3'></form>
-            <textarea id="settings_translation" name="settings_translation" rows="3" class='full_box' wrap="off"
+            <textarea id="settings_translation" name="settings_translation" rows="4" class='full_box' wrap="off"
                 form='settings_form3'><?=$this->CustomTranslationContent?></textarea>
             <input class='button' form="settings_form3" type="submit" name='settings_save_translation'
                 value='<?=$this->T('保存翻译')?>' />
-            <p>&nbsp;</p>
+
+            <?php if($this->NewsletterEnabled){
+                $subs=file_get_contents("all_subscribers.php"); ?>
+                <br /><br /><h3><?=$this->T('邮件订阅者')?></h3>
+                <textarea rows="4" class='full_box' wrap="off"><?=$subs?substr($subs,5):"error"?></textarea>
+            <?php } ?>
+
+            <br />
             <p class='smaller gray'><?=$this->T('ActivityPub 测试:')?></p>
             <ul>
                 <li><a href='?TestAPubDeliver=1'><?=$this->T('测试发送')?></a></li></ui>

+ 170 - 0
mailsub.php

@@ -0,0 +1,170 @@
+<?php
+
+require_once("PHPMailer/PHPMailer.php");
+require_once("PHPMailer/SMTP.php");
+require_once("PHPMailer/Exception.php");
+
+require_once("mailconf.php");
+
+use PHPMailer\PHPMailer\PHPMailer;
+use PHPMailer\PHPMailer\SMTP;
+
+$mail = new PHPMailer(true);
+
+if(!isset($GLOBALS['MAILSUB_CONFIRM'])){
+    $GLOBALS['MAILSUB_CONFIRM']="<h2>Confirm Subscription</h2>
+<p>You are subscribing to my email newsletter. Click the link below to confirm:</p><br />
+<a href='{CONFIRMLINK}'>{CONFIRMLINK}</a>";
+}
+if(!isset($GLOBALS['MAILSUB_REGULAR'])){
+    $GLOBALS['MAILSUB_REGULAR']="
+<p>This is my email newsletter. <a href='{EDITSUBSCRIPTION}'>Edit your subscription</a></p><br />";
+}
+if(!isset($GLOBALS['MAILSUB_WELCOME'])){
+    $GLOBALS['MAILSUB_WELCOME']="<h2>Welcome</h2>
+<p>You have subscribed to my email newsletter. Edit your subscription below:</p><br />
+<a href='{EDITSUBSCRIPTION}'>{EDITSUBSCRIPTION}</a>";
+}
+if(!isset($GLOBALS['MAILSUB_EDIT'])){
+    $GLOBALS['MAILSUB_EDIT']="<h2>Edit Subscription</h2>
+<p>Unsubscribe my newsletter: <a href='{UNSUBSCRIBE}'>CONFIRM</a></p><br />";
+}
+if(!isset($GLOBALS['MY_HOST'])){
+    $GLOBALS['MY_HOST']="https://www.example.com";
+}
+
+
+$PENDING=[];
+$ACCEPTED=[];
+
+$f = fopen("pending_confirm.php",'r'); $tries=0;
+while(!$f && $tries<100){ $f = fopen("pending_confirm.php",'w'); fclose($f); $tries++;} $f=0;
+$content = file_get_contents("pending_confirm.php");
+
+$f = fopen("all_subscribers.php",'r'); $tries=0;
+while(!$f && $tries<100){ $f = fopen("all_subscribers.php",'w'); fclose($f); $tries++;} $f=0;
+$subscribers = file_get_contents("all_subscribers.php");
+
+
+if(preg_match_all("/(.*)\s+?\[\[\[(.*)\]\]\]\s*?(zh|en|)/",$content,$matches,PREG_SET_ORDER)){
+    foreach($matches as $m){ $PENDING[]=[$m[1],$m[2],$m[3]]; }
+}
+
+if(preg_match_all("/(.*)\s+?\[\[\[(.*)\]\]\]\s*?(zh|en|)/",$subscribers,$matches,PREG_SET_ORDER)){
+    foreach($matches as $m){ $ACCEPTED[]=[$m[1],$m[2],$m[3]]; }
+}
+
+if(isset($_GET['subscribe']) && isset($_POST['email_subscribe_name'])){
+    if(preg_match("/^((?!\.)[\w\-_.]*[^.])(@\w+)(\.\w+(\.\w+)?[^.\W])$/",$_POST['email_subscribe_name'])){
+        $item=[uniqid(),$_POST['email_subscribe_name'],'en'];
+        $PENDING[]=$item;
+        send_verification($item[0],$_POST['email_subscribe_name']);
+    }else{
+        echo "Not a valid email.";
+    }
+
+    $tries=0; while(!$f && $tries<100){ $f = fopen("pending_confirm.php",'w'); $tries++; }
+    fwrite($f,"<php".PHP_EOL);
+    foreach($PENDING as $p){ if($p[1]==0) continue; fwrite($f,"".$p[0]." [[[".$p[1]."]]] $p[2]".PHP_EOL); }
+    fclose($f); $f=0;
+}
+
+if(isset($_GET['confirm']) && isset($_GET['id'])){
+    $address=urldecode($_GET['confirm']); $any=0;
+    foreach($PENDING as $p){
+        if($p[0]==$_GET['id'] && $address==$p[1]){
+            $ACCEPTED[]=$p; unset($PENDING[key($PENDING)]); $any=1;
+            send_welcome($p[0],$address); break;
+        }
+    }
+    if(!$any){ echo "<h2>Couldn't confirm your subscription.</h2>"; exit; }
+
+    $tries=0; while(!$f && $tries<100){ $f = fopen("all_subscribers.php",'w'); $tries++; }
+    fwrite($f,"<php".PHP_EOL);
+    foreach($ACCEPTED as $p){ if($p[1]==0) continue; fwrite($f,"".$p[0]." [[[".$p[1]."]]] $p[2]".PHP_EOL); }
+    fclose($f); $f=0;
+
+    $tries=0; while(!$f && $tries<100){ $f = fopen("pending_confirm.php",'w'); $tries++; }
+    fwrite($f,"<php".PHP_EOL);
+    foreach($PENDING as $p){ if($p[1]==0) continue; fwrite($f,"".$p[0]." [[[".$p[1]."]]] $p[2]".PHP_EOL); }
+    fclose($f); $f=0;
+
+    echo "<h2>Successfully subscribed</h2>";
+}
+
+if(isset($_GET['unsubscribe'])&&isset($_GET['id'])){
+    if(!isset($_GET['doit'])){
+        $link="{$GLOBALS['MY_HOST']}/mailsub.php?unsubscribe={$_GET['unsubscribe']}&doit=1&id={$_GET['id']}";
+        $body=preg_replace("/\{UNSUBSCRIBE\}/",$link,$GLOBALS['MAILSUB_EDIT']);
+        echo $body; exit;
+    }
+
+    $any=0;
+    foreach(array_values($ACCEPTED) as $key=>$p){
+        if($p[0]==$_GET['id'] && $_GET['unsubscribe']==$p[1]){
+            unset($ACCEPTED[$key]); $any=1;
+        }
+    }
+    if(!$any){ echo "<h2>Unknown error</h2>"; exit; }
+
+    $tries=0; while(!$f && $tries<100){ $f = fopen("all_subscribers.php",'w'); $tries++; }
+    fwrite($f,"<php".PHP_EOL);
+    foreach($ACCEPTED as $p){ if($p[1]==0) continue; fwrite($f,"".$p[0]." [[[".$p[1]."]]] $p[2]".PHP_EOL); }
+    fclose($f); $f=0;
+
+    $tries=0; while(!$f && $tries<100){ $f = fopen("pending_confirm.php",'w'); $tries++; }
+    fwrite($f,"<php".PHP_EOL);
+    foreach($PENDING as $p){ if($p[1]==0) continue; fwrite($f,"".$p[0]." [[[".$p[1]."]]] $p[2]".PHP_EOL); }
+    fclose($f); $f=0;
+
+    echo "<h2>Successfully unsubscribed</h2>";
+}
+
+function send_email($to,$subject,$body){
+    try {
+        global $mail;
+        global $mailconf;
+        //Server settings
+        //$mail->SMTPDebug = SMTP::DEBUG_SERVER;                      //Enable verbose debug output
+        $mail->isSMTP();                                            //Send using SMTP
+        $mail->Host       = $mailconf['host'];                     //Set the SMTP server to send through
+        $mail->SMTPAuth   = true;                                   //Enable SMTP authentication
+        $mail->Username   = $mailconf['username'];                     //SMTP username
+        $mail->Password   = $mailconf['password'];                            //SMTP password
+        $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;            //Enable implicit TLS encryption
+        $mail->Port       = 587;                                    //TCP port to connect to; use 587 if you have set `SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS`
+    
+        //Recipients
+        $mail->setFrom($mailconf['from'], $mailconf['name']);
+        $mail->addAddress($to);
+    
+        //Content
+        $mail->isHTML(true);                                  //Set email format to HTML
+        $mail->Subject = $subject;
+        $mail->Body    = $body;
+    
+        $mail->send();
+        
+        return null;
+    } catch (Exception $e) {
+        echo "Message could not be sent."; #Mailer Error: {$mail->ErrorInfo}";
+        return -1;
+    }
+}
+
+function send_verification($id,$address){
+    $addressencode=urlencode($address);
+    $link="{$GLOBALS['MY_HOST']}/mailsub.php?confirm=$addressencode&id=$id";
+    $body=preg_replace("/\{CONFIRMLINK\}/",$link,$GLOBALS['MAILSUB_CONFIRM']);
+    if(!send_email($address,"Confirm Subscription",$body)){
+        echo "Please check your inbox for confirmation e-mail.";
+    }else{
+        echo "Error sending email.";
+    }
+}
+function send_welcome($id,$address){
+    $addressencode=urlencode($address);
+    $link="{$GLOBALS['MY_HOST']}/mailsub.php?unsubscribe=$addressencode&id=$id";
+    $body=preg_replace("/\{EDITSUBSCRIPTION\}/",$link,$GLOBALS['MAILSUB_WELCOME']);
+    send_email($address,"Welcome!",$body);
+}

+ 6 - 0
translations.md

@@ -1,3 +1,9 @@
+- 置顶备忘 | Pinned Reminder
+- 备忘录 | Reminders
+- 备忘 | Remind
+- 订阅 | Subscribe
+- 输入您的邮件: | Enter your email:
+- 订阅我的新闻 | Newsletters
 - 那么的维基 | laMDWiki
 - 基 | Ki
 - 管理员 | Administrator