mirror of
https://github.com/jkjoy/Typecho-Theme-Puock.git
synced 2026-06-09 22:34:12 +00:00
Compare commits
7 Commits
1.2.1
...
57aeb81c62
| Author | SHA1 | Date | |
|---|---|---|---|
| 57aeb81c62 | |||
| 4dcaefb291 | |||
| 0017693c81 | |||
| d268bd10bb | |||
| b416e58596 | |||
| 5d67235be0 | |||
| 134bb0d66c |
@@ -1 +1,3 @@
|
||||
*.html
|
||||
/.vercel
|
||||
page-talks copy.php
|
||||
|
||||
@@ -39,12 +39,14 @@
|
||||
- 将表情短代码(如 :smile:)自动解析为图片表情,集成到主题评论内容输出中。
|
||||
|
||||
- 2025.07.08
|
||||
|
||||
- 1.1.6
|
||||
|
||||
- 修复头像区域背景的bug
|
||||
- 优化php8.3兼容性
|
||||
|
||||
- 1.1.8
|
||||
|
||||
- 优化github链接的正则表达式,只解析主仓库链接(如 https://github.com/用户名/仓库名),不再解析子路径(如 /tree/、/blob/ 等)为卡片。
|
||||
- 实现文章内容图片懒加载,自动将常见图片格式(jpg、jpeg、png、webp)的<img>标签替换为带懒加载属性的格式。
|
||||
- 修正getPostCover函数,确保只从原始内容中提取第一张真实图片地址,不受懒加载替换影响,避免首页首图变成load.svg。
|
||||
@@ -56,4 +58,25 @@
|
||||
|
||||
- 1.2.0
|
||||
|
||||
- 新增支持首页登录
|
||||
- 新增支持首页登录
|
||||
|
||||
- 2025.08.02
|
||||
|
||||
- 1.2.2
|
||||
|
||||
- 增加侧边栏显示的全局开关
|
||||
- 修复代码块中的短代码解析问题
|
||||
- 新增一个随机文章阅读的独立页面
|
||||
|
||||
- 2025.08.03
|
||||
|
||||
- 1.2.3
|
||||
|
||||
- 修复随机页面在 PJAX 模式下的缓存问题
|
||||
- 在随机页面添加缓存控制头,防止 PJAX 缓存
|
||||
- 在 JavaScript 中添加随机页面检测,强制刷新确保获取新文章
|
||||
- 修复后端登录验证问题,确保密码错误时返回正确的错误信息
|
||||
- 重新设计随机页面模板,添加完整的页面结构和加载动画
|
||||
- 修复随机页面重定向问题,使用 JavaScript 跳转避免缓存
|
||||
- 修复随机页面 JavaScript 错误,移除不存在的 InstantClick.preload 方法调用
|
||||
- 优化随机页面跳转逻辑,确保在 PJAX 模式下也能正常自动跳转
|
||||
+14
-4
@@ -3,10 +3,16 @@ if (!defined('__TYPECHO_ROOT_DIR__')) exit;
|
||||
$this->need('header.php');
|
||||
?>
|
||||
<div class="row row-cols-1">
|
||||
<?php if ($this->options->showsidebar): ?>
|
||||
<div class="col-lg-8 col-md-12 animated fadeInLeft ">
|
||||
<div class="animated fadeInLeft ">
|
||||
<?php else: ?>
|
||||
<div class="col-lg-12 col-md-12">
|
||||
<div class="row box-plr15">
|
||||
<?php endif; ?>
|
||||
<div> <!--文章列表-->
|
||||
<div id="posts">
|
||||
<?php if ($this->options->listmodel): ?>
|
||||
<div class=" mr-0 ml-0">
|
||||
<?php while ($this->next()): ?>
|
||||
<?php
|
||||
@@ -61,8 +67,8 @@ $coverImage = getPostCover($this->content, $this->cid);
|
||||
</article>
|
||||
<?php endwhile; ?>
|
||||
</div>
|
||||
<div class="mt20 p-flex-s-right" data-no-instant>
|
||||
<?php $this->pageNav('«', '»', 1, '...', array(
|
||||
<div class="mt20 p-flex-s-right" data-no-instant>
|
||||
<?php $this->pageNav('«', '»', 1, '...', array(
|
||||
'wrapTag' => 'ul',
|
||||
'wrapClass' => 'pagination comment-ajax-load',
|
||||
'itemTag' => 'li',
|
||||
@@ -71,11 +77,15 @@ $coverImage = getPostCover($this->content, $this->cid);
|
||||
'prevClass' => 'prev',
|
||||
'nextClass' => 'next'
|
||||
)); ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<?php $this->need('card.php'); ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php if ($this->options->showsidebar): ?>
|
||||
<?php $this->need('sidebar.php'); ?>
|
||||
|
||||
<?php endif; ?>
|
||||
<?php $this->need('footer.php'); ?>
|
||||
+1
-1
@@ -171,7 +171,7 @@
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="t-sm c-sub">
|
||||
<span><?php $comments->date('Y-m-d H:i:s'); ?></span>
|
||||
<span><?php echo friendly_date($comments->created); ?></span>
|
||||
<a rel="nofollow" class="hide-info animated bounceIn c-sub-a t-sm ml-1 comment-reply" href="javascript:void(0);" data-coid="<?php echo $comments->coid; ?>"><span class="comment-reply-text"><i class="fa fa-share-from-square"></i>回复</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+1
-1
@@ -68,7 +68,7 @@
|
||||
© <?php echo date('Y'); ?> <a href="<?php $this->options->siteUrl(); ?>"><?php $this->options->title(); ?></a>
|
||||
<div class="fs12 mt10 c-sub">
|
||||
<span> Theme by
|
||||
<a target="_blank" class="c-sub" title="Puock v2.8.14" href="https://github.com/jkjoy/typecho-theme-puock">Puock</a>
|
||||
<a target="_blank" class="c-sub" title="Puock v1.2.2" href="https://github.com/jkjoy/typecho-theme-puock">Puock</a>
|
||||
</span>
|
||||
<span> Powered by
|
||||
<a target="_blank" class="c-sub" title="Typecho" href="https://typecho.org">Typecho</a> <p><a target="_blank" class="c-sub" title="老孙博客" href="https://imsun.org">老孙博客</a>制作</p>
|
||||
|
||||
+283
-210
@@ -33,13 +33,13 @@ function themeConfig($form)
|
||||
$form->addInput($cmsmodel);
|
||||
$friendlink = new Typecho_Widget_Helper_Form_Element_Radio('friendlink',
|
||||
array('0'=> _t('否'), '1'=> _t('是')),
|
||||
'0', _t('友情链接'), _t('选择"是"在首页显示友情链接。开启前请安装"Links"插件。链接分类需设置为home,默认关闭'));
|
||||
'0', _t('友情链接'), _t('选择"是"在首页显示友情链接。开启前请安装"Links"插件。链接分类需设置为<b>home</b>,默认关闭'));
|
||||
$form->addInput($friendlink);
|
||||
$social = new Typecho_Widget_Helper_Form_Element_Radio('social',
|
||||
array('0'=> _t('否'), '1'=> _t('是')),
|
||||
'0', _t('社交分享显示'), _t('选择"是"在文章页面显示社交分享。需要搭配插件使用,默认关闭'));
|
||||
$form->addInput($social);
|
||||
$gonggao = new Typecho_Widget_Helper_Form_Element_Textarea('gonggao', NULL, NULL, _t('站点公告'), _t('支持HTML'));
|
||||
$gonggao = new Typecho_Widget_Helper_Form_Element_Textarea('gonggao', NULL, NULL, _t('站点公告'), _t('<b style=color:red>使用格式: </b><b>标题|链接|图标</b><br>多条公告回车分隔.链接和图标可以为空.图标使用Font Awesome,如: fa-regular fa-bell'));
|
||||
$form->addInput($gonggao);
|
||||
$adlisttop = new Typecho_Widget_Helper_Form_Element_Textarea('adlisttop', NULL, NULL, _t('文章列表上方广告位'), _t('支持HTML'));
|
||||
$form->addInput($adlisttop);
|
||||
@@ -51,14 +51,24 @@ function themeConfig($form)
|
||||
$form->addInput($articlemid);
|
||||
$articlefoot = new Typecho_Widget_Helper_Form_Element_Textarea('articlefoot', NULL, NULL, _t('文章页底部广告位'), _t('支持HTML'));
|
||||
$form->addInput($articlefoot);
|
||||
$addhead = new Typecho_Widget_Helper_Form_Element_Textarea('addhead', NULL, NULL, _t('网站验证代码'), _t('若开启无刷新加载,请在标签上加上data-instant属性'));
|
||||
$addhead = new Typecho_Widget_Helper_Form_Element_Textarea('addhead', NULL, '<link rel="stylesheet" href="https://cdnjs.imsun.org/lxgw-wenkai-screen-webfont/style.css"></link>
|
||||
<style>* {font-family: -apple-system, BlinkMacSystemFont,"LXGW WenKai Screen", sans-serif;}</style>', _t('网站验证代码'), _t('若开启无刷新加载,请在标签上加上data-instant属性'));
|
||||
$form->addInput($addhead);
|
||||
$tongji = new Typecho_Widget_Helper_Form_Element_Textarea('tongji', NULL, NULL, _t('网站统计代码'), _t('支持HTML'));
|
||||
$tongji = new Typecho_Widget_Helper_Form_Element_Textarea('tongji', NULL, '<script async defer src="https://0tz.top/tracker.js" data-website-id="Puock"></script>', _t('网站统计代码'), _t('支持HTML'));
|
||||
$form->addInput($tongji);
|
||||
$footerinfo = new Typecho_Widget_Helper_Form_Element_Textarea('footerinfo', NULL, NULL, _t('底部关于我们'), _t('支持HTML'));
|
||||
$footerinfo = new Typecho_Widget_Helper_Form_Element_Textarea('footerinfo', NULL, '<a href="/feed" target="_blank"><i class="fa-solid fa-rss fa-2x"></i></a>
|
||||
<a href="https://jiong.us/@sun" target="_blank"><i class="fa-brands fa-mastodon fa-2x"></i></a>
|
||||
<a href="https://discord.gg/RUUcPEQKNt" target="_blank"><i class="fa-brands fa-discord fa-2x"></i></a>
|
||||
<a href="https://t.me/imsunpw" target="_blank"><i class="fa-brands fa-telegram fa-2x"></i></a>
|
||||
<a href="mailto:imsunpw@gmail.com" target="_blank"><i class="fa-solid fa-envelope fa-2x"></i></a>
|
||||
<a href="/sitemap.xml" target="_blank"><i class="fa-solid fa-sitemap fa-2x"></i></a>', _t('底部关于我们'), _t('支持HTML'));
|
||||
$form->addInput($footerinfo);
|
||||
$footercopyright = new Typecho_Widget_Helper_Form_Element_Textarea('footercopyright', NULL, NULL, _t('底部版权信息'), _t('支持HTML'));
|
||||
$footercopyright = new Typecho_Widget_Helper_Form_Element_Textarea('footercopyright', NULL, '<b>版权所有 转载请注明出处</b>', _t('底部版权信息'), _t('支持HTML'));
|
||||
$form->addInput($footercopyright);
|
||||
$showsidebar = new Typecho_Widget_Helper_Form_Element_Radio('showsidebar',
|
||||
array('0'=> _t('关闭'), '1'=> _t('显示')),
|
||||
'0', _t('全局侧边栏显示'), _t('<p style=color:red>注意!</p>如果选择关闭侧边栏则下方的侧边栏显示设置将无效'));
|
||||
$form->addInput($showsidebar);
|
||||
$sidebarBlock = new \Typecho\Widget\Helper\Form\Element\Checkbox(
|
||||
'sidebarBlock',
|
||||
[
|
||||
@@ -72,7 +82,6 @@ function themeConfig($form)
|
||||
['ShowSearch', 'ShowAdmin', 'ShowRecentPosts', 'ShowHotPosts', 'ShowRecentComments', 'ShowTags'],
|
||||
_t('侧边栏显示')
|
||||
);
|
||||
|
||||
$form->addInput($sidebarBlock->multiMode());
|
||||
}
|
||||
|
||||
@@ -83,6 +92,16 @@ function themeFields($layout) {
|
||||
$layout->addItem($cover);
|
||||
}
|
||||
|
||||
/** 头像镜像加速全局设置
|
||||
* @param $email
|
||||
* @param $size
|
||||
* @param $default
|
||||
* @return string
|
||||
*/
|
||||
$options = Typecho_Widget::widget('Widget_Options');
|
||||
$gravatarPrefix = empty($options->cnavatar) ? 'https://cravatar.cn/avatar/' : $options->cnavatar;
|
||||
define('__TYPECHO_GRAVATAR_PREFIX__', $gravatarPrefix);
|
||||
|
||||
/*
|
||||
* 文章浏览数统计
|
||||
*/
|
||||
@@ -313,92 +332,93 @@ function getBrowsersInfo($userAgent) {
|
||||
"version" => "",
|
||||
"device" => "PC"
|
||||
];
|
||||
|
||||
|
||||
$match = [
|
||||
// 浏览器 - 国外浏览器
|
||||
"Safari" => strstr($userAgent, 'Safari') != false ,
|
||||
"Chrome" => strstr($userAgent, 'Chrome') != false || strstr($userAgent, 'CriOS') != false ,
|
||||
"IE" => strstr($userAgent, 'MSIE') != false || strstr($userAgent, 'Trident') != false ,
|
||||
"Edge" => strstr($userAgent, 'Edge') != false || strstr($userAgent, 'Edg/') != false || strstr($userAgent, 'EdgA') != false || strstr($userAgent, 'EdgiOS') != false,
|
||||
"Firefox" => strstr($userAgent, 'Firefox') != false || strstr($userAgent, 'FxiOS') != false ,
|
||||
"Firefox Focus" => strstr($userAgent, 'Focus') != false,
|
||||
"Chromium" => strstr($userAgent,'Chromium') != false,
|
||||
"Opera" => strstr($userAgent,'Opera') != false || strstr($userAgent,'OPR') != false,
|
||||
"Vivaldi" => strstr($userAgent,'Vivaldi') != false,
|
||||
"Yandex" => strstr($userAgent,'YaBrowser') != false,
|
||||
"Arora" => strstr($userAgent,'Arora') != false,
|
||||
"Lunascape" => strstr($userAgent,'Lunascape') != false,
|
||||
"QupZilla" => strstr($userAgent,'QupZilla') != false,
|
||||
"Coc Coc" => strstr($userAgent,'coc_coc_browser') != false,
|
||||
"Kindle" => strstr($userAgent,'Kindle') != false || strstr($userAgent,'Silk/') != false,
|
||||
"Iceweasel" => strstr($userAgent,'Iceweasel') != false,
|
||||
"Konqueror" => strstr($userAgent,'Konqueror') != false,
|
||||
"Iceape" => strstr($userAgent,'Iceape') != false,
|
||||
"SeaMonkey" => strstr($userAgent,'SeaMonkey') != false,
|
||||
"Epiphany" => strstr($userAgent,'Epiphany') != false,
|
||||
"Safari" => strstr($userAgent, 'Safari') !== false,
|
||||
"Chrome" => strstr($userAgent, 'Chrome') !== false || strstr($userAgent, 'CriOS') !== false,
|
||||
"IE" => strstr($userAgent, 'MSIE') !== false || strstr($userAgent, 'Trident') !== false,
|
||||
"Edge" => strstr($userAgent, 'Edge') !== false || strstr($userAgent, 'Edg/') !== false || strstr($userAgent, 'EdgA') !== false || strstr($userAgent, 'EdgiOS') !== false,
|
||||
"Firefox" => strstr($userAgent, 'Firefox') !== false || strstr($userAgent, 'FxiOS') !== false,
|
||||
"Firefox Focus" => strstr($userAgent, 'Focus') !== false,
|
||||
"Chromium" => strstr($userAgent, 'Chromium') !== false,
|
||||
"Opera" => strstr($userAgent, 'Opera') !== false || strstr($userAgent, 'OPR') !== false,
|
||||
"Vivaldi" => strstr($userAgent, 'Vivaldi') !== false,
|
||||
"Yandex" => strstr($userAgent, 'YaBrowser') !== false,
|
||||
"Arora" => strstr($userAgent, 'Arora') !== false,
|
||||
"Lunascape" => strstr($userAgent, 'Lunascape') !== false,
|
||||
"QupZilla" => strstr($userAgent, 'QupZilla') !== false,
|
||||
"Coc Coc" => strstr($userAgent, 'coc_coc_browser') !== false,
|
||||
"Kindle" => strstr($userAgent, 'Kindle') !== false || strstr($userAgent, 'Silk/') !== false,
|
||||
"Iceweasel" => strstr($userAgent, 'Iceweasel') !== false,
|
||||
"Konqueror" => strstr($userAgent, 'Konqueror') !== false,
|
||||
"Iceape" => strstr($userAgent, 'Iceape') !== false,
|
||||
"SeaMonkey" => strstr($userAgent, 'SeaMonkey') !== false,
|
||||
"Epiphany" => strstr($userAgent, 'Epiphany') !== false,
|
||||
// 浏览器 - 国内浏览器
|
||||
"360" => strstr($userAgent,'QihooBrowser') != false || strstr($userAgent,'QHBrowser') != false,
|
||||
"360EE" => strstr($userAgent,'360EE') != false,
|
||||
"360SE" => strstr($userAgent,'360SE') != false,
|
||||
"UC" => strstr($userAgent,'UCBrowser') != false || strstr($userAgent,' UBrowser') != false || strstr($userAgent,'UCWEB') != false,
|
||||
"QQBrowser" => strstr($userAgent,'QQBrowser') != false,
|
||||
"QQ" => strstr($userAgent,'QQ/') != false,
|
||||
"Baidu" => strstr($userAgent,'Baidu') != false || strstr($userAgent,'BIDUBrowser') != false || strstr($userAgent,'baidubrowser') != false || strstr($userAgent,'baiduboxapp') != false || strstr($userAgent,'BaiduHD') != false,
|
||||
"Maxthon" => strstr($userAgent,'Maxthon') != false,
|
||||
"Sogou" => strstr($userAgent,'MetaSr') != false || strstr($userAgent,'Sogou') != false,
|
||||
"Liebao" => strstr($userAgent,'LBBROWSER') != false || strstr($userAgent,'LieBaoFast') != false,
|
||||
"2345Explorer" => strstr($userAgent,'2345Explorer') != false || strstr($userAgent,'Mb2345Browser') != false || strstr($userAgent,'2345chrome') != false,
|
||||
"115Browser" => strstr($userAgent,'115Browser') != false,
|
||||
"TheWorld" => strstr($userAgent,'TheWorld') != false,
|
||||
"Quark" => strstr($userAgent,'Quark') != false,
|
||||
"Qiyu" => strstr($userAgent,'Qiyu') != false,
|
||||
"360" => strstr($userAgent, 'QihooBrowser') !== false || strstr($userAgent, 'QHBrowser') !== false,
|
||||
"360EE" => strstr($userAgent, '360EE') !== false,
|
||||
"360SE" => strstr($userAgent, '360SE') !== false,
|
||||
"UC" => strstr($userAgent, 'UCBrowser') !== false || strstr($userAgent, ' UBrowser') !== false || strstr($userAgent, 'UCWEB') !== false,
|
||||
"QQBrowser" => strstr($userAgent, 'QQBrowser') !== false,
|
||||
"QQ" => strstr($userAgent, 'QQ/') !== false,
|
||||
"Baidu" => strstr($userAgent, 'Baidu') !== false || strstr($userAgent, 'BIDUBrowser') !== false || strstr($userAgent, 'baidubrowser') !== false || strstr($userAgent, 'baiduboxapp') !== false || strstr($userAgent, 'BaiduHD') !== false,
|
||||
"Maxthon" => strstr($userAgent, 'Maxthon') !== false,
|
||||
"Sogou" => strstr($userAgent, 'MetaSr') !== false || strstr($userAgent, 'Sogou') !== false,
|
||||
"Liebao" => strstr($userAgent, 'LBBROWSER') !== false || strstr($userAgent, 'LieBaoFast') !== false,
|
||||
"2345Explorer" => strstr($userAgent, '2345Explorer') !== false || strstr($userAgent, 'Mb2345Browser') !== false || strstr($userAgent, '2345chrome') !== false,
|
||||
"115Browser" => strstr($userAgent, '115Browser') !== false,
|
||||
"TheWorld" => strstr($userAgent, 'TheWorld') !== false,
|
||||
"Quark" => strstr($userAgent, 'Quark') !== false,
|
||||
"Qiyu" => strstr($userAgent, 'Qiyu') !== false,
|
||||
// 浏览器 - 手机厂商
|
||||
"XiaoMi" => strstr($userAgent,'MiuiBrowser') != false,
|
||||
"Huawei" => strstr($userAgent,'HuaweiBrowser') != false || strstr($userAgent,'HUAWEI/') != false || strstr($userAgent,'HONOR') != false || strstr($userAgent,'HBPC/') != false,
|
||||
"Vivo" => strstr($userAgent,'VivoBrowser') != false,
|
||||
"OPPO" => strstr($userAgent,'HeyTapBrowser') != false,
|
||||
"XiaoMi" => strstr($userAgent, 'MiuiBrowser') !== false,
|
||||
"Huawei" => strstr($userAgent, 'HuaweiBrowser') !== false || strstr($userAgent, 'HUAWEI/') !== false || strstr($userAgent, 'HONOR') !== false || strstr($userAgent, 'HBPC/') !== false,
|
||||
"Vivo" => strstr($userAgent, 'VivoBrowser') !== false,
|
||||
"OPPO" => strstr($userAgent, 'HeyTapBrowser') !== false,
|
||||
// 浏览器 - 客户端
|
||||
"Wechat" => strstr($userAgent,'MicroMessenger') != false,
|
||||
"WechatWork" => strstr($userAgent,'wxwork/') != false,
|
||||
"Taobao" => strstr($userAgent,'AliApp(TB') != false,
|
||||
"Alipay" => strstr($userAgent,'AliApp(AP') != false,
|
||||
"Weibo" => strstr($userAgent,'Weibo') != false,
|
||||
"Douban" => strstr($userAgent,'com.douban.frodo') != false,
|
||||
"Suning" => strstr($userAgent,'SNEBUY-APP') != false,
|
||||
"iQiYi" => strstr($userAgent,'IqiyiApp') != false,
|
||||
"DingTalk" => strstr($userAgent,'DingTalk') != false,
|
||||
"Douyin" => strstr($userAgent,'aweme') != false,
|
||||
"Wechat" => strstr($userAgent, 'MicroMessenger') !== false,
|
||||
"WechatWork" => strstr($userAgent, 'wxwork/') !== false,
|
||||
"Taobao" => strstr($userAgent, 'AliApp(TB') !== false,
|
||||
"Alipay" => strstr($userAgent, 'AliApp(AP') !== false,
|
||||
"Weibo" => strstr($userAgent, 'Weibo') !== false,
|
||||
"Douban" => strstr($userAgent, 'com.douban.frodo') !== false,
|
||||
"Suning" => strstr($userAgent, 'SNEBUY-APP') !== false,
|
||||
"iQiYi" => strstr($userAgent, 'IqiyiApp') !== false,
|
||||
"DingTalk" => strstr($userAgent, 'DingTalk') !== false,
|
||||
"Douyin" => strstr($userAgent, 'aweme') !== false,
|
||||
// 系统或平台
|
||||
"Windows" => strstr($userAgent,'Windows') != false,
|
||||
"Linux" => strstr($userAgent,'Linux') != false || strstr($userAgent,'X11') != false,
|
||||
"Mac OS" => strstr($userAgent,'Macintosh') != false,
|
||||
"Android" => strstr($userAgent,'Android') != false || strstr($userAgent,'Adr') != false,
|
||||
"HarmonyOS" => strstr($userAgent,'HarmonyOS') != false,
|
||||
"Ubuntu" => strstr($userAgent,'Ubuntu') != false,
|
||||
"FreeBSD" => strstr($userAgent,'FreeBSD') != false,
|
||||
"Debian" => strstr($userAgent,'Debian') != false,
|
||||
"Windows Phone" => strstr($userAgent,'IEMobile') != false || strstr($userAgent,'Windows Phone') != false,
|
||||
"BlackBerry" => strstr($userAgent,'BlackBerry') != false || strstr($userAgent,'RIM') != false,
|
||||
"MeeGo" => strstr($userAgent,'MeeGo') != false,
|
||||
"Symbian" => strstr($userAgent,'Symbian') != false,
|
||||
"iOS" => strstr($userAgent,'like Mac OS X') != false,
|
||||
"Chrome OS" => strstr($userAgent,'CrOS') != false,
|
||||
"WebOS" => strstr($userAgent,'hpwOS') != false,
|
||||
"Windows" => strstr($userAgent, 'Windows') !== false,
|
||||
"Linux" => strstr($userAgent, 'Linux') !== false || strstr($userAgent, 'X11') !== false,
|
||||
"Mac OS" => strstr($userAgent, 'Macintosh') !== false,
|
||||
"Android" => strstr($userAgent, 'Android') !== false || strstr($userAgent, 'Adr') !== false,
|
||||
"HarmonyOS" => strstr($userAgent, 'HarmonyOS') !== false,
|
||||
"Ubuntu" => strstr($userAgent, 'Ubuntu') !== false,
|
||||
"FreeBSD" => strstr($userAgent, 'FreeBSD') !== false,
|
||||
"Debian" => strstr($userAgent, 'Debian') !== false,
|
||||
"Windows Phone" => strstr($userAgent, 'IEMobile') !== false || strstr($userAgent, 'Windows Phone') !== false,
|
||||
"BlackBerry" => strstr($userAgent, 'BlackBerry') !== false || strstr($userAgent, 'RIM') !== false,
|
||||
"MeeGo" => strstr($userAgent, 'MeeGo') !== false,
|
||||
"Symbian" => strstr($userAgent, 'Symbian') !== false,
|
||||
"iOS" => strstr($userAgent, 'like Mac OS X') !== false,
|
||||
"Chrome OS" => strstr($userAgent, 'CrOS') !== false,
|
||||
"WebOS" => strstr($userAgent, 'hpwOS') !== false,
|
||||
// 设备
|
||||
"Mobile" => strstr($userAgent,'Mobi') != false || strstr($userAgent,'iPh') != false || strstr($userAgent,'480') != false,
|
||||
"Tablet" => strstr($userAgent,'Tablet') != false || strstr($userAgent,'Pad') != false || strstr($userAgent,'Nexus 7') != false,
|
||||
"Mobile" => strstr($userAgent, 'Mobi') !== false || strstr($userAgent, 'iPh') !== false || strstr($userAgent, '480') !== false,
|
||||
"Tablet" => strstr($userAgent, 'Tablet') !== false || strstr($userAgent, 'Pad') !== false || strstr($userAgent, 'Nexus 7') !== false,
|
||||
];
|
||||
// 部分修正 | 因typecho评论数据只存储了ua的信息,所以不能完全进行修正尤其是360相关浏览器
|
||||
|
||||
// 部分修正
|
||||
if ($match['Baidu'] && $match['Opera']) $match['Baidu'] = false;
|
||||
if ($match['iOS']) $match['Safari'] = true;
|
||||
|
||||
|
||||
// 基本信息
|
||||
$baseInfo = [
|
||||
"browser" => [
|
||||
'Safari', 'Chrome', 'Edge', 'IE', 'Firefox', 'Firefox Focus', 'Chromium',
|
||||
'Opera', 'Vivaldi', 'Yandex', 'Arora', 'Lunascape','QupZilla', 'Coc Coc',
|
||||
'Kindle', 'Iceweasel', 'Konqueror', 'Iceape','SeaMonkey', 'Epiphany', 'XiaoMi',
|
||||
'Vivo', 'OPPO', '360', '360SE','360EE', 'UC', 'QQBrowser', 'QQ', 'Huawei', 'Baidu',
|
||||
'Opera', 'Vivaldi', 'Yandex', 'Arora', 'Lunascape', 'QupZilla', 'Coc Coc',
|
||||
'Kindle', 'Iceweasel', 'Konqueror', 'Iceape', 'SeaMonkey', 'Epiphany', 'XiaoMi',
|
||||
'Vivo', 'OPPO', '360', '360SE', '360EE', 'UC', 'QQBrowser', 'QQ', 'Huawei', 'Baidu',
|
||||
'Maxthon', 'Sogou', 'Liebao', '2345Explorer', '115Browser', 'TheWorld', 'Quark', 'Qiyu',
|
||||
'Wechat', 'WechatWork', 'Taobao', 'Alipay', 'Weibo', 'Douban', 'Suning', 'iQiYi', 'DingTalk', 'Douyin'
|
||||
],
|
||||
@@ -409,17 +429,15 @@ function getBrowsersInfo($userAgent) {
|
||||
],
|
||||
"device" => ['Mobile', 'Tablet'],
|
||||
];
|
||||
|
||||
|
||||
foreach ($baseInfo as $k => $v) {
|
||||
foreach ($v as $xv) {
|
||||
if ($match[$xv]) $deviceInfo[$k] = $xv;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 操作系统版本信息
|
||||
$windowsVersion = [
|
||||
'10' => "10",
|
||||
'6.4' => '10',
|
||||
'6.3' => '8.1',
|
||||
'6.2' => '8',
|
||||
'6.1' => '7',
|
||||
@@ -428,29 +446,58 @@ function getBrowsersInfo($userAgent) {
|
||||
'5.1' => 'XP',
|
||||
'5.0' => '2000',
|
||||
];
|
||||
$wv = pregMatch("/^Mozilla\/\d.0 \(Windows NT ([\d.]+)[;)].*$/", $userAgent);
|
||||
|
||||
// Extract Windows NT version and build number
|
||||
if (preg_match("/\(Windows NT ([\d.]+)(?:;[^)]*Build\/(\d+))?(?:;[^)]*)?\)/i", $userAgent, $matches)) {
|
||||
$ntVersion = $matches[1];
|
||||
$buildNumber = isset($matches[2]) ? (int)$matches[2] : 0;
|
||||
|
||||
if ($ntVersion === '10.0') {
|
||||
// Check build number for Windows 11
|
||||
if ($buildNumber >= 22000) {
|
||||
$deviceInfo['systemVersion'] = '11';
|
||||
} else {
|
||||
// Fallback heuristic: Check Edge version (Windows 11 requires Edge >= 91)
|
||||
if ($deviceInfo['browser'] === 'Edge' && preg_match("/Edg\/([\d.]+)/", $userAgent, $edgeMatch)) {
|
||||
$edgeVersion = (float)$edgeMatch[1];
|
||||
if ($edgeVersion >= 91) {
|
||||
$deviceInfo['systemVersion'] = '11'; // Assume Windows 11 for modern Edge
|
||||
} else {
|
||||
$deviceInfo['systemVersion'] = '10';
|
||||
}
|
||||
} else {
|
||||
$deviceInfo['systemVersion'] = '10';
|
||||
// Log ambiguous case for debugging
|
||||
error_log("Ambiguous Windows version (NT 10.0, no build number): $userAgent");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$deviceInfo['systemVersion'] = $windowsVersion[$ntVersion] ?? $ntVersion;
|
||||
}
|
||||
}
|
||||
|
||||
$HarmonyOSVersion = [
|
||||
10 => "2",
|
||||
12 => "3"
|
||||
];
|
||||
$systemVersion = [
|
||||
"Windows" => $windowsVersion[$wv] ?? $wv,
|
||||
"Android" => pregMatch("/^.*Android ([\d.]+);.*$/", $userAgent),
|
||||
"HarmonyOS" => $HarmonyOSVersion[pregMatch("/^Mozilla.*Android ([\d.]+)[;)].*$/", $userAgent)] ?? '',
|
||||
"iOS" => preg_replace("/_/", '.', pregMatch("/^.*OS ([\d_]+) like.*$/", $userAgent)),
|
||||
"Debian" => pregMatch("/^.*Debian\/([\d.]+).*$/", $userAgent),
|
||||
"Windows Phone" => pregMatch("/^.*Windows Phone( OS)? ([\d.]+);.*$/", $userAgent),
|
||||
"Mac OS" => preg_replace("/_/", '.',pregMatch("/^.*Mac OS X ([\d_]+).*$/", $userAgent)),
|
||||
"WebOS" => pregMatch("/^.*hpwOS\/([\d.]+);.*$/", $userAgent)
|
||||
"Windows" => $deviceInfo['systemVersion'], // Already set above
|
||||
"Android" => preg_match("/Android ([\d.]+);/", $userAgent, $matches) ? $matches[1] : '',
|
||||
"HarmonyOS" => preg_match("/Android ([\d.]+)[;)]/", $userAgent, $matches) ? ($HarmonyOSVersion[(int)$matches[1]] ?? '') : '',
|
||||
"iOS" => preg_match("/OS ([\d_]+) like/", $userAgent, $matches) ? str_replace('_', '.', $matches[1]) : '',
|
||||
"Debian" => preg_match("/Debian\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : '',
|
||||
"Windows Phone" => preg_match("/Windows Phone( OS)? ([\d.]+);/", $userAgent, $matches) ? $matches[2] : '',
|
||||
"Mac OS" => preg_match("/Mac OS X ([\d_]+)/", $userAgent, $matches) ? str_replace('_', '.', $matches[1]) : '',
|
||||
"WebOS" => preg_match("/hpwOS\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : ''
|
||||
];
|
||||
|
||||
|
||||
if (isset($deviceInfo['system']) && $deviceInfo['system'] !== "" && isset($systemVersion[$deviceInfo['system']])) {
|
||||
$deviceInfo['systemVersion'] = $systemVersion[$deviceInfo['system']];
|
||||
if ($deviceInfo['systemVersion'] == $userAgent) {
|
||||
$deviceInfo['systemVersion'] = '';
|
||||
}
|
||||
$deviceInfo['systemVersion'] = $systemVersion[$deviceInfo['system']];
|
||||
if ($deviceInfo['systemVersion'] == $userAgent) {
|
||||
$deviceInfo['systemVersion'] = '';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 浏览器版本信息
|
||||
$browsers_360SE = [
|
||||
108 => '14.0',
|
||||
@@ -475,7 +522,7 @@ function getBrowsersInfo($userAgent) {
|
||||
30 => '7.5',
|
||||
];
|
||||
$browsers_liebao = [
|
||||
57 => '6.5',
|
||||
57 => '6.5',
|
||||
49 => '6.0',
|
||||
46 => '5.9',
|
||||
42 => '5.3',
|
||||
@@ -487,82 +534,81 @@ function getBrowsersInfo($userAgent) {
|
||||
$browsers_2345 = [
|
||||
69 => '10.0',
|
||||
55 => '9.9',
|
||||
69 => '10.0',
|
||||
55 => '9.9',
|
||||
69 => '10.0',
|
||||
55 => '9.9'
|
||||
];
|
||||
|
||||
$chromeVersion = pregMatch('/^.*Chrome\/([\d]+).*$/', $userAgent);
|
||||
|
||||
|
||||
$chromeVersion = preg_match('/Chrome\/([\d]+)/', $userAgent, $matches) ? (int)$matches[1] : 0;
|
||||
|
||||
$browsersVersion = [
|
||||
"Safari" => pregMatch("/^.*Version\/([\d.]+).*$/", $userAgent),
|
||||
"Chrome" => pregMatch("/^.*Chrome\/([\d.]+).*$/", $userAgent) ?? pregMatch("/^.*CriOS\/([\d.]+).*$/", $userAgent),
|
||||
"IE" => pregMatch("/^.*MSIE ([\d.]+).*$/", $userAgent) ?? pregMatch("/^.*rv:([\d.]+).*$/", $userAgent),
|
||||
"Edge" => pregMatch("/^.*Edge\/([\d.]+).*$/", $userAgent) ?? pregMatch("/^.*Edg\/([\d.]+).*$/", $userAgent) ?? pregMatch("/^.*EdgA\/([\d.]+).*$/", $userAgent) ?? pregMatch("/^.*EdgiOS\/([\d.]+).*$/", $userAgent),
|
||||
"Firefox" => pregMatch("/^.*Firefox\/([\d.]+).*$/", $userAgent) ?? pregMatch("/^.*FxiOS\/([\d.]+).*$/", $userAgent),
|
||||
"Firefox Focus" => pregMatch("/^.*Focus\/([\d.]+).*$/", $userAgent),
|
||||
"Chromium" => pregMatch("/^.*Chromium\/([\d.]+).*$/", $userAgent),
|
||||
"Opera" => pregMatch("/^.*Opera\/([\d.]+).*$/", $userAgent) ?? pregMatch("/^.*OPR\/([\d.]+).*$/", $userAgent),
|
||||
"Vivaldi" => pregMatch("/^.*Vivaldi\/([\d.]+).*$/", $userAgent),
|
||||
"Yandex" => pregMatch("/^.*YaBrowser\/([\d.]+).*$/", $userAgent),
|
||||
"Brave" => pregMatch("/^.*Chrome\/([\d.]+).*$/", $userAgent),
|
||||
"Arora" => pregMatch("/^.*Arora\/([\d.]+).*$/", $userAgent),
|
||||
"Lunascape" => pregMatch("/^.*Lunascape[\/\s]([\d.]+).*$/", $userAgent),
|
||||
"QupZilla" => pregMatch("/^.*QupZilla[\/\s]([\d.]+).*$/", $userAgent),
|
||||
"Coc Coc" => pregMatch("/^.*coc_coc_browser\/([\d.]+).*$/", $userAgent),
|
||||
"Kindle" => pregMatch("/^.*Version\/([\d.]+).*$/", $userAgent),
|
||||
"Iceweasel" => pregMatch("/^.*Iceweasel\/([\d.]+).*$/", $userAgent),
|
||||
"Konqueror" => pregMatch("/^.*Konqueror\/([\d.]+).*$/", $userAgent),
|
||||
"Iceape" => pregMatch("/^.*Iceape\/([\d.]+).*$/", $userAgent),
|
||||
"SeaMonkey" => pregMatch("/^.*SeaMonkey\/([\d.]+).*$/", $userAgent),
|
||||
"Epiphany" => pregMatch("/^.*Epiphany\/([\d.]+).*$/", $userAgent),
|
||||
"360" => pregMatch("/^.*QihooBrowser(HD)?\/([\d.]+).*$/", $userAgent),
|
||||
"Maxthon" => pregMatch("/^.*Maxthon\/([\d.]+).*$/", $userAgent),
|
||||
"QQBrowser" => pregMatch("/^.*QQBrowser\/([\d.]+).*$/", $userAgent),
|
||||
"QQ" => pregMatch("/^.*QQ\/([\d.]+).*$/", $userAgent),
|
||||
"Baidu" => pregMatch("/^.*BIDUBrowser[\s\/]([\d.]+).*$/", $userAgent) ?? pregMatch("/^.*baiduboxapp\/([\d.]+).*$/", $userAgent),
|
||||
"UC" => pregMatch("/^.*UC?Browser\/([\d.]+).*$/", $userAgent),
|
||||
"Sogou" => pregMatch("/^.*SE ([\d.X]+).*$/", $userAgent) ?? pregMatch("/^.*SogouMobileBrowser\/([\d.]+).*$/", $userAgent),
|
||||
"115Browser" => pregMatch("/^.*115Browser\/([\d.]+).*$/", $userAgent),
|
||||
"TheWorld" => pregMatch("/^.*TheWorld ([\d.]+).*$/", $userAgent),
|
||||
"XiaoMi" => pregMatch("/^.*MiuiBrowser\/([\d.]+).*$/", $userAgent),
|
||||
"Vivo" => pregMatch("/^.*VivoBrowser\/([\d.]+).*$/", $userAgent),
|
||||
"OPPO" => pregMatch("/^.*HeyTapBrowser\/([\d.]+).*$/", $userAgent),
|
||||
"Quark" => pregMatch("/^.*Quark\/([\d.]+).*$/", $userAgent),
|
||||
"Qiyu" => pregMatch("/^.*Qiyu\/([\d.]+).*$/", $userAgent),
|
||||
"Wechat" => pregMatch("/^.*MicroMessenger\/([\d.]+).*$/", $userAgent),
|
||||
"WechatWork" => pregMatch("/^.*wxwork\/([\d.]+).*$/", $userAgent),
|
||||
"Taobao" => pregMatch("/^.*AliApp\(TB\/([\d.]+).*$/", $userAgent),
|
||||
"Alipay" => pregMatch("/^.*AliApp\(AP\/([\d.]+).*$/", $userAgent),
|
||||
"Weibo" => pregMatch("/^.*weibo__([\d.]+).*$/", $userAgent),
|
||||
"Douban" => pregMatch("/^.*com.douban.frodo\/([\d.]+).*$/", $userAgent),
|
||||
"Suning" => pregMatch("/^.*SNEBUY-APP([\d.]+).*$/", $userAgent),
|
||||
"iQiYi" => pregMatch("/^.*IqiyiVersion\/([\d.]+).*$/", $userAgent),
|
||||
"DingTalk" => pregMatch("/^.*DingTalk\/([\d.]+).*$/", $userAgent),
|
||||
"Douyin" => pregMatch("/^.*app_version\/([\d.]+).*$/", $userAgent),
|
||||
"Huawei" => pregMatch("/^.*Version\/([\d.]+).*$/", $userAgent) ?? pregMatch("/^.*HuaweiBrowser\/([\d.]+).*$/", $userAgent) ?? pregMatch("/^.*HBPC\/([\d.]+).*$/", $userAgent),
|
||||
"360SE" => $browsers_360SE[$chromeVersion] ?? '',
|
||||
"360EE" => $browsers_360EE[$chromeVersion] ?? '',
|
||||
"Liebao" => pregMatch("/^.*LieBaoFast\/([\d.]+).*$/", $userAgent) ?? $browsers_liebao[$chromeVersion],
|
||||
"2345Explorer" => $browsers_2345[$chromeVersion] ?? pregMatch("/^.*2345Explorer\/([\d.]+).*$/", $userAgent) ?? pregMatch("/^.*Mb2345Browser\/([\d.]+).*$/", $userAgent),
|
||||
"Safari" => preg_match("/Version\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : '',
|
||||
"Chrome" => preg_match("/Chrome\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : (preg_match("/CriOS\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : ''),
|
||||
"IE" => preg_match("/MSIE ([\d.]+)/", $userAgent, $matches) ? $matches[1] : (preg_match("/rv:([\d.]+)/", $userAgent, $matches) ? $matches[1] : ''),
|
||||
"Edge" => preg_match("/Edge\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : (preg_match("/Edg\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : (preg_match("/EdgA\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : (preg_match("/EdgiOS\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : ''))),
|
||||
"Firefox" => preg_match("/Firefox\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : (preg_match("/FxiOS\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : ''),
|
||||
"Firefox Focus" => preg_match("/Focus\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : '',
|
||||
"Chromium" => preg_match("/Chromium\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : '',
|
||||
"Opera" => preg_match("/Opera\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : (preg_match("/OPR\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : ''),
|
||||
"Vivaldi" => preg_match("/Vivaldi\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : '',
|
||||
"Yandex" => preg_match("/YaBrowser\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : '',
|
||||
"Brave" => preg_match("/Chrome\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : '',
|
||||
"Arora" => preg_match("/Arora\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : '',
|
||||
"Lunascape" => preg_match("/Lunascape[\/\s]([\d.]+)/", $userAgent, $matches) ? $matches[1] : '',
|
||||
"QupZilla" => preg_match("/QupZilla[\/\s]([\d.]+)/", $userAgent, $matches) ? $matches[1] : '',
|
||||
"Coc Coc" => preg_match("/coc_coc_browser\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : '',
|
||||
"Kindle" => preg_match("/Version\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : '',
|
||||
"Iceweasel" => preg_match("/Iceweasel\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : '',
|
||||
"Konqueror" => preg_match("/Konqueror\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : '',
|
||||
"Iceape" => preg_match("/Iceape\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : '',
|
||||
"SeaMonkey" => preg_match("/SeaMonkey\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : '',
|
||||
"Epiphany" => preg_match("/Epiphany\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : '',
|
||||
"360" => preg_match("/QihooBrowser(HD)?\/([\d.]+)/", $userAgent, $matches) ? $matches[2] : '',
|
||||
"Maxthon" => preg_match("/Maxthon\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : '',
|
||||
"QQBrowser" => preg_match("/QQBrowser\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : '',
|
||||
"QQ" => preg_match("/QQ\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : '',
|
||||
"Baidu" => preg_match("/BIDUBrowser[\s\/]([\d.]+)/", $userAgent, $matches) ? $matches[1] : (preg_match("/baiduboxapp\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : ''),
|
||||
"UC" => preg_match("/UC?Browser\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : '',
|
||||
"Sogou" => preg_match("/SE ([\d.X]+)/", $userAgent, $matches) ? $matches[1] : (preg_match("/SogouMobileBrowser\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : ''),
|
||||
"115Browser" => preg_match("/115Browser\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : '',
|
||||
"TheWorld" => preg_match("/TheWorld ([\d.]+)/", $userAgent, $matches) ? $matches[1] : '',
|
||||
"XiaoMi" => preg_match("/MiuiBrowser\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : '',
|
||||
"Vivo" => preg_match("/VivoBrowser\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : '',
|
||||
"OPPO" => preg_match("/HeyTapBrowser\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : '',
|
||||
"Quark" => preg_match("/Quark\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : '',
|
||||
"Qiyu" => preg_match("/Qiyu\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : '',
|
||||
"Wechat" => preg_match("/MicroMessenger\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : '',
|
||||
"WechatWork" => preg_match("/wxwork\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : '',
|
||||
"Taobao" => preg_match("/AliApp\(TB\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : '',
|
||||
"Alipay" => preg_match("/AliApp\(AP\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : '',
|
||||
"Weibo" => preg_match("/weibo__([\d.]+)/", $userAgent, $matches) ? $matches[1] : '',
|
||||
"Douban" => preg_match("/com.douban.frodo\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : '',
|
||||
"Suning" => preg_match("/SNEBUY-APP([\d.]+)/", $userAgent, $matches) ? $matches[1] : '',
|
||||
"iQiYi" => preg_match("/IqiyiVersion\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : '',
|
||||
"DingTalk" => preg_match("/DingTalk\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : '',
|
||||
"Douyin" => preg_match("/app_version\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : '',
|
||||
"Huawei" => preg_match("/Version\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : (preg_match("/HuaweiBrowser\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : (preg_match("/HBPC\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : '')),
|
||||
"360SE" => isset($browsers_360SE[$chromeVersion]) ? $browsers_360SE[$chromeVersion] : '',
|
||||
"360EE" => isset($browsers_360EE[$chromeVersion]) ? $browsers_360EE[$chromeVersion] : '',
|
||||
"Liebao" => preg_match("/LieBaoFast\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : (isset($browsers_liebao[$chromeVersion]) ? $browsers_liebao[$chromeVersion] : ''),
|
||||
"2345Explorer" => preg_match("/2345Explorer\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : (preg_match("/Mb2345Browser\/([\d.]+)/", $userAgent, $matches) ? $matches[1] : (isset($browsers_2345[$chromeVersion]) ? $browsers_2345[$chromeVersion] : '')),
|
||||
];
|
||||
|
||||
|
||||
|
||||
if (isset($deviceInfo['browser'], $browsersVersion[$deviceInfo['browser']])) {
|
||||
$deviceInfo['version'] = $browsersVersion[$deviceInfo['browser']];
|
||||
if ($deviceInfo['version'] == $userAgent) {
|
||||
$deviceInfo['version'] = '';
|
||||
}
|
||||
$deviceInfo['version'] = $browsersVersion[$deviceInfo['browser']];
|
||||
if ($deviceInfo['version'] == $userAgent) {
|
||||
$deviceInfo['version'] = '';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 修正浏览器版本信息
|
||||
$chrome = pregMatch('/\S+Browser/', $userAgent);
|
||||
if ($deviceInfo['browser'] == 'Chrome' && $chrome) {
|
||||
$deviceInfo['browser'] = $chrome;
|
||||
$deviceInfo['version'] = pregMatch('/^.*Browser\/([\d.]+).*$/', $userAgent);
|
||||
if (preg_match('/\S+Browser/', $userAgent, $matches)) {
|
||||
$chrome = $matches[0];
|
||||
if ($deviceInfo['browser'] == 'Chrome' && $chrome !== 'Chrome') {
|
||||
$deviceInfo['browser'] = $chrome;
|
||||
if (preg_match('/Browser\/([\d.]+)/', $userAgent, $matches)) {
|
||||
$deviceInfo['version'] = $matches[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return $deviceInfo;
|
||||
}
|
||||
|
||||
@@ -984,7 +1030,8 @@ function parse_smiley_shortcode($content) {
|
||||
/**
|
||||
* 短代码实现
|
||||
*/
|
||||
function get_article_info($atts) {
|
||||
function get_article_info($atts)
|
||||
{
|
||||
$default_atts = array('id' => '');
|
||||
$atts = array_merge($default_atts, $atts);
|
||||
$db = Typecho_Db::get();
|
||||
@@ -996,7 +1043,6 @@ function get_article_info($atts) {
|
||||
if (!$post) {
|
||||
return '未找到文章';
|
||||
}
|
||||
// 获取文章对象,避免permalink警告
|
||||
$post = Typecho_Widget::widget('Widget_Abstract_Contents')->push($post);
|
||||
$permalink = $post['permalink'];
|
||||
$title = htmlspecialchars($post['title']);
|
||||
@@ -1011,17 +1057,37 @@ function get_article_info($atts) {
|
||||
|
||||
return $output;
|
||||
}
|
||||
// 创建一个新的类来处理内容过滤
|
||||
class ContentFilter
|
||||
{
|
||||
/**
|
||||
* 过滤内容中的短代码
|
||||
*
|
||||
* @param string $content 内容
|
||||
* @param object $widget 小工具对象
|
||||
* @param array $lastResult 上一次结果
|
||||
* @return string 处理后的内容
|
||||
*/
|
||||
public static function filterContent($content, $widget, $lastResult)
|
||||
{
|
||||
// 先做github短代码和链接替换
|
||||
// Step 1: 保护代码块
|
||||
$codeBlocks = [];
|
||||
$content = preg_replace_callback(
|
||||
'/```[\s\S]*?```/m', // 匹配 Markdown 代码块(包括多行)
|
||||
function ($matches) use (&$codeBlocks) {
|
||||
$placeholder = '<!--CODEBLOCK_' . count($codeBlocks) . '-->';
|
||||
$codeBlocks[$placeholder] = $matches[0]; // 存储原始代码块内容
|
||||
return $placeholder;
|
||||
},
|
||||
$content
|
||||
);
|
||||
|
||||
// Step 2: 执行现有的短代码处理
|
||||
// GitHub 短代码替换
|
||||
$content = preg_replace_callback('/\[github=([\w\-\.]+\/[\w\-\.]+)\]/i', function($matches) {
|
||||
$repo = htmlspecialchars($matches[1]);
|
||||
return '<div class="github-card text-center" data-repo="' . $repo . '"><div class="spinner-grow text-primary"></div></div>';
|
||||
}, $content);
|
||||
// 只匹配主仓库链接,后面只能是空格、标点、换行或结尾
|
||||
|
||||
$content = preg_replace_callback(
|
||||
'#https://github\.com/([\w\-\.]+/[\w\-\.]+)(?=[\s\.,;:!\?\)\]\}\"\'\n]|$)#i',
|
||||
function($matches) {
|
||||
@@ -1031,10 +1097,7 @@ class ContentFilter
|
||||
$content
|
||||
);
|
||||
|
||||
// 再进行 Markdown 解析
|
||||
$content = empty($lastResult) ? $widget->markdown($content) : $lastResult;
|
||||
|
||||
// alert类短代码批量替换
|
||||
// alert 类短代码
|
||||
$alertShortcodes = [
|
||||
'success' => 'success',
|
||||
'primary' => 'primary',
|
||||
@@ -1051,12 +1114,12 @@ class ContentFilter
|
||||
);
|
||||
}
|
||||
|
||||
// 其他短代码处理
|
||||
// article 短代码
|
||||
$content = preg_replace_callback('/\[article\s+([^\]]+)\]/', function($matches) {
|
||||
$atts = self::parse_atts($matches[1]);
|
||||
return get_article_info($atts);
|
||||
}, $content);
|
||||
|
||||
|
||||
// 懒加载图片替换
|
||||
$themeUrl = Helper::options()->themeUrl;
|
||||
$loadSvg = $themeUrl . '/assets/img/load.svg';
|
||||
@@ -1069,7 +1132,8 @@ class ContentFilter
|
||||
},
|
||||
$content
|
||||
);
|
||||
// collapse折叠面板短代码
|
||||
|
||||
// collapse 折叠面板短代码
|
||||
static $collapseIndex = 0;
|
||||
$content = preg_replace_callback(
|
||||
'/\[collapse\s+title=(?:\'([^\']*)\'|\"([^\"]*)\")\](.*?)\[\/collapse\]/is',
|
||||
@@ -1082,7 +1146,8 @@ class ContentFilter
|
||||
},
|
||||
$content
|
||||
);
|
||||
// download下载短代码
|
||||
|
||||
// download 短代码
|
||||
$content = preg_replace_callback(
|
||||
'/\[download\s+file=(?:\'([^\']*)\'|\"([^\"]*)\")\s+size=(?:\'([^\']*)\'|\"([^\"]*)\")\](.*?)\[\/download\]/is',
|
||||
function($matches) {
|
||||
@@ -1097,17 +1162,16 @@ class ContentFilter
|
||||
},
|
||||
$content
|
||||
);
|
||||
// 回复可见短代码
|
||||
|
||||
// reply 短代码
|
||||
$content = preg_replace_callback(
|
||||
'/\[reply\](.*?)\[\/reply\]/is',
|
||||
function($matches) use ($widget) {
|
||||
$show = false;
|
||||
// 仅在文章页生效
|
||||
if ($widget instanceof Widget_Archive && $widget->is('single')) {
|
||||
$user = Typecho_Widget::widget('Widget_User');
|
||||
$db = Typecho_Db::get();
|
||||
if ($user->hasLogin) {
|
||||
// 登录用户,判断是否有通过审核的评论
|
||||
$hasComment = $db->fetchRow($db->select()->from('table.comments')
|
||||
->where('cid = ?', $widget->cid)
|
||||
->where('mail = ?', $user->mail)
|
||||
@@ -1115,7 +1179,6 @@ class ContentFilter
|
||||
);
|
||||
if ($hasComment) $show = true;
|
||||
} else {
|
||||
// 未登录,判断IP
|
||||
$hasComment = $db->fetchRow($db->select()->from('table.comments')
|
||||
->where('cid = ?', $widget->cid)
|
||||
->where('status = ?', 'approved')
|
||||
@@ -1132,9 +1195,19 @@ class ContentFilter
|
||||
},
|
||||
$content
|
||||
);
|
||||
|
||||
// Step 3: 恢复代码块
|
||||
foreach ($codeBlocks as $placeholder => $code) {
|
||||
$content = str_replace($placeholder, $code, $content);
|
||||
}
|
||||
|
||||
// Step 4: 进行 Markdown 解析
|
||||
$content = empty($lastResult) ? $widget->markdown($content) : $lastResult;
|
||||
|
||||
return $content;
|
||||
}
|
||||
// 解析短代码属性
|
||||
|
||||
// 解析短代码属性(保持不变)
|
||||
private static function parse_atts($text) {
|
||||
$atts = array();
|
||||
$pattern = '/(\w+)\s*=\s*"([^"]*)"(?:\s|$)|(\w+)\s*=\s*\'([^\']*)\'(?:\s|$)|(\w+)\s*=\s*([^\s\'"]+)(?:\s|$)|"([^"]*)"(?:\s|$)|(\S+)(?:\s|$)/';
|
||||
@@ -1156,7 +1229,8 @@ class ContentFilter
|
||||
return $atts;
|
||||
}
|
||||
}
|
||||
// 注册钩子,自动处理所有内容输出
|
||||
|
||||
// 注册钩子
|
||||
Typecho_Plugin::factory('Widget_Abstract_Contents')->content = array('ContentFilter', 'filterContent');
|
||||
Typecho_Plugin::factory('Widget_Abstract_Contents')->contentEx = array('ContentFilter', 'filterContent');
|
||||
|
||||
@@ -1373,26 +1447,25 @@ function get_site_statistics() {
|
||||
];
|
||||
}
|
||||
|
||||
// Typecho AJAX 登录接口,支持前端 AJAX 提交并返回 JSON
|
||||
//if (!empty($_GET['ajaxLogin']) && $_GET['ajaxLogin'] == 1) {
|
||||
// header('Content-Type: application/json; charset=utf-8');
|
||||
// if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
// echo json_encode(['success' => false, 'msg' => '请求方式错误']);
|
||||
// exit;
|
||||
// }
|
||||
// $name = isset($_POST['name']) ? trim($_POST['name']) : '';
|
||||
// $password = isset($_POST['password']) ? $_POST['password'] : '';
|
||||
// $referer = isset($_POST['referer']) ? $_POST['referer'] : '/';
|
||||
// if (!$name || !$password) {
|
||||
// echo json_encode(['success' => false, 'msg' => '用户名或密码不能为空']);
|
||||
// exit;
|
||||
// }
|
||||
// $user = Typecho_Widget::widget('Widget_User');
|
||||
// try {
|
||||
// $user->login($name, $password, isset($_POST['remember']) ? 1 : 0);
|
||||
// echo json_encode(['success' => true, 'msg' => '登录成功', 'redirect' => $referer]);
|
||||
// } catch (Typecho_Exception $e) {
|
||||
// echo json_encode(['success' => false, 'msg' => $e->getMessage()]);
|
||||
// }
|
||||
// exit;
|
||||
//}
|
||||
/**
|
||||
* 友好时间显示函数
|
||||
* @param $timestamp
|
||||
* @return string
|
||||
*/
|
||||
function friendly_date($timestamp) {
|
||||
$time = is_numeric($timestamp) ? $timestamp : strtotime($timestamp);
|
||||
$diff = time() - $time;
|
||||
if ($diff < 60) {
|
||||
return '刚刚';
|
||||
} elseif ($diff < 3600) {
|
||||
return floor($diff / 60) . '分钟前';
|
||||
} elseif ($diff < 86400) {
|
||||
return floor($diff / 3600) . '小时前';
|
||||
} elseif ($diff < 2592000) {
|
||||
return floor($diff / 86400) . '天前';
|
||||
} elseif ($diff < 31536000) {
|
||||
return floor($diff / 2592000) . '月前';
|
||||
} else {
|
||||
return date('Y-m-d H:i:s', $time);
|
||||
}
|
||||
}
|
||||
+28
-6
@@ -177,12 +177,34 @@
|
||||
<div data-swiper="init" data-swiper-class="global-top-notice-swiper" data-swiper-args='{"direction":"vertical","autoplay":{"delay":3000,"disableOnInteraction":false},"loop":true}'>
|
||||
<div class="swiper global-top-notice-swiper">
|
||||
<div class="swiper-wrapper">
|
||||
<div class="swiper-slide t-line-1">
|
||||
<a class="ta3" data-no-instant href="javascript:void(0)">
|
||||
<span class="notice-icon"><i class="fa-regular fa-bell"></i></span>
|
||||
<span><?php $this->options->gonggao(); ?></span>
|
||||
</a>
|
||||
</div>
|
||||
<?php
|
||||
// 获取公告内容
|
||||
$gonggao = $this->options->gonggao;
|
||||
if ($gonggao) {
|
||||
// 按行分割
|
||||
$lines = explode("\n", $gonggao);
|
||||
foreach ($lines as $line) {
|
||||
$parts = explode('|', $line);
|
||||
// 只处理格式正确的行
|
||||
if (count($parts) >= 3) {
|
||||
$title = trim($parts[0]);
|
||||
$url = trim($parts[1]);
|
||||
$icon = trim($parts[2]);
|
||||
// 链接为空时使用 javascript:void(0)
|
||||
$href = $url !== '' ? htmlspecialchars($url) : 'javascript:void(0)';
|
||||
// 图标为空时使用默认
|
||||
$icon_class = $icon !== '' ? $icon : 'fa-regular fa-bell';
|
||||
// 输出 HTML
|
||||
echo '<div class="swiper-slide t-line-1">';
|
||||
echo '<a class="ta3" data-no-instant href="' . $href . '">';
|
||||
echo '<span class="notice-icon"><i class="' . $icon_class . '"></i></span>';
|
||||
echo '<span>' . htmlspecialchars($title) . '</span>';
|
||||
echo '</a>';
|
||||
echo '</div>';
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<?php
|
||||
/**
|
||||
* Pouck theme for Typecho
|
||||
*
|
||||
* 老孙移植
|
||||
*
|
||||
* @package Typecho Pouck Theme
|
||||
* @author 老孙博客
|
||||
* @version 1.2.0
|
||||
* @version 1.2.3
|
||||
* @link http://www.imsun.org
|
||||
*/
|
||||
|
||||
@@ -13,8 +14,13 @@ $this->need('header.php');
|
||||
$this->need('sticky.php');
|
||||
?>
|
||||
<div class="row row-cols-1">
|
||||
<?php if ($this->options->showsidebar): ?>
|
||||
<div class="col-lg-8 col-md-12 animated fadeInLeft ">
|
||||
<div class="animated fadeInLeft ">
|
||||
<?php else: ?>
|
||||
<div class="col-lg-12 col-md-12">
|
||||
<div class="row box-plr15">
|
||||
<?php endif; ?>
|
||||
<div> <!--文章列表-->
|
||||
<div id="posts">
|
||||
<?php if ($this->options->listmodel): ?>
|
||||
@@ -96,5 +102,7 @@ if ($pageprev == '1' && $this->have()):
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php if ($this->options->showsidebar): ?>
|
||||
<?php $this->need('sidebar.php'); ?>
|
||||
<?php endif; ?>
|
||||
<?php $this->need('footer.php'); ?>
|
||||
+1
-1
@@ -16,7 +16,7 @@ if (!defined('__TYPECHO_ROOT_DIR__')) exit; ?>
|
||||
</div>
|
||||
<div id="page">
|
||||
<div class="row row-cols-1">
|
||||
<div id="posts" class="col-12 animated fadeInLeft ">
|
||||
<div id="posts" class="col-12">
|
||||
<div class="puock-text no-style">
|
||||
<p><?php $this->content(); ?></p>
|
||||
</div>
|
||||
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
/**
|
||||
* 随机阅读
|
||||
*
|
||||
* @package custom
|
||||
*/
|
||||
if (!defined('__TYPECHO_ROOT_DIR__')) exit;
|
||||
|
||||
// 防止 PJAX 缓存,确保每次都是随机文章
|
||||
header('Cache-Control: no-cache, no-store, must-revalidate');
|
||||
header('Pragma: no-cache');
|
||||
header('Expires: 0');
|
||||
header('X-InstantClick: no-cache');
|
||||
|
||||
// 获取随机文章
|
||||
function getRandomPost() {
|
||||
$db = Typecho_Db::get();
|
||||
|
||||
// 统计符合条件的文章总数
|
||||
$countSql = $db->select('COUNT(*) AS count')
|
||||
->from('table.contents')
|
||||
->where('status = ?', 'publish')
|
||||
->where('type = ?', 'post')
|
||||
->where('created <= ?', time());
|
||||
$countResult = $db->fetchRow($countSql);
|
||||
$total = $countResult['count'];
|
||||
|
||||
if ($total > 0) {
|
||||
// 随机选择一个偏移量
|
||||
$offset = mt_rand(0, $total - 1);
|
||||
|
||||
// 根据偏移量获取一篇文章
|
||||
$sql = $db->select()
|
||||
->from('table.contents')
|
||||
->where('status = ?', 'publish')
|
||||
->where('type = ?', 'post')
|
||||
->where('created <= ?', time())
|
||||
->limit(1)
|
||||
->offset($offset);
|
||||
|
||||
$result = $db->fetchRow($sql);
|
||||
|
||||
if (!empty($result)) {
|
||||
$target = Typecho_Widget::widget('Widget_Abstract_Contents')->filter($result);
|
||||
return $target['permalink'];
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 获取随机文章链接
|
||||
$randomPostUrl = getRandomPost();
|
||||
|
||||
$this->need('header.php');
|
||||
?>
|
||||
<div id="breadcrumb" class="animated fadeInUp">
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a class="a-link" href="<?php $this->options->siteUrl(); ?>">首页</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">随机阅读</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
<div id="page-empty">
|
||||
<div id="page" class="row row-cols-1">
|
||||
<?php if ($this->options->showsidebar): ?>
|
||||
<div id="post-main" class="col-lg-8 col-md-12 animated fadeInLeft">
|
||||
<?php else: ?>
|
||||
<div id="post-main" class="col-lg-12 col-md-12">
|
||||
<?php endif; ?>
|
||||
<div class="p-block">
|
||||
<div>
|
||||
<h1 id="post-title" class="mb-0 puock-text t-xxl">随机阅读</h1>
|
||||
</div>
|
||||
<div class="mt20 puock-text entry-content show-link-icon">
|
||||
<div class="text-center">
|
||||
<div class="mb-4">
|
||||
<i class="fa fa-random fa-3x text-primary mb-3"></i>
|
||||
<h3>正在为您随机选择一篇文章...</h3>
|
||||
<p class="text-muted">请稍候,正在跳转中...</p>
|
||||
</div>
|
||||
<div class="spinner-border text-primary" role="status">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php if ($this->options->showsidebar): ?>
|
||||
<?php $this->need('sidebar.php'); ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 立即执行的跳转函数
|
||||
function performRandomRedirect() {
|
||||
setTimeout(function() {
|
||||
<?php if ($randomPostUrl): ?>
|
||||
// 跳转到随机文章
|
||||
window.location.href = '<?php echo $randomPostUrl; ?>';
|
||||
<?php else: ?>
|
||||
// 如果没有文章,跳转到首页
|
||||
window.location.href = '<?php $this->options->siteUrl(); ?>';
|
||||
<?php endif; ?>
|
||||
}, 1500);
|
||||
}
|
||||
|
||||
// 在 DOMContentLoaded 和页面加载完成后都执行
|
||||
document.addEventListener('DOMContentLoaded', performRandomRedirect);
|
||||
window.addEventListener('load', performRandomRedirect);
|
||||
|
||||
// 立即执行一次,确保在 PJAX 模式下也能工作
|
||||
performRandomRedirect();
|
||||
</script>
|
||||
|
||||
<?php $this->need('footer.php'); ?>
|
||||
+8
-2
@@ -17,7 +17,11 @@ if (!defined('__TYPECHO_ROOT_DIR__')) exit; ?>
|
||||
<?php $commenters = getAllCommenters(); ?>
|
||||
<div id="page-reads">
|
||||
<div id="page" class="row row-cols-1">
|
||||
<?php if ($this->options->showsidebar): ?>
|
||||
<div id="posts" class="col-lg-8 col-md-12 animated fadeInLeft ">
|
||||
<?php else: ?>
|
||||
<div id="posts" class="col-lg-12 col-md-12">
|
||||
<?php endif; ?>
|
||||
<div class="p-block puock-text">
|
||||
<h2 class="t-lg"><?php $this->title() ?></h2>
|
||||
<div class="mt20 row pd-links">
|
||||
@@ -44,5 +48,7 @@ if (!defined('__TYPECHO_ROOT_DIR__')) exit; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php $this->need('sidebar.php'); ?>
|
||||
<?php $this->need('footer.php'); ?>
|
||||
<?php if ($this->options->showsidebar): ?>
|
||||
<?php $this->need('sidebar.php'); ?>
|
||||
<?php endif; ?>
|
||||
<?php $this->need('footer.php'); ?>
|
||||
+182
@@ -0,0 +1,182 @@
|
||||
<?php
|
||||
/**
|
||||
* 说说页面
|
||||
* @package custom
|
||||
* @author 老孙
|
||||
* @version 1.0
|
||||
*/
|
||||
if (!defined('__TYPECHO_ROOT_DIR__')) exit;
|
||||
$this->need('header.php');
|
||||
?>
|
||||
<div id="breadcrumb" class="animated fadeInUp">
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a class="a-link" href="<?php $this->options->siteUrl(); ?>">首页</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page"><?php $this->title() ?></li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
<div id="page-moments">
|
||||
<div class="row">
|
||||
<?php if ($this->options->showsidebar): ?>
|
||||
<div id="comments" class="col-lg-8 col-md-12 animated fadeInLeft">
|
||||
<?php else: ?>
|
||||
<div id="comments" class="col-lg-12 col-md-12">
|
||||
<?php endif; ?>
|
||||
<?php
|
||||
// 登录状态检测
|
||||
if ($this->user->hasLogin()) {
|
||||
$GLOBALS['isLogin'] = true;
|
||||
} else {
|
||||
$GLOBALS['isLogin'] = false;
|
||||
}
|
||||
|
||||
// 评论回调函数
|
||||
function threadedComments($comments, $options) {
|
||||
$mail = $comments->mail;
|
||||
$mailHash = md5(strtolower(trim($mail)));
|
||||
$purl = $comments->url;
|
||||
$nickname = $comments->author;
|
||||
$cnavatar = Helper::options()->cnavatar ? Helper::options()->cnavatar : 'https://cravatar.cn/avatar/';
|
||||
$avatarurl = rtrim($cnavatar, '/') . '/' . $mailHash . '?s=80&d=identicon';
|
||||
$loadingImg = Helper::options()->themeUrl . '/assets/img/load.svg';
|
||||
?>
|
||||
<div class="mb20 puock-text moments-item">
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-1">
|
||||
<a class="meta ta3" href="<?php echo $purl; ?>" target="_blank">
|
||||
<div class="avatar mb10">
|
||||
<img src='<?php echo $loadingImg; ?>'
|
||||
class='lazy md-avatar mt-1'
|
||||
data-src='<?php echo $avatarurl; ?>'
|
||||
>
|
||||
</div>
|
||||
<div class="t-line-1 info fs12"><?php echo $nickname; ?></div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-12 col-md-11">
|
||||
<div class="p-block moment-content-box"> <span class="al"></span>
|
||||
<div class="mt10 moment-content entry-content show-link-icon">
|
||||
<?php if ($comments->parent) {echo getPermalinkFromCoid($comments->parent);} echo parse_smiley_shortcode($comments->content);?>
|
||||
</div>
|
||||
<div class="mt10 moment-footer p-flex-s-right">
|
||||
<span class="t-sm c-sub">
|
||||
<span class="mr-2"><i class="fa-regular fa-clock mr-1"></i><?php echo friendly_date($comments->created); ?></span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
<?php $this->comments()->to($comments); ?>
|
||||
<?php if ($this->user->hasLogin() && $this->user->group == 'administrator') : ?>
|
||||
<div class="p-block">
|
||||
<input type="hidden" value="<?php $this->commentUrl() ?>">
|
||||
<div>
|
||||
<span class="t-lg border-bottom border-primary puock-text pb-2">
|
||||
<i class="fa-regular fa-comments mr-1"></i>有什么新鲜事
|
||||
</span>
|
||||
</div>
|
||||
<div class="mt20 clearfix" id="comment-form-box">
|
||||
<form method="post" action="<?php $this->commentUrl() ?>" id="comment-form" class="mt10" role="form">
|
||||
<div class="form-group">
|
||||
<textarea rows="4" name="text" id="comment" class="form-control form-control-sm t-sm" placeholder="发表您的新鲜事儿..." required><?php $this->remember('text'); ?></textarea>
|
||||
</div>
|
||||
<input type="hidden" value="<?php $this->user->screenName(); ?>" name="author" />
|
||||
<input type="hidden" value="<?php $this->user->mail(); ?>" name="mail" />
|
||||
<input type="hidden" value="<?php $this->options->siteUrl(); ?>" name="url" />
|
||||
<input type="hidden" name="_" value="<?php Typecho_Widget::widget('Widget_Security')->to($security);
|
||||
echo $security->getToken($this->request->getRequestUrl()); ?>">
|
||||
<div class="p-flex-sbc mt10">
|
||||
<div class="form-foot">
|
||||
<?php if($this->options->social): ?>
|
||||
<button id="comment-insert-image" class="btn btn-outline-secondary btn-ssm pk-modal-toggle" type="button" title="插入图片">
|
||||
<i class="fa-solid fa-image"></i>
|
||||
</button>
|
||||
<button id="comment-smiley" class="btn btn-outline-secondary btn-ssm pk-modal-toggle" type="button" title="表情" data-once-load="true"
|
||||
data-url="<?php echo get_correct_url('/emoji/'); ?>">
|
||||
<i class="fa-regular fa-face-smile t-md"></i>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
<button type="submit" class="btn btn-primary btn-ssm"><i class="fa-regular fa-paper-plane"></i> 立即发表</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if ($comments->have()): ?>
|
||||
<!-- 评论列表 -->
|
||||
<?php while ($comments->next()): ?>
|
||||
<?php threadedComments($comments, $this->options); ?>
|
||||
<?php endwhile; ?>
|
||||
<!-- 分页导航 -->
|
||||
<div class="mt20 p-flex-s-right" data-no-instant>
|
||||
<?php $comments->pageNav('«', '»', 1, '...', array(
|
||||
'wrapTag' => 'ul',
|
||||
'wrapClass' => 'pagination comment-ajax-load',
|
||||
'itemTag' => 'li',
|
||||
'textTag' => 'span',
|
||||
'currentClass' => 'active',
|
||||
'prevClass' => 'prev',
|
||||
'nextClass' => 'next'
|
||||
)); ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if ($this->options->showsidebar): ?>
|
||||
<?php $this->need('sidebar.php'); ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php $this->need('footer.php'); ?>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
var btn = document.getElementById('comment-insert-image');
|
||||
if (!btn) return;
|
||||
btn.addEventListener('click', function() {
|
||||
let modal = document.createElement('div');
|
||||
modal.innerHTML = `
|
||||
<div id="img-insert-modal" style="position:fixed;z-index:9999;left:0;top:0;width:100vw;height:100vh;background:rgba(0,0,0,0.3);display:flex;align-items:center;justify-content:center;">
|
||||
<div style="background:#fff;padding:24px 32px;border-radius:8px;min-width:320px;box-shadow:0 2px 16px rgba(0,0,0,0.15);">
|
||||
<div style="font-size:18px;font-weight:bold;margin-bottom:12px;">插入图片</div>
|
||||
<div style="margin-bottom:10px;">
|
||||
<label style="display:block;font-size:14px;margin-bottom:4px;">标题(可选)</label>
|
||||
<input id="img-insert-title" type="text" style="width:100%;padding:6px 8px;border:1px solid #ccc;border-radius:4px;">
|
||||
</div>
|
||||
<div style="margin-bottom:10px;">
|
||||
<label style="display:block;font-size:14px;margin-bottom:4px;">图片地址 <span style="color:red">*</span></label>
|
||||
<input id="img-insert-url" type="text" style="width:100%;padding:6px 8px;border:1px solid #ccc;border-radius:4px;" required>
|
||||
</div>
|
||||
<div style="text-align:right;">
|
||||
<button id="img-insert-cancel" style="margin-right:10px;padding:6px 16px;">取消</button>
|
||||
<button id="img-insert-confirm" style="background:#007bff;color:#fff;padding:6px 16px;border:none;border-radius:4px;">插入</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
document.body.appendChild(modal);
|
||||
document.getElementById('img-insert-cancel').onclick = function() {
|
||||
document.body.removeChild(modal);
|
||||
};
|
||||
document.getElementById('img-insert-confirm').onclick = function() {
|
||||
let url = document.getElementById('img-insert-url').value.trim();
|
||||
let title = document.getElementById('img-insert-title').value.trim();
|
||||
if (!url) {
|
||||
alert('图片地址不能为空!');
|
||||
return;
|
||||
}
|
||||
let tag = `<img src=\"${url}\"` + (title ? ` alt=\"${title}\" title=\"${title}\"` : '') + ` />`;
|
||||
let textarea = document.getElementById('comment');
|
||||
if (textarea) {
|
||||
let start = textarea.selectionStart, end = textarea.selectionEnd;
|
||||
let val = textarea.value;
|
||||
textarea.value = val.substring(0, start) + tag + val.substring(end);
|
||||
textarea.focus();
|
||||
textarea.selectionStart = textarea.selectionEnd = start + tag.length;
|
||||
}
|
||||
document.body.removeChild(modal);
|
||||
};
|
||||
});
|
||||
});
|
||||
</script>
|
||||
+9
-14
@@ -16,20 +16,21 @@ if (!defined('__TYPECHO_ROOT_DIR__')) exit; ?>
|
||||
</div>
|
||||
<div id="page-tags">
|
||||
<div id="page" class="row row-cols-1">
|
||||
<?php if ($this->options->showsidebar): ?>
|
||||
<div id="posts" class="col-lg-8 col-md-12 animated fadeInLeft">
|
||||
<?php else: ?>
|
||||
<div id="posts" class="col-lg-12 col-md-12">
|
||||
<?php endif; ?>
|
||||
<div class="puock-text p-block no-style pb-2">
|
||||
<?php
|
||||
// 获取所有标签
|
||||
$tags = Typecho_Widget::widget('Widget_Metas_Tag_Cloud');
|
||||
|
||||
// 准备字母数组
|
||||
$letters = range('A', 'Z');
|
||||
$letters[] = '0';
|
||||
|
||||
$letters[] = '0';
|
||||
// 获取所有存在的首字母
|
||||
$existingLetters = array();
|
||||
$tagsArray = array();
|
||||
|
||||
$tagsArray = array();
|
||||
while ($tags->next()) {
|
||||
$firstChar = getFirstChar($tags->name);
|
||||
if (!in_array($firstChar, $existingLetters)) {
|
||||
@@ -41,7 +42,6 @@ if (!defined('__TYPECHO_ROOT_DIR__')) exit; ?>
|
||||
'count' => $tags->count
|
||||
);
|
||||
}
|
||||
|
||||
// 对每个字母下的标签按名称排序
|
||||
foreach ($tagsArray as &$letterTags) {
|
||||
usort($letterTags, function($a, $b) {
|
||||
@@ -49,7 +49,6 @@ if (!defined('__TYPECHO_ROOT_DIR__')) exit; ?>
|
||||
});
|
||||
}
|
||||
?>
|
||||
|
||||
<!-- 字母导航 -->
|
||||
<ul class='pl-0' id='tags-main-index'>
|
||||
<?php foreach ($letters as $letter): ?>
|
||||
@@ -63,13 +62,11 @@ if (!defined('__TYPECHO_ROOT_DIR__')) exit; ?>
|
||||
<li class='t'><?php echo $i; ?></li>
|
||||
<?php endfor; ?>
|
||||
</ul>
|
||||
|
||||
<!-- 标签列表 -->
|
||||
<ul id='tags-main-box' class='pl-0'>
|
||||
<?php
|
||||
// 按字母顺序排序
|
||||
ksort($tagsArray);
|
||||
|
||||
foreach ($tagsArray as $letter => $tags): ?>
|
||||
<li class='n' id='<?php echo $letter; ?>'>
|
||||
<h4 class='tag-name'><span class='t-lg c-sub'>#</span><?php echo $letter; ?></h4>
|
||||
@@ -81,9 +78,7 @@ if (!defined('__TYPECHO_ROOT_DIR__')) exit; ?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
|
||||
?>
|
||||
|
||||
<?php if ($this->options->showsidebar): ?>
|
||||
<?php $this->need('sidebar.php'); ?>
|
||||
<?php $this->need('footer.php'); ?>
|
||||
<?php endif; ?>
|
||||
<?php $this->need('footer.php'); ?>
|
||||
-168
@@ -1,168 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* 说说页面
|
||||
*
|
||||
* @package custom
|
||||
*/
|
||||
if (!defined('__TYPECHO_ROOT_DIR__')) exit; ?>
|
||||
<?php $this->need('header.php'); ?>
|
||||
<div id="breadcrumb" class="animated fadeInUp">
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a class="a-link" href="<?php $this->options->siteUrl(); ?>">首页</a></li>
|
||||
<li class="breadcrumb-item active " aria-current="page"><?php $this->title() ?></li>
|
||||
</ol>
|
||||
</nav>
|
||||
<div id="page-moments">
|
||||
<div class="row">
|
||||
<div id="posts" class="col-lg-8 col-md-12 animated fadeInLeft ">
|
||||
<?php $tooot = $this->fields->tooot ? $this->fields->tooot : 'https://www.imsun.org/toot.json'; ?>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/marked/15.0.12/marked.min.js" integrity="sha512-rCQgmUulW6f6QegOvTntKKb5IAoxTpGVCdWqYjkXEpzAns6XUFs8NKVqWe+KQpctp/EoRSFSuykVputqknLYMg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/lightbox2/2.11.5/css/lightbox.min.css" integrity="sha512-xtV3HfYNbQXS/1R1jP53KbFcU9WXiSA1RFKzl5hRlJgdOJm4OxHCWYpskm6lN0xp0XtKGpAfVShpbvlFH3MDAA==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/lightbox2/2.11.5/js/lightbox.min.js" integrity="sha512-KbRFbjA5bwNan6DvPl1ODUolvTTZ/vckssnFhka5cG80JVa5zSlRPCr055xSgU/q6oMIGhZWLhcbgIC0fyw3RQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
<div id="tooot"></div>
|
||||
</div>
|
||||
<script>
|
||||
function fetchAndDisplayToots() {
|
||||
let offset = 0;
|
||||
const limit = 20;
|
||||
function formatHTML(toots) {
|
||||
let htmlString = '';
|
||||
toots.forEach(toot => {
|
||||
const isReblog = toot.reblog && toot.reblog.content;
|
||||
const content = isReblog ? toot.reblog.content : toot.content;
|
||||
const url = isReblog ? toot.reblog.url : toot.url;
|
||||
const account = isReblog ? toot.reblog.account : toot.account;
|
||||
const created_at = isReblog ? toot.reblog.created_at : toot.created_at;
|
||||
const media_attachments = isReblog ? toot.reblog.media_attachments : toot.media_attachments;
|
||||
let mediaHTML = '';
|
||||
if (media_attachments && media_attachments.length > 0) {
|
||||
media_attachments.forEach(attachment => {
|
||||
if (attachment.type === 'image') {
|
||||
mediaHTML += `<a href="${attachment.url}" target="_blank" data-lightbox="image-set"><img src="${attachment.preview_url}" class="thumbnail-image img" ></a>`;
|
||||
}
|
||||
});
|
||||
}
|
||||
const htmlContent = marked.parse(content || '');
|
||||
htmlString += `
|
||||
<div class="mb20 puock-text moments-item">
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-1">
|
||||
<a class="meta ta3" href="${account.url}" target="_blank" rel="nofollow">
|
||||
<div class="avatar mb10">
|
||||
<img src='${account.avatar}'
|
||||
class='lazy md-avatar mt-1'
|
||||
data-src='${account.avatar}'
|
||||
alt="${account.display_name}" title="${account.display_name}">
|
||||
</div>
|
||||
<div class="t-line-1 info fs12">${account.display_name}</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-12 col-md-11">
|
||||
<div class="p-block moment-content-box"> <span class="al"></span>
|
||||
<div class="mt10 moment-content entry-content show-link-icon">
|
||||
<p>${htmlContent}</p>
|
||||
<div class="resimg">${mediaHTML}</div>
|
||||
</div>
|
||||
<div class="mt10 moment-footer p-flex-s-right"> <span class="t-sm c-sub">
|
||||
<a class="c-sub-a" href="${url}">
|
||||
<span class="mr-2"><i class="fa-regular fa-clock mr-1"></i>${new Date(created_at).toLocaleString()}</span>
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
return htmlString;
|
||||
}
|
||||
function fetchToots() {
|
||||
return fetch('<?php echo $tooot; ?>')
|
||||
.then(response => response.json())
|
||||
.catch(error => {
|
||||
console.error('Error fetching toots:', error);
|
||||
return [];
|
||||
});
|
||||
}
|
||||
const memosContainer = document.getElementById('tooot');
|
||||
if (memosContainer) memosContainer.innerHTML = '';
|
||||
fetchToots().then(data => {
|
||||
if (!Array.isArray(data)) {
|
||||
console.error('toot.json is not an array:', data);
|
||||
return;
|
||||
}
|
||||
const tootsToShow = data.slice(offset, offset + limit);
|
||||
if (memosContainer) memosContainer.innerHTML += formatHTML(tootsToShow);
|
||||
});
|
||||
}
|
||||
|
||||
// 保证首次和 pjax 都能调用
|
||||
if (document.readyState === "loading") {
|
||||
document.addEventListener("DOMContentLoaded", fetchAndDisplayToots);
|
||||
} else {
|
||||
fetchAndDisplayToots();
|
||||
}
|
||||
document.addEventListener('pjax:end', fetchAndDisplayToots);
|
||||
</script>
|
||||
<style>
|
||||
div pre code {
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
overflow-wrap: break-word;
|
||||
word-break: break-all;
|
||||
word-break: break-word;
|
||||
}
|
||||
div p a {
|
||||
word-break: break-all;
|
||||
word-break: break-word;
|
||||
}
|
||||
.resimg {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
column-gap: 10px;
|
||||
row-gap: 10px;
|
||||
}
|
||||
/* 单个缩略图的样式 */
|
||||
.thumbnail-image {
|
||||
width: 100%; /* 确保其宽度填满父容器 */
|
||||
height: 200px; /* 固定高度 */
|
||||
display: flex; /* 使用 flexbox 居中 */
|
||||
align-items: center; /* 垂直居中 */
|
||||
justify-content: center; /* 水平居中 */
|
||||
overflow: hidden; /* 确保容器内的多余内容不会显示出来 */
|
||||
border-radius: 4px; /* 圆角 */
|
||||
transition: transform .3s ease; /* 鼠标悬停时的过渡效果 */
|
||||
cursor: zoom-in; /* 鼠标指针变为放大镜 */
|
||||
}
|
||||
img {
|
||||
object-fit: cover; /* 保持图片的纵横比,但会将图片裁剪以填充容器 */
|
||||
object-position: center; /* 保证中央部分 */
|
||||
}
|
||||
/* 缩略图内的图片样式 */
|
||||
.thumbnail-image img {
|
||||
width: 100%;
|
||||
min-height: 200px;
|
||||
}
|
||||
/* 当屏幕宽度小于732px时 */
|
||||
@media (max-width: 732px) {
|
||||
.resimg {
|
||||
grid-template-columns: repeat(2, 1fr); /* 修改为两列 */
|
||||
}
|
||||
}
|
||||
/* 当屏幕宽度小于400px时 */
|
||||
@media (max-width: 400px) {
|
||||
.resimg {
|
||||
grid-template-columns: 1fr; /* 修改为一列 */
|
||||
}
|
||||
.thumbnail-image img {
|
||||
width: 100%;
|
||||
height: 480px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<?php $this->need('sidebar.php'); ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php $this->need('footer.php'); ?>
|
||||
@@ -10,7 +10,11 @@
|
||||
</div>
|
||||
<div id="page-empty">
|
||||
<div id="page" class="row row-cols-1">
|
||||
<?php if ($this->options->showsidebar): ?>
|
||||
<div id="post-main" class="col-lg-8 col-md-12 animated fadeInLeft ">
|
||||
<?php else: ?>
|
||||
<div id="post-main" class="col-lg-12 col-md-12">
|
||||
<?php endif; ?>
|
||||
<div class="p-block"><div>
|
||||
<h1 id="post-title" class="mb-0 puock-text t-xxl"><?php $this->title() ?></h1>
|
||||
</div>
|
||||
@@ -60,5 +64,7 @@ if($days > 180){
|
||||
<?php $this->need('comments.php'); ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php if ($this->options->showsidebar): ?>
|
||||
<?php $this->need('sidebar.php'); ?>
|
||||
<?php endif; ?>
|
||||
<?php $this->need('footer.php'); ?>
|
||||
@@ -15,7 +15,11 @@
|
||||
<div class="puock-text p-block t-md ad-page-top"><?php $this->options->articletop(); ?></div>
|
||||
<?php endif; ?>
|
||||
<div class="row row-cols-1 post-row">
|
||||
<?php if ($this->options->showsidebar): ?>
|
||||
<div id="post-main" class="col-lg-8 col-md-12 animated fadeInLeft ">
|
||||
<?php else: ?>
|
||||
<div id="post-main" class="col-lg-12 col-md-12">
|
||||
<?php endif; ?>
|
||||
<div class="p-block"><div>
|
||||
<h1 id="post-title" class="mb-0 puock-text t-xxl"><?php $this->title() ?></h1>
|
||||
</div>
|
||||
@@ -216,5 +220,7 @@ if($days > 180){
|
||||
<div class="puock-text p-block t-md ad-comment-top"><?php $this->options->articlefoot(); ?></div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php if ($this->options->showsidebar): ?>
|
||||
<?php $this->need('sidebar.php'); ?>
|
||||
<?php endif; ?>
|
||||
<?php $this->need('footer.php'); ?>
|
||||
+1
-1
@@ -109,7 +109,7 @@
|
||||
<div class="pk-widget p-block">
|
||||
<div>
|
||||
<span class="t-lg border-bottom border-primary puock-text pb-2">
|
||||
<i class="fa fa-chart-simple mr-1"></i>热门文章
|
||||
<i class="fa-solid fa-fire"></i> 热门文章
|
||||
</span>
|
||||
</div>
|
||||
<div class="mt20">
|
||||
|
||||
Reference in New Issue
Block a user