mirror of
https://github.com/jkjoy/typecho-theme-farallon.git
synced 2026-06-27 23:44:28 +00:00
Compare commits
8 Commits
a6883c5ce7
...
0.7.3
| Author | SHA1 | Date | |
|---|---|---|---|
| 0ed7e7b5e8 | |||
| 6f37575943 | |||
| 6b8f758dcf | |||
| 1f535bb9d6 | |||
| a42f5f41ca | |||
| 16e91b835e | |||
| 9671712412 | |||
| 4df85ae062 |
@@ -1,3 +1,4 @@
|
||||
|
||||
tooot.php
|
||||
Parsedown.php
|
||||
/assets/images/covers
|
||||
|
||||
@@ -7,6 +7,11 @@
|
||||
|
||||
## 更新日志 & 预览
|
||||
|
||||
### 0.7.2
|
||||
|
||||
- 优化页面加载速度,自动裁切封面,并压缩为`webp`格式,并保存在主题目录`assets`-`images`-`covers`下,使用前必须开启`php`的`GD拓展`和主题目录的写入权限
|
||||
- 修复了置顶文章和翻页的问题
|
||||
|
||||
### 0.7.1
|
||||
|
||||
- 调整了赞赏的样式,同时填写支付宝和微信收款码的图片地址即可显示
|
||||
@@ -38,7 +43,7 @@
|
||||
|
||||
|
||||
|
||||
[预览](https://www.imsun.org/)
|
||||
[预览](https://blog.imsun.org/)
|
||||
|
||||
https://www.imsun.org/archives/1640.html
|
||||
|
||||
|
||||
+2
-2
@@ -17,7 +17,7 @@
|
||||
is_single = false;
|
||||
post_id = 0;
|
||||
is_archive = false;
|
||||
VERSION = "0.7.1";
|
||||
VERSION = "0.7.2";
|
||||
constructor() {
|
||||
super();
|
||||
this.initCopyright();
|
||||
@@ -46,7 +46,7 @@
|
||||
}
|
||||
initCopyright() {
|
||||
const copyright = `<div class="site--footer__info">由<a href="https://www.typecho.org" target="_blank">Typecho</a> 驱动 <br>
|
||||
Theme <a href="https://fatesinger.com/101971" target="_blank">farallon</a> by bigfa <br>Made with<a href="https://www.imsun.org" target="_blank">jkjoy</a> / version ${this.VERSION}
|
||||
Theme <a href="https://fatesinger.com/101971" target="_blank">farallon</a> by bigfa <br>Made with <a href="https://www.imsun.org" target="_blank">老孙博客</a> / version ${this.VERSION}
|
||||
</div>`;
|
||||
document.querySelector(".site--footer__content").insertAdjacentHTML("afterend", copyright);
|
||||
document.querySelector(".icon--copryrights").addEventListener("click", () => {
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
});
|
||||
}
|
||||
// 给所有复制链接添加点击事件
|
||||
document.querySelectorAll('.text').forEach(link => {
|
||||
document.querySelectorAll('.copy').forEach(link => {
|
||||
link.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
const textToCopy = this.getAttribute('data-copy') || this.textContent;
|
||||
|
||||
+325
-50
@@ -22,25 +22,30 @@ function themeConfig($form) {
|
||||
$form->addInput($twitterurl);
|
||||
$mastodonurl = new Typecho_Widget_Helper_Form_Element_Text('mastodonurl', NULL, NULL, _t('mastodon'), _t('会在个人信息显示'));
|
||||
$form->addInput($mastodonurl);
|
||||
$friendlyTime = new Typecho_Widget_Helper_Form_Element_Radio('friendlyTime',
|
||||
array('0' => _t('否'),
|
||||
'1' => _t('是')),
|
||||
'0', _t('是否显示友好时间'), _t('默认不显示友好时间,显示标准时间格式'));
|
||||
$form->addInput($friendlyTime);
|
||||
$showProfile = new Typecho_Widget_Helper_Form_Element_Radio('showProfile',
|
||||
array('0'=> _t('否'), '1'=> _t('是')),
|
||||
'0', _t('是否在文章页面显示作者信息'), _t('选择“是”将在文章页面包含显示作者信息。'));
|
||||
'0', _t('是否在文章页面显示作者信息'), _t('选择"是"将在文章页面包含显示作者信息。'));
|
||||
$form->addInput($showProfile);
|
||||
$showcate = new Typecho_Widget_Helper_Form_Element_Radio('showcate',
|
||||
array('0'=> _t('否'), '1'=> _t('是')),
|
||||
'0', _t('是否在文章页面显示文章分类'), _t('选择“是”将在文章页面显示文章的分类信息。'));
|
||||
'0', _t('是否在文章页面显示文章分类'), _t('选择"是"将在文章页面显示文章的分类信息。'));
|
||||
$form->addInput($showcate);
|
||||
$showrelated = new Typecho_Widget_Helper_Form_Element_Radio('showrelated',
|
||||
array('0'=> _t('否'), '1'=> _t('是')),
|
||||
'0', _t('是否显示相关文章'), _t('选择“是”将在文章页面显示相关文章。'));
|
||||
'0', _t('是否显示相关文章'), _t('选择"是"将在文章页面显示相关文章。'));
|
||||
$form->addInput($showrelated);
|
||||
$showshare = new Typecho_Widget_Helper_Form_Element_Radio('showshare',
|
||||
array('0'=> _t('否'), '1'=> _t('是')),
|
||||
'0', _t('是否显示复制链接'), _t('选择“是”将在文章页面显示复制链接。'));
|
||||
'0', _t('是否显示复制链接'), _t('选择"是"将在文章页面显示复制链接。'));
|
||||
$form->addInput($showshare);
|
||||
$showtime = new Typecho_Widget_Helper_Form_Element_Radio('showtime',
|
||||
array('0'=> _t('否'), '1'=> _t('是')),
|
||||
'0', _t('是否显示页面加载时间'), _t('选择“是”将在页脚显示加载时间。'));
|
||||
'0', _t('是否显示页面加载时间'), _t('选择"是"将在页脚显示加载时间。'));
|
||||
$form->addInput($showtime);
|
||||
$loadmore = new Typecho_Widget_Helper_Form_Element_Radio('loadmore',
|
||||
array('0'=> _t('加载更多'), '1'=> _t('页码模式')),
|
||||
@@ -111,6 +116,17 @@ $options = Typecho_Widget::widget('Widget_Options');
|
||||
$gravatarPrefix = empty($options->cnavatar) ? 'https://cravatar.cn/avatar/' : $options->cnavatar;
|
||||
define('__TYPECHO_GRAVATAR_PREFIX__', $gravatarPrefix);
|
||||
|
||||
// 初始化主题
|
||||
function init_theme() {
|
||||
// 检查并创建封面图片目录
|
||||
$coversDir = dirname(__FILE__) . '/assets/images/covers';
|
||||
if (!is_dir($coversDir)) {
|
||||
@mkdir($coversDir, 0755, true);
|
||||
}
|
||||
}
|
||||
// 在主题加载时执行初始化
|
||||
init_theme();
|
||||
|
||||
/**
|
||||
* 页面加载时间
|
||||
*/
|
||||
@@ -138,6 +154,19 @@ function timer_start() {
|
||||
*/
|
||||
function img_postthumb($cid) {
|
||||
$db = Typecho_Db::get();
|
||||
|
||||
// 首先检查是否设置了自定义封面
|
||||
$cover = $db->fetchRow($db->select('str_value')
|
||||
->from('table.fields')
|
||||
->where('cid = ?', $cid)
|
||||
->where('name = ?', 'cover'));
|
||||
|
||||
// 如果找到自定义封面,直接返回
|
||||
if ($cover && !empty($cover['str_value'])) {
|
||||
return $cover['str_value'];
|
||||
}
|
||||
|
||||
// 否则尝试从文章内容中获取第一张图片
|
||||
$rs = $db->fetchRow($db->select('table.contents.text')
|
||||
->from('table.contents')
|
||||
->where('table.contents.cid=?', $cid)
|
||||
@@ -168,20 +197,16 @@ function getPermalinkFromCoid($coid) {
|
||||
* 图片灯箱
|
||||
*/
|
||||
class ImageStructureProcessor {
|
||||
public static function processContent($content, $widget) {
|
||||
// 首先检查内容是否为空
|
||||
public static function processContent($content, $widget, $lastResult = null) {
|
||||
$content = empty($lastResult) ? $content : $lastResult;
|
||||
if (empty($content) || !is_string($content)) {
|
||||
return $content;
|
||||
}
|
||||
if ($widget instanceof Widget_Archive) {
|
||||
try {
|
||||
// 使用 DOM 操作确保结构完整性
|
||||
$dom = new DOMDocument('1.0', 'UTF-8');
|
||||
// 添加错误处理
|
||||
libxml_use_internal_errors(true);
|
||||
// 添加基础 HTML 结构以确保正确解析
|
||||
$content = '<!DOCTYPE html><html><head><meta charset="UTF-8"></head><body><div>' . $content . '</div></body></html>';
|
||||
// 直接加载内容到 DOM
|
||||
$dom->loadHTML($content,
|
||||
LIBXML_HTML_NOIMPLIED |
|
||||
LIBXML_HTML_NODEFDTD |
|
||||
@@ -236,15 +261,126 @@ class ImageStructureProcessor {
|
||||
} catch (Exception $e) {
|
||||
// 记录错误但返回原始内容
|
||||
error_log('Image processing error: ' . $e->getMessage());
|
||||
return $content;
|
||||
// 如果发生错误,返回上一个过滤器结果或原始内容
|
||||
return empty($lastResult) ? $content : $lastResult;
|
||||
}
|
||||
}
|
||||
return $content;
|
||||
}
|
||||
}
|
||||
Typecho_Plugin::factory('Widget_Abstract_Contents')->contentEx = function($content, $widget) {
|
||||
return ImageStructureProcessor::processContent($content, $widget);
|
||||
};
|
||||
|
||||
/**
|
||||
* 处理图片为封面图(裁剪为5:3,最大宽度500px,转换为webp)
|
||||
*
|
||||
* @param string $imageUrl 原始图片URL
|
||||
* @return string 处理后的图片URL
|
||||
*/
|
||||
function process_cover_image($imageUrl) {
|
||||
// 检查GD库是否可用
|
||||
if (!function_exists('imagecreatetruecolor')) {
|
||||
return $imageUrl; // 如果GD库不可用,返回原图
|
||||
}
|
||||
|
||||
// 分析URL
|
||||
$parsed = parse_url($imageUrl);
|
||||
|
||||
// 如果图片是外部链接,需要下载
|
||||
$isExternalUrl = !empty($parsed['host']) && $parsed['host'] !== $_SERVER['HTTP_HOST'];
|
||||
|
||||
// 生成唯一的文件名(使用MD5哈希)
|
||||
$filename = md5($imageUrl) . '.webp';
|
||||
|
||||
// 处理后图片的保存路径
|
||||
$themeDir = dirname(__FILE__);
|
||||
$savePath = $themeDir . '/assets/images/covers/' . $filename;
|
||||
$webPath = Helper::options()->themeUrl . '/assets/images/covers/' . $filename;
|
||||
|
||||
// 如果缓存文件已存在,直接返回
|
||||
if (file_exists($savePath)) {
|
||||
return $webPath;
|
||||
}
|
||||
|
||||
// 获取原始图片内容
|
||||
if ($isExternalUrl) {
|
||||
// 外部图片,需要下载
|
||||
$imageContent = @file_get_contents($imageUrl);
|
||||
if (!$imageContent) {
|
||||
return $imageUrl; // 无法下载,返回原图
|
||||
}
|
||||
} else {
|
||||
// 本地图片
|
||||
$localPath = $_SERVER['DOCUMENT_ROOT'] . $parsed['path'];
|
||||
if (!file_exists($localPath)) {
|
||||
return $imageUrl; // 无法找到本地文件,返回原图
|
||||
}
|
||||
$imageContent = @file_get_contents($localPath);
|
||||
}
|
||||
|
||||
// 创建图像资源
|
||||
$originalImage = @imagecreatefromstring($imageContent);
|
||||
if (!$originalImage) {
|
||||
return $imageUrl; // 无法创建图像资源,返回原图
|
||||
}
|
||||
|
||||
// 获取原始图片尺寸
|
||||
$originalWidth = imagesx($originalImage);
|
||||
$originalHeight = imagesy($originalImage);
|
||||
|
||||
// 计算目标尺寸(5:3比例,最大宽度500px)
|
||||
$targetWidth = min(500, $originalWidth);
|
||||
$targetHeight = intval($targetWidth * 3 / 5);
|
||||
|
||||
// 计算裁剪坐标(居中裁剪)
|
||||
$cropX = 0;
|
||||
$cropY = 0;
|
||||
$cropWidth = $originalWidth;
|
||||
$cropHeight = $originalHeight;
|
||||
|
||||
// 计算比例
|
||||
$originalRatio = $originalWidth / $originalHeight;
|
||||
$targetRatio = 5 / 3;
|
||||
|
||||
if ($originalRatio > $targetRatio) {
|
||||
// 原图过宽,需要裁剪宽度
|
||||
$cropWidth = intval($originalHeight * $targetRatio);
|
||||
$cropX = intval(($originalWidth - $cropWidth) / 2);
|
||||
} else {
|
||||
// 原图过高,需要裁剪高度
|
||||
$cropHeight = intval($originalWidth / $targetRatio);
|
||||
$cropY = intval(($originalHeight - $cropHeight) / 2);
|
||||
}
|
||||
|
||||
// 创建目标图像
|
||||
$targetImage = imagecreatetruecolor($targetWidth, $targetHeight);
|
||||
|
||||
// 裁剪并调整大小
|
||||
imagecopyresampled(
|
||||
$targetImage,
|
||||
$originalImage,
|
||||
0, 0,
|
||||
$cropX, $cropY,
|
||||
$targetWidth, $targetHeight,
|
||||
$cropWidth, $cropHeight
|
||||
);
|
||||
|
||||
// 保存为webp格式
|
||||
if (!function_exists('imagewebp')) {
|
||||
// 如果不支持webp,保存为png
|
||||
$filename = md5($imageUrl) . '.png';
|
||||
$savePath = $themeDir . '/assets/images/covers/' . $filename;
|
||||
$webPath = Helper::options()->themeUrl . '/assets/images/covers/' . $filename;
|
||||
imagepng($targetImage, $savePath, 9); // 9是最高压缩质量
|
||||
} else {
|
||||
// 保存为webp
|
||||
imagewebp($targetImage, $savePath, 80); // 80是质量参数
|
||||
}
|
||||
|
||||
// 释放资源
|
||||
imagedestroy($originalImage);
|
||||
imagedestroy($targetImage);
|
||||
|
||||
return $webPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* *获取文章卡片
|
||||
@@ -297,6 +433,9 @@ function get_article_info($atts) {
|
||||
$imageToDisplay = img_postthumb($post['cid']);
|
||||
if (empty($imageToDisplay)) {
|
||||
$imageToDisplay = $default_thumbnail;
|
||||
} else {
|
||||
// 处理封面图片
|
||||
$imageToDisplay = process_cover_image($imageToDisplay);
|
||||
}
|
||||
// 构建输出
|
||||
$output = '<div class="graph--mixtapeEmbed">';
|
||||
@@ -315,11 +454,16 @@ class ContentFilter
|
||||
{
|
||||
// 首先运行之前的过滤器结果
|
||||
$content = empty($lastResult) ? $content : $lastResult;
|
||||
|
||||
// 处理图片灯箱
|
||||
$content = ImageStructureProcessor::processContent($content, $widget, $content);
|
||||
|
||||
// 然后处理我们的文章短代码
|
||||
$content = preg_replace_callback('/\[article\s+([^\]]+)\]/', function($matches) {
|
||||
$atts = self::parse_atts($matches[1]);
|
||||
return get_article_info($atts);
|
||||
}, $content);
|
||||
|
||||
return $content;
|
||||
}
|
||||
// 解析短代码属性
|
||||
@@ -377,8 +521,11 @@ EOF;
|
||||
}
|
||||
}
|
||||
// 注册编辑器按钮钩子
|
||||
Typecho_Plugin::factory('admin/write-post.php')->bottom = array('EditorButton', 'render');
|
||||
Typecho_Plugin::factory('admin/write-page.php')->bottom = array('EditorButton', 'render');
|
||||
// 避免重复注册,在最后执行
|
||||
if (!Typecho_Plugin::exists('Widget_Abstract_Contents', 'editor')) {
|
||||
Typecho_Plugin::factory('admin/write-post.php')->bottom = array('EditorButton', 'render');
|
||||
Typecho_Plugin::factory('admin/write-page.php')->bottom = array('EditorButton', 'render');
|
||||
}
|
||||
|
||||
/**
|
||||
* 评论者认证等级 + 身份
|
||||
@@ -452,57 +599,185 @@ function commentApprove($widget, $email = NULL)
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改附件插入功能
|
||||
* Typecho后台附件增强:图片预览、批量插入、保留官方删除按钮与逻辑
|
||||
* @author 老孙博客
|
||||
* @date 2025-04-25
|
||||
*/
|
||||
// 添加批量插入按钮的JavaScript
|
||||
Typecho_Plugin::factory('admin/write-post.php')->bottom = array('MyHelper', 'addBatchInsertButton');
|
||||
Typecho_Plugin::factory('admin/write-page.php')->bottom = array('MyHelper', 'addBatchInsertButton');
|
||||
Typecho_Plugin::factory('admin/write-post.php')->bottom = array('AttachmentHelper', 'addEnhancedFeatures');
|
||||
Typecho_Plugin::factory('admin/write-page.php')->bottom = array('AttachmentHelper', 'addEnhancedFeatures');
|
||||
|
||||
class MyHelper {
|
||||
public static function addBatchInsertButton() {
|
||||
class AttachmentHelper {
|
||||
public static function addEnhancedFeatures() {
|
||||
?>
|
||||
<style>
|
||||
#file-list{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:15px;padding:15px;list-style:none;margin:0;}
|
||||
#file-list li{position:relative;border:1px solid #e0e0e0;border-radius:4px;padding:10px;background:#fff;transition:all 0.3s ease;list-style:none;margin:0;}
|
||||
#file-list li:hover{box-shadow:0 2px 8px rgba(0,0,0,0.1);}
|
||||
#file-list li.loading{opacity:0.7;pointer-events:none;}
|
||||
.att-enhanced-thumb{position:relative;width:100%;height:150px;margin-bottom:8px;background:#f5f5f5;overflow:hidden;border-radius:3px;display:flex;align-items:center;justify-content:center;}
|
||||
.att-enhanced-thumb img{width:100%;height:100%;object-fit:contain;display:block;}
|
||||
.att-enhanced-thumb .file-icon{display:flex;align-items:center;justify-content:center;width:100%;height:100%;font-size:40px;color:#999;}
|
||||
.att-enhanced-finfo{padding:5px 0;}
|
||||
.att-enhanced-fname{font-size:13px;margin-bottom:5px;word-break:break-all;color:#333;}
|
||||
.att-enhanced-fsize{font-size:12px;color:#999;}
|
||||
.att-enhanced-factions{display:flex;justify-content:space-between;align-items:center;margin-top:8px;gap:8px;}
|
||||
.att-enhanced-factions button{flex:1;padding:4px 8px;border:none;border-radius:3px;background:#e0e0e0;color:#333;cursor:pointer;font-size:12px;transition:all 0.2s ease;}
|
||||
.att-enhanced-factions button:hover{background:#d0d0d0;}
|
||||
.att-enhanced-factions .btn-insert{background:#467B96;color:white;}
|
||||
.att-enhanced-factions .btn-insert:hover{background:#3c6a81;}
|
||||
.att-enhanced-checkbox{position:absolute;top:5px;right:5px;z-index:2;width:18px;height:18px;cursor:pointer;}
|
||||
.batch-actions{margin:15px;display:flex;gap:10px;align-items:center;}
|
||||
.btn-batch{padding:8px 15px;border-radius:4px;border:none;cursor:pointer;transition:all 0.3s ease;font-size:10px;display:inline-flex;align-items:center;justify-content:center;}
|
||||
.btn-batch.primary{background:#467B96;color:white;}
|
||||
.btn-batch.primary:hover{background:#3c6a81;}
|
||||
.btn-batch.secondary{background:#e0e0e0;color:#333;}
|
||||
.btn-batch.secondary:hover{background:#d0d0d0;}
|
||||
.upload-progress{position:absolute;bottom:0;left:0;width:100%;height:2px;background:#467B96;transition:width 0.3s ease;}
|
||||
</style>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
// 添加批量插入按钮
|
||||
var batchButton = $('<button type="button" class="btn primary" id="batch-insert">批量插入所有附件</button>');
|
||||
$('#file-list').before(batchButton);
|
||||
|
||||
// 修改单个附件的插入格式
|
||||
// 批量操作UI按钮
|
||||
var $batchActions = $('<div class="batch-actions"></div>')
|
||||
.append('<button type="button" class="btn-batch primary" id="batch-insert">批量插入</button>')
|
||||
.append('<button type="button" class="btn-batch secondary" id="select-all">全选</button>')
|
||||
.append('<button type="button" class="btn-batch secondary" id="unselect-all">取消全选</button>');
|
||||
$('#file-list').before($batchActions);
|
||||
|
||||
// 插入格式
|
||||
Typecho.insertFileToEditor = function(title, url, isImage) {
|
||||
var textarea = $('#text'), sel = textarea.getSelection(),
|
||||
var textarea = $('#text'),
|
||||
sel = textarea.getSelection(),
|
||||
insertContent = isImage ? '' :
|
||||
'[' + title + '](' + url + ')';
|
||||
|
||||
textarea.replaceSelection(insertContent);
|
||||
textarea.replaceSelection(insertContent + '\n');
|
||||
textarea.focus();
|
||||
};
|
||||
|
||||
// 批量插入功能
|
||||
$('#batch-insert').click(function() {
|
||||
|
||||
// 批量插入
|
||||
$('#batch-insert').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
var content = '';
|
||||
$('#file-list li').each(function() {
|
||||
var $this = $(this),
|
||||
title = $this.find('.insert').text(),
|
||||
url = $this.data('url'),
|
||||
isImage = $this.data('image') == 1;
|
||||
|
||||
content += isImage ? '\n' :
|
||||
'[' + title + '](' + url + ')\n';
|
||||
if ($(this).find('.att-enhanced-checkbox').is(':checked')) {
|
||||
var $li = $(this);
|
||||
var title = $li.find('.att-enhanced-fname').text();
|
||||
var url = $li.data('url');
|
||||
var isImage = $li.data('image') == 1;
|
||||
content += isImage ? '\n' : '[' + title + '](' + url + ')\n';
|
||||
}
|
||||
});
|
||||
|
||||
var textarea = $('#text');
|
||||
var pos = textarea.getSelection();
|
||||
var newContent = textarea.val();
|
||||
if (pos.start === pos.end) {
|
||||
newContent = newContent.substring(0, pos.start) + content + newContent.substring(pos.start);
|
||||
} else {
|
||||
if (content) {
|
||||
var textarea = $('#text');
|
||||
var pos = textarea.getSelection();
|
||||
var newContent = textarea.val();
|
||||
newContent = newContent.substring(0, pos.start) + content + newContent.substring(pos.end);
|
||||
textarea.val(newContent);
|
||||
textarea.focus();
|
||||
}
|
||||
textarea.val(newContent);
|
||||
textarea.focus();
|
||||
});
|
||||
|
||||
$('#select-all').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
$('#file-list .att-enhanced-checkbox').prop('checked', true);
|
||||
return false;
|
||||
});
|
||||
$('#unselect-all').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
$('#file-list .att-enhanced-checkbox').prop('checked', false);
|
||||
return false;
|
||||
});
|
||||
|
||||
// 防止复选框冒泡
|
||||
$(document).on('click', '.att-enhanced-checkbox', function(e) {e.stopPropagation();});
|
||||
|
||||
// 增强文件列表样式,但不破坏li原结构和官方按钮
|
||||
function enhanceFileList() {
|
||||
$('#file-list li').each(function() {
|
||||
var $li = $(this);
|
||||
if ($li.hasClass('att-enhanced')) return;
|
||||
$li.addClass('att-enhanced');
|
||||
// 只增强,不清空li
|
||||
// 增加批量选择框
|
||||
if ($li.find('.att-enhanced-checkbox').length === 0) {
|
||||
$li.prepend('<input type="checkbox" class="att-enhanced-checkbox" />');
|
||||
}
|
||||
// 增加图片预览(如已有则不重复加)
|
||||
if ($li.find('.att-enhanced-thumb').length === 0) {
|
||||
var url = $li.data('url');
|
||||
var isImage = $li.data('image') == 1;
|
||||
var fileName = $li.find('.insert').text();
|
||||
var $thumbContainer = $('<div class="att-enhanced-thumb"></div>');
|
||||
if (isImage) {
|
||||
var $img = $('<img src="' + url + '" alt="' + fileName + '" />');
|
||||
$img.on('error', function() {
|
||||
$(this).replaceWith('<div class="file-icon">🖼️</div>');
|
||||
});
|
||||
$thumbContainer.append($img);
|
||||
} else {
|
||||
$thumbContainer.append('<div class="file-icon">📄</div>');
|
||||
}
|
||||
// 插到插入按钮之前
|
||||
$li.find('.insert').before($thumbContainer);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
// 插入按钮事件
|
||||
$(document).on('click', '.btn-insert', function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
var $li = $(this).closest('li');
|
||||
var title = $li.find('.att-enhanced-fname').text();
|
||||
Typecho.insertFileToEditor(title, $li.data('url'), $li.data('image') == 1);
|
||||
});
|
||||
|
||||
// 上传完成后增强新项
|
||||
var originalUploadComplete = Typecho.uploadComplete;
|
||||
Typecho.uploadComplete = function(attachment) {
|
||||
setTimeout(function() {
|
||||
enhanceFileList();
|
||||
}, 200);
|
||||
if (typeof originalUploadComplete === 'function') {
|
||||
originalUploadComplete(attachment);
|
||||
}
|
||||
};
|
||||
|
||||
// 首次增强
|
||||
enhanceFileList();
|
||||
});
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
?>
|
||||
<?php
|
||||
/**
|
||||
* 友好时间显示函数
|
||||
* @param int $time 时间戳
|
||||
* @param int $threshold 阈值(秒),超过此值则显示标准日期格式(Y-m-d)
|
||||
* @return string
|
||||
*/
|
||||
function time_ago($time, $threshold = 31536000) { // 31536000秒 = 1年
|
||||
$now = time();
|
||||
$difference = $now - $time;
|
||||
|
||||
// 如果时间差超过阈值(默认1年),则返回标准日期格式(不带时间)
|
||||
if ($difference >= $threshold) {
|
||||
return date('Y-m-d', $time);
|
||||
}
|
||||
|
||||
// 1年以内的时间,返回友好格式(如 "3天前")
|
||||
$periods = array("秒", "分钟", "小时", "天", "周", "个月", "年");
|
||||
$lengths = array("60", "60", "24", "7", "4.35", "12");
|
||||
|
||||
for ($j = 0; $difference >= $lengths[$j] && $j < count($lengths); $j++) {
|
||||
$difference /= $lengths[$j];
|
||||
}
|
||||
|
||||
$difference = round($difference);
|
||||
return $difference . $periods[$j] . "前";
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
* 一款单栏主题. 移植自HUGO主题 Farallon 原作者 bigfa
|
||||
* @package Farallon
|
||||
* @author 老孙
|
||||
* @version 0.7.1
|
||||
* @version 0.7.3
|
||||
* @link https://www.imsun.org
|
||||
*/
|
||||
if (!defined('__TYPECHO_ROOT_DIR__')) exit; ?>
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@
|
||||
<img src="<?php $this->options->logoUrl() ?>" class="avatar" width="48" height="48" />
|
||||
<a datetime='<?php $this->date('Y-m-d'); ?>' class="humane--time" href="<?php $this->permalink() ?>"
|
||||
itemprop="datePublished">
|
||||
<?php $this->date('Y-m-d'); ?>
|
||||
<?php $options = Helper::options();if ($options->friendlyTime == '1') {echo time_ago($this->created);} else {$this->date('Y-m-d H:i'); }?>
|
||||
</a>
|
||||
</header>
|
||||
<div class="description" itemprop="about">
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@
|
||||
'...',
|
||||
array(
|
||||
'wrapTag' => 'nav',
|
||||
'wrapClass' => 'nav-links nav-links__comment',
|
||||
'wrapClass' => 'nav-links',
|
||||
'itemTag' => '',
|
||||
'textTag' => 'span',
|
||||
'itemClass' => 'page-numbers',
|
||||
|
||||
+4
-3
@@ -22,7 +22,7 @@
|
||||
<img src="<?php $this->options->logoUrl() ?>" class="avatar" width="48" height="48" />
|
||||
<a datetime='<?php $this->date('Y-m-d'); ?>' class="humane--time" href="<?php $this->permalink() ?>"
|
||||
itemprop="datePublished">
|
||||
<?php $this->date('Y-m-d H:i'); ?>
|
||||
<?php $options = Helper::options();if ($options->friendlyTime == '1') {echo time_ago($this->created);} else {$this->date('Y-m-d H:i'); }?>
|
||||
</a>
|
||||
</header>
|
||||
<div class="description" itemprop="about">
|
||||
@@ -37,7 +37,7 @@
|
||||
<div class="content">
|
||||
<h2 class="post--title">
|
||||
<a href="<?php $this->permalink() ?>">
|
||||
<?php $this->title() ?>
|
||||
<?php $this->title() ?><?php if (isset($this->isSticky) && $this->isSticky): ?><?php echo $this->stickyHtml; ?><?php endif; ?>
|
||||
<?php if((time() - $this->created) < 60*60*24*3): ?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
class="icon--sticky" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
||||
@@ -58,7 +58,7 @@
|
||||
<div class="meta">
|
||||
<svg class="icon" viewBox="0 0 1024 1024" width="16" height="16"><path d="M512 97.52381c228.912762 0 414.47619 185.563429 414.47619 414.47619s-185.563429 414.47619-414.47619 414.47619S97.52381 740.912762 97.52381 512 283.087238 97.52381 512 97.52381z m0 73.142857C323.486476 170.666667 170.666667 323.486476 170.666667 512s152.81981 341.333333 341.333333 341.333333 341.333333-152.81981 341.333333-341.333333S700.513524 170.666667 512 170.666667z m36.571429 89.697523v229.86362h160.865523v73.142857H512a36.571429 36.571429 0 0 1-36.571429-36.571429V260.388571h73.142858z"></path></svg>
|
||||
<time>
|
||||
<?php $this->date('Y-m-d'); ?>
|
||||
<?php $options = Helper::options();if ($options->friendlyTime == '1') {echo time_ago($this->created);} else {$this->date('Y-m-d H:i'); }?>
|
||||
</time>
|
||||
<svg class="icon" viewBox="0 0 1024 1024" width="16" height="16"><path d="M408.551619 97.52381a73.142857 73.142857 0 0 1 51.736381 21.430857L539.306667 197.973333A73.142857 73.142857 0 0 0 591.067429 219.428571H804.571429a73.142857 73.142857 0 0 1 73.142857 73.142858v560.761904a73.142857 73.142857 0 0 1-73.142857 73.142857H219.428571a73.142857 73.142857 0 0 1-73.142857-73.142857V170.666667a73.142857 73.142857 0 0 1 73.142857-73.142857h189.123048z m0 73.142857H219.428571v682.666666h585.142858V292.571429h-213.504a146.285714 146.285714 0 0 1-98.499048-38.13181L487.619048 249.734095 408.551619 170.666667zM365.714286 633.904762v73.142857h-73.142857v-73.142857h73.142857z m365.714285 0v73.142857H414.47619v-73.142857h316.952381z m-365.714285-195.047619v73.142857h-73.142857v-73.142857h73.142857z m365.714285 0v73.142857H414.47619v-73.142857h316.952381z"></path></svg>
|
||||
<?php $this->category(','); ?>
|
||||
@@ -75,6 +75,7 @@
|
||||
$cover = $this->fields->cover;
|
||||
$imageToDisplay = !empty($cover) ? $cover : $firstImage;
|
||||
if($imageToDisplay):
|
||||
$imageToDisplay = process_cover_image($imageToDisplay);
|
||||
?>
|
||||
<a href="<?php $this->permalink() ?>" class="cover--link">
|
||||
<img src="<?php echo $imageToDisplay; ?>" alt="<?php $this->title() ?>" class="cover" itemprop="image"/>
|
||||
|
||||
+70
-31
@@ -1,23 +1,25 @@
|
||||
<?php if (!defined('__TYPECHO_ROOT_DIR__')) exit; ?>
|
||||
<?php
|
||||
/** 文章置顶 */
|
||||
$sticky = $this->options->sticky; // 置顶的文章id,多个用|隔开
|
||||
<?php if (!defined('__TYPECHO_ROOT_DIR__')) exit;
|
||||
$sticky = $this->options->sticky;
|
||||
$db = Typecho_Db::get();
|
||||
$pageSize = $this->options->pageSize;
|
||||
if ($sticky && !empty(trim($sticky))) {
|
||||
$sticky_cids = array_filter(explode('|', $sticky)); // 分割文本并过滤空值
|
||||
$sticky_cids = array_filter(explode('|', $sticky));
|
||||
if (!empty($sticky_cids)) {
|
||||
$sticky_html = " <span class='sticky--post'> 置顶 </span> "; // 置顶标题的 html
|
||||
// 清空原有文章的队列
|
||||
$sticky_html = " <span class='sticky--post'> 置顶 </span>";
|
||||
// 保存原始对象状态
|
||||
$originalRows = $this->row;
|
||||
$originalStack = $this->stack;
|
||||
$originalLength = $this->length;
|
||||
$totalOriginal = $this->getTotal();
|
||||
// 重置当前对象状态
|
||||
$this->row = [];
|
||||
$this->stack = [];
|
||||
$this->length = 0;
|
||||
// 获取总数,并排除置顶文章数量
|
||||
$this->length = 0;
|
||||
// 关键修改:不再减少总文章数
|
||||
// 保持原始总数,这样分页逻辑不会受影响
|
||||
// $this->setTotal(max($totalOriginal - $stickyCount, 0));
|
||||
if (isset($this->currentPage) && $this->currentPage == 1) {
|
||||
$totalOriginal = $this->getTotal();
|
||||
$stickyCount = count($sticky_cids);
|
||||
$this->setTotal(max($totalOriginal - $stickyCount, 0));
|
||||
// 构建置顶文章的查询
|
||||
// 查询置顶文章
|
||||
$selectSticky = $this->select()->where('type = ?', 'post');
|
||||
foreach ($sticky_cids as $i => $cid) {
|
||||
if ($i == 0)
|
||||
@@ -25,29 +27,65 @@ if ($sticky && !empty(trim($sticky))) {
|
||||
else
|
||||
$selectSticky->orWhere('cid = ?', $cid);
|
||||
}
|
||||
// 获取置顶文章
|
||||
$stickyPosts = $db->fetchAll($selectSticky);
|
||||
// 压入置顶文章到文章队列
|
||||
|
||||
// 添加置顶文章到结果集
|
||||
foreach ($stickyPosts as &$stickyPost) {
|
||||
$stickyPost['title'] .= $sticky_html;
|
||||
$stickyPost['isSticky'] = true;
|
||||
$stickyPost['stickyHtml'] = $sticky_html;
|
||||
$this->push($stickyPost);
|
||||
}
|
||||
|
||||
// 计算当前页应显示的普通文章数量
|
||||
$standardPageSize = $pageSize - count($stickyPosts);
|
||||
|
||||
// 确保第一页不会显示太多文章
|
||||
if ($standardPageSize <= 0) {
|
||||
$standardPageSize = 0; // 如果置顶文章已经填满或超过一页,则不显示普通文章
|
||||
}
|
||||
} else {
|
||||
// 非第一页显示正常数量的文章
|
||||
$standardPageSize = $pageSize;
|
||||
}
|
||||
// 构建正常文章查询,排除置顶文章
|
||||
$selectNormal = $this->select()
|
||||
->where('type = ?', 'post')
|
||||
->where('status = ?', 'publish')
|
||||
->where('created < ?', time())
|
||||
->order('created', Typecho_Db::SORT_DESC)
|
||||
->page(isset($this->currentPage) ? $this->currentPage : 1, $standardPageSize);
|
||||
foreach ($sticky_cids as $cid) {
|
||||
$selectNormal->where('table.contents.cid != ?', $cid);
|
||||
}
|
||||
// 查询普通文章
|
||||
if ($this->currentPage == 1) {
|
||||
// 第一页需要排除置顶文章并限制数量
|
||||
$selectNormal = $this->select()
|
||||
->where('type = ?', 'post')
|
||||
->where('status = ?', 'publish')
|
||||
->where('created < ?', time());
|
||||
|
||||
// 排除所有置顶文章
|
||||
foreach ($sticky_cids as $cid) {
|
||||
$selectNormal->where('table.contents.cid != ?', $cid);
|
||||
}
|
||||
|
||||
$selectNormal->order('created', Typecho_Db::SORT_DESC)
|
||||
->limit($standardPageSize)
|
||||
->offset(0);
|
||||
} else {
|
||||
// 非第一页的查询
|
||||
// 计算正确的偏移量:(当前页码-1) * 每页数量 - 置顶文章数
|
||||
// 这样可以确保不会漏掉文章
|
||||
$offset = ($this->currentPage - 1) * $pageSize - count($sticky_cids);
|
||||
$offset = max($offset, 0); // 确保偏移量不为负
|
||||
|
||||
$selectNormal = $this->select()
|
||||
->where('type = ?', 'post')
|
||||
->where('status = ?', 'publish')
|
||||
->where('created < ?', time());
|
||||
|
||||
// 排除所有置顶文章
|
||||
foreach ($sticky_cids as $cid) {
|
||||
$selectNormal->where('table.contents.cid != ?', $cid);
|
||||
}
|
||||
|
||||
$selectNormal->order('created', Typecho_Db::SORT_DESC)
|
||||
->limit($pageSize)
|
||||
->offset($offset);
|
||||
}
|
||||
} else {
|
||||
// 如果sticky_cids为空,使用默认查询
|
||||
// 没有有效的置顶文章ID,正常查询
|
||||
$selectNormal = $this->select()
|
||||
->where('type = ?', 'post')
|
||||
->where('status = ?', 'publish')
|
||||
@@ -56,7 +94,7 @@ if ($sticky && !empty(trim($sticky))) {
|
||||
->page(isset($this->currentPage) ? $this->currentPage : 1, $pageSize);
|
||||
}
|
||||
} else {
|
||||
// 如果没有置顶文章,使用默认查询
|
||||
// 没有设置置顶文章,正常查询
|
||||
$selectNormal = $this->select()
|
||||
->where('type = ?', 'post')
|
||||
->where('status = ?', 'publish')
|
||||
@@ -64,21 +102,22 @@ if ($sticky && !empty(trim($sticky))) {
|
||||
->order('created', Typecho_Db::SORT_DESC)
|
||||
->page(isset($this->currentPage) ? $this->currentPage : 1, $pageSize);
|
||||
}
|
||||
// 登录用户显示私密文章
|
||||
// 添加私有文章查询条件
|
||||
if ($this->user->hasLogin()) {
|
||||
$uid = $this->user->uid;
|
||||
if ($uid) {
|
||||
$selectNormal->orWhere('authorId = ? AND status = ?', $uid, 'private');
|
||||
}
|
||||
}
|
||||
// 获取普通文章
|
||||
$normalPosts = $db->fetchAll($selectNormal);
|
||||
// 如果之前没有清空队列(没有置顶文章的情况),现在清空
|
||||
// 如果没有置顶文章或在前面的代码中没有重置对象状态,则在这里重置
|
||||
if (empty($sticky) || empty(trim($sticky)) || empty($sticky_cids)) {
|
||||
$this->row = [];
|
||||
$this->stack = [];
|
||||
$this->length = 0;
|
||||
}
|
||||
// 压入正常文章到文章队列
|
||||
// 将普通文章添加到结果集
|
||||
foreach ($normalPosts as $normalPost) {
|
||||
$this->push($normalPost);
|
||||
}
|
||||
|
||||
+5
-2
@@ -12,8 +12,11 @@
|
||||
if (empty($imageToDisplay)) {
|
||||
$imageToDisplay = $firstImage;
|
||||
}
|
||||
if (!empty($imageToDisplay) && $imageToDisplay != $default_thumbnail) {
|
||||
$imageToDisplay = process_cover_image($imageToDisplay);
|
||||
}
|
||||
?>
|
||||
<article class="post--card" id="loadpost" itemscope itemtype="http://schema.org/Article">
|
||||
<article class="post--card" id="loadpost">
|
||||
<img src="<?php echo $imageToDisplay; ?>" alt="<?php $this->title() ?>" class="cover" itemprop="image"/>
|
||||
<div class="content">
|
||||
<h2 class="post--title">
|
||||
@@ -29,7 +32,7 @@
|
||||
<path d="M512 97.52381c228.912762 0 414.47619 185.563429 414.47619 414.47619s-185.563429 414.47619-414.47619 414.47619S97.52381 740.912762 97.52381 512 283.087238 97.52381 512 97.52381z m0 73.142857C323.486476 170.666667 170.666667 323.486476 170.666667 512s152.81981 341.333333 341.333333 341.333333 341.333333-152.81981 341.333333-341.333333S700.513524 170.666667 512 170.666667z m36.571429 89.697523v229.86362h160.865523v73.142857H512a36.571429 36.571429 0 0 1-36.571429-36.571429V260.388571h73.142858z"></path>
|
||||
</svg>
|
||||
<time datetime='<?php $this->date('Y-m-d'); ?>' class="humane--time">
|
||||
<?php $this->date('Y-m-d'); ?>
|
||||
<?php $options = Helper::options();if ($options->friendlyTime == '1') {echo time_ago($this->created);} else {$this->date('Y-m-d H:i'); }?>
|
||||
</time>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<path
|
||||
d="M512 97.52381c228.912762 0 414.47619 185.563429 414.47619 414.47619s-185.563429 414.47619-414.47619 414.47619S97.52381 740.912762 97.52381 512 283.087238 97.52381 512 97.52381z m0 73.142857C323.486476 170.666667 170.666667 323.486476 170.666667 512s152.81981 341.333333 341.333333 341.333333 341.333333-152.81981 341.333333-341.333333S700.513524 170.666667 512 170.666667z m36.571429 89.697523v229.86362h160.865523v73.142857H512a36.571429 36.571429 0 0 1-36.571429-36.571429V260.388571h73.142858z">
|
||||
</path>
|
||||
</svg><time class="humane--time"><?php $this->date('Y-m-d'); ?></time>
|
||||
</svg><time class="humane--time"><?php $options = Helper::options();if ($options->friendlyTime == '1') {echo time_ago($this->created);} else {$this->date('Y-m-d H:i'); }?></time>
|
||||
<svg class="icon" viewBox="0 0 1024 1024" width="16" height="16">
|
||||
<path
|
||||
d="M408.551619 97.52381a73.142857 73.142857 0 0 1 51.736381 21.430857L539.306667 197.973333A73.142857 73.142857 0 0 0 591.067429 219.428571H804.571429a73.142857 73.142857 0 0 1 73.142857 73.142858v560.761904a73.142857 73.142857 0 0 1-73.142857 73.142857H219.428571a73.142857 73.142857 0 0 1-73.142857-73.142857V170.666667a73.142857 73.142857 0 0 1 73.142857-73.142857h189.123048z m0 73.142857H219.428571v682.666666h585.142858V292.571429h-213.504a146.285714 146.285714 0 0 1-98.499048-38.13181L487.619048 249.734095 408.551619 170.666667zM365.714286 633.904762v73.142857h-73.142857v-73.142857h73.142857z m365.714285 0v73.142857H414.47619v-73.142857h316.952381z m-365.714285-195.047619v73.142857h-73.142857v-73.142857h73.142857z m365.714285 0v73.142857H414.47619v-73.142857h316.952381z">
|
||||
@@ -61,7 +61,9 @@
|
||||
<?php if($this->options->showshare): ?>
|
||||
<div class="post--share">
|
||||
<svg viewBox="0 0 24 24" aria-hidden="true"><g><path d="M18.36 5.64c-1.95-1.96-5.11-1.96-7.07 0L9.88 7.05 8.46 5.64l1.42-1.42c2.73-2.73 7.16-2.73 9.9 0 2.73 2.74 2.73 7.17 0 9.9l-1.42 1.42-1.41-1.42 1.41-1.41c1.96-1.96 1.96-5.12 0-7.07zm-2.12 3.53l-7.07 7.07-1.41-1.41 7.07-7.07 1.41 1.41zm-12.02.71l1.42-1.42 1.41 1.42-1.41 1.41c-1.96 1.96-1.96 5.12 0 7.07 1.95 1.96 5.11 1.96 7.07 0l1.41-1.41 1.42 1.41-1.42 1.42c-2.73 2.73-7.16 2.73-9.9 0-2.73-2.74-2.73-7.17 0-9.9z"></path></g></svg>
|
||||
<span class="text" data-copy="<?php $this->permalink(); ?>">复制链接</span><span class="link text"><?php $this->permalink(); ?></span><div class="notice--wrapper" id="copyTooltip" style="display: none;">复制成功!</div>
|
||||
<span class="cpoy" data-copy="<?php $this->permalink(); ?>">复制链接</span>
|
||||
<span class="link copy"><?php $this->permalink(); ?></span>
|
||||
<div class="notice--wrapper" id="copyTooltip" style="display: none;">复制成功!</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<!-- TAG -->
|
||||
|
||||
Reference in New Issue
Block a user