mirror of https://github.com/mashirozx/sakura.git
Compare commits
No commits in common. "v5.0.0-rc1" and "3.x" have entirely different histories.
v5.0.0-rc1
...
3.x
|
@ -1,8 +0,0 @@
|
|||
> 1%
|
||||
last 2 versions
|
||||
not IE 11
|
||||
Android >= 6
|
||||
Firefox >= 69
|
||||
Chrome >= 64
|
||||
iOS >= 9
|
||||
not dead
|
|
@ -1,18 +0,0 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
|
||||
[*.{js,ts,json,vue,php}]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[/node_modules/**]
|
||||
charset = unset
|
||||
end_of_line = unset
|
||||
insert_final_newline = unset
|
||||
trim_trailing_whitespace = unset
|
||||
indent_style = unset
|
||||
indent_size = unset
|
|
@ -1 +0,0 @@
|
|||
src/locales/*.json
|
44
.eslintrc.js
44
.eslintrc.js
|
@ -1,44 +0,0 @@
|
|||
module.exports = {
|
||||
env: {
|
||||
browser: true,
|
||||
es2021: true,
|
||||
},
|
||||
extends: [
|
||||
'plugin:vue/essential',
|
||||
'eslint:recommended',
|
||||
'@vue/typescript/recommended',
|
||||
'@vue/prettier',
|
||||
'@vue/prettier/@typescript-eslint',
|
||||
],
|
||||
parserOptions: {
|
||||
ecmaVersion: 12,
|
||||
parser: '@typescript-eslint/parser',
|
||||
sourceType: 'module',
|
||||
},
|
||||
plugins: ['vue', '@typescript-eslint', 'file-progress', 'formatjs'],
|
||||
rules: {
|
||||
'formatjs/no-offset': 'error',
|
||||
'file-progress/activate': 1,
|
||||
indent: ['error', 2, { SwitchCase: 1 }],
|
||||
'linebreak-style': ['error', 'unix'],
|
||||
'array-element-newline': ['error', { multiline: true, minItems: 3 }],
|
||||
quotes: ['error', 'single'],
|
||||
semi: ['error', 'never'],
|
||||
'@typescript-eslint/no-explicit-any': 0,
|
||||
'@typescript-eslint/ban-types': 0,
|
||||
'vue/no-multiple-template-root': 0,
|
||||
'prettier/prettier': [
|
||||
'error',
|
||||
{
|
||||
endOfLine: 'lf',
|
||||
},
|
||||
],
|
||||
},
|
||||
globals: {
|
||||
Pagination: 'readonly',
|
||||
WPPostAbstract: 'readonly',
|
||||
Post: 'readonly',
|
||||
PostListData: 'readonly',
|
||||
PostStore: 'readonly',
|
||||
},
|
||||
}
|
|
@ -1,14 +1,2 @@
|
|||
# Set the default behavior, in case people don't have core.autocrlf set.
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
|
||||
# Explicitly declare text files you want to always be normalized and converted
|
||||
# to native line endings on checkout.
|
||||
*.c text
|
||||
*.h text
|
||||
|
||||
# Declare files that will always have LF line endings on checkout.
|
||||
*.sln text eol=lf
|
||||
|
||||
# Denote all files that are truly binary and should not be modified.
|
||||
*.png binary
|
||||
*.jpg binary
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
---
|
||||
name: 报告 bug
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
如果这是您第一次在GitHub上发 issue,请阅读【提问的智慧】:https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/master/README-zh_CN.md
|
||||
-->
|
||||
|
||||
**描述问题**
|
||||
|
||||
**bug 重现步骤**
|
||||
|
||||
**截图(如有)**
|
||||
|
||||
**系统信息**
|
||||
- (前端)操作系统: [e.g. Windows 10, Android 9.0]
|
||||
- 浏览器: [e.g. chrome, safari]
|
||||
- PHP 版本
|
||||
- WordPress 版本
|
||||
- Sakura 主题版本
|
||||
|
||||
**补充信息**
|
|
@ -0,0 +1,20 @@
|
|||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
|
@ -1,24 +0,0 @@
|
|||
# To get started with Dependabot version updates, you'll need to specify which
|
||||
# package ecosystems to update and where the package manifests are located.
|
||||
# Please see the documentation for all configuration options:
|
||||
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
# Maintain dependencies for GitHub Actions
|
||||
- package-ecosystem: 'github-actions'
|
||||
directory: '/'
|
||||
schedule:
|
||||
interval: 'daily'
|
||||
|
||||
# Maintain dependencies for npm
|
||||
- package-ecosystem: 'npm'
|
||||
directory: '/'
|
||||
schedule:
|
||||
interval: 'daily'
|
||||
|
||||
# Maintain dependencies for Composer
|
||||
- package-ecosystem: 'composer'
|
||||
directory: '/'
|
||||
schedule:
|
||||
interval: 'daily'
|
|
@ -1,16 +0,0 @@
|
|||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
# node
|
||||
yarn-error.log
|
||||
package-lock.json
|
||||
composer.phar
|
||||
# private config
|
||||
.env.development
|
||||
# mac
|
||||
.DS_Store
|
||||
# jest
|
||||
coverage
|
||||
# release
|
||||
sakura-next.zip
|
|
@ -1,8 +0,0 @@
|
|||
module.exports = ({ env, options }) => ({
|
||||
...options,
|
||||
plugins: [
|
||||
require('autoprefixer')({}),
|
||||
// require('flex-gap-polyfill')() // bugly with vite
|
||||
// require('stylelint')({}), //
|
||||
],
|
||||
})
|
|
@ -1 +0,0 @@
|
|||
src/locales/*.json
|
|
@ -1,50 +0,0 @@
|
|||
module.exports = {
|
||||
// 行宽 default:80
|
||||
printWidth: 100,
|
||||
// tab 宽度 default:2
|
||||
tabWidth: 2,
|
||||
// 使用 tab 键 default:false
|
||||
useTabs: false,
|
||||
// 语句行末是否添加分号 default:true
|
||||
semi: false,
|
||||
// 是否使用单引号 default:false
|
||||
singleQuote: true,
|
||||
// 对象需要引号在加 default:"as-needed"
|
||||
quoteProps: 'as-needed',
|
||||
// jsx单引号 default:false
|
||||
jsxSingleQuote: false,
|
||||
// 最后一个对象元素加逗号 default:"es5"
|
||||
trailingComma: 'es5',
|
||||
// 在对象字面量声明所使用的的花括号后({)和前(})输出空格 default:true
|
||||
bracketSpacing: true,
|
||||
// 将 > 多行 JSX 元素放在最后一行的末尾,而不是单独放在下一行(不适用于自闭元素)。default:false
|
||||
jsxBracketSameLine: false,
|
||||
// (x) => {} 是否要有小括号 default:"always"
|
||||
arrowParens: 'always',
|
||||
// default:0
|
||||
rangeStart: 0,
|
||||
// default:Infinity
|
||||
rangeEnd: Infinity,
|
||||
// default:false
|
||||
insertPragma: false,
|
||||
// default:false
|
||||
requirePragma: false,
|
||||
// 不包装 markdown text default:"preserve"
|
||||
proseWrap: 'never',
|
||||
// HTML空白敏感性 default:"css"
|
||||
htmlWhitespaceSensitivity: 'strict',
|
||||
// 在 *.vue 文件中 Script 和 Style 标签内的代码是否缩进 default:false
|
||||
vueIndentScriptAndStyle: false,
|
||||
// 末尾换行符 default:"lf"
|
||||
endOfLine: 'lf',
|
||||
// default:"auto"
|
||||
embeddedLanguageFormatting: 'auto',
|
||||
overrides: [
|
||||
{
|
||||
files: '*.md',
|
||||
options: {
|
||||
tabWidth: 2,
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
node_modules
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"plugins": [
|
||||
"stylelint-scss"
|
||||
],
|
||||
"extends": "stylelint-config-standard",
|
||||
"rules": {
|
||||
"rule-empty-line-before": "never",
|
||||
"indentation": 2
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
{
|
||||
"recommendations": [
|
||||
"bmewburn.vscode-intelephense-client",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"mhutchie.git-graph",
|
||||
"donjayamanne.githistory",
|
||||
"eamodio.gitlens",
|
||||
"esbenp.prettier-vscode",
|
||||
"octref.vetur",
|
||||
"editorconfig.editorconfig",
|
||||
"neilbrayfield.php-docblocker"
|
||||
]
|
||||
}
|
|
@ -1,132 +0,0 @@
|
|||
{
|
||||
"stylelint.enable": false,
|
||||
"php-docblocker.returnGap": true,
|
||||
"php-docblocker.qualifyClassNames": true,
|
||||
"php-docblocker.author": {
|
||||
"name": "mashirozx",
|
||||
"email": "moezhx@outlook.com"
|
||||
},
|
||||
"editor.formatOnSave": true,
|
||||
"emmet.extensionsPath": [
|
||||
".vscode/"
|
||||
],
|
||||
"emmet.triggerExpansionOnTab": true,
|
||||
"emmet.showExpandedAbbreviation": "always",
|
||||
"emmet.includeLanguages": {
|
||||
"vue": "html",
|
||||
// "twig": "html"
|
||||
},
|
||||
"prettier.requireConfig": true,
|
||||
"prettier.configPath": ".prettierrc.js",
|
||||
"prettier.semi": true,
|
||||
"files.associations": {
|
||||
"*.json": "jsonc",
|
||||
// "*.html": "twig"
|
||||
},
|
||||
"[javascript]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[javascript|react]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[typescript|react]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[less]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[css]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[json]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[php]": {
|
||||
"editor.defaultFormatter": "bmewburn.vscode-intelephense-client"
|
||||
},
|
||||
"[twig]": {
|
||||
"editor.defaultFormatter": "mblode.twig-language-2"
|
||||
},
|
||||
"intelephense.telemetry.enabled": false,
|
||||
"intelephense.format.enable": true,
|
||||
"intelephense.completion.triggerParameterHints": true,
|
||||
"intelephense.completion.insertUseDeclaration": true,
|
||||
"intelephense.files.maxSize": 3000000,
|
||||
"intelephense.stubs": [
|
||||
"apache",
|
||||
"bcmath",
|
||||
"bz2",
|
||||
"calendar",
|
||||
"com_dotnet",
|
||||
"Core",
|
||||
"ctype",
|
||||
"curl",
|
||||
"date",
|
||||
"dba",
|
||||
"dom",
|
||||
"enchant",
|
||||
"exif",
|
||||
"FFI",
|
||||
"fileinfo",
|
||||
"filter",
|
||||
"fpm",
|
||||
"ftp",
|
||||
"gd",
|
||||
"gettext",
|
||||
"gmp",
|
||||
"hash",
|
||||
"iconv",
|
||||
"imap",
|
||||
"intl",
|
||||
"json",
|
||||
"ldap",
|
||||
"libxml",
|
||||
"mbstring",
|
||||
"meta",
|
||||
"mysqli",
|
||||
"oci8",
|
||||
"odbc",
|
||||
"openssl",
|
||||
"pcntl",
|
||||
"pcre",
|
||||
"PDO",
|
||||
"pdo_ibm",
|
||||
"pdo_mysql",
|
||||
"pdo_pgsql",
|
||||
"pdo_sqlite",
|
||||
"pgsql",
|
||||
"Phar",
|
||||
"posix",
|
||||
"pspell",
|
||||
"readline",
|
||||
"Reflection",
|
||||
"session",
|
||||
"shmop",
|
||||
"SimpleXML",
|
||||
"snmp",
|
||||
"soap",
|
||||
"sockets",
|
||||
"sodium",
|
||||
"SPL",
|
||||
"sqlite3",
|
||||
"standard",
|
||||
"superglobals",
|
||||
"sysvmsg",
|
||||
"sysvsem",
|
||||
"sysvshm",
|
||||
"tidy",
|
||||
"tokenizer",
|
||||
"xml",
|
||||
"xmlreader",
|
||||
"xmlrpc",
|
||||
"xmlwriter",
|
||||
"xsl",
|
||||
"Zend OPcache",
|
||||
"zip",
|
||||
"zlib",
|
||||
"wordpress"
|
||||
]
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"html": {
|
||||
"snippets": {
|
||||
"divc": "div[class=${1}]",
|
||||
"view": "div[class=${1}]",
|
||||
"text": "span[class=\"text\"]",
|
||||
"image": "Image[src=${1} placeholder=${2} :avatar=\"false\" alt=${2} :draggable=\"false\"]",
|
||||
"icon": "UiIcon[name=${1} :width=\"100%\" :height=\"100%\"]",
|
||||
"slot": "slot[name=${1}]"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
/**
|
||||
* The template for displaying 404 pages (not found).
|
||||
*
|
||||
* @link https://codex.wordpress.org/Creating_an_Error_404_Page
|
||||
*
|
||||
* @package Akina
|
||||
*/
|
||||
|
||||
?>
|
||||
<html <?php language_attributes(); ?>>
|
||||
<head>
|
||||
<meta charset="<?php bloginfo( 'charset' ); ?>">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="shortcut icon" href="<?php echo akina_option('favicon_link', ''); ?>"/>
|
||||
<title itemprop="name"><?php global $page, $paged;wp_title( '-', true, 'right' );
|
||||
bloginfo( 'name' );$site_description = get_bloginfo( 'description', 'display' );
|
||||
if ( $site_description && ( is_home() || is_front_page() ) ) echo " - $site_description";if ( $paged >= 2 || $page >= 2 ) echo ' - ' . sprintf( __( 'page %s'), max( $paged, $page ) );/*第 %s 页*/?>
|
||||
</title>
|
||||
<link type="text/css" media="all" href="https://cdn.jsdelivr.net/gh/moezx/cdn@3.2.2/css/lib.css" rel="stylesheet" />
|
||||
<?php wp_head(); ?>
|
||||
<script>
|
||||
var the_url=window.location.href;
|
||||
var the_dom="<?php echo str_replace("http://", "", str_replace("https://", "", get_site_url())); ?>";
|
||||
var no_report = false;
|
||||
if (the_dom!= '2heng.xin') {
|
||||
no_report = true;
|
||||
}
|
||||
var the_ua=navigator.userAgent;
|
||||
var the_ref=document.referrer;
|
||||
function httpGet(theUrl) {
|
||||
var xmlHttp = new XMLHttpRequest();
|
||||
xmlHttp.open( "GET", theUrl, false ); // false for synchronous request
|
||||
xmlHttp.send( null );
|
||||
return xmlHttp.responseText;
|
||||
}
|
||||
var report_url = "https://api.mashiro.top/count/404/?" + "url="+the_url+"&ua="+the_ua+"&ref="+the_ref;
|
||||
if (!no_report) httpGet(report_url);
|
||||
</script>
|
||||
</head>
|
||||
<body <?php body_class(); ?>>
|
||||
<section class="error-404 not-found">
|
||||
<div class="error-img">
|
||||
<div class="anim-icon" id="404" style="height: 66%;"></div>
|
||||
</div>
|
||||
<div class="err-button back">
|
||||
<a id="golast" href=javascript:history.go(-1);><?php _e('return to previous page','sakura');/*返回上一页*/?></a>
|
||||
<a id="gohome" href="<?php bloginfo('url');?>"><?php _e('return to home page','sakura');/*返回主页*/?></a>
|
||||
</div>
|
||||
<div style="display:block; width:284px;margin: auto;">
|
||||
<p style="margin-bottom: 1em;margin-top: 1.5em;text-align: center;font-size: 15px;"><?php _e('Don\'t worry, search in site?','sakura');/*别急,试试站内搜索?*/?></p>
|
||||
<form class="s-search" method="get" action="/" role="search">
|
||||
<i class="iconfont icon-search" style="bottom: 8px;left: 12px;"></i>
|
||||
<input class="text-input" style="padding: 8px 20px 8px 46px;" type="search" name="s" placeholder="<?php _e('Search...', 'akina') ?>" required>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
<script src="https://cdn.jsdelivr.net/gh/moezx/cdn@3.1.5/js/other/404.min.js" type="text/javascript"></script>
|
||||
</body>
|
|
@ -0,0 +1,339 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
|
@ -0,0 +1,47 @@
|
|||
Sakura🌸: A Wonderful WordPress Theme
|
||||
===
|
||||
|
||||
[中文](README.md) | English
|
||||
|
||||
![Sakura](screenshot.jpg)
|
||||
|
||||
![PHP version](https://img.shields.io/badge/PHP-7.1+-4F5B93.svg?style=flat-square&logo=php)
|
||||
![WP version](https://img.shields.io/badge/WordPress-5.3-0073aa.svg?style=flat-square&logo=wordpress)
|
||||
[![GitHub release](https://img.shields.io/github/release/mashirozx/Sakura.svg?style=flat-square)](https://github.com/mashirozx/Sakura/releases/latest)
|
||||
[![Github commits (since latest release)](https://img.shields.io/github/commits-since/mashirozx/Sakura/latest/dev.svg?style=flat-square)](https://github.com/mashirozx/Sakura/commits/dev)
|
||||
[![](https://data.jsdelivr.com/v1/package/gh/moezx/cdn/badge)](https://www.jsdelivr.com/package/gh/moezx/cdn)
|
||||
|
||||
Modified based on theme [Akina (by Fuzzz)](http://www.akina.pw/themeakina) and [Siren (by Louie)](https://github.com/louie-senpai/Siren).
|
||||
|
||||
The rebuild version is on the way :)
|
||||
|
||||
### Install
|
||||
|
||||
#### By GIT
|
||||
```bash
|
||||
cd /wp-content/themes/
|
||||
git clone https://github.com/mashirozx/Sakura.git
|
||||
```
|
||||
|
||||
#### By FTP
|
||||
**Rename the theme folder name as `Sakura`** if you download form the green [Clone or download] button on this page. Make sure the path to the theme root is /wp-content/themes/Sakura/`.
|
||||
|
||||
### Configuration
|
||||
Config your theme at `Mune-Appearance-Sakura Options`. Please turn on `Use js and css file of the theme locally` under CDN tag if you want to modify local SCC an Javascript files.
|
||||
|
||||
### Update
|
||||
```bash
|
||||
cd /wp-content/themes/Sakura
|
||||
git fetch
|
||||
git pull
|
||||
```
|
||||
|
||||
[Learn more info about the theme (Chinese)](https://2heng.xin/theme-sakura/)
|
||||
|
||||
Enjoy it!
|
||||
|
||||
### Donate
|
||||
[WeChat Pay](https://view.moezx.cc/images/2018/05/28/WeChanQR.png) | [AliPay](https://view.moezx.cc/images/2018/05/28/AliPayQR.jpg) | [PayPal](https://paypal.me/mashirozx)
|
||||
|
||||
### Need a server?
|
||||
[![](https://www.vultr.com/media/banners/banner_728x90.png)](https://www.vultr.com/?ref=7674346)
|
53
README.md
53
README.md
|
@ -1,27 +1,34 @@
|
|||
# sakura-next
|
||||
Sakura🌸: 樱花庄的白猫博客主题
|
||||
===
|
||||
|
||||
## Requirement
|
||||
中文 | [English](README-en.md)
|
||||
|
||||
- PHP=7.4
|
||||
- WordPress>=5.6.0
|
||||
- Node.js>=14.17.1
|
||||
- yarn>=1.22.10
|
||||
![Sakura](screenshot.jpg)
|
||||
|
||||
## Commands
|
||||
![PHP version](https://img.shields.io/badge/PHP-7.1+-4F5B93.svg?style=flat-square&logo=php)
|
||||
![WP version](https://img.shields.io/badge/WordPress-5.3-0073aa.svg?style=flat-square&logo=wordpress)
|
||||
[![GitHub release](https://img.shields.io/github/v/release/mashirozx/Sakura.svg?style=flat-square&logo=github)](https://github.com/mashirozx/Sakura/releases/latest)
|
||||
[![Github commits (since latest release)](https://img.shields.io/github/commits-since/mashirozx/Sakura/latest/dev.svg?style=flat-square&logo=git&color=important)](https://github.com/mashirozx/Sakura/commits/dev)
|
||||
[![](https://data.jsdelivr.com/v1/package/gh/moezx/cdn/badge)](https://www.jsdelivr.com/package/gh/moezx/cdn)
|
||||
|
||||
```sh
|
||||
composer install # install php dependencies
|
||||
yarn install # install node dependencies
|
||||
yarn dev # run dev server
|
||||
yarn build # build assets
|
||||
yarn test # Jest test
|
||||
yarn lint # eslint
|
||||
yarn format # auto format
|
||||
yarn i18n # export i18n variables
|
||||
yarn rsync # sync backend app with server, see docs/dev.md
|
||||
yarn composer # run `composer install` on remote server
|
||||
yarn icon # generate svg icon component
|
||||
yarn remote-download:geoip2 # download GeoIP db on remote server
|
||||
yarn local-download:geoip2 # download GeoIP db locally
|
||||
yarn options # export node side admin options.ts to php side options.json
|
||||
```
|
||||
在 Louie 基于 Fuzzz 的 [Akina](http://www.akina.pw/themeakina) 主题修改的主题 [Siren](https://github.com/louie-senpai/Siren) 基础上三次修改 =.=
|
||||
|
||||
两位前辈做得已经很棒了,或许我所做的只是把他们的代码弄得凌乱不堪吧 :)
|
||||
|
||||
特别感谢 [@Spirit](https://github.com/spirit1431007) 对本项目的贡献!
|
||||
|
||||
注意:建议 `git clone` 下载([简易 Git 使用指南](https://github.com/mashirozx/Sakura/wiki/Git-%E4%B8%8B%E8%BD%BD%E3%80%81%E6%9B%B4%E6%96%B0%E6%8C%87%E5%8D%97));如果选择下载压缩包,**解压后记得把文件夹名改回 `Sakura`,也即保证主题路径为 `/wp-content/themes/Sakura/`**;主题设置在 `菜单-外观-Sakura 主题设置` 中;DIY 的时候建议采用[子主题](https://github.com/mashirozx/Sakura/tree/child) 并勾选 `Sakura 主题设置-CDN-本地调用主题 js、css 文件`;请留意主题说明里的其他注意事项。
|
||||
|
||||
主题使用说明见:<https://2heng.xin/theme-sakura/>
|
||||
|
||||
本仓库国内镜像:<https://git.moezx.cc/mirrors/sakura>
|
||||
|
||||
主题交流群:860262481
|
||||
|
||||
希望你喜欢!
|
||||
|
||||
### 打赏支持~
|
||||
[微信支付](https://view.moezx.cc/images/2018/05/28/WeChanQR.png) | [支付宝](https://view.moezx.cc/images/2018/05/28/AliPayQR.jpg) | [PayPal](https://paypal.me/mashirozx)
|
||||
|
||||
### 需要服务器吗?
|
||||
[![](https://www.vultr.com/media/banners/banner_728x90.png)](https://www.vultr.com/?ref=7674346)
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
vendor
|
||||
cache
|
|
@ -1,2 +0,0 @@
|
|||
main/
|
||||
admin/
|
|
@ -1,291 +0,0 @@
|
|||
{
|
||||
"basic.site.title": {
|
||||
"namespace": "basic.site.title",
|
||||
"public": true,
|
||||
"title": "Site title",
|
||||
"desc": "The site title",
|
||||
"type": "string",
|
||||
"default": "Theme Sakura"
|
||||
},
|
||||
"basic.site.logo": {
|
||||
"namespace": "basic.site.logo",
|
||||
"public": true,
|
||||
"title": "Site logo",
|
||||
"desc": "The site's Logo image, will display on navigation bar.",
|
||||
"type": "mediaPicker",
|
||||
"default": [
|
||||
{
|
||||
"id": 0,
|
||||
"url": "https://v3.vuejs.org/logo.png"
|
||||
}
|
||||
],
|
||||
"binds": {
|
||||
"title": "Select image for site logo.",
|
||||
"button": "Use this image",
|
||||
"type": "image",
|
||||
"multiple": false
|
||||
}
|
||||
},
|
||||
"homepage.slogan": {
|
||||
"namespace": "homepage.slogan",
|
||||
"public": true,
|
||||
"title": "Slogan",
|
||||
"desc": "The slogan text (with typewriter effect), recommend 10-20 characters.",
|
||||
"type": "string",
|
||||
"default": "Hello World!"
|
||||
},
|
||||
"homepage.quote": {
|
||||
"namespace": "homepage.quote",
|
||||
"public": true,
|
||||
"title": "Quote",
|
||||
"desc": "The quote text (behinds the slogan).",
|
||||
"type": "longString",
|
||||
"default": "The most beautiful things in the world cannot be seen or even touched. \nThey must be felt with the heart."
|
||||
},
|
||||
"homepage.signature": {
|
||||
"namespace": "homepage.signature",
|
||||
"public": true,
|
||||
"title": "Signature",
|
||||
"desc": "The signature text (follows the quote).",
|
||||
"type": "string",
|
||||
"default": "—Helen Keller"
|
||||
},
|
||||
"homepage.cover.image": {
|
||||
"namespace": "homepage.cover.image",
|
||||
"public": true,
|
||||
"title": "Cover image",
|
||||
"desc": "Homepage cover image.",
|
||||
"type": "mediaPicker",
|
||||
"default": [
|
||||
{
|
||||
"id": 0,
|
||||
"url": "https://view.moezx.cc/images/2021/06/19/ca4748651c3c67e7e4c29c34fb13bc33.jpg"
|
||||
},
|
||||
{
|
||||
"id": 0,
|
||||
"url": "https://view.moezx.cc/images/2021/07/21/c21fcdbf4cf09674537d928884863ecc.jpg"
|
||||
}
|
||||
],
|
||||
"binds": {
|
||||
"title": "Select image for homepage cover.",
|
||||
"button": "Use this image",
|
||||
"type": "image",
|
||||
"multiple": true
|
||||
}
|
||||
},
|
||||
"social.github": {
|
||||
"namespace": "social.github",
|
||||
"public": true,
|
||||
"title": "Github username",
|
||||
"desc": "Your '<a href=\"https://github.com\" target=\"_blank\">Github</a>' username",
|
||||
"type": "string",
|
||||
"default": ""
|
||||
},
|
||||
"social.gitlab": {
|
||||
"namespace": "social.gitlab",
|
||||
"public": true,
|
||||
"title": "Gitlab username",
|
||||
"desc": "Your '<a href=\"https://gitlab.com\" target=\"_blank\">Gitlab</a>' username",
|
||||
"type": "string",
|
||||
"default": ""
|
||||
},
|
||||
"social.twitter": {
|
||||
"namespace": "social.twitter",
|
||||
"public": true,
|
||||
"title": "Twitter username",
|
||||
"desc": "Your '<a href=\"https://twitter.com\" target=\"_blank\">Twitter</a>' username",
|
||||
"type": "string",
|
||||
"default": ""
|
||||
},
|
||||
"social.weibo": {
|
||||
"namespace": "social.weibo",
|
||||
"public": true,
|
||||
"title": "Weibo username",
|
||||
"desc": "Your '<a href=\"https://weibo.com\" target=\"_blank\">Weibo</a>' username",
|
||||
"type": "string",
|
||||
"default": ""
|
||||
},
|
||||
"social.facebook": {
|
||||
"namespace": "social.facebook",
|
||||
"public": true,
|
||||
"title": "Facebook username",
|
||||
"desc": "Your '<a href=\"https://facebook.com\" target=\"_blank\">Facebook</a>' username",
|
||||
"type": "string",
|
||||
"default": ""
|
||||
},
|
||||
"social.stackoverflow": {
|
||||
"namespace": "social.stackoverflow",
|
||||
"public": true,
|
||||
"title": "Stackoverflow username",
|
||||
"desc": "Your '<a href=\"https://stackoverflow.com\" target=\"_blank\">Stackoverflow</a>' username",
|
||||
"type": "string",
|
||||
"default": ""
|
||||
},
|
||||
"thirdParty.reCaptcha.enable": {
|
||||
"namespace": "thirdParty.reCaptcha.enable",
|
||||
"public": true,
|
||||
"title": "Enable reCAPTCHA",
|
||||
"desc": "Use reCAPTCHA for anti-spam check.",
|
||||
"type": "switcher",
|
||||
"default": false,
|
||||
"binds": {
|
||||
"positiveLabel": "Enabled",
|
||||
"negativeLabel": "Disabled",
|
||||
"disabled": false
|
||||
}
|
||||
},
|
||||
"thirdParty.reCaptcha.version": {
|
||||
"namespace": "thirdParty.reCaptcha.version",
|
||||
"public": true,
|
||||
"title": "reCAPTCHA version",
|
||||
"desc": "Register your reCAPTCHA app '<a href=\"https://www.google.com/recaptcha/about/\" target=\"_blank\">here</a>', and choose a version.",
|
||||
"type": "choose",
|
||||
"default": null,
|
||||
"binds": {
|
||||
"options": [
|
||||
{
|
||||
"label": "reCAPTCHA version 3",
|
||||
"disabled": false
|
||||
},
|
||||
{
|
||||
"label": "reCAPTCHA version 2",
|
||||
"disabled": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"thirdParty.reCaptcha.siteKey": {
|
||||
"namespace": "thirdParty.reCaptcha.siteKey",
|
||||
"public": true,
|
||||
"title": "reCAPTCHA site key",
|
||||
"type": "string",
|
||||
"default": ""
|
||||
},
|
||||
"thirdParty.reCaptcha.secretKey": {
|
||||
"namespace": "thirdParty.reCaptcha.secretKey",
|
||||
"public": false,
|
||||
"title": "reCAPTCHA secret key",
|
||||
"type": "string",
|
||||
"default": ""
|
||||
},
|
||||
"other.hello": {
|
||||
"namespace": "other.hello",
|
||||
"public": true,
|
||||
"title": "Hello world",
|
||||
"type": "string",
|
||||
"default": "world"
|
||||
},
|
||||
"demo.string": {
|
||||
"namespace": "demo.string",
|
||||
"public": true,
|
||||
"title": "String",
|
||||
"desc": "One line string input.",
|
||||
"type": "string",
|
||||
"default": "Hello world!"
|
||||
},
|
||||
"demo.longString": {
|
||||
"namespace": "demo.longString",
|
||||
"public": true,
|
||||
"title": "Long string",
|
||||
"desc": "Textarea for long string input.",
|
||||
"type": "longString",
|
||||
"default": "\"It is the unknown we fear when we look upon death and darkness, nothing more.\"\n-- Albus Dumbledore"
|
||||
},
|
||||
"demo.switcher": {
|
||||
"namespace": "demo.switcher",
|
||||
"public": true,
|
||||
"title": "Switcher",
|
||||
"type": "switcher",
|
||||
"desc": "True/False switcher.",
|
||||
"default": true,
|
||||
"binds": {
|
||||
"positiveLabel": "current on",
|
||||
"negativeLabel": "current off",
|
||||
"disabled": false
|
||||
}
|
||||
},
|
||||
"demo.choose": {
|
||||
"namespace": "demo.choose",
|
||||
"public": true,
|
||||
"title": "Choose",
|
||||
"desc": "Choose one from options.",
|
||||
"type": "choose",
|
||||
"default": null,
|
||||
"binds": {
|
||||
"options": [
|
||||
{
|
||||
"label": "op 1",
|
||||
"disabled": false
|
||||
},
|
||||
{
|
||||
"label": "op 2",
|
||||
"disabled": false
|
||||
},
|
||||
{
|
||||
"label": "op 3",
|
||||
"disabled": false
|
||||
},
|
||||
{
|
||||
"label": "op 4",
|
||||
"disabled": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"demo.selection": {
|
||||
"namespace": "demo.selection",
|
||||
"public": true,
|
||||
"title": "Selection",
|
||||
"desc": "Selection multiple items from options. max: {0: no limit, >0: limit}",
|
||||
"type": "selection",
|
||||
"default": [
|
||||
true,
|
||||
false,
|
||||
true
|
||||
],
|
||||
"binds": {
|
||||
"options": [
|
||||
{
|
||||
"label": "op 1",
|
||||
"disabled": false
|
||||
},
|
||||
{
|
||||
"label": "op 2",
|
||||
"disabled": false
|
||||
},
|
||||
{
|
||||
"label": "op 3",
|
||||
"disabled": false
|
||||
},
|
||||
{
|
||||
"label": "op 4",
|
||||
"disabled": true
|
||||
}
|
||||
],
|
||||
"max": 2
|
||||
}
|
||||
},
|
||||
"demo.mediaPicker": {
|
||||
"namespace": "demo.mediaPicker",
|
||||
"public": true,
|
||||
"title": "Media picker",
|
||||
"desc": "<code>type=\"image\"|\"video\"|\"audio?\"</code>, the object must include id, id=0 for remote media.",
|
||||
"type": "mediaPicker",
|
||||
"default": [
|
||||
{
|
||||
"id": 0,
|
||||
"url": "https://view.moezx.cc/images/2021/07/02/d5ab73174d18652d890e2f4d1b9bef8f.gif"
|
||||
},
|
||||
{
|
||||
"id": 0,
|
||||
"url": "https://view.moezx.cc/images/2021/07/02/a90553bf5b67770e87a89b2ce204eaa7.gif"
|
||||
}
|
||||
],
|
||||
"binds": {
|
||||
"title": "Select Media",
|
||||
"button": "Use this media",
|
||||
"type": "image",
|
||||
"multiple": true
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Sakura\Controllers;
|
||||
|
||||
use Sakura\Controllers\UserController;
|
||||
use Sakura\Controllers\AvatarController;
|
||||
use Sakura\Lib\Exception;
|
||||
|
||||
class AuthorController extends UserController
|
||||
{
|
||||
/**
|
||||
* Get author meta by ID with mutiple fields
|
||||
*
|
||||
* @param integer $author_id
|
||||
* @param array $fields
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function get_author_meta_fields(int $author_id, array $fields)
|
||||
{
|
||||
$author_meta = [];
|
||||
foreach ($fields as $field) {
|
||||
$meta = get_the_author_meta($field, $author_id);
|
||||
if (isset($meta)) {
|
||||
$author_meta[$field] = $meta;
|
||||
} else {
|
||||
throw new Exception("No such author or field: \$id={$author_id}, \$fields={$field}");
|
||||
}
|
||||
}
|
||||
return $author_meta;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get usefull meta fileds of author
|
||||
*
|
||||
* @param integer $author_id
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function get_author_meta(int $author_id)
|
||||
{
|
||||
$fields = ['description', 'display_name', 'nickname', 'user_level', 'user_nicename', 'user_status', 'user_url'];
|
||||
$meta = self::get_author_meta_fields($author_id, $fields);
|
||||
$meta['avatar'] = AvatarController::get_avatar($author_id);
|
||||
return $meta;
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Sakura\Controllers;
|
||||
|
||||
use Sakura\Controllers\BaseController;
|
||||
|
||||
class AvatarController extends BaseController
|
||||
{
|
||||
/**
|
||||
* Get avatar set of all sizes
|
||||
*
|
||||
* @param mixed (int|string) $id_or_email
|
||||
* @return string
|
||||
*/
|
||||
public static function get_avatar($id_or_email)
|
||||
{
|
||||
// TODO: use standard 24/48/96
|
||||
$sizes = [
|
||||
// 'small' => 24,
|
||||
// 'normal' => 48,
|
||||
// 'large' => 96,
|
||||
'24' => 24,
|
||||
'48' => 48,
|
||||
'96' => 96
|
||||
];
|
||||
$avatar_array = [];
|
||||
foreach ($sizes as $key => $value) {
|
||||
$avatar_array[$key] = get_avatar_url($id_or_email, ['size' => $value, 'default' => 'avatar_default']);
|
||||
}
|
||||
return $avatar_array;
|
||||
}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Sakura\Controllers;
|
||||
|
||||
use WP_REST_Controller;
|
||||
|
||||
/**
|
||||
* The controller abstract base
|
||||
* @since 1.0.0
|
||||
* @license GPLv3
|
||||
* @author mashirozx <moezhx@outlook.com>
|
||||
*/
|
||||
class BaseController extends WP_REST_Controller
|
||||
{
|
||||
public static $version = SAKURA_VERSION;
|
||||
public static $text_domain = SAKURA_TEXT_DOMAIN;
|
||||
|
||||
/**
|
||||
* The rest API request parameters
|
||||
* @since 0.0.1
|
||||
* @var WP_REST_Request
|
||||
*/
|
||||
protected $request;
|
||||
|
||||
|
||||
/**
|
||||
* Response status code
|
||||
* @since 0.0.1
|
||||
* @var WP_REST_Request
|
||||
*/
|
||||
protected $code = 200;
|
||||
|
||||
protected function request_parser(\WP_REST_Request $request)
|
||||
{
|
||||
$this->request = $request;
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Sakura\Controllers;
|
||||
|
||||
use Sakura\Controllers\TermController;
|
||||
|
||||
class CategoryController extends TermController
|
||||
{
|
||||
public static function get_the_category(int $post_id)
|
||||
{
|
||||
return get_the_category($post_id);
|
||||
}
|
||||
}
|
|
@ -1,108 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Sakura\Controllers;
|
||||
|
||||
use Sakura\Lib\Exception;
|
||||
use Sakura\Controllers\BaseController;
|
||||
use Sakura\Models\CommentModel;
|
||||
use Sakura\Controllers\AvatarController;
|
||||
use WP_REST_Request;
|
||||
use WP_REST_Response;
|
||||
|
||||
class CommentController extends BaseController
|
||||
{
|
||||
/**
|
||||
* Set comment ancestor_id from meta data when init
|
||||
* @return void
|
||||
*/
|
||||
public static function init_comment_ancestor_meta()
|
||||
{
|
||||
$res = [];
|
||||
$comments = get_comments();
|
||||
foreach ($comments as $comment) {
|
||||
$comment_ID = $comment->comment_ID;
|
||||
// delete_comment_meta($comment_ID, self::$ancestor_id_meta_key);
|
||||
$ancestor_id = CommentModel::get_comment_ancestor_meta($comment_ID);
|
||||
// $ancestor_id = $ancestor_id == false ? false : intval($ancestor_id);
|
||||
// array_push($res, [$comment_ID, $ancestor_id]);
|
||||
if ($ancestor_id === 0) {
|
||||
array_push($res, "[KEEPT] {$comment_ID}:{$ancestor_id} -> {$comment_ID}:{$ancestor_id}");
|
||||
} elseif (empty($ancestor_id)) {
|
||||
$meta = CommentModel::set_comment_ancestor_meta($comment_ID);
|
||||
array_push($res, "[CREATE] {$comment_ID}:{$ancestor_id} -> {$comment_ID}:{$meta}");
|
||||
} elseif (empty(CommentModel::get_comments([$ancestor_id]))) {
|
||||
$meta = CommentModel::update_comment_ancestor_meta($comment_ID);
|
||||
array_push($res, "[UPDATE] {$comment_ID}:{$ancestor_id} -> {$comment_ID}:{$meta}");
|
||||
} else {
|
||||
array_push($res, "[KEEPT] {$comment_ID}:{$ancestor_id} -> {$comment_ID}:{$ancestor_id}");
|
||||
}
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set comment ancestor_id from meta data when init
|
||||
* @return void
|
||||
*/
|
||||
public static function init_comment_user_agent_info_meta()
|
||||
{
|
||||
$res = [];
|
||||
$comments = get_comments();
|
||||
foreach ($comments as $comment) {
|
||||
$comment_ID = $comment->comment_ID;
|
||||
// delete_comment_meta($comment_ID, self::$ancestor_id_meta_key);
|
||||
$user_agent_info = CommentModel::get_comment_user_agent_info_meta($comment_ID);
|
||||
if (empty($user_agent_info)) {
|
||||
$meta = CommentModel::set_comment_user_agent_info_meta($comment_ID);
|
||||
array_push($res, ['type' => 'CREATE', 'ID' => $comment_ID, 'ua' => $meta]);
|
||||
} else {
|
||||
$meta = CommentModel::update_comment_user_agent_info_meta($comment_ID);
|
||||
array_push($res, ['type' => 'UPDATE', 'ID' => $comment_ID, 'ua' => $meta]);
|
||||
}
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get comment's all children/descendant
|
||||
*
|
||||
* @param integer $comment_ID
|
||||
* @param integer $per_page
|
||||
* @param integer $page
|
||||
* @param integer $offset
|
||||
* @param string $order (string) How to order retrieved comments. Accepts 'ASC', 'DESC'. Default: 'DESC'.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_comment_children(int $comment_ID, int $per_page, int $page, int $offset, string $order)
|
||||
{
|
||||
return CommentModel::get_comments_with_public_fields([
|
||||
'meta_key' => CommentModel::$ancestor_id_meta_key,
|
||||
'meta_value' => $comment_ID,
|
||||
'number' => $per_page,
|
||||
'paged' => $page,
|
||||
'offset' => $offset,
|
||||
// (string|array) Comment status or array of statuses. To use 'meta_value' or 'meta_value_num', $meta_key must also be defined. To sort by a specific $meta_query clause, use that clause's array key. Accepts 'comment_agent', 'comment_approved', 'comment_author', 'comment_author_email', 'comment_author_IP', 'comment_author_url', 'comment_content', 'comment_date', 'comment_date_gmt', 'comment_ID', 'comment_karma', 'comment_parent', 'comment_post_ID', 'comment_type', 'user_id', 'comment__in', 'meta_value', 'meta_value_num', the value of $meta_key, and the array keys of $meta_query. Also accepts false, an empty array, or 'none' to disable ORDER BY clause. Default: 'comment_date_gmt'.
|
||||
// TODO: order by 'like'
|
||||
'orderby' => 'comment_date_gmt',
|
||||
'order' => $order,
|
||||
]);
|
||||
}
|
||||
|
||||
public static function get_comment_meta_fields(int $comment_ID)
|
||||
{
|
||||
return CommentModel::get_comment_meta_fields($comment_ID);
|
||||
}
|
||||
|
||||
public static function get_comment_plain(int $comment_ID)
|
||||
{
|
||||
$comment = CommentModel::get_comment($comment_ID);
|
||||
return $comment->comment_content;
|
||||
}
|
||||
|
||||
public static function rest_api_comment_content_filter(array $comment)
|
||||
{
|
||||
$comment['content']['plain'] = self::get_comment_plain($comment['id']);
|
||||
return $comment['content'];
|
||||
}
|
||||
}
|
|
@ -1,109 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Sakura\Controllers;
|
||||
|
||||
use WP_REST_Response;
|
||||
use WP_REST_Request;
|
||||
use WP_Rewrite;
|
||||
|
||||
class InitStateController extends BaseController
|
||||
{
|
||||
public function show(WP_REST_Request $request)
|
||||
{
|
||||
$this->request_parser($request);
|
||||
|
||||
$data = $this->get_initial_state();
|
||||
|
||||
$response = new WP_REST_Response($data);
|
||||
$response->set_status($this->code);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function get_initial_state()
|
||||
{
|
||||
return array(
|
||||
'api_base' => get_rest_url(),
|
||||
'root' => esc_url_raw(rest_url()),
|
||||
'nonce' => wp_create_nonce('wp_rest'),
|
||||
'routing' => $this->get_routing(),
|
||||
'site_info' => $this->get_site_info(),
|
||||
'menus' => (new MenuController)->get_menus(),
|
||||
// 'rewrite_rules' => (new \WP_Rewrite())->rewrite_rules(),
|
||||
'index' => (new WP_Rewrite())->index,
|
||||
'config' => (new OptionController)->get_public_display_options(),
|
||||
// 'recaptcha_site_key' => sakura_options('thirdParty.reCaptcha.siteKey', ''), // use thirdParty.reCaptcha.siteKey
|
||||
);
|
||||
}
|
||||
|
||||
public static function get_routing()
|
||||
{
|
||||
$routing = array(
|
||||
'category_base' => get_option('category_base'),
|
||||
'page_on_front' => null,
|
||||
'page_for_posts' => null,
|
||||
'permalink_structure' => get_option('permalink_structure'),
|
||||
'show_on_front' => get_option('show_on_front'),
|
||||
'tag_base' => get_option('tag_base'),
|
||||
'url' => get_bloginfo('url')
|
||||
);
|
||||
|
||||
if ($routing['show_on_front'] === 'page') {
|
||||
$front_page_id = get_option('page_on_front');
|
||||
$posts_page_id = get_option('page_for_posts');
|
||||
|
||||
if ($front_page_id) {
|
||||
$front_page = get_post($front_page_id);
|
||||
$routing['page_on_front'] = $front_page->post_name;
|
||||
}
|
||||
|
||||
if ($posts_page_id) {
|
||||
$posts_page = get_post($posts_page_id);
|
||||
$routing['page_for_posts'] = $posts_page->post_name;
|
||||
}
|
||||
}
|
||||
|
||||
return $routing;
|
||||
}
|
||||
|
||||
public static function get_site_info()
|
||||
{
|
||||
return array(
|
||||
'woordpress_version' => get_bloginfo('version'),
|
||||
'sakura_version' => self::$version,
|
||||
'sakura_text_domain' => self::$text_domain,
|
||||
'description' => get_bloginfo('description'),
|
||||
'docTitle' => '',
|
||||
'loading' => false,
|
||||
'logo' => get_theme_mod('custom_logo'),
|
||||
'name' => get_bloginfo('name'),
|
||||
'posts_per_page' => get_option('posts_per_page'),
|
||||
'url' => get_bloginfo('url')
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: need auth first
|
||||
public function init_ancestor_meta_show(WP_REST_Request $request)
|
||||
{
|
||||
$this->request_parser($request);
|
||||
|
||||
$data = CommentController::init_comment_ancestor_meta();
|
||||
|
||||
$response = new WP_REST_Response($data);
|
||||
$response->set_status($this->code);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function init_user_agent_info_meta_show(WP_REST_Request $request)
|
||||
{
|
||||
$this->request_parser($request);
|
||||
|
||||
$data = CommentController::init_comment_user_agent_info_meta();
|
||||
|
||||
$response = new WP_REST_Response($data);
|
||||
$response->set_status($this->code);
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Sakura\Controllers;
|
||||
|
||||
use Sakura\Controllers\BaseController;
|
||||
use Sakura\Lib\Exception;
|
||||
|
||||
class MediaController extends BaseController
|
||||
{
|
||||
/**
|
||||
* Markup for wp_upload_dir, drop sensitive fs info
|
||||
*
|
||||
* @return string ie. "http://wp.moezx.cc/wp-content/uploads"
|
||||
*/
|
||||
public static function get_upload_baseurl()
|
||||
{
|
||||
$dir = wp_upload_dir();
|
||||
return $dir['baseurl'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get attachment metadata by attachment_id, also returns the resources' url
|
||||
*
|
||||
* @param integer $attachment_id
|
||||
* @return mixed (array | false) return false if attachment_id is invalid (in rest API post endpoint, WP will return attachment_id as 0, which means there is no attachment)
|
||||
*/
|
||||
public static function get_attachment_metadata(int $attachment_id)
|
||||
{
|
||||
$metadata = wp_get_attachment_metadata($attachment_id);
|
||||
if (!$metadata) {
|
||||
// throw new Exception("Invalid file name. \$attachment_id=$attachment_id");
|
||||
return false;
|
||||
}
|
||||
$file = $metadata['file'];
|
||||
$file_name = basename($file);
|
||||
$subdir = str_replace($file_name, '', $file);
|
||||
$url_prefix = Self::get_upload_baseurl() . '/' . $subdir;
|
||||
|
||||
$metadata['url'] = $url_prefix . $file_name;
|
||||
|
||||
foreach ($metadata['sizes'] as $size => $meta) {
|
||||
$metadata['sizes'][$size]['url'] = $url_prefix . $meta['file'];
|
||||
}
|
||||
return $metadata;
|
||||
}
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Sakura\Controllers;
|
||||
|
||||
use Sakura\Helpers\CustomMenuMetaFieldsHelper;
|
||||
|
||||
class MenuController extends BaseController
|
||||
{
|
||||
public function show(\WP_REST_Request $request)
|
||||
{
|
||||
$this->request_parser($request);
|
||||
|
||||
$location = isset($_GET['location']) ?? $_GET['location'];
|
||||
|
||||
$data = !$location ? $this->get_menus() : $this->get_menu($location);
|
||||
|
||||
$response = new \WP_REST_Response($data);
|
||||
$response->set_status($this->code);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function get_menu_location(string $location_name)
|
||||
{
|
||||
$locations = \get_nav_menu_locations();
|
||||
return $locations[$location_name];
|
||||
}
|
||||
|
||||
public function get_menu($location)
|
||||
{
|
||||
$id = $this->get_menu_location($location);
|
||||
if (!$id) {
|
||||
return [];
|
||||
}
|
||||
$menu_items = \wp_get_nav_menu_items($id, array());
|
||||
$fitered_menu_items = array();
|
||||
foreach ($menu_items as $menu_item) {
|
||||
$fitered_menu_item = array(
|
||||
"id" => $menu_item->ID,
|
||||
'title' => $menu_item->title,
|
||||
'url' => $menu_item->url,
|
||||
'type' => $menu_item->type,
|
||||
'parent' => intval($menu_item->menu_item_parent),
|
||||
);
|
||||
|
||||
foreach (array_keys(CustomMenuMetaFieldsHelper::fileds()) as $name) {
|
||||
$fitered_menu_item[$name] = get_post_meta($menu_item->ID, "_custom_menu_meta_{$name}", true);
|
||||
}
|
||||
|
||||
array_push($fitered_menu_items, $fitered_menu_item);
|
||||
}
|
||||
return $fitered_menu_items;
|
||||
}
|
||||
|
||||
public function get_menus()
|
||||
{
|
||||
$menus = array();
|
||||
// $locations is an array where ([NAME] = MENU_ID);
|
||||
$locations = get_nav_menu_locations();
|
||||
|
||||
foreach (array_keys($locations) as $location) {
|
||||
$menu = $this->get_menu($location);
|
||||
$menus[$location] = $menu;
|
||||
}
|
||||
|
||||
return $menus;
|
||||
}
|
||||
}
|
|
@ -1,203 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Sakura\Controllers;
|
||||
|
||||
use WP_REST_Server;
|
||||
use WP_REST_Request;
|
||||
use WP_Error;
|
||||
use Sakura\Models\OptionModel;
|
||||
|
||||
class OptionController extends BaseController
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @since 5.0.0
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->namespace = 'sakura/v1';
|
||||
$this->rest_base = 'config';
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the routes for comments.
|
||||
*
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @see register_rest_route()
|
||||
*/
|
||||
public function register_routes()
|
||||
{
|
||||
register_rest_route(
|
||||
$this->namespace,
|
||||
'/' . $this->rest_base,
|
||||
array(
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array($this, 'get_public_config'),
|
||||
'permission_callback' => array($this, 'get_public_config_permissions_check'),
|
||||
// 'args' => $this->get_collection_params(),
|
||||
),
|
||||
array(
|
||||
'methods' => WP_REST_Server::EDITABLE,
|
||||
'callback' => array($this, 'update_config'),
|
||||
'permission_callback' => array($this, 'update_config_permissions_check'),
|
||||
// 'args' => $this->get_endpoint_args_for_item_schema(WP_REST_Server::CREATABLE),
|
||||
),
|
||||
// 'schema' => array($this, 'get_public_item_schema'),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public function get_public_config(WP_REST_Request $request)
|
||||
{
|
||||
return $this->get_public_display_options();
|
||||
}
|
||||
|
||||
public function get_public_config_permissions_check(WP_REST_Request $request)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function get_config(WP_REST_Request $request)
|
||||
{
|
||||
$config = (array) OptionModel::get($this->rest_base);
|
||||
if (!$config) {
|
||||
return new WP_Error(
|
||||
'no_such_option',
|
||||
__('Maybe you should save the configuration bufore using it.', self::$text_domain),
|
||||
array('status' => 500)
|
||||
);
|
||||
} else {
|
||||
return $config;
|
||||
}
|
||||
}
|
||||
|
||||
public function get_config_permissions_check(WP_REST_Request $request)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function update_config(WP_REST_Request $request)
|
||||
{
|
||||
$db = (array) $this->get_config($request);
|
||||
$cache = $db;
|
||||
$json = (array) self::json_validate($request->get_body());
|
||||
$hasNoDiff = true;
|
||||
|
||||
foreach ($json as $key => $value) {
|
||||
if (array_key_exists($key, $cache)) {
|
||||
$nv = json_encode($value);
|
||||
$ov = json_encode($cache[$key]);
|
||||
if ($hasNoDiff) $hasNoDiff = $nv === $ov;
|
||||
} else {
|
||||
if ($hasNoDiff) $hasNoDiff = false;
|
||||
}
|
||||
$db[$key] = $value;
|
||||
}
|
||||
|
||||
if ($hasNoDiff) {
|
||||
return [
|
||||
'code' => 'save_config_succeed',
|
||||
'message' => __('Configuration is already up to date.', self::$text_domain),
|
||||
];
|
||||
}
|
||||
|
||||
$config = OptionModel::update($this->rest_base, $db);
|
||||
if (!$config) {
|
||||
return new WP_Error(
|
||||
'save_config_failure',
|
||||
__('Unable to save the configuration.', self::$text_domain),
|
||||
array('status' => 500)
|
||||
);
|
||||
} else {
|
||||
return [
|
||||
'code' => 'save_config_succeed',
|
||||
'message' => __('Configuration saved successfully.', self::$text_domain),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
public function update_config_permissions_check(WP_REST_Request $request)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// public function inite_theme()
|
||||
// {
|
||||
// $config = OptionModel::create($this->rest_base, (array)[]);
|
||||
// }
|
||||
|
||||
public static function json_validate(string $string)
|
||||
{
|
||||
$json = json_decode($string);
|
||||
|
||||
return $json;
|
||||
}
|
||||
|
||||
public function set_key_value(string $key, $value)
|
||||
{
|
||||
$json = (array) OptionModel::get($this->rest_base);
|
||||
if (!$json) {
|
||||
return new WP_Error(
|
||||
'no_such_option',
|
||||
__('Maybe you should save the configuration bufore using it.', self::$text_domain),
|
||||
array('status' => 500)
|
||||
);
|
||||
}
|
||||
$json[$key] = $value;
|
||||
$config = OptionModel::update($this->rest_base, $json);
|
||||
$config = $config ? $config : OptionModel::create($this->rest_base, $json);
|
||||
return $config;
|
||||
}
|
||||
|
||||
public function sakura_options(string $namespace, $default)
|
||||
{
|
||||
$config = (array) OptionModel::get($this->rest_base);
|
||||
if (array_key_exists($namespace, $config)) {
|
||||
return $config[$namespace];
|
||||
} else {
|
||||
$this->set_key_value($namespace, $default);
|
||||
return $default;
|
||||
}
|
||||
// translators: %s: $namespace */
|
||||
// throw new Exception(
|
||||
// sprintf(__("No existing database saving value or default value for option '%s'.", self::$text_domain), $namespace)
|
||||
// );
|
||||
}
|
||||
|
||||
public static function get_option_json()
|
||||
{
|
||||
$options = file_get_contents(__DIR__ . "/../configs/options.json");
|
||||
return json_decode($options, true);
|
||||
}
|
||||
|
||||
public function get_public_display_options()
|
||||
{
|
||||
$output = [];
|
||||
$defaults = (array) self::get_option_json();
|
||||
// return $defaults;
|
||||
foreach ($defaults as $key => $value) {
|
||||
if ($value['public']) {
|
||||
$output[$value['namespace']] = $this->sakura_options($value['namespace'], $value['default']);
|
||||
}
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use in admin page only
|
||||
* @return array
|
||||
*/
|
||||
public function get_all_options()
|
||||
{
|
||||
$output = [];
|
||||
$defaults = (array) self::get_option_json();
|
||||
// return $defaults;
|
||||
foreach ($defaults as $key => $value) {
|
||||
$output[$value['namespace']] = $this->sakura_options($value['namespace'], $value['default']);
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Sakura\Controllers;
|
||||
|
||||
use Sakura\Controllers\PostController;
|
||||
|
||||
class PageController extends PostController
|
||||
{
|
||||
}
|
|
@ -1,118 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Sakura\Controllers;
|
||||
|
||||
use Sakura\Controllers\BaseController;
|
||||
use Sakura\Lib\Exception;
|
||||
use DOMDocument;
|
||||
|
||||
class PostController extends BaseController
|
||||
{
|
||||
/**
|
||||
* Get post comment count
|
||||
*
|
||||
* @param integer $post_id
|
||||
* @return number
|
||||
*/
|
||||
public static function get_comments_number(int $post_id)
|
||||
{
|
||||
return intval(get_comments_number($post_id));
|
||||
}
|
||||
|
||||
public static function get_pagination_info($request)
|
||||
{
|
||||
$the_query = new \WP_Query($_GET);
|
||||
$total_page = $the_query->post_count;
|
||||
return $the_query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get original post expert
|
||||
*
|
||||
* @param integer $post_id
|
||||
* @return string
|
||||
*/
|
||||
public static function get_post_excerpt(int $post_id)
|
||||
{
|
||||
$post = get_post($post_id);
|
||||
if ($post) {
|
||||
// throw new Exception('whoop');
|
||||
return $post->post_excerpt;
|
||||
} else {
|
||||
throw new Exception("No such post \$id={$post_id}!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get post original Markdown content
|
||||
* based on https://wordpress.org/plugins/wp-githuber-md/
|
||||
*
|
||||
* @param integer $post_id
|
||||
* @return mixed string | null
|
||||
*/
|
||||
public static function get_post_markdown(int $post_id)
|
||||
{
|
||||
$post = get_post($post_id);
|
||||
if ($post) {
|
||||
// won't check if post_content_filtered is empty, will check it in js
|
||||
// TODO: global check if markdown available.
|
||||
if (property_exists($post, 'post_content_filtered')) {
|
||||
return html_entity_decode($post->post_content_filtered, ENT_QUOTES);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Content filter
|
||||
*
|
||||
* @param object $post $post obj in register_rest_field
|
||||
* @return object $post content modified
|
||||
*/
|
||||
public static function rest_api_post_content_filter(array $post)
|
||||
{
|
||||
$post['content']['markdown'] = self::get_post_markdown($post['id']);
|
||||
return $post['content'];
|
||||
}
|
||||
|
||||
public static function rest_api_post_excerpt_filter($post)
|
||||
{
|
||||
$post['excerpt']['plain'] = self::get_post_excerpt($post['id']);
|
||||
return $post['excerpt'];
|
||||
}
|
||||
|
||||
public static function get_post_views($post_id)
|
||||
{
|
||||
if (false) {
|
||||
// if (!function_exists('wp_statistics_pages')) {
|
||||
// throw new Exception(__('Please install pulgin WP-Statistics (https://wordpress.org/plugins/wp-statistics)', SAKURA_TEXT_DOMAIN));
|
||||
// } else {
|
||||
// return intval(wp_statistics_pages('total', 'uri', $post_id));
|
||||
// }
|
||||
} else {
|
||||
$views = get_post_meta($post_id, 'views', true);
|
||||
if (!$views) {
|
||||
return 0;
|
||||
} else {
|
||||
return intval($views);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function get_post_word_count($post_id)
|
||||
{
|
||||
$post = get_post($post_id);
|
||||
if ($post) {
|
||||
// return $post->post_content;
|
||||
$doc = new DOMDocument();
|
||||
$internalErrors = libxml_use_internal_errors(true);
|
||||
$doc->loadHTML('<?xml encoding="utf-8" ?>' . $post->post_content);
|
||||
libxml_use_internal_errors($internalErrors);
|
||||
$string = $doc->textContent;
|
||||
$string = preg_replace('/\s+/', '', $string);
|
||||
return strlen($string);
|
||||
}
|
||||
return NAN;
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Sakura\Controllers;
|
||||
|
||||
use Sakura\Controllers\TermController;
|
||||
|
||||
class TagController extends TermController
|
||||
{
|
||||
public static function get_the_tags(int $post_id)
|
||||
{
|
||||
return get_the_tags($post_id);
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Sakura\Controllers;
|
||||
|
||||
use Sakura\Controllers\BaseController;
|
||||
|
||||
/**
|
||||
* Base controller for WP_Term
|
||||
*/
|
||||
class TermController extends BaseController
|
||||
{
|
||||
public static function get_terms(int $post_id)
|
||||
{
|
||||
return get_terms($post_id);
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Sakura\Controllers;
|
||||
|
||||
use Sakura\Controllers\BaseController;
|
||||
|
||||
class ThemeController extends BaseController
|
||||
{
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Sakura\Controllers;
|
||||
|
||||
use Sakura\Controllers\BaseController;
|
||||
use Sakura\Controllers\AvatarController;
|
||||
|
||||
class UserController extends BaseController
|
||||
{
|
||||
/**
|
||||
* Warning: be carefull to use this, use UserController::get_user_public_meta
|
||||
* instead if not necessary
|
||||
*
|
||||
* @param integer $user_id
|
||||
* @param string $key
|
||||
* @param boolean $single
|
||||
*
|
||||
* @return mixed array | false
|
||||
*/
|
||||
public static function get_user_meta(int $user_id, string $key = '', bool $single = false)
|
||||
{
|
||||
return get_user_meta($user_id, $key, $single);
|
||||
}
|
||||
|
||||
public static function get_user_public_meta(int $user_id)
|
||||
{
|
||||
$white_list = ['nickname', 'first_name', 'last_name', 'description', 'wp_user_level'];
|
||||
$meta = self::get_user_meta($user_id);
|
||||
$public_meta = [];
|
||||
|
||||
foreach ($white_list as $key) {
|
||||
$public_meta[$key] = $meta[$key];
|
||||
}
|
||||
|
||||
$public_meta['avatar'] = AvatarController::get_avatar($user_id);
|
||||
|
||||
return $public_meta;
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* The template for displaying the footer
|
||||
*
|
||||
* Contains the closing of the #content div and all content after.
|
||||
*
|
||||
* @link https://developer.wordpress.org/themes/basics/template-files/#template-partials
|
||||
*
|
||||
* @package WordPress
|
||||
* @subpackage Twenty_Twenty_One
|
||||
* @since 1.0.0
|
||||
*/
|
||||
|
||||
?>
|
||||
</div><!-- #app -->
|
||||
|
||||
<?php wp_footer(); ?>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -1,29 +0,0 @@
|
|||
<?php
|
||||
|
||||
// namespace Sakura;
|
||||
|
||||
define('SAKURA_VERSION', wp_get_theme()->get('Version'));
|
||||
define('SAKURA_TEXT_DOMAIN', wp_get_theme()->get('TextDomain'));
|
||||
|
||||
define('SAKURA_DEVEPLOMENT', false);
|
||||
define('SAKURA_DEVEPLOMENT_HOST', 'http://127.0.0.1:9000');
|
||||
|
||||
// PHP loaders
|
||||
require_once(__DIR__ . '/loader.php');
|
||||
|
||||
new Sakura\Helpers\SetupHelper();
|
||||
new Sakura\Helpers\WhoopsHelper();
|
||||
new Sakura\Helpers\ViteHelper();
|
||||
new Sakura\Helpers\AdminPageHelper();
|
||||
new Sakura\Helpers\CustomMenuMetaFieldsHelper();
|
||||
new Sakura\Helpers\CommentHelper();
|
||||
new Sakura\Helpers\PostQueryHelper('post');
|
||||
|
||||
new Sakura\Routers\ApiRouter();
|
||||
new Sakura\Routers\PagesRouter();
|
||||
|
||||
function sakura_options(string $namespace, $default)
|
||||
{
|
||||
$CF = new Sakura\Controllers\OptionController();
|
||||
return $CF->sakura_options($namespace, $default);
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* The header.
|
||||
*
|
||||
* This is the template that displays all of the <head> section and everything up until main.
|
||||
*
|
||||
* @link https://developer.wordpress.org/themes/basics/template-files/#template-partials
|
||||
*
|
||||
* @package WordPress
|
||||
* @subpackage Twenty_Twenty_One
|
||||
* @since 1.0.0
|
||||
*/
|
||||
|
||||
// namespace Sakura;
|
||||
|
||||
// use Sakura\Utils;
|
||||
|
||||
// $template = new Helpers\TemplateHelper();
|
||||
// $params = [
|
||||
// 'language_attributes' => Utils\echo_interceptor('language_attributes'),
|
||||
// 'bloginfo' => Utils\echo_interceptor('bloginfo', 'charset'),
|
||||
// 'wp_head' => Utils\echo_interceptor('wp_head')
|
||||
// ];
|
||||
// echo $template->render('header.twig', $params);
|
||||
|
||||
?>
|
||||
<!doctype html>
|
||||
<html <?php language_attributes(); ?>>
|
||||
|
||||
<head>
|
||||
<meta charset="<?php bloginfo('charset'); ?>" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<?php wp_head(); ?>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app" class="container">
|
||||
<h1>Vite is loading</h1>
|
||||
<p>we will render basic content with PHP here in terms of better SEO.</p>
|
|
@ -1,104 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Sakura\Helpers;
|
||||
|
||||
use Sakura\Helpers\ViteHelper;
|
||||
use Sakura\Controllers\InitStateController;
|
||||
use Sakura\Controllers\OptionController;
|
||||
|
||||
class AdminPageHelper extends ViteHelper
|
||||
{
|
||||
public $page_title;
|
||||
public $menu_title;
|
||||
public $menu_slug;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->page_title = __('Sakura theme options', self::$text_domain);
|
||||
$this->menu_title = __('Sakura Options', self::$text_domain);
|
||||
$this->menu_slug = __('sakura_options', self::$text_domain);
|
||||
add_action('admin_menu', [$this, 'add_theme_page']);
|
||||
add_action('admin_enqueue_scripts', [$this, 'enqueue_scripts']);
|
||||
}
|
||||
|
||||
public function add_theme_page()
|
||||
{
|
||||
add_theme_page($this->page_title, $this->menu_title, 'edit_theme_options', $this->menu_slug, function () {
|
||||
$template = new TemplateHelper();
|
||||
echo $template->load('admin-page-helper.twig')->renderBlock('admin_app', []);
|
||||
});
|
||||
}
|
||||
|
||||
public function enqueue_scripts($hook)
|
||||
{
|
||||
if ("appearance_page_{$this->menu_slug}" === $hook) {
|
||||
$this->enqueue_common_scripts();
|
||||
if (SAKURA_DEVEPLOMENT) {
|
||||
$this->enqueue_development_scripts();
|
||||
} else {
|
||||
$this->enqueue_production_scripts();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function enqueue_development_scripts()
|
||||
{
|
||||
wp_enqueue_script('[type:module]vite-client', self::$development_host . '/@vite/client', array(), null, false);
|
||||
|
||||
wp_enqueue_script('[type:module]dev-main', self::$development_host . '/src/admin/main.ts', array(), null, true);
|
||||
|
||||
wp_localize_script('[type:module]dev-main', 'AdminColors', $this->get_admin_color_css());
|
||||
|
||||
wp_localize_script('[type:module]dev-main', 'InitState', (new InitStateController())->get_initial_state());
|
||||
|
||||
wp_localize_script('[type:module]dev-main', 'SakuraOptions', ['data' => (new OptionController())->get_all_options()]);
|
||||
}
|
||||
|
||||
public function enqueue_production_scripts()
|
||||
{
|
||||
$entry_key = 'src/admin/main.ts';
|
||||
$assets_base_path = get_template_directory_uri() . '/assets/admin/';
|
||||
$manifest = self::get_manifest_file('admin');
|
||||
|
||||
// <script type="module" crossorigin src="http://localhost:9000/assets/index.36b06f45.js"></script>
|
||||
wp_enqueue_script('[type:module]chunk-entrance.js', $assets_base_path . $manifest[$entry_key]['file'], array(), null, false);
|
||||
|
||||
wp_localize_script('[type:module]chunk-entrance.js', 'AdminColors', $this->get_admin_color_css());
|
||||
|
||||
wp_localize_script('[type:module]chunk-entrance.js', 'InitState', (new InitStateController())->get_initial_state());
|
||||
|
||||
wp_localize_script('[type:module]chunk-entrance.js', 'SakuraOptions', ['data' => (new OptionController())->get_all_options()]);
|
||||
|
||||
// <link rel="modulepreload" href="http://localhost:9000/assets/vendor.b3a324ba.js">
|
||||
foreach ($manifest[$entry_key]['imports'] as $index => $import) {
|
||||
wp_enqueue_style("[ref:modulepreload]chunk-vendors{$import}", $assets_base_path . $manifest[$import]['file']);
|
||||
if (empty($manifest[$import]['css'])) {
|
||||
continue;
|
||||
}
|
||||
foreach ($manifest[$import]['css'] as $css_index => $css_path) {
|
||||
wp_enqueue_style("sakura-chunk-{$import}-{$css_index}.css", $assets_base_path . $css_path);
|
||||
}
|
||||
}
|
||||
|
||||
// <link rel="stylesheet" href="http://localhost:9000/assets/index.2c78c25a.css">
|
||||
foreach ($manifest[$entry_key]['css'] as $index => $path) {
|
||||
wp_enqueue_style("sakura-chunk-{$index}.css", $assets_base_path . $path);
|
||||
}
|
||||
}
|
||||
|
||||
public function enqueue_common_scripts()
|
||||
{
|
||||
wp_enqueue_media();
|
||||
|
||||
wp_enqueue_style('style.css', get_template_directory_uri() . '/style.css');
|
||||
|
||||
wp_enqueue_style('fontawesome-free', 'https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.15.3/css/all.min.css');
|
||||
}
|
||||
|
||||
public function get_admin_color_css()
|
||||
{
|
||||
global $_wp_admin_css_colors;
|
||||
$theme = (array) $_wp_admin_css_colors[get_user_option('admin_color')];
|
||||
return $theme;
|
||||
}
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Sakura\Helpers;
|
||||
|
||||
use Sakura\Controllers\CommentController;
|
||||
use Sakura\Models\CommentModel;
|
||||
use WP_Comment;
|
||||
use WP_Theme;
|
||||
|
||||
class CommentHelper
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
add_action('comment_post', [$this, 'create_comment_actions'], 1, 3);
|
||||
add_action('edit_comment', [$this, 'update_comment_actions'], 1, 2);
|
||||
add_action('delete_comment', [$this, 'delete_comment_actions'], 1, 2);
|
||||
|
||||
// TODO: not sure if it's ok to handle a lot of comments? If not ok, provide only the manual method
|
||||
// add_action('after_switch_theme', [$this, 'after_switch_theme_actions'], 1, 2);
|
||||
|
||||
// deprecated, extends class-wp-rest-comments-controller instaed.
|
||||
// add_filter('rest_allow_anonymous_comments', '__return_true');
|
||||
}
|
||||
|
||||
/**
|
||||
* Actions after create comment
|
||||
*
|
||||
* @param integer $comment_ID
|
||||
* @param int|string $comment_approved
|
||||
* @param array $commentdata
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function create_comment_actions(int $comment_ID, $comment_approved, array $commentdata)
|
||||
{
|
||||
CommentModel::set_comment_ancestor_meta($comment_ID);
|
||||
}
|
||||
|
||||
public static function update_comment_actions(int $comment_ID, array $data)
|
||||
{
|
||||
CommentModel::update_comment_ancestor_meta($comment_ID);
|
||||
}
|
||||
|
||||
public static function delete_comment_actions(int $comment_ID, WP_Comment $comment)
|
||||
{
|
||||
// upgrade children/descendant comments' ancestor meta (ancestor means the parent/ancestor whose parent_id === 0)
|
||||
if (CommentModel::get_comment_ancestor_meta($comment_ID) == 0) {
|
||||
$descendant_comments = get_comments([
|
||||
'meta_key' => CommentModel::$ancestor_id_meta_key,
|
||||
'meta_value' => $comment_ID,
|
||||
]);
|
||||
|
||||
$child_comments = get_comments([
|
||||
'parent' => $comment_ID,
|
||||
]);
|
||||
|
||||
// set children's parent to 0
|
||||
foreach ($child_comments as $child_comment) {
|
||||
// https://developer.wordpress.org/reference/functions/wp_insert_comment/
|
||||
wp_update_comment([
|
||||
'comment_ID' => $child_comment->comment_ID,
|
||||
'comment_parent' => 0,
|
||||
], false);
|
||||
}
|
||||
|
||||
// update ancestor for descendant
|
||||
foreach ($descendant_comments as $descendant_comment) {
|
||||
CommentModel::update_comment_ancestor_meta($descendant_comment->comment_ID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function after_switch_theme_actions(string $old_name, WP_Theme $old_theme)
|
||||
{
|
||||
CommentController::init_comment_ancestor_meta();
|
||||
}
|
||||
|
||||
public static function filter_rest_allow_anonymous_comments($false, $request)
|
||||
{
|
||||
// return [
|
||||
// 'code' => 123
|
||||
// ];
|
||||
throw new \Exception("opps");
|
||||
// return true;
|
||||
}
|
||||
}
|
|
@ -1,83 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Sakura\Helpers;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Add custom fields to menu item
|
||||
* https://www.kathyisawesome.com/add-custom-fields-to-wordpress-menu-items/
|
||||
*/
|
||||
class CustomMenuMetaFieldsHelper
|
||||
{
|
||||
public static function fileds()
|
||||
{
|
||||
return [
|
||||
'icon' => [
|
||||
'label' => __('Icon', SAKURA_TEXT_DOMAIN),
|
||||
'desc' => __('Menu item icon', SAKURA_TEXT_DOMAIN),
|
||||
],
|
||||
'class' => [
|
||||
'label' => __('Class', SAKURA_TEXT_DOMAIN),
|
||||
'desc' => __('Menu item class class <code>Array<string></code>', SAKURA_TEXT_DOMAIN),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public static function is_key_in_fields(string $key)
|
||||
{
|
||||
return array_key_exists($key, self::fileds());
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
add_action('wp_nav_menu_item_custom_fields', [$this, 'add_fileds'], 10, 2);
|
||||
add_action('wp_update_nav_menu_item', [$this, 'update_fileds'], 10, 2);
|
||||
}
|
||||
|
||||
public function add_fileds($item_id, $item)
|
||||
{
|
||||
$template = new TemplateHelper();
|
||||
echo $template->load('custom-menu-meta-fields-helper.twig')->renderBlock('id_input', ['item_id' => $item_id,]);
|
||||
|
||||
foreach ($this->fileds() as $key => $value) {
|
||||
wp_nonce_field("custom_menu_meta_{$key}_nonce", "_custom_menu_meta_{$key}_nonce_name");
|
||||
$custom_menu_meta = get_post_meta($item_id, "_custom_menu_meta_{$key}", true);
|
||||
$label = $value['label'];
|
||||
$desc = $value['desc'];
|
||||
$esc_attr_custom_menu_meta = esc_attr($custom_menu_meta);
|
||||
|
||||
echo $template->load('custom-menu-meta-fields-helper.twig')->renderBlock('input_field', [
|
||||
'item_id' => $item_id,
|
||||
'key' => $key,
|
||||
'label' => $label,
|
||||
'esc_attr_custom_menu_meta' => $esc_attr_custom_menu_meta,
|
||||
'desc' => $desc
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* admain-ajax filter
|
||||
*/
|
||||
public function update_fileds($menu_id, $menu_item_db_id)
|
||||
{
|
||||
// throw new Exception("Debug $menu_id");
|
||||
foreach ($this->fileds() as $key => $value) {
|
||||
if (!isset($_POST["_custom_menu_meta_{$key}_nonce_name"])) {
|
||||
// when first add a menu item, this can be empty (undefined)
|
||||
return $menu_id;
|
||||
} else if (!wp_verify_nonce($_POST["_custom_menu_meta_{$key}_nonce_name"], "custom_menu_meta_{$key}_nonce")) {
|
||||
throw new Exception("Invalid `_custom_menu_meta_{$key}_nonce_name` in {$_POST}, \$menu_id={$menu_id}");
|
||||
return $menu_id;
|
||||
}
|
||||
|
||||
if (isset($_POST["custom_menu_meta_{$key}"][$menu_item_db_id])) {
|
||||
$sanitized_data = sanitize_text_field($_POST["custom_menu_meta_{$key}"][$menu_item_db_id]);
|
||||
update_post_meta($menu_item_db_id, "_custom_menu_meta_{$key}", $sanitized_data);
|
||||
} else {
|
||||
delete_post_meta($menu_item_db_id, "_custom_menu_meta_{$key}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Sakura\Helpers;
|
||||
|
||||
class PostQueryHelper
|
||||
{
|
||||
/**
|
||||
* Post type.
|
||||
*
|
||||
* @since 5.0.0
|
||||
* @var string
|
||||
*/
|
||||
protected $post_type;
|
||||
|
||||
public function __construct(string $post_type)
|
||||
{
|
||||
$this->post_type = $post_type;
|
||||
add_filter("rest_{$post_type}_query", [$this, 'filter_rest_post_query'], 10, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter rest posts by category slug
|
||||
*
|
||||
* @param array $args
|
||||
* @param WP_Rest_Rquest $request
|
||||
* @return array $args
|
||||
*/
|
||||
public function filter_rest_post_query($args, $request)
|
||||
{
|
||||
$args['tax_query'] = [];
|
||||
|
||||
$taxonomies = wp_list_filter(get_object_taxonomies($this->post_type, 'objects'), array('show_in_rest' => true));
|
||||
|
||||
foreach ($taxonomies as $taxonomy) {
|
||||
$base = !empty($taxonomy->rest_base) ? $taxonomy->rest_base : $taxonomy->name;
|
||||
|
||||
if (!isset($request["{$base}_slug"])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
array_push($args['tax_query'], [
|
||||
'taxonomy' => $taxonomy->name,
|
||||
'field' => 'slug',
|
||||
'terms' => explode(',', $request["{$base}_slug"]),
|
||||
'include_children' => true,
|
||||
'operator' => 'IN',
|
||||
]);
|
||||
}
|
||||
return $args;
|
||||
}
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Sakura\Helpers;
|
||||
|
||||
/**
|
||||
* @deprecated use apply_filters( "rest_{$this->post_type}_query", array $args, WP_REST_Request $request ) or filter instead
|
||||
*/
|
||||
class RestApiFilterHelper
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
add_action('rest_api_init', [$this, 'rest_api_filter_add_filters']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the necessary filter to each post type
|
||||
**/
|
||||
public function rest_api_filter_add_filters()
|
||||
{
|
||||
foreach (get_post_types(array('show_in_rest' => true), 'objects') as $post_type) {
|
||||
add_filter('rest_' . $post_type->name . '_query', [$this, 'rest_api_filter_add_filter_param'], 10, 2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the filter parameter
|
||||
*
|
||||
* @param array $args The query arguments.
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
* @return array $args.
|
||||
**/
|
||||
public function rest_api_filter_add_filter_param($args, $request)
|
||||
{
|
||||
// Bail out if no filter parameter is set.
|
||||
if (empty($request['filter']) || !is_array($request['filter'])) {
|
||||
return $args;
|
||||
}
|
||||
|
||||
$filter = $request['filter'];
|
||||
|
||||
if (isset($filter['posts_per_page']) && ((int) $filter['posts_per_page'] >= 1 && (int) $filter['posts_per_page'] <= 100)) {
|
||||
$args['posts_per_page'] = $filter['posts_per_page'];
|
||||
}
|
||||
|
||||
global $wp;
|
||||
$vars = apply_filters('rest_query_vars', $wp->public_query_vars);
|
||||
|
||||
// Allow valid meta query vars.
|
||||
$vars = array_unique(array_merge($vars, array('meta_query', 'meta_key', 'meta_value', 'meta_compare')));
|
||||
|
||||
foreach ($vars as $var) {
|
||||
if (isset($filter[$var])) {
|
||||
$args[$var] = $filter[$var];
|
||||
}
|
||||
}
|
||||
return $args;
|
||||
}
|
||||
}
|
|
@ -1,93 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Sakura\Helpers;
|
||||
|
||||
// use Sakura\Controllers\OptionController;
|
||||
|
||||
class SetupHelper
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
add_action('after_setup_theme', [$this, 'setup']);
|
||||
// Disable WP Admin Bar
|
||||
add_filter('show_admin_bar', '__return_false');
|
||||
// TODO: enable this if http?
|
||||
// add_filter('wp_is_application_passwords_available', '__return_true');
|
||||
// Allow rest API CORS.
|
||||
add_action('rest_api_init', [$this, 'wp_rest_allow_all_cors'], 15);
|
||||
// post excerpt more context
|
||||
add_filter('excerpt_more', [$this, 'changes_post_excerpt_more']);
|
||||
// post excerpt length
|
||||
add_filter('excerpt_length', [$this, 'changes_post_excerpt_length'], 10);
|
||||
// count post views
|
||||
add_action('get_header', [$this, 'set_post_views']);
|
||||
// Inite config options
|
||||
// won't need anymore with options?
|
||||
// add_action('after_switch_theme', [new OptionController(), 'inite_theme'], 1, 2);
|
||||
}
|
||||
|
||||
public function setup()
|
||||
{
|
||||
|
||||
add_theme_support('title-tag');
|
||||
|
||||
add_theme_support('post-thumbnails');
|
||||
|
||||
add_theme_support('custom-logo', array(
|
||||
'height' => 160,
|
||||
'width' => 160,
|
||||
));
|
||||
|
||||
register_nav_menus($this->menu_locations());
|
||||
}
|
||||
|
||||
public static function menu_locations()
|
||||
{
|
||||
return [
|
||||
'header_menu' => esc_html('Header Menu (show on page header)', SAKURA_TEXT_DOMAIN),
|
||||
];
|
||||
}
|
||||
|
||||
public static function wp_rest_allow_all_cors()
|
||||
{
|
||||
// Remove the default filter.
|
||||
remove_filter('rest_pre_serve_request', 'rest_send_cors_headers');
|
||||
|
||||
// Add a Custom filter.
|
||||
add_filter('rest_pre_serve_request', function ($value) {
|
||||
header('Access-Control-Allow-Origin: *');
|
||||
header('Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE');
|
||||
header('Access-Control-Allow-Credentials: true');
|
||||
return $value;
|
||||
});
|
||||
}
|
||||
|
||||
public function changes_post_excerpt_more(string $more)
|
||||
{
|
||||
return ' ...';
|
||||
}
|
||||
|
||||
public function changes_post_excerpt_length(int $length)
|
||||
{
|
||||
return 120;
|
||||
}
|
||||
|
||||
/**
|
||||
* Post view times counter
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set_post_views()
|
||||
{
|
||||
if (is_singular()) {
|
||||
global $post;
|
||||
$post_id = intval($post->ID);
|
||||
if ($post_id) {
|
||||
$views = (int) get_post_meta($post_id, 'views', true);
|
||||
if (!update_post_meta($post_id, 'views', ($views + 1))) {
|
||||
add_post_meta($post_id, 'views', 1, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Sakura\Helpers;
|
||||
|
||||
use Twig\Loader\FilesystemLoader;
|
||||
use Twig\Environment;
|
||||
use Twig\TwigFunction;
|
||||
|
||||
/**
|
||||
* Twig engine template loader markup
|
||||
* @since 0.0.1
|
||||
* @license MIT
|
||||
* @author mashirozx <moezhx@outlook.com>
|
||||
*/
|
||||
class TemplateHelper
|
||||
{
|
||||
public $loader;
|
||||
public $twig;
|
||||
public $template;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->loader = new FilesystemLoader(array_map(function ($path) {
|
||||
return __DIR__ . '/' . $path;
|
||||
}, $this->loader_path_array()));
|
||||
$this->twig = new Environment($this->loader);
|
||||
}
|
||||
|
||||
public static function loader_path_array()
|
||||
{
|
||||
return [
|
||||
'../views/helpers',
|
||||
'../views'
|
||||
];
|
||||
}
|
||||
|
||||
public function load($template_name)
|
||||
{
|
||||
$this->template = $this->twig->load($template_name);
|
||||
return $this->template;
|
||||
}
|
||||
|
||||
public function render(...$params)
|
||||
{
|
||||
return $this->twig->render(...$params);
|
||||
}
|
||||
|
||||
public function addFunction($function_names)
|
||||
{
|
||||
if (is_array($function_names)) {
|
||||
foreach ($function_names as $function_name) {
|
||||
$this->twig->addFunction(new TwigFunction($function_name, $function_name));
|
||||
}
|
||||
} elseif (is_string($function_names)) {
|
||||
$this->twig->addFunction(new TwigFunction($function_names, $function_names));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,98 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Sakura\Helpers;
|
||||
|
||||
use Sakura\Lib\BaseClass;
|
||||
use Sakura\Controllers\InitStateController;
|
||||
|
||||
class ViteHelper extends BaseClass
|
||||
{
|
||||
public static $development_host = SAKURA_DEVEPLOMENT_HOST;
|
||||
|
||||
function __construct()
|
||||
{
|
||||
add_action('wp_enqueue_scripts', [$this, 'enqueue_common_scripts']);
|
||||
if (SAKURA_DEVEPLOMENT) {
|
||||
add_action('wp_enqueue_scripts', [$this, 'enqueue_development_scripts']);
|
||||
} else {
|
||||
add_action('wp_enqueue_scripts', [$this, 'enqueue_production_scripts']);
|
||||
}
|
||||
// add tag filters
|
||||
add_filter('script_loader_tag', [$this, 'script_tag_filter'], 10, 3);
|
||||
add_filter('style_loader_tag', [$this, 'style_tag_filter'], 10, 3);
|
||||
}
|
||||
|
||||
public function enqueue_development_scripts()
|
||||
{
|
||||
wp_enqueue_script('[type:module]vite-client', self::$development_host . '/@vite/client', array(), null, false);
|
||||
|
||||
wp_enqueue_script('[type:module]dev-main', self::$development_host . '/src/main.ts', array(), null, true);
|
||||
|
||||
wp_localize_script('[type:module]dev-main', 'InitState', (new InitStateController())->get_initial_state());
|
||||
}
|
||||
|
||||
public function enqueue_production_scripts()
|
||||
{
|
||||
$entry_key = 'src/main.ts';
|
||||
$assets_base_path = get_template_directory_uri() . '/assets/main/';
|
||||
$manifest = $this->get_manifest_file('main');
|
||||
|
||||
// <script type="module" crossorigin src="http://localhost:9000/assets/index.36b06f45.js"></script>
|
||||
wp_enqueue_script('[type:module]chunk-entrance.js', $assets_base_path . $manifest[$entry_key]['file'], array(), null, false);
|
||||
|
||||
wp_localize_script('[type:module]chunk-entrance.js', 'InitState', (new InitStateController())->get_initial_state());
|
||||
|
||||
// <link rel="modulepreload" href="http://localhost:9000/assets/vendor.b3a324ba.js">
|
||||
foreach ($manifest[$entry_key]['imports'] as $index => $import) {
|
||||
wp_enqueue_style("[ref:modulepreload]chunk-vendors{$import}", $assets_base_path . $manifest[$import]['file']);
|
||||
if (empty($manifest[$import]['css'])) {
|
||||
continue;
|
||||
}
|
||||
foreach ($manifest[$import]['css'] as $css_index => $css_path) {
|
||||
wp_enqueue_style("sakura-chunk-{$import}-{$css_index}.css", $assets_base_path . $css_path);
|
||||
}
|
||||
}
|
||||
|
||||
// <link rel="stylesheet" href="http://localhost:9000/assets/index.2c78c25a.css">
|
||||
foreach ($manifest[$entry_key]['css'] as $index => $path) {
|
||||
wp_enqueue_style("sakura-chunk-{$index}.css", $assets_base_path . $path);
|
||||
}
|
||||
}
|
||||
|
||||
public function enqueue_common_scripts()
|
||||
{
|
||||
wp_enqueue_style('style.css', get_template_directory_uri() . '/style.css');
|
||||
|
||||
wp_enqueue_style('fontawesome-free.css', 'https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.15.3/css/all.min.css');
|
||||
|
||||
wp_enqueue_style('normalize.css', 'https://cdn.jsdelivr.net/npm/normalize.css/normalize.css');
|
||||
|
||||
wp_enqueue_script('recaptcha', 'https://www.recaptcha.net/recaptcha/api.js', array(), false, true);
|
||||
}
|
||||
|
||||
public static function script_tag_filter($tag, $handle, $src)
|
||||
{
|
||||
if (preg_match('/^\[([^:]*)\:([^\]]*)\]/', $handle)) {
|
||||
preg_match('/^\[([^:]*)\:([^\]]*)\]/', $handle, $matches, PREG_OFFSET_CAPTURE);
|
||||
$template = new TemplateHelper();
|
||||
$tag = $template->load('vite-require-helper.twig')->renderBlock('script', ['key' => $matches[1][0], 'value' => $matches[2][0], 'src' => esc_url($src)]);
|
||||
}
|
||||
return $tag;
|
||||
}
|
||||
|
||||
public static function style_tag_filter($tag, $handle, $src)
|
||||
{
|
||||
if (preg_match('/^\[([^:]*)\:([^\]]*)\]/', $handle)) {
|
||||
preg_match('/^\[([^:]*)\:([^\]]*)\]/', $handle, $matches, PREG_OFFSET_CAPTURE);
|
||||
$template = new TemplateHelper();
|
||||
$tag = $template->load('vite-require-helper.twig')->renderBlock('style', ['key' => $matches[1][0], 'value' => $matches[2][0], 'href' => esc_url($src)]);
|
||||
}
|
||||
return $tag;
|
||||
}
|
||||
|
||||
public static function get_manifest_file(string $namespace)
|
||||
{
|
||||
$manifest = file_get_contents(__DIR__ . "/../assets/{$namespace}/manifest.json");
|
||||
return json_decode($manifest, true);
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Sakura\Helpers;
|
||||
|
||||
use Whoops\Handler\PrettyPageHandler;
|
||||
use Whoops\Handler\JsonResponseHandler;
|
||||
use Whoops\Handler\PlainTextHandler;
|
||||
use Whoops\Util\Misc;
|
||||
use Whoops\Run;
|
||||
|
||||
class WhoopsHelper
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
if (self::is_debug()) {
|
||||
$whoops = new Run();
|
||||
// TODO: not working??
|
||||
if (wp_is_json_request()) {
|
||||
$whoops->pushHandler(new JsonResponseHandler);
|
||||
} elseif (Misc::isCommandLine()) {
|
||||
$whoops->pushHandler(new PlainTextHandler);
|
||||
} else {
|
||||
$whoops->pushHandler(new PrettyPageHandler);
|
||||
}
|
||||
$whoops->register();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_debug()
|
||||
{
|
||||
return defined('WP_DEBUG') && WP_DEBUG;
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* The main template file
|
||||
*
|
||||
* This is the most generic template file in a WordPress theme
|
||||
* and one of the two required files for a theme (the other being style.css).
|
||||
* It is used to display a page when nothing more specific matches a query.
|
||||
* E.g., it puts together the home page when no home.php file exists.
|
||||
*
|
||||
* @link https://developer.wordpress.org/themes/basics/template-hierarchy/
|
||||
*
|
||||
* @package WordPress
|
||||
* @subpackage Twenty_Twenty_One
|
||||
* @since 1.0.0
|
||||
*/
|
||||
|
||||
get_header();
|
||||
|
||||
if (have_posts()) {
|
||||
|
||||
// Load posts loop.
|
||||
while (have_posts()) {
|
||||
the_post();
|
||||
}
|
||||
|
||||
// Previous/next page navigation.
|
||||
}
|
||||
|
||||
get_footer();
|
|
@ -1,9 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Sakura\Lib;
|
||||
|
||||
class BaseClass
|
||||
{
|
||||
public static $version = SAKURA_VERSION;
|
||||
public static $text_domain = SAKURA_TEXT_DOMAIN;
|
||||
}
|
|
@ -1,141 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Sakura\Lib;
|
||||
|
||||
use WP_REST_Comments_Controller;
|
||||
use WP_Error;
|
||||
use WP_REST_Request;
|
||||
|
||||
class ClassWpRestCommentsController extends WP_REST_Comments_Controller
|
||||
{
|
||||
/**
|
||||
* Checks if a given request has access to create a comment.
|
||||
*
|
||||
* wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php
|
||||
*
|
||||
* Source: https://git.io/JcSan
|
||||
* Modify based on commit 278843f
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
* @return true|WP_Error True if the request has access to create items, error object otherwise.
|
||||
*/
|
||||
public function create_item_permissions_check($request)
|
||||
{
|
||||
if (!is_user_logged_in()) {
|
||||
if (get_option('comment_registration')) {
|
||||
return new WP_Error(
|
||||
'rest_comment_login_required',
|
||||
__('Sorry, you must be logged in to comment.'),
|
||||
array('status' => 401)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters whether comments can be created via the REST API without authentication.
|
||||
*
|
||||
* Enables creating comments for anonymous users.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param bool $allow_anonymous Whether to allow anonymous comments to
|
||||
* be created. Default `false`.
|
||||
* @param WP_REST_Request $request Request used to generate the
|
||||
* response.
|
||||
*/
|
||||
// $allow_anonymous = apply_filters( 'rest_allow_anonymous_comments', false, $request );
|
||||
$allow_anonymous = true;
|
||||
|
||||
if (!$allow_anonymous) {
|
||||
return new WP_Error(
|
||||
'rest_comment_login_required',
|
||||
__('Sorry, you must be logged in to comment.'),
|
||||
array('status' => 401)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Limit who can set comment `author`, `author_ip` or `status` to anything other than the default.
|
||||
if (isset($request['author']) && get_current_user_id() !== $request['author'] && !current_user_can('moderate_comments')) {
|
||||
return new WP_Error(
|
||||
'rest_comment_invalid_author',
|
||||
/* translators: %s: Request parameter. */
|
||||
sprintf(__("Sorry, you are not allowed to edit '%s' for comments."), 'author'),
|
||||
array('status' => rest_authorization_required_code())
|
||||
);
|
||||
}
|
||||
|
||||
if (isset($request['author_ip']) && !current_user_can('moderate_comments')) {
|
||||
if (empty($_SERVER['REMOTE_ADDR']) || $request['author_ip'] !== $_SERVER['REMOTE_ADDR']) {
|
||||
return new WP_Error(
|
||||
'rest_comment_invalid_author_ip',
|
||||
/* translators: %s: Request parameter. */
|
||||
sprintf(__("Sorry, you are not allowed to edit '%s' for comments."), 'author_ip'),
|
||||
array('status' => rest_authorization_required_code())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($request['status']) && !current_user_can('moderate_comments')) {
|
||||
return new WP_Error(
|
||||
'rest_comment_invalid_status',
|
||||
/* translators: %s: Request parameter. */
|
||||
sprintf(__("Sorry, you are not allowed to edit '%s' for comments."), 'status'),
|
||||
array('status' => rest_authorization_required_code())
|
||||
);
|
||||
}
|
||||
|
||||
if (empty($request['post'])) {
|
||||
return new WP_Error(
|
||||
'rest_comment_invalid_post_id',
|
||||
__('Sorry, you are not allowed to create this comment without a post.'),
|
||||
array('status' => 403)
|
||||
);
|
||||
}
|
||||
|
||||
$post = get_post((int) $request['post']);
|
||||
|
||||
if (!$post) {
|
||||
return new WP_Error(
|
||||
'rest_comment_invalid_post_id',
|
||||
__('Sorry, you are not allowed to create this comment without a post.'),
|
||||
array('status' => 403)
|
||||
);
|
||||
}
|
||||
|
||||
if ('draft' === $post->post_status) {
|
||||
return new WP_Error(
|
||||
'rest_comment_draft_post',
|
||||
__('Sorry, you are not allowed to create a comment on this post.'),
|
||||
array('status' => 403)
|
||||
);
|
||||
}
|
||||
|
||||
if ('trash' === $post->post_status) {
|
||||
return new WP_Error(
|
||||
'rest_comment_trash_post',
|
||||
__('Sorry, you are not allowed to create a comment on this post.'),
|
||||
array('status' => 403)
|
||||
);
|
||||
}
|
||||
|
||||
if (!$this->check_read_post_permission($post, $request)) {
|
||||
return new WP_Error(
|
||||
'rest_cannot_read_post',
|
||||
__('Sorry, you are not allowed to read the post for this comment.'),
|
||||
array('status' => rest_authorization_required_code())
|
||||
);
|
||||
}
|
||||
|
||||
if (!comments_open($post->ID)) {
|
||||
return new WP_Error(
|
||||
'rest_comment_closed',
|
||||
__('Sorry, comments are closed for this item.'),
|
||||
array('status' => 403)
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -1,357 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Sakura\Lib;
|
||||
|
||||
use WP_REST_Posts_Controller;
|
||||
use WP_REST_Request;
|
||||
use WP_Error;
|
||||
use WP_Query;
|
||||
|
||||
/**
|
||||
* @deprecated use apply_filters( "rest_{$this->post_type}_query", array $args, WP_REST_Request $request ) instead
|
||||
*/
|
||||
class ClassWpRestPostsController extends WP_REST_Posts_Controller
|
||||
{
|
||||
/**
|
||||
* Retrieves a collection of posts.
|
||||
* Source: https://github.com/WordPress/wordpress-develop/blob/master/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php
|
||||
* Memo: only change $registered = $this->get_collection_params_mod();
|
||||
* Based on commit 5383af8
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
|
||||
*/
|
||||
public function get_items($request)
|
||||
{
|
||||
// Ensure a search string is set in case the orderby is set to 'relevance'.
|
||||
if (!empty($request['orderby']) && 'relevance' === $request['orderby'] && empty($request['search'])) {
|
||||
return new WP_Error(
|
||||
'rest_no_search_term_defined',
|
||||
__('You need to define a search term to order by relevance.'),
|
||||
array('status' => 400)
|
||||
);
|
||||
}
|
||||
|
||||
// Ensure an include parameter is set in case the orderby is set to 'include'.
|
||||
if (!empty($request['orderby']) && 'include' === $request['orderby'] && empty($request['include'])) {
|
||||
return new WP_Error(
|
||||
'rest_orderby_include_missing_include',
|
||||
__('You need to define an include parameter to order by include.'),
|
||||
array('status' => 400)
|
||||
);
|
||||
}
|
||||
|
||||
// Retrieve the list of registered collection query parameters.
|
||||
$registered = $this->get_collection_params_mod();
|
||||
$args = array();
|
||||
|
||||
/*
|
||||
* This array defines mappings between public API query parameters whose
|
||||
* values are accepted as-passed, and their internal WP_Query parameter
|
||||
* name equivalents (some are the same). Only values which are also
|
||||
* present in $registered will be set.
|
||||
*/
|
||||
$parameter_mappings = array(
|
||||
'author' => 'author__in',
|
||||
'author_exclude' => 'author__not_in',
|
||||
'exclude' => 'post__not_in',
|
||||
'include' => 'post__in',
|
||||
'menu_order' => 'menu_order',
|
||||
'offset' => 'offset',
|
||||
'order' => 'order',
|
||||
'orderby' => 'orderby',
|
||||
'page' => 'paged',
|
||||
'parent' => 'post_parent__in',
|
||||
'parent_exclude' => 'post_parent__not_in',
|
||||
'search' => 's',
|
||||
'slug' => 'post_name__in',
|
||||
'status' => 'post_status',
|
||||
);
|
||||
|
||||
/*
|
||||
* For each known parameter which is both registered and present in the request,
|
||||
* set the parameter's value on the query $args.
|
||||
*/
|
||||
foreach ($parameter_mappings as $api_param => $wp_param) {
|
||||
if (isset($registered[$api_param], $request[$api_param])) {
|
||||
$args[$wp_param] = $request[$api_param];
|
||||
}
|
||||
}
|
||||
|
||||
// Check for & assign any parameters which require special handling or setting.
|
||||
$args['date_query'] = array();
|
||||
|
||||
if (isset($registered['before'], $request['before'])) {
|
||||
$args['date_query'][] = array(
|
||||
'before' => $request['before'],
|
||||
'column' => 'post_date',
|
||||
);
|
||||
}
|
||||
|
||||
if (isset($registered['modified_before'], $request['modified_before'])) {
|
||||
$args['date_query'][] = array(
|
||||
'before' => $request['modified_before'],
|
||||
'column' => 'post_modified',
|
||||
);
|
||||
}
|
||||
|
||||
if (isset($registered['after'], $request['after'])) {
|
||||
$args['date_query'][] = array(
|
||||
'after' => $request['after'],
|
||||
'column' => 'post_date',
|
||||
);
|
||||
}
|
||||
|
||||
if (isset($registered['modified_after'], $request['modified_after'])) {
|
||||
$args['date_query'][] = array(
|
||||
'after' => $request['modified_after'],
|
||||
'column' => 'post_modified',
|
||||
);
|
||||
}
|
||||
|
||||
// Ensure our per_page parameter overrides any provided posts_per_page filter.
|
||||
if (isset($registered['per_page'])) {
|
||||
$args['posts_per_page'] = $request['per_page'];
|
||||
}
|
||||
|
||||
if (isset($registered['sticky'], $request['sticky'])) {
|
||||
$sticky_posts = get_option('sticky_posts', array());
|
||||
if (!is_array($sticky_posts)) {
|
||||
$sticky_posts = array();
|
||||
}
|
||||
if ($request['sticky']) {
|
||||
/*
|
||||
* As post__in will be used to only get sticky posts,
|
||||
* we have to support the case where post__in was already
|
||||
* specified.
|
||||
*/
|
||||
$args['post__in'] = $args['post__in'] ? array_intersect($sticky_posts, $args['post__in']) : $sticky_posts;
|
||||
|
||||
/*
|
||||
* If we intersected, but there are no post IDs in common,
|
||||
* WP_Query won't return "no posts" for post__in = array()
|
||||
* so we have to fake it a bit.
|
||||
*/
|
||||
if (!$args['post__in']) {
|
||||
$args['post__in'] = array(0);
|
||||
}
|
||||
} elseif ($sticky_posts) {
|
||||
/*
|
||||
* As post___not_in will be used to only get posts that
|
||||
* are not sticky, we have to support the case where post__not_in
|
||||
* was already specified.
|
||||
*/
|
||||
$args['post__not_in'] = array_merge($args['post__not_in'], $sticky_posts);
|
||||
}
|
||||
}
|
||||
|
||||
$args = $this->prepare_tax_query($args, $request);
|
||||
|
||||
// Force the post_type argument, since it's not a user input variable.
|
||||
$args['post_type'] = $this->post_type;
|
||||
|
||||
/**
|
||||
* Filters WP_Query arguments when querying posts via the REST API.
|
||||
*
|
||||
* The dynamic portion of the hook name, `$this->post_type`, refers to the post type slug.
|
||||
*
|
||||
* Possible hook names include:
|
||||
*
|
||||
* - `rest_post_query`
|
||||
* - `rest_page_query`
|
||||
* - `rest_attachment_query`
|
||||
*
|
||||
* Enables adding extra arguments or setting defaults for a post collection request.
|
||||
*
|
||||
* @since 4.7.0
|
||||
* @since 5.7.0 Moved after the `tax_query` query arg is generated.
|
||||
*
|
||||
* @link https://developer.wordpress.org/reference/classes/wp_query/
|
||||
*
|
||||
* @param array $args Array of arguments for WP_Query.
|
||||
* @param WP_REST_Request $request The REST API request.
|
||||
*/
|
||||
$args = apply_filters("rest_{$this->post_type}_query", $args, $request);
|
||||
$query_args = $this->prepare_items_query($args, $request);
|
||||
$posts_query = new WP_Query();
|
||||
$query_result = $posts_query->query($query_args);
|
||||
|
||||
// Allow access to all password protected posts if the context is edit.
|
||||
if ('edit' === $request['context']) {
|
||||
add_filter('post_password_required', array($this, 'check_password_required'), 10, 2);
|
||||
}
|
||||
|
||||
$posts = array();
|
||||
|
||||
foreach ($query_result as $post) {
|
||||
if (!$this->check_read_permission($post)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$data = $this->prepare_item_for_response($post, $request);
|
||||
$posts[] = $this->prepare_response_for_collection($data);
|
||||
}
|
||||
|
||||
// Reset filter.
|
||||
if ('edit' === $request['context']) {
|
||||
remove_filter('post_password_required', array($this, 'check_password_required'));
|
||||
}
|
||||
|
||||
$page = (int) $query_args['paged'];
|
||||
$total_posts = $posts_query->found_posts;
|
||||
|
||||
if ($total_posts < 1) {
|
||||
// Out-of-bounds, run the query again without LIMIT for total count.
|
||||
unset($query_args['paged']);
|
||||
|
||||
$count_query = new WP_Query();
|
||||
$count_query->query($query_args);
|
||||
$total_posts = $count_query->found_posts;
|
||||
}
|
||||
|
||||
$max_pages = ceil($total_posts / (int) $posts_query->query_vars['posts_per_page']);
|
||||
|
||||
if ($page > $max_pages && $total_posts > 0) {
|
||||
return new WP_Error(
|
||||
'rest_post_invalid_page_number',
|
||||
__('The page number requested is larger than the number of pages available.'),
|
||||
array('status' => 400)
|
||||
);
|
||||
}
|
||||
|
||||
$response = rest_ensure_response($posts);
|
||||
|
||||
$response->header('X-WP-Total', (int) $total_posts);
|
||||
$response->header('X-WP-TotalPages', (int) $max_pages);
|
||||
|
||||
$request_params = $request->get_query_params();
|
||||
$base = add_query_arg(urlencode_deep($request_params), rest_url(sprintf('%s/%s', $this->namespace, $this->rest_base)));
|
||||
|
||||
if ($page > 1) {
|
||||
$prev_page = $page - 1;
|
||||
|
||||
if ($prev_page > $max_pages) {
|
||||
$prev_page = $max_pages;
|
||||
}
|
||||
|
||||
$prev_link = add_query_arg('page', $prev_page, $base);
|
||||
$response->link_header('prev', $prev_link);
|
||||
}
|
||||
if ($max_pages > $page) {
|
||||
$next_page = $page + 1;
|
||||
$next_link = add_query_arg('page', $next_page, $base);
|
||||
|
||||
$response->link_header('next', $next_link);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the 'tax_query' for a collection of posts.
|
||||
*
|
||||
* @since 5.7.0
|
||||
*
|
||||
* @param array $args WP_Query arguments.
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
* @return array Updated query arguments.
|
||||
*/
|
||||
private function prepare_tax_query(array $args, WP_REST_Request $request)
|
||||
{
|
||||
$relation = $request['tax_relation'];
|
||||
|
||||
if ($relation) {
|
||||
$args['tax_query'] = array('relation' => $relation);
|
||||
}
|
||||
|
||||
$taxonomies = wp_list_filter(
|
||||
get_object_taxonomies($this->post_type, 'objects'),
|
||||
array('show_in_rest' => true)
|
||||
);
|
||||
|
||||
foreach ($taxonomies as $taxonomy) {
|
||||
$base = !empty($taxonomy->rest_base) ? $taxonomy->rest_base : $taxonomy->name;
|
||||
|
||||
$tax_include = $request[$base];
|
||||
$tax_exclude = $request[$base . '_exclude'];
|
||||
|
||||
if ($tax_include) {
|
||||
$terms = array();
|
||||
$include_children = false;
|
||||
$operator = 'IN';
|
||||
|
||||
if (rest_is_array($tax_include)) {
|
||||
$terms = $tax_include;
|
||||
} elseif (rest_is_object($tax_include)) {
|
||||
$terms = empty($tax_include['terms']) ? array() : $tax_include['terms'];
|
||||
$include_children = !empty($tax_include['include_children']);
|
||||
|
||||
if (isset($tax_include['operator']) && 'AND' === $tax_include['operator']) {
|
||||
$operator = 'AND';
|
||||
}
|
||||
}
|
||||
|
||||
if ($terms) {
|
||||
$args['tax_query'][] = array(
|
||||
'taxonomy' => $taxonomy->name,
|
||||
'field' => 'slug', // 'term_id',
|
||||
'terms' => $terms,
|
||||
'include_children' => $include_children,
|
||||
'operator' => $operator,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ($tax_exclude) {
|
||||
$terms = array();
|
||||
$include_children = false;
|
||||
|
||||
if (rest_is_array($tax_exclude)) {
|
||||
$terms = $tax_exclude;
|
||||
} elseif (rest_is_object($tax_exclude)) {
|
||||
$terms = empty($tax_exclude['terms']) ? array() : $tax_exclude['terms'];
|
||||
$include_children = !empty($tax_exclude['include_children']);
|
||||
}
|
||||
|
||||
if ($terms) {
|
||||
$args['tax_query'][] = array(
|
||||
'taxonomy' => $taxonomy->name,
|
||||
'field' => 'term_id',
|
||||
'terms' => $terms,
|
||||
'include_children' => $include_children,
|
||||
'operator' => 'NOT IN',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
||||
public function get_public_item_schema_mod()
|
||||
{
|
||||
$schema = $this->get_public_item_schema();
|
||||
$schema['properties']['categories']['items']['type'] = [
|
||||
"string",
|
||||
"integer"
|
||||
];
|
||||
return $schema;
|
||||
}
|
||||
|
||||
public function get_collection_params_mod()
|
||||
{
|
||||
$params = $this->get_collection_params();
|
||||
$new = [
|
||||
"title" => "Term Slug",
|
||||
"description" => "Match terms with the listed Slug.",
|
||||
"type" => "array",
|
||||
"items" => [
|
||||
"type" => "string"
|
||||
]
|
||||
];
|
||||
$params['categories']['oneOf'][0] = $new;
|
||||
return $params;
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
<?php
|
||||
|
||||
// memo: https://learnku.com/articles/5657/laravel-exceptions-exception-and-error-handling
|
||||
|
||||
namespace Sakura\Lib;
|
||||
|
||||
use Exception as BaseException;
|
||||
|
||||
class Exception extends BaseException
|
||||
{
|
||||
public function __construct($message, $code = 0)
|
||||
{
|
||||
parent::__construct($message, $code);
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
<?php
|
||||
/*------------------------------------*\
|
||||
Auto loaders
|
||||
\*------------------------------------*/
|
||||
|
||||
// Composer autoload
|
||||
require_once(__DIR__ . '/vendor/autoload.php');
|
||||
|
||||
// Autoload namespace Sakura
|
||||
spl_autoload_register(function ($class_name) {
|
||||
$namespaces = explode('\\', $class_name);
|
||||
$namespaces_length = count($namespaces);
|
||||
|
||||
if ($namespaces[0] !== 'Sakura') {
|
||||
// new Exception("No such class '{$class_name}'");
|
||||
return;
|
||||
}
|
||||
|
||||
$path = __DIR__;
|
||||
$index = 1;
|
||||
|
||||
foreach ($namespaces as $namespace) {
|
||||
if ($index === 1) {
|
||||
$path .= '';
|
||||
} elseif ($index < $namespaces_length) {
|
||||
$path .= '/' . strtolower($namespace);
|
||||
} else {
|
||||
$path .= '/' . strtolower(preg_replace('%([a-z])([A-Z])%', '\1-\2', $namespace));
|
||||
}
|
||||
$index++;
|
||||
}
|
||||
|
||||
// TODO: check if file exists before require
|
||||
require_once $path . '.php';
|
||||
});
|
|
@ -1,9 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Sakura\Models;
|
||||
|
||||
use Sakura\Lib\BaseClass;
|
||||
|
||||
class BaseModel extends BaseClass
|
||||
{
|
||||
}
|
|
@ -1,231 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Sakura\Models;
|
||||
|
||||
use Sakura\Lib\Exception;
|
||||
use Sakura\Models\BaseModel;
|
||||
use Sakura\Utils\UaParser;
|
||||
use Sakura\Utils\IpParser;
|
||||
use Sakura\Controllers\AvatarController;
|
||||
|
||||
class CommentModel extends BaseModel
|
||||
{
|
||||
public static $ancestor_id_meta_key = 'ancestor_id';
|
||||
public static $user_agent_info_meta_key = 'user_agent_info';
|
||||
public static $user_location_meta_key = 'user_location';
|
||||
|
||||
public static function get_comments(array $comment_IDs)
|
||||
{
|
||||
return get_comments(['comment__in' => $comment_IDs]);
|
||||
}
|
||||
|
||||
public static function get_comment(int $comment_ID)
|
||||
{
|
||||
return get_comment($comment_ID);
|
||||
}
|
||||
|
||||
public static function get_comment_childern(int $comment_ID)
|
||||
{
|
||||
return get_comments(['parent' => $comment_ID]);
|
||||
}
|
||||
|
||||
public static function get_comments_of_post(int $post_id)
|
||||
{
|
||||
return get_comments(['post_id' => $post_id]);
|
||||
}
|
||||
|
||||
public static function get_comment_parent_id(int $comment_ID)
|
||||
{
|
||||
$comment = self::get_comments([$comment_ID]);
|
||||
return intval($comment[0]->comment_parent);
|
||||
}
|
||||
|
||||
public static function get_comment_ancestor_id(int $comment_ID, $target = true)
|
||||
{
|
||||
$parent_id = self::get_comment_parent_id($comment_ID);
|
||||
if ($parent_id > 0) {
|
||||
return self::get_comment_ancestor_id($parent_id, false);
|
||||
} else {
|
||||
return $target ? $parent_id : $comment_ID;
|
||||
}
|
||||
}
|
||||
|
||||
public static function set_comment_ancestor_meta(int $comment_ID)
|
||||
{
|
||||
$ancestor_id = self::get_comment_ancestor_id($comment_ID);
|
||||
add_comment_meta($comment_ID, self::$ancestor_id_meta_key, $ancestor_id, true);
|
||||
return $ancestor_id;
|
||||
}
|
||||
|
||||
public static function update_comment_ancestor_meta(int $comment_ID)
|
||||
{
|
||||
$ancestor_id = self::get_comment_ancestor_id($comment_ID);
|
||||
update_comment_meta($comment_ID, self::$ancestor_id_meta_key, $ancestor_id);
|
||||
return $ancestor_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ancestor id from meta
|
||||
*
|
||||
* @param integer $comment_ID
|
||||
* @param boolean $display If ture, will throw error if meta not exist. If flase, will return NULL if not exist.
|
||||
* @return void
|
||||
*/
|
||||
public static function get_comment_ancestor_meta(int $comment_ID, $display = false)
|
||||
{
|
||||
$ancestor_id = get_comment_meta($comment_ID, self::$ancestor_id_meta_key, true);
|
||||
if ($ancestor_id == '0') {
|
||||
return 0;
|
||||
} elseif (!$ancestor_id) {
|
||||
if ($display) {
|
||||
throw new Exception("Please init ancestor_id first");
|
||||
}
|
||||
return NULL;
|
||||
} else {
|
||||
return intval($ancestor_id);
|
||||
}
|
||||
}
|
||||
|
||||
public static function set_comment_user_agent_info_meta(int $comment_ID)
|
||||
{
|
||||
$user_agent = self::get_comment($comment_ID)->comment_agent;
|
||||
$parser = new UaParser($user_agent);
|
||||
$user_agent_info = $parser->get_public_display_content();
|
||||
add_comment_meta($comment_ID, self::$user_agent_info_meta_key, $user_agent_info, true);
|
||||
return $user_agent_info;
|
||||
}
|
||||
|
||||
public static function update_comment_user_agent_info_meta(int $comment_ID)
|
||||
{
|
||||
$user_agent = self::get_comment($comment_ID)->comment_agent;
|
||||
$parser = new UaParser($user_agent);
|
||||
$user_agent_info = $parser->get_public_display_content();
|
||||
update_comment_meta($comment_ID, self::$user_agent_info_meta_key, $user_agent_info);
|
||||
return $user_agent_info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user agent info from meta
|
||||
*
|
||||
* @param integer $comment_ID
|
||||
* @param boolean $display If ture, will throw error if meta not exist. If flase, will return [] if not exist.
|
||||
* @return void
|
||||
*/
|
||||
public static function get_comment_user_agent_info_meta(int $comment_ID, $display = false)
|
||||
{
|
||||
$user_agent_info = get_comment_meta($comment_ID, self::$user_agent_info_meta_key, false);
|
||||
if (empty($user_agent_info) && $display) {
|
||||
throw new Exception("Please init user_agent_info first");
|
||||
}
|
||||
return $user_agent_info;
|
||||
}
|
||||
|
||||
public static function set_comment_user_location_meta(int $comment_ID)
|
||||
{
|
||||
$comment_author_IP = self::get_comment($comment_ID)->comment_author_IP;
|
||||
$location = IpParser::get_location($comment_author_IP);
|
||||
add_comment_meta($comment_ID, self::$user_location_meta_key, $location, true);
|
||||
return $location;
|
||||
}
|
||||
|
||||
public static function update_comment_user_location_meta(int $comment_ID)
|
||||
{
|
||||
$comment_author_IP = self::get_comment($comment_ID)->comment_author_IP;
|
||||
$location = IpParser::get_location($comment_author_IP);
|
||||
update_comment_meta($comment_ID, self::$user_location_meta_key, $location);
|
||||
return $location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user location from meta
|
||||
*
|
||||
* @param integer $comment_ID
|
||||
* @param boolean $display If ture, will throw error if meta not exist. If flase, will return false if not exist.
|
||||
* @return void
|
||||
*/
|
||||
public static function get_comment_user_location_meta(int $comment_ID, $display = false)
|
||||
{
|
||||
$location = get_comment_meta($comment_ID, self::$user_location_meta_key, true);
|
||||
if (empty($location) && $display) {
|
||||
throw new Exception("Please init user_location first");
|
||||
}
|
||||
return $location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get comment public display meta
|
||||
*
|
||||
* @param array string|array $args Optional. Array or string of arguments. See WP_Comment_Query::__construct() for information on accepted arguments. Default empty.
|
||||
* @return void
|
||||
*/
|
||||
public static function get_comments_with_public_fields(array $args)
|
||||
{
|
||||
$comments = get_comments($args);
|
||||
|
||||
$output_comments = [];
|
||||
|
||||
foreach ($comments as $comment) {
|
||||
$output_comment = [
|
||||
'id' => intval($comment->comment_ID),
|
||||
'post' => intval($comment->comment_post_ID),
|
||||
'parent' => intval($comment->comment_parent),
|
||||
'author' => intval($comment->user_id),
|
||||
'author_name' => $comment->comment_author,
|
||||
// 'comment_author_email' => $comment->comment_author_email,
|
||||
'author_url' => $comment->comment_author_url,
|
||||
// 'comment_author_IP' => $comment->comment_author_IP,
|
||||
'date' => $comment->comment_date,
|
||||
'date_gmt' => $comment->comment_date_gmt,
|
||||
'content' => [
|
||||
'rendered' => '', // TODO
|
||||
'plain' => $comment->comment_content
|
||||
],
|
||||
'link' => '', // TODO: get_comment_link(),
|
||||
// 'comment_karma' => $comment->comment_karma,
|
||||
'status' => $comment->comment_approved === '1' ? 'approved' : '', // TODO
|
||||
// 'comment_agent' => $comment->comment_agent,
|
||||
'type' => $comment->comment_type,
|
||||
'author_avatar_urls' => AvatarController::get_avatar($comment->comment_author_email),
|
||||
];
|
||||
$output_comment['meta_fields'] = self::get_comment_meta_fields($comment->comment_ID);
|
||||
|
||||
array_push($output_comments, $output_comment);
|
||||
}
|
||||
|
||||
return $output_comments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add fields to input array $comment and return it
|
||||
*
|
||||
* @param integer $comment_ID
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function get_comment_meta_fields(int $comment_ID)
|
||||
{
|
||||
$meta = [];
|
||||
|
||||
// $ancestor_id = self::get_comment_ancestor_meta($comment_ID);
|
||||
// if ($ancestor_id === NULL) {
|
||||
// $ancestor_id = self::set_comment_ancestor_meta($comment_ID);
|
||||
// }
|
||||
// $meta['ancestor_id'] = $ancestor_id;
|
||||
|
||||
$user_agent_info = self::get_comment_user_agent_info_meta($comment_ID);
|
||||
if (empty($user_agent_info)) {
|
||||
$user_agent_info = self::set_comment_user_agent_info_meta($comment_ID);
|
||||
}
|
||||
$meta['user_agent_info'] = $user_agent_info;
|
||||
|
||||
$user_location = self::get_comment_user_location_meta($comment_ID);
|
||||
// TODO: not fully tested if '' or false or NULL
|
||||
// TODO: language option
|
||||
if ($user_location === '') {
|
||||
$user_location = self::set_comment_user_location_meta($comment_ID);
|
||||
}
|
||||
$meta['user_location'] = $user_location;
|
||||
|
||||
return $meta;
|
||||
}
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Sakura\Models;
|
||||
|
||||
class OptionModel extends BaseModel
|
||||
{
|
||||
public static $namespace = 'sakura_options';
|
||||
|
||||
public static function the_key(string $key)
|
||||
{
|
||||
return self::$namespace . "_{$key}";
|
||||
}
|
||||
|
||||
public static function create(string $key, $value)
|
||||
{
|
||||
return add_option(self::the_key($key), $value);
|
||||
}
|
||||
|
||||
public static function get(string $key)
|
||||
{
|
||||
return get_option(self::the_key($key));
|
||||
}
|
||||
|
||||
public static function update(string $key, $value)
|
||||
{
|
||||
return update_option(self::the_key($key), $value);
|
||||
}
|
||||
|
||||
public static function delete(string $key)
|
||||
{
|
||||
return delete_option(self::the_key($key));
|
||||
}
|
||||
}
|
|
@ -1,365 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Sakura\Routers;
|
||||
|
||||
use WP_REST_Controller;
|
||||
use WP_REST_Server;
|
||||
use Sakura\Controllers\OptionController;
|
||||
use Sakura\Controllers\InitStateController;
|
||||
use Sakura\Controllers\MenuController;
|
||||
use Sakura\Controllers\PostController;
|
||||
use Sakura\Controllers\AuthorController;
|
||||
use Sakura\Controllers\MediaController;
|
||||
use Sakura\Controllers\CategoryController;
|
||||
use Sakura\Controllers\TagController;
|
||||
use Sakura\Controllers\CommentController;
|
||||
use Sakura\Lib\ClassWpRestCommentsController;
|
||||
use Sakura\Lib\ClassWpRestPostsController;
|
||||
|
||||
class ApiRouter extends WP_REST_Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->namespace = 'sakura/v1';
|
||||
$this->register_rest_routes();
|
||||
$this->register_rest_fields();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add routers
|
||||
* @since 1.0.0
|
||||
* @license MIT
|
||||
* @author mashirozx <moezhx@outlook.com>
|
||||
*/
|
||||
public function register_rest_routes()
|
||||
{
|
||||
// add options support
|
||||
add_action('rest_api_init', [new OptionController(), 'register_routes']);
|
||||
|
||||
add_action('rest_api_init', function () {
|
||||
// theme's initial states
|
||||
register_rest_route(
|
||||
$this->namespace,
|
||||
'/init-state',
|
||||
[
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => [new InitStateController(), 'show'],
|
||||
'permission_callback' => function () {
|
||||
return true;
|
||||
}
|
||||
]
|
||||
);
|
||||
|
||||
// get menu items
|
||||
register_rest_route(
|
||||
$this->namespace,
|
||||
'/menu',
|
||||
[
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => [new MenuController(), 'show'],
|
||||
'permission_callback' => function () {
|
||||
return true;
|
||||
}
|
||||
]
|
||||
);
|
||||
|
||||
// initial comment ancestor meta
|
||||
// TODO: AUTH
|
||||
register_rest_route(
|
||||
$this->namespace,
|
||||
'/init-comments-ancestor-meta',
|
||||
[
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => [new InitStateController(), 'init_ancestor_meta_show'],
|
||||
'permission_callback' => function () {
|
||||
return true;
|
||||
}
|
||||
]
|
||||
);
|
||||
|
||||
// initial comment ua info meta
|
||||
// TODO: AUTH
|
||||
register_rest_route(
|
||||
$this->namespace,
|
||||
'/init-comments-user-agent-info-meta',
|
||||
[
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => [new InitStateController(), 'init_user_agent_info_meta_show'],
|
||||
'permission_callback' => function () {
|
||||
return true;
|
||||
}
|
||||
]
|
||||
);
|
||||
|
||||
$rest_comments_controller = new ClassWpRestCommentsController();
|
||||
|
||||
// custom create comment
|
||||
register_rest_route(
|
||||
$this->namespace,
|
||||
'/comments',
|
||||
[
|
||||
'methods' => WP_REST_Server::CREATABLE,
|
||||
'callback' => [$rest_comments_controller, 'create_item'],
|
||||
'permission_callback' => [$rest_comments_controller, 'create_item_permissions_check'],
|
||||
]
|
||||
);
|
||||
|
||||
// custom edit comment
|
||||
register_rest_route(
|
||||
$this->namespace,
|
||||
'/comments' . '/(?P<id>[\d]+)',
|
||||
array(
|
||||
'args' => array(
|
||||
'id' => array(
|
||||
'description' => __('Unique identifier for the comment.'),
|
||||
'type' => 'integer',
|
||||
),
|
||||
),
|
||||
array(
|
||||
'methods' => WP_REST_Server::EDITABLE,
|
||||
'callback' => [$rest_comments_controller, 'update_item'],
|
||||
'permission_callback' => [$rest_comments_controller, 'update_item_permissions_check'],
|
||||
'args' => $this->get_endpoint_args_for_item_schema(WP_REST_Server::EDITABLE),
|
||||
),
|
||||
array(
|
||||
'methods' => WP_REST_Server::DELETABLE,
|
||||
'callback' => [$rest_comments_controller, 'delete_item'],
|
||||
'permission_callback' => [$rest_comments_controller, 'delete_item_permissions_check'],
|
||||
'args' => array(
|
||||
'force' => array(
|
||||
'type' => 'boolean',
|
||||
'default' => false,
|
||||
'description' => __('Whether to bypass Trash and force deletion.'),
|
||||
),
|
||||
'password' => array(
|
||||
'description' => __('The password for the parent post of the comment (if the post is password protected).'),
|
||||
'type' => 'string',
|
||||
),
|
||||
),
|
||||
),
|
||||
'schema' => array($this, 'get_public_item_schema'),
|
||||
)
|
||||
);
|
||||
|
||||
// @deprecated using PostQueryHelper instaed
|
||||
// $rest_posts_controller = new ClassWpRestPostsController('post');
|
||||
// custom get posts by category slugs
|
||||
// register_rest_route(
|
||||
// $this->namespace,
|
||||
// '/posts',
|
||||
// array(
|
||||
// array(
|
||||
// 'methods' => WP_REST_Server::READABLE,
|
||||
// 'callback' => array($rest_posts_controller, 'get_items'),
|
||||
// 'permission_callback' => array($rest_posts_controller, 'get_items_permissions_check'),
|
||||
// 'args' => $rest_posts_controller->get_collection_params_mod(),
|
||||
// ),
|
||||
// array(
|
||||
// 'methods' => WP_REST_Server::CREATABLE,
|
||||
// 'callback' => array($rest_posts_controller, 'create_item'),
|
||||
// 'permission_callback' => array($rest_posts_controller, 'create_item_permissions_check'),
|
||||
// 'args' => $rest_posts_controller->get_endpoint_args_for_item_schema(WP_REST_Server::CREATABLE),
|
||||
// ),
|
||||
// 'schema' => array($rest_posts_controller, 'get_public_item_schema_mod'),
|
||||
// )
|
||||
// );
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Add fields to existing endpoint
|
||||
* @since 1.0.0
|
||||
* @license MIT
|
||||
* @author mashirozx <moezhx@outlook.com>
|
||||
*/
|
||||
public function register_rest_fields()
|
||||
{
|
||||
// add fields to /posts & /pages endpoint
|
||||
add_action('rest_api_init', function () {
|
||||
$this->register_wp_post_rest_fields(['post', 'page']);
|
||||
});
|
||||
|
||||
// add fields to /comments endpoint
|
||||
add_action('rest_api_init', function () {
|
||||
$this->register_wp_comment_rest_fields(['comment']);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Common method of adding rest api fields to WP_POST output
|
||||
*
|
||||
* @param array $object_type
|
||||
* @return void
|
||||
*/
|
||||
public function register_wp_post_rest_fields(array $object_type)
|
||||
{
|
||||
/**
|
||||
* Add comment_count field to $post
|
||||
*/
|
||||
register_rest_field(
|
||||
$object_type,
|
||||
'comment_count',
|
||||
[
|
||||
'get_callback' => function ($post, $attr, $request, $object_type) {
|
||||
return PostController::get_comments_number($post['id']);
|
||||
},
|
||||
'update_callback' => null,
|
||||
'schema' => null
|
||||
]
|
||||
);
|
||||
|
||||
register_rest_field(
|
||||
$object_type,
|
||||
'view_count',
|
||||
[
|
||||
'get_callback' => function ($post, $attr, $request, $object_type) {
|
||||
return PostController::get_post_views($post['id']);
|
||||
},
|
||||
'update_callback' => null,
|
||||
'schema' => null
|
||||
]
|
||||
);
|
||||
|
||||
register_rest_field(
|
||||
$object_type,
|
||||
'words_count',
|
||||
[
|
||||
'get_callback' => function ($post, $attr, $request, $object_type) {
|
||||
return PostController::get_post_word_count($post['id']);
|
||||
},
|
||||
'update_callback' => null,
|
||||
'schema' => null
|
||||
]
|
||||
);
|
||||
|
||||
/**
|
||||
* Add markdown field to $post['content]
|
||||
*/
|
||||
register_rest_field(
|
||||
$object_type,
|
||||
'content',
|
||||
[
|
||||
'get_callback' => function ($post, $attr, $request, $object_type) {
|
||||
return PostController::rest_api_post_content_filter($post);
|
||||
},
|
||||
'update_callback' => null,
|
||||
'schema' => null
|
||||
]
|
||||
);
|
||||
|
||||
/**
|
||||
* Add plain field to $post['excerpt]
|
||||
*/
|
||||
register_rest_field(
|
||||
$object_type,
|
||||
'excerpt',
|
||||
[
|
||||
'get_callback' => function ($post, $attr, $request, $object_type) {
|
||||
return PostController::rest_api_post_excerpt_filter($post);
|
||||
},
|
||||
'update_callback' => null,
|
||||
'schema' => null
|
||||
]
|
||||
);
|
||||
|
||||
register_rest_field(
|
||||
$object_type,
|
||||
'author_meta',
|
||||
[
|
||||
'get_callback' => function ($post, $attr, $request, $object_type) {
|
||||
return AuthorController::get_author_meta($post['author']);
|
||||
},
|
||||
'update_callback' => null,
|
||||
'schema' => null
|
||||
]
|
||||
);
|
||||
|
||||
register_rest_field(
|
||||
$object_type,
|
||||
'featured_media_meta',
|
||||
[
|
||||
'get_callback' => function ($post, $attr, $request, $object_type) {
|
||||
return MediaController::get_attachment_metadata($post['featured_media']);
|
||||
},
|
||||
'update_callback' => null,
|
||||
'schema' => null
|
||||
]
|
||||
);
|
||||
|
||||
|
||||
register_rest_field(
|
||||
$object_type,
|
||||
'categories_meta',
|
||||
[
|
||||
'get_callback' => function ($post, $attr, $request, $object_type) {
|
||||
return CategoryController::get_the_category($post['id']);
|
||||
},
|
||||
'update_callback' => null,
|
||||
'schema' => null
|
||||
]
|
||||
);
|
||||
|
||||
register_rest_field(
|
||||
$object_type,
|
||||
'tags_meta',
|
||||
[
|
||||
'get_callback' => function ($post, $attr, $request, $object_type) {
|
||||
return TagController::get_the_tags($post['id']);
|
||||
},
|
||||
'update_callback' => null,
|
||||
'schema' => null
|
||||
]
|
||||
);
|
||||
// end of public func
|
||||
}
|
||||
|
||||
/**
|
||||
* Common method of adding rest api fields to WP_COMMENT output
|
||||
*
|
||||
* @param array $object_type
|
||||
* @return void
|
||||
*/
|
||||
public static function register_wp_comment_rest_fields(array $object_type)
|
||||
{
|
||||
/**
|
||||
* Add markdown field to $post['content]
|
||||
*/
|
||||
register_rest_field(
|
||||
$object_type,
|
||||
'content',
|
||||
[
|
||||
'get_callback' => function ($comment, $attr, $request, $object_type) {
|
||||
return CommentController::rest_api_comment_content_filter($comment);
|
||||
},
|
||||
'update_callback' => null,
|
||||
'schema' => null
|
||||
]
|
||||
);
|
||||
|
||||
// get the custom meta fields
|
||||
register_rest_field(
|
||||
$object_type,
|
||||
'meta_fields',
|
||||
[
|
||||
'get_callback' => function ($comment, $attr, $request, $object_type) {
|
||||
return CommentController::get_comment_meta_fields($comment['id']);
|
||||
},
|
||||
'update_callback' => null,
|
||||
'schema' => null
|
||||
]
|
||||
);
|
||||
|
||||
// get comment children preview
|
||||
// register_rest_field(
|
||||
// $object_type,
|
||||
// 'children_preview',
|
||||
// [
|
||||
// 'get_callback' => function ($comment, $attr, $request, $object_type) {
|
||||
// return CommentController::get_comment_children($comment['id'], 3, 1, 0, 'DESC');
|
||||
// },
|
||||
// 'update_callback' => null,
|
||||
// 'schema' => null
|
||||
// ]
|
||||
// );
|
||||
}
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Sakura\Routers;
|
||||
|
||||
class PagesRouter
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->add_rewrite_rules();
|
||||
}
|
||||
|
||||
public function add_rewrite_rules()
|
||||
{
|
||||
// This is the front end auth page. Add this rewrite rule
|
||||
// to avoid 404 message when auth page first load, so the
|
||||
// response from PHP can be a blank page.
|
||||
// TODO: blank
|
||||
add_action('init', function () {
|
||||
add_rewrite_rule('sakura/auth$', 'index.php', 'top');
|
||||
});
|
||||
|
||||
// TODO: Docker health check route
|
||||
// add_action('init', function () {
|
||||
// add_rewrite_rule('health$', 'index.php', 'top');
|
||||
// });
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Sakura\Services;
|
||||
|
||||
class PostCommentService
|
||||
{
|
||||
// public function create_comment(){
|
||||
// wp_insert_comment()
|
||||
// }
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
/*
|
||||
Theme Name: sakura-next
|
||||
Author: Mashiro
|
||||
Author URI: https://github.com/mashirozx
|
||||
Description: Next generation Sakura theme.
|
||||
Version: 5.0.0
|
||||
Text Domain: sakura-next
|
||||
*/
|
||||
|
||||
.grecaptcha-badge {
|
||||
opacity: 0;
|
||||
}
|
|
@ -1,145 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Sakura\Utils;
|
||||
|
||||
use Sakura\Lib\Exception;
|
||||
use GeoIp2\Database\Reader;
|
||||
use Ritaswc\ZxIPAddress\IPTool;
|
||||
|
||||
class IpParser
|
||||
{
|
||||
public static $version = SAKURA_VERSION;
|
||||
public static $text_domain = SAKURA_TEXT_DOMAIN;
|
||||
|
||||
public static function get_location(string $ip)
|
||||
{
|
||||
try {
|
||||
// return self::get_ip_location_geoip2_string($ip);
|
||||
return self::get_ip_location_qqwary_string($ip);
|
||||
} catch (Exception $e) {
|
||||
return self::message()['unknown_error'] . " [current: {$ip}]";
|
||||
}
|
||||
}
|
||||
|
||||
public static function get_ip_location_qqwary_string(string $ip)
|
||||
{
|
||||
return preg_replace('/\s+/', ' ', self::get_ip_location_qqwary($ip)['disp']);
|
||||
}
|
||||
|
||||
public static function get_ip_location_geoip2_string(string $ip)
|
||||
{
|
||||
// de en es fr ja pt-BR ru zh-CN
|
||||
$lang = "zh-CN";
|
||||
if (self::is_private_ip($ip)) {
|
||||
return [self::message()['private']];
|
||||
}
|
||||
$db = self::get_ip_location_geoip2($ip);
|
||||
$city = self::auto_select_geoip2_lang($lang, $db->city->names);
|
||||
$subdivisions = self::auto_select_geoip2_lang($lang, $db->subdivisions[0]->names);
|
||||
$country = self::auto_select_geoip2_lang($lang, $db->country->names);
|
||||
$array = [$city, $subdivisions, $country];
|
||||
if ($lang === 'zh-CN' || 'ja') {
|
||||
$array = array_reverse($array);
|
||||
}
|
||||
return join(" ", array_filter($array));
|
||||
}
|
||||
|
||||
private static function auto_select_geoip2_lang(string $default, array $names)
|
||||
{
|
||||
return $names[$default] ?? $names['en'] ?? $names['zh-CN'] ?? $names['de'] ?? $names['es'] ?? $names['fr'] ?? $names['ja'] ?? $names['ru'] ?? $names['pt-BR'] ?? '';
|
||||
}
|
||||
|
||||
public static function message()
|
||||
{
|
||||
return [
|
||||
'private' => __("Intranet", self::$text_domain),
|
||||
'nomatch' => __("Earth", self::$text_domain),
|
||||
'unknown_error' => __("IP parser handling error.", self::$text_domain),
|
||||
];
|
||||
}
|
||||
|
||||
// https://github.com/maxmind/GeoIP2-php#readme
|
||||
public static function get_ip_location_geoip2(string $ip)
|
||||
{
|
||||
if (self::is_private_ip($ip)) {
|
||||
throw new Exception("GeoIP2 doesn't support private IP range. [current: {$ip}]");
|
||||
}
|
||||
$reader = new Reader(__DIR__ . '/../cache/GeoLite2-City.mmdb');
|
||||
$record = $reader->city($ip);
|
||||
return $record;
|
||||
}
|
||||
|
||||
public static function get_ip_location_qqwary(string $ip)
|
||||
{
|
||||
return IPTool::query($ip);
|
||||
}
|
||||
|
||||
static public function is_ip($ip = NULL): bool
|
||||
{
|
||||
return filter_var(
|
||||
$ip,
|
||||
FILTER_VALIDATE_IP,
|
||||
FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6
|
||||
) === $ip ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
static public function is_ipv4($ip = NULL): bool
|
||||
{
|
||||
return filter_var(
|
||||
$ip,
|
||||
FILTER_VALIDATE_IP,
|
||||
FILTER_FLAG_IPV4
|
||||
) === $ip ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
static public function is_ipv6($ip = NULL): bool
|
||||
{
|
||||
return filter_var(
|
||||
$ip,
|
||||
FILTER_VALIDATE_IP,
|
||||
FILTER_FLAG_IPV6
|
||||
) === $ip ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
static public function is_public_ip($ip = NULL): bool
|
||||
{
|
||||
return filter_var(
|
||||
$ip,
|
||||
FILTER_VALIDATE_IP,
|
||||
FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE
|
||||
) === $ip ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
static public function is_public_ipv4($ip = NULL): bool
|
||||
{
|
||||
return filter_var(
|
||||
$ip,
|
||||
FILTER_VALIDATE_IP,
|
||||
FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE
|
||||
) === $ip ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
static public function is_public_ipv6($ip = NULL): bool
|
||||
{
|
||||
return filter_var(
|
||||
$ip,
|
||||
FILTER_VALIDATE_IP,
|
||||
FILTER_FLAG_IPV6 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE
|
||||
) === $ip ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
static public function is_private_ip($ip = NULL): bool
|
||||
{
|
||||
return self::is_ip($ip) && !self::is_public_ip($ip);
|
||||
}
|
||||
|
||||
static public function is_private_ipv4($ip = NULL): bool
|
||||
{
|
||||
return self::is_ipv4($ip) && !self::is_public_ipv4($ip);
|
||||
}
|
||||
|
||||
static public function is_private_ipv6($ip = NULL): bool
|
||||
{
|
||||
return self::is_ipv6($ip) && !self::is_public_ipv6($ip);
|
||||
}
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Sakura\Utils;
|
||||
|
||||
use Rogervila\ArrayDiffMultidimensional;
|
||||
|
||||
class Tools
|
||||
{
|
||||
public static function echo_interceptor(callable $callback, ...$args)
|
||||
{
|
||||
ob_start();
|
||||
call_user_func($callback, ...$args);
|
||||
$output = ob_get_contents();
|
||||
ob_end_clean();
|
||||
return $output;
|
||||
}
|
||||
|
||||
public static function get_text_from_dom($node, $text)
|
||||
{
|
||||
if (!is_null($node->childNodes)) {
|
||||
foreach ($node->childNodes as $node) {
|
||||
$text = self::get_text_from_dom($node, $text);
|
||||
}
|
||||
} else {
|
||||
return $text . $node->textContent . ' ';
|
||||
}
|
||||
return $text;
|
||||
}
|
||||
|
||||
/**
|
||||
* https://stackoverflow.com/a/3877494/8083009
|
||||
*
|
||||
* @param array $aArray1
|
||||
* @param array $aArray2
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function array_recursive_diff(array $aArray1, array $aArray2)
|
||||
{
|
||||
$aReturn = array();
|
||||
|
||||
foreach ($aArray1 as $mKey => $mValue) {
|
||||
if (array_key_exists($mKey, $aArray2)) {
|
||||
if (is_array($mValue)) {
|
||||
$aRecursiveDiff = self::array_recursive_diff($mValue, $aArray2[$mKey]);
|
||||
if (count($aRecursiveDiff)) {
|
||||
$aReturn[$mKey] = $aRecursiveDiff;
|
||||
}
|
||||
} else {
|
||||
if ($mValue != $aArray2[$mKey]) {
|
||||
$aReturn[$mKey] = $mValue;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$aReturn[$mKey] = $mValue;
|
||||
}
|
||||
}
|
||||
return $aReturn;
|
||||
}
|
||||
}
|
|
@ -1,76 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Sakura\Utils;
|
||||
|
||||
use WhichBrowser\Parser;
|
||||
|
||||
class UaParser
|
||||
{
|
||||
private $result;
|
||||
|
||||
public function __construct(string $ua)
|
||||
{
|
||||
$this->result = new Parser($ua);
|
||||
}
|
||||
|
||||
public function get_browser_name()
|
||||
{
|
||||
return $this->result->browser->getName();
|
||||
}
|
||||
|
||||
public function get_browser_version()
|
||||
{
|
||||
return $this->result->browser->getVersion();
|
||||
}
|
||||
|
||||
public function get_engine_name()
|
||||
{
|
||||
return $this->result->engine->getName();
|
||||
}
|
||||
|
||||
public function get_engine_version()
|
||||
{
|
||||
return $this->result->engine->getVersion();
|
||||
}
|
||||
|
||||
public function get_os_name()
|
||||
{
|
||||
return $this->result->os->getName();
|
||||
}
|
||||
|
||||
public function get_os_version()
|
||||
{
|
||||
return $this->result->os->getVersion();
|
||||
}
|
||||
|
||||
public function get_manufacturer()
|
||||
{
|
||||
return $this->result->device->getManufacturer();
|
||||
}
|
||||
|
||||
public function get_model()
|
||||
{
|
||||
return $this->result->device->getModel();
|
||||
}
|
||||
|
||||
public function get_device_type()
|
||||
{
|
||||
// TODO: does this need any exception handling?
|
||||
return $this->result->device->type;
|
||||
}
|
||||
|
||||
public function get_public_display_content()
|
||||
{
|
||||
return [
|
||||
'os_name' => $this->get_os_name(),
|
||||
'os_version' => $this->get_os_version(),
|
||||
'browser_name' => $this->get_browser_name(),
|
||||
'browser_version' => $this->get_browser_version(),
|
||||
'engine_name' => $this->get_engine_name(),
|
||||
'engine_version' => $this->get_engine_version(),
|
||||
'manufacturer' => $this->get_manufacturer(),
|
||||
'model' => $this->get_model(),
|
||||
'device_type' => $this->get_device_type(),
|
||||
];
|
||||
}
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
<head>
|
||||
<meta charset="{{bloginfo}}"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
{{wp_head}}
|
||||
</head>
|
|
@ -1,5 +0,0 @@
|
|||
{% block admin_app %}
|
||||
<div id="app" class="sakura-options-page__app" style="{{scheme}}">
|
||||
Loading
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -1,14 +0,0 @@
|
|||
{% block id_input %}
|
||||
<input type="hidden" class="nav-menu-id" value="{{item_id}}"/>
|
||||
{% endblock %}
|
||||
|
||||
{% block input_field %}
|
||||
<p class="field-custom-{{key}} description description-wide">
|
||||
<label for="custom-menu-meta-{{key}}-{{item_id}}">
|
||||
{{label}}
|
||||
<br>
|
||||
<input type="text" name="custom_menu_meta_{{key}}[{{item_id}}]" id="custom-menu-meta-{{key}}-{{item_id}}" class="widefat edit-menu-item-custom-menu-meta-{{key}}" value="{{esc_attr_custom_menu_meta}}"/>
|
||||
</label>
|
||||
{{desc}}
|
||||
</p>
|
||||
{% endblock %}
|
|
@ -1,7 +0,0 @@
|
|||
{% block style %}
|
||||
<link {{key}}="{{value}}" href="{{href}}">
|
||||
{% endblock %}
|
||||
|
||||
{% block script %}
|
||||
<script {{key}}="{{value}}" crossorigin src="{{src}}"></script>
|
||||
{% endblock %}
|
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
/**
|
||||
* The template for displaying archive pages.
|
||||
*
|
||||
* @link https://codex.wordpress.org/Template_Hierarchy
|
||||
*
|
||||
* @package Akina
|
||||
*/
|
||||
|
||||
get_header(); ?>
|
||||
|
||||
<div id="primary" class="content-area">
|
||||
<main id="main" class="site-main" role="main">
|
||||
|
||||
<?php
|
||||
if ( have_posts() ) : ?>
|
||||
|
||||
<?php if(akina_option('patternimg') || !z_taxonomy_image_url()) { ?>
|
||||
<header class="page-header">
|
||||
<h1 class="cat-title"><?php single_cat_title('', true); ?></h1>
|
||||
<span class="cat-des">
|
||||
<?php
|
||||
if(category_description() != ""){
|
||||
echo "" . category_description();
|
||||
}
|
||||
?>
|
||||
</span>
|
||||
</header><!-- .page-header -->
|
||||
<?php } // page-header ?>
|
||||
|
||||
<?php
|
||||
/* Start the Loop */
|
||||
while ( have_posts() ) : the_post();
|
||||
/*
|
||||
* 图片展示分类
|
||||
*/
|
||||
if ( akina_option('image_category') && is_category(explode(',',akina_option('image_category'))) ){
|
||||
get_template_part( 'tpl/content', 'category' );
|
||||
} else {
|
||||
get_template_part( 'tpl/content', get_post_format() );
|
||||
}
|
||||
|
||||
endwhile;
|
||||
?>
|
||||
<div class="clearer"></div>
|
||||
|
||||
<?php else :
|
||||
|
||||
get_template_part( 'tpl/content', 'none' );
|
||||
|
||||
endif; ?>
|
||||
|
||||
</main><!-- #main -->
|
||||
<?php if ( akina_option('pagenav_style') == 'ajax') { ?>
|
||||
<div id="pagination" <?php if(akina_option('image_category') && is_category(explode(',',akina_option('image_category')))) echo 'class="pagination-archive"'; ?>><?php next_posts_link(' Previous'); ?></div>
|
||||
<div id="add_post"><span id="add_post_time" style="visibility: hidden;" title="<?php echo akina_option('auto_load_post',''); ?>" ></span></div>
|
||||
<?php }else{ ?>
|
||||
<nav class="navigator">
|
||||
<?php previous_posts_link('<i class="iconfont icon-back"></i>') ?><?php next_posts_link('<i class="iconfont icon-right"></i>') ?>
|
||||
</nav>
|
||||
<?php } ?>
|
||||
</div><!-- #primary -->
|
||||
|
||||
<?php
|
||||
get_footer();
|
|
@ -0,0 +1,86 @@
|
|||
<?php
|
||||
|
||||
get_header();
|
||||
|
||||
?>
|
||||
<div class="author_info">
|
||||
<div class="avatar">
|
||||
<img src="<?php echo get_avatar_profile_url(); ?>" itemprop="image" alt="<?php the_author(); ?>" height="70" width="70">
|
||||
</div>
|
||||
<div class="author-center">
|
||||
<h3><?php the_author() ?></h3>
|
||||
<div class="description"><?php echo get_the_author_meta( 'description' ) ? get_the_author_meta( 'description' ) : akina_option('admin_des', 'Carpe Diem and Do what I like'); ?></div>
|
||||
</div>
|
||||
</div>
|
||||
<style type="text/css">
|
||||
.author_info{
|
||||
margin-top: 50px;
|
||||
overflow: hidden;
|
||||
padding: 40px 0;
|
||||
position: relative;
|
||||
border-bottom: 1px solid #eee;
|
||||
font-family: miranafont,"Hiragino Sans GB",STXihei,"Microsoft YaHei",SimSun,sans-serif;
|
||||
}
|
||||
.author_info .avatar{
|
||||
float: left;
|
||||
margin-right: 12px;
|
||||
margin-left: 8px;
|
||||
}
|
||||
.author_info .avatar img{
|
||||
border-radius: 100%;
|
||||
border: 2px solid #fff;
|
||||
background: #fff;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.author_info .author-center{
|
||||
line-height: 28px;
|
||||
padding-top: 9px;
|
||||
}
|
||||
.author_info .author-center h3{
|
||||
font-weight: 700;
|
||||
font-size: 20px;
|
||||
line-height: 1.2;
|
||||
margin-bottom: 5px;
|
||||
display: inline;
|
||||
}
|
||||
.author-description {
|
||||
font-size: 14px;
|
||||
color: rgba(0,0,0,.4);
|
||||
line-height: 1.2;
|
||||
}
|
||||
</style>
|
||||
<div id="primary" class="content-area">
|
||||
<main id="main" class="site-main" role="main">
|
||||
|
||||
<?php
|
||||
if ( have_posts() ) :
|
||||
/* Start the Loop */
|
||||
while ( have_posts() ) : the_post();
|
||||
/*
|
||||
* Include the Post-Format-specific template for the content.
|
||||
* If you want to override this in a child theme, then include a file
|
||||
* called content-___.php (where ___ is the Post Format name) and that will be used instead.
|
||||
*/
|
||||
get_template_part( 'tpl/content', get_post_format() );
|
||||
endwhile;
|
||||
?>
|
||||
<div class="clearer"></div>
|
||||
<?php else :
|
||||
|
||||
get_template_part( 'tpl/content', 'none' );
|
||||
|
||||
endif; ?>
|
||||
|
||||
</main><!-- #main -->
|
||||
<?php if ( akina_option('pagenav_style') == 'ajax') { ?>
|
||||
<div id="pagination"><?php next_posts_link(' Previous'); ?></div>
|
||||
<div id="add_post"><span id="add_post_time" style="visibility: hidden;" title="<?php echo akina_option('auto_load_post',''); ?>" ></span></div>
|
||||
<?php }else{ ?>
|
||||
<nav class="navigator">
|
||||
<?php previous_posts_link('<i class="iconfont icon-back"></i>') ?><?php next_posts_link('<i class="iconfont icon-right"></i>') ?>
|
||||
</nav>
|
||||
<?php } ?>
|
||||
</div><!-- #primary -->
|
||||
|
||||
<?php
|
||||
get_footer();
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,6 @@
|
|||
/*!
|
||||
* baguetteBox.js
|
||||
* @author feimosi
|
||||
* @version 1.11.0
|
||||
* @url https://github.com/feimosi/baguetteBox.js
|
||||
*/#baguetteBox-overlay{display:none;opacity:0;position:fixed;overflow:hidden;top:0;left:0;width:100%;height:100%;z-index:1000000;background-color:#222;background-color:rgba(0,0,0,.8);-webkit-transition:opacity .5s ease;transition:opacity .5s ease}#baguetteBox-overlay.visible{opacity:1}#baguetteBox-overlay .full-image{display:inline-block;position:relative;width:100%;height:100%;text-align:center}#baguetteBox-overlay .full-image figure{display:inline;margin:0;height:100%}#baguetteBox-overlay .full-image img{display:inline-block;width:auto;height:auto;max-height:100%;max-width:100%;vertical-align:middle;-webkit-box-shadow:0 0 8px rgba(0,0,0,.6);-moz-box-shadow:0 0 8px rgba(0,0,0,.6);box-shadow:0 0 8px rgba(0,0,0,.6)}#baguetteBox-overlay .full-image figcaption{display:block;position:absolute;bottom:0;width:100%;text-align:center;line-height:1.8;white-space:normal;color:#ccc;background-color:#000;background-color:rgba(0,0,0,.6);font-family:sans-serif}#baguetteBox-overlay .full-image:before{content:"";display:inline-block;height:50%;width:1px;margin-right:-1px}#baguetteBox-slider{position:absolute;left:0;top:0;height:100%;width:100%;white-space:nowrap;-webkit-transition:left .4s ease,-webkit-transform .4s ease;transition:left .4s ease,-webkit-transform .4s ease;transition:left .4s ease,transform .4s ease;transition:left .4s ease,transform .4s ease,-webkit-transform .4s ease,-moz-transform .4s ease}#baguetteBox-slider.bounce-from-right{-webkit-animation:bounceFromRight .4s ease-out;animation:bounceFromRight .4s ease-out}#baguetteBox-slider.bounce-from-left{-webkit-animation:bounceFromLeft .4s ease-out;animation:bounceFromLeft .4s ease-out}@-webkit-keyframes bounceFromRight{0%,100%{margin-left:0}50%{margin-left:-30px}}@keyframes bounceFromRight{0%,100%{margin-left:0}50%{margin-left:-30px}}@-webkit-keyframes bounceFromLeft{0%,100%{margin-left:0}50%{margin-left:30px}}@keyframes bounceFromLeft{0%,100%{margin-left:0}50%{margin-left:30px}}.baguetteBox-button#next-button,.baguetteBox-button#previous-button{top:50%;top:calc(50% - 30px);width:44px;height:60px}.baguetteBox-button{position:absolute;cursor:pointer;outline:0;padding:0;margin:0;border:0;-moz-border-radius:15%;border-radius:15%;background-color:#323232;background-color:rgba(50,50,50,.5);color:#ddd;font:1.6em sans-serif;-webkit-transition:background-color .4s ease;transition:background-color .4s ease}.baguetteBox-button:focus,.baguetteBox-button:hover{background-color:rgba(50,50,50,.9)}.baguetteBox-button#next-button{right:2%}.baguetteBox-button#previous-button{left:2%}.baguetteBox-button#close-button{top:20px;right:2%;right:calc(2% + 6px);width:30px;height:30px}.baguetteBox-button svg{position:absolute;left:0;top:0}.baguetteBox-spinner{width:40px;height:40px;display:inline-block;position:absolute;top:50%;left:50%;margin-top:-20px;margin-left:-20px}.baguetteBox-double-bounce1,.baguetteBox-double-bounce2{width:100%;height:100%;-moz-border-radius:50%;border-radius:50%;background-color:#fff;opacity:.6;position:absolute;top:0;left:0;-webkit-animation:bounce 2s infinite ease-in-out;animation:bounce 2s infinite ease-in-out}.baguetteBox-double-bounce2{-webkit-animation-delay:-1s;animation-delay:-1s}@-webkit-keyframes bounce{0%,100%{-webkit-transform:scale(0);transform:scale(0)}50%{-webkit-transform:scale(1);transform:scale(1)}}@keyframes bounce{0%,100%{-webkit-transform:scale(0);-moz-transform:scale(0);transform:scale(0)}50%{-webkit-transform:scale(1);-moz-transform:scale(1);transform:scale(1)}}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,270 @@
|
|||
@font-face {
|
||||
font-family:"socialshare";src:url("https://cdn.jsdelivr.net/gh/moezx/share.js@1.0.3/src/fonts/iconfont.eot");
|
||||
src:url("https://cdn.jsdelivr.net/gh/moezx/share.js@1.0.3/src/fonts/iconfont.eot?#iefix") format("embedded-opentype"),url("https://cdn.jsdelivr.net/gh/moezx/share.js@1.0.3/src/fonts/iconfont.woff") format("woff"),url("https://cdn.jsdelivr.net/gh/moezx/share.js@1.0.3/src/fonts/iconfont.ttf") format("truetype"),url("https://cdn.jsdelivr.net/gh/moezx/share.js@1.0.3/src/fonts/iconfont.svg#iconfont") format("svg")
|
||||
}
|
||||
|
||||
.social-share {
|
||||
display: inline-block;
|
||||
font-family: "socialshare" !important;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-webkit-text-stroke-width: 0.2px;
|
||||
-moz-osx-font-smoothing: grayscale
|
||||
}
|
||||
|
||||
.social-share * {
|
||||
font-family: "socialshare" !important
|
||||
}
|
||||
|
||||
.social-share .icon-tencent:before {
|
||||
content: "\f07a"
|
||||
}
|
||||
|
||||
.social-share .icon-qq:before {
|
||||
content: "\f11a"
|
||||
}
|
||||
|
||||
.social-share .icon-weibo:before {
|
||||
content: "\f12a"
|
||||
}
|
||||
|
||||
.social-share .icon-wechat:before {
|
||||
content: "\f09a"
|
||||
}
|
||||
|
||||
.social-share .icon-douban:before {
|
||||
content: "\f10a"
|
||||
}
|
||||
|
||||
.social-share .icon-heart:before {
|
||||
content: "\f20a"
|
||||
}
|
||||
|
||||
.social-share .icon-like:before {
|
||||
content: "\f00a"
|
||||
}
|
||||
|
||||
.social-share .icon-qzone:before {
|
||||
content: "\f08a"
|
||||
}
|
||||
|
||||
.social-share .icon-linkedin:before {
|
||||
content: "\f01a"
|
||||
}
|
||||
|
||||
.social-share .icon-diandian:before {
|
||||
content: "\f05a"
|
||||
}
|
||||
|
||||
.social-share .icon-facebook:before {
|
||||
content: "\f03a"
|
||||
}
|
||||
|
||||
.social-share .icon-google:before {
|
||||
content: "\f04a"
|
||||
}
|
||||
|
||||
.social-share .icon-twitter:before {
|
||||
content: "\f06a"
|
||||
}
|
||||
|
||||
.social-share a {
|
||||
position: relative;
|
||||
text-decoration: none;
|
||||
margin: 0 4px;
|
||||
display: inline-block;
|
||||
outline: none
|
||||
}
|
||||
|
||||
.social-share .social-share-icon {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
font-size: 10px;
|
||||
border-radius: 50%;
|
||||
line-height: 16px;
|
||||
border: 1px solid #666;
|
||||
color: #666;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
transition: background 0.6s ease-out 0s;
|
||||
}
|
||||
|
||||
.social-share .social-share-icon:hover {
|
||||
background: #666;
|
||||
color: #fff
|
||||
}
|
||||
|
||||
.social-share .icon-weibo {
|
||||
color: #ff763b;
|
||||
border-color: #ff763b
|
||||
}
|
||||
|
||||
.social-share .icon-weibo:hover {
|
||||
background: #ff763b
|
||||
}
|
||||
|
||||
.social-share .icon-tencent {
|
||||
color: #56b6e7;
|
||||
border-color: #56b6e7
|
||||
}
|
||||
|
||||
.social-share .icon-tencent:hover {
|
||||
background: #56b6e7
|
||||
}
|
||||
|
||||
.social-share .icon-qq {
|
||||
color: #56b6e7;
|
||||
border-color: #56b6e7
|
||||
}
|
||||
|
||||
.social-share .icon-qq:hover {
|
||||
background: #56b6e7
|
||||
}
|
||||
|
||||
.social-share .icon-qzone {
|
||||
color: #FDBE3D;
|
||||
border-color: #FDBE3D
|
||||
}
|
||||
|
||||
.social-share .icon-qzone:hover {
|
||||
background: #FDBE3D
|
||||
}
|
||||
|
||||
.social-share .icon-douban {
|
||||
color: #33b045;
|
||||
border-color: #33b045
|
||||
}
|
||||
|
||||
.social-share .icon-douban:hover {
|
||||
background: #33b045
|
||||
}
|
||||
|
||||
.social-share .icon-linkedin {
|
||||
color: #0077B5;
|
||||
border-color: #0077B5
|
||||
}
|
||||
|
||||
.social-share .icon-linkedin:hover {
|
||||
background: #0077B5
|
||||
}
|
||||
|
||||
.social-share .icon-facebook {
|
||||
color: #44619D;
|
||||
border-color: #44619D
|
||||
}
|
||||
|
||||
.social-share .icon-facebook:hover {
|
||||
background: #44619D
|
||||
}
|
||||
|
||||
.social-share .icon-google {
|
||||
color: #db4437;
|
||||
border-color: #db4437
|
||||
}
|
||||
|
||||
.social-share .icon-google:hover {
|
||||
background: #db4437
|
||||
}
|
||||
|
||||
.social-share .icon-twitter {
|
||||
color: #55acee;
|
||||
border-color: #55acee
|
||||
}
|
||||
|
||||
.social-share .icon-twitter:hover {
|
||||
background: #55acee
|
||||
}
|
||||
|
||||
.social-share .icon-diandian {
|
||||
color: #307DCA;
|
||||
border-color: #307DCA
|
||||
}
|
||||
|
||||
.social-share .icon-diandian:hover {
|
||||
background: #307DCA
|
||||
}
|
||||
|
||||
.social-share .icon-wechat {
|
||||
position: relative;
|
||||
color: #7bc549;
|
||||
border-color: #7bc549
|
||||
}
|
||||
|
||||
.social-share .icon-wechat:hover {
|
||||
background: #7bc549
|
||||
}
|
||||
|
||||
.social-share .icon-wechat .wechat-qrcode {
|
||||
display: none;
|
||||
border: 1px solid #eee;
|
||||
position: absolute;
|
||||
z-index: 9;
|
||||
top: -205px;
|
||||
left: -84px;
|
||||
width: 200px;
|
||||
height: 192px;
|
||||
color: #666;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 2px 10px #aaa;
|
||||
transition: all 200ms;
|
||||
-webkit-tansition: all 350ms;
|
||||
-moz-transition: all 350ms
|
||||
}
|
||||
|
||||
.social-share .icon-wechat .wechat-qrcode.bottom {
|
||||
top: 40px;
|
||||
left: -84px
|
||||
}
|
||||
|
||||
.social-share .icon-wechat .wechat-qrcode.bottom:after {
|
||||
display: none
|
||||
}
|
||||
|
||||
.social-share .icon-wechat .wechat-qrcode h4 {
|
||||
font-weight: normal;
|
||||
height: 26px;
|
||||
line-height: 26px;
|
||||
font-size: 12px;
|
||||
background-color: #f3f3f3;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: #777
|
||||
}
|
||||
|
||||
.social-share .icon-wechat .wechat-qrcode .qrcode {
|
||||
width: 105px;
|
||||
margin: 10px auto
|
||||
}
|
||||
|
||||
.social-share .icon-wechat .wechat-qrcode .qrcode table {
|
||||
margin: 0 !important
|
||||
}
|
||||
|
||||
.social-share .icon-wechat .wechat-qrcode .help p {
|
||||
font-weight: normal;
|
||||
line-height: 16px;
|
||||
padding: 0;
|
||||
margin: 0
|
||||
}
|
||||
|
||||
.social-share .icon-wechat .wechat-qrcode:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
margin-left: -6px;
|
||||
bottom: -13px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-width: 8px 6px 6px 6px;
|
||||
border-style: solid;
|
||||
border-color: #fff transparent transparent transparent
|
||||
}
|
||||
|
||||
.social-share .icon-wechat:hover .wechat-qrcode {
|
||||
display: block
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
/* Fix: Aplayer beautify*/
|
||||
.aplayer {
|
||||
background: rgba(255, 255, 255, .3);
|
||||
font-family: 'Noto Serif CJK SC', 'Noto Serif CJK', 'Source Han Serif SC', 'Source Han Serif', 'source-han-serif-sc', 'PT Serif', 'SongTi SC', 'MicroSoft Yahei', Georgia, serif;
|
||||
}
|
||||
|
||||
.aplayer .aplayer-lrc::before {
|
||||
background: rgba(255, 255, 255, 0);
|
||||
filter: none
|
||||
}
|
||||
|
||||
.aplayer .aplayer-lrc::after {
|
||||
background: rgba(255, 255, 255, 0);
|
||||
filter: none
|
||||
}
|
||||
|
||||
.aplayer {
|
||||
box-shadow: 0 0 0 1px #eee;
|
||||
border-radius: 3px;
|
||||
margin: 15px 0
|
||||
}
|
||||
|
||||
.aplayer .aplayer-info {
|
||||
padding: 9px 7px 0 10px
|
||||
}
|
||||
|
||||
.aplayer .aplayer-info .aplayer-controller .aplayer-bar-wrap {
|
||||
margin-left: 1px;
|
||||
padding-right: 3px
|
||||
}
|
||||
|
||||
.aplayer .aplayer-info .aplayer-controller .aplayer-bar-wrap .aplayer-bar,
|
||||
.aplayer .aplayer-info .aplayer-controller .aplayer-bar-wrap .aplayer-bar .aplayer-loaded,
|
||||
.aplayer .aplayer-info .aplayer-controller .aplayer-bar-wrap .aplayer-bar .aplayer-played {
|
||||
height: 6px;
|
||||
border-radius: 10px
|
||||
}
|
||||
|
||||
.aplayer .aplayer-info .aplayer-controller .aplayer-bar-wrap .aplayer-bar .aplayer-played .aplayer-thumb {
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
right: 3px;
|
||||
box-shadow: 0 0 5px 0 rgba(0, 0, 0, .18);
|
||||
transition: all .35s
|
||||
}
|
||||
|
||||
.aplayer .aplayer-info .aplayer-controller .aplayer-volume-wrap .aplayer-volume-bar-wrap .aplayer-volume-bar,
|
||||
.aplayer .aplayer-info .aplayer-controller .aplayer-volume-wrap .aplayer-volume-bar-wrap .aplayer-volume-bar .aplayer-volume {
|
||||
border-radius: 10px;
|
||||
width: 6px
|
||||
}
|
||||
|
||||
.aplayer .aplayer-info .aplayer-controller .aplayer-volume-wrap .aplayer-volume-bar-wrap .aplayer-volume-bar {
|
||||
right: 10.5px
|
||||
}
|
||||
|
||||
.aplayer .aplayer-list ol li {
|
||||
border-top: none
|
||||
}
|
||||
|
||||
.aplayer .aplayer-list ol li.aplayer-list-light {
|
||||
background: #f8f8f8
|
||||
}
|
||||
|
||||
#aplayer-float {
|
||||
background: rgba(255, 255, 255, 1);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.ap-hover {
|
||||
left: -66px !important;
|
||||
}
|
||||
|
||||
.ap-hover:hover {
|
||||
left: 0px !important;
|
||||
}
|
||||
|
||||
#aplayer-float .aplayer-lrc-current {
|
||||
color: orange;
|
||||
font-size: 15px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.aplayer-lrc {
|
||||
pointer-events: none;
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
# coding: utf-8
|
||||
'''
|
||||
Created on Apr 12, 2018
|
||||
Update on 2018-04-13
|
||||
@author: Mashiro @ https://2heng.xin
|
||||
|
||||
Desc: Auto compress & minfy JavaScript codes and CSS style sheet
|
||||
'''
|
||||
import os
|
||||
from os import listdir
|
||||
from os.path import isfile, join
|
||||
from jsmin import jsmin
|
||||
from csscompressor import compress
|
||||
import time
|
||||
import codecs
|
||||
|
||||
localtime = time.asctime( time.localtime(time.time()) )
|
||||
print (localtime)
|
||||
|
||||
pathJS = 'js/src/'
|
||||
pathJSroot = 'js/'
|
||||
pathCSS = 'css/src/'
|
||||
pathCSSroot = 'css/'
|
||||
|
||||
jsfiles = [f for f in listdir(pathJS) if isfile(join(pathJS, f))]
|
||||
cssfiles = [f for f in listdir(pathCSS) if isfile(join(pathCSS, f))]
|
||||
|
||||
strJS = '/*! Generate by Mashiro. ' + localtime + '*/'
|
||||
strCSS = '/*! Generate by Mashiro. ' + localtime + '*/'
|
||||
|
||||
for f in jsfiles:
|
||||
with codecs.open(pathJS + f, 'r', encoding='utf-8') as file:
|
||||
data = file.read()
|
||||
strJS = strJS + data
|
||||
print(f)
|
||||
|
||||
JSminified = jsmin(strJS)
|
||||
|
||||
with codecs.open(pathJSroot + "lib.js", "w", encoding='utf-8') as text_file:
|
||||
print(JSminified, file=text_file)
|
||||
|
||||
|
||||
print('------------------JS Done------------------')
|
||||
|
||||
for f in cssfiles:
|
||||
with codecs.open(pathCSS + f, 'r', encoding='utf-8') as file:
|
||||
data = file.read()
|
||||
strCSS = strCSS + data
|
||||
print(f)
|
||||
|
||||
CSSminified = compress(strCSS)
|
||||
|
||||
with codecs.open(pathCSSroot + "lib.css", "w", encoding='utf-8') as text_file:
|
||||
print(CSSminified, file=text_file)
|
||||
|
||||
print('------------------CSS Done------------------')
|
||||
|
||||
key = input('Press any key to quit')
|
||||
quit()
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,2 @@
|
|||
/*! line-number */
|
||||
!function(n,e){"use strict";function t(){var n=e.createElement("style");n.type="text/css",n.innerHTML=h(".{0}{border-collapse:collapse}.{0} td{padding:0}.{1}:before{content:attr({2})}",[f,m,j]),e.getElementsByTagName("head")[0].appendChild(n)}function r(t){"complete"===e.readyState?l(t):n.addEventListener("DOMContentLoaded",function(){l(t)})}function l(t){try{var r=e.querySelectorAll("code.hljs");for(var l in r)r.hasOwnProperty(l)&&i(r[l],t)}catch(o){n.console.error("LineNumbers error: ",o)}}function i(n,e){if("object"==typeof n){e=e||{singleLine:!1};var t=e.singleLine?0:1;u(function(){s(n),n.innerHTML=o(n.innerHTML,t)})}}function o(n,e){var t=c(n);if(""===t[t.length-1].trim()&&t.pop(),t.length>e){for(var r="",l=0,i=t.length;l<i;l++)r+=h('<tr><td class="{0}"><div class="{1} {2}" {3}="{5}"></div></td><td class="{4}"><div class="{1}">{6}</div></td></tr>',[v,g,m,j,p,l+1,t[l].length>0?t[l]:" "]);return h('<table class="{0}">{1}</table>',[f,r])}return n}function s(n){var e=n.childNodes;for(var t in e)if(e.hasOwnProperty(t)){var r=e[t];d(r.textContent)>0&&(r.childNodes.length>0?s(r):a(r.parentNode))}}function a(n){var e=n.className;if(/hljs-/.test(e)){for(var t=c(n.innerHTML),r=0,l="";r<t.length;r++)l+=h('<span class="{0}">{1}</span>\n',[e,t[r]]);n.innerHTML=l.trim()}}function c(n){return 0===n.length?[]:n.split(L)}function d(n){return(n.trim().match(L)||[]).length}function u(e){n.setTimeout(e,0)}function h(n,e){return n.replace(/\{(\d+)\}/g,function(n,t){return e[t]?e[t]:n})}var f="hljs-ln",g="hljs-ln-line",p="hljs-ln-code",v="hljs-ln-numbers",m="hljs-ln-n",j="data-line-number",L=/\r\n|\r|\n/g;n.hljs?(n.hljs.initLineNumbersOnLoad=r,n.hljs.lineNumbersBlock=i,t()):n.console.error("highlight.js not detected!")}(window,document);
|
|
@ -0,0 +1 @@
|
|||
!function(n,e){"function"==typeof define&&define.amd?define(e):"object"==typeof exports?module.exports=e():n.NProgress=e()}(this,function(){function n(n,e,t){return e>n?e:n>t?t:n}function e(n){return 100*(-1+n)}function t(n,t,r){var i;return i="translate3d"===c.positionUsing?{transform:"translate3d("+e(n)+"%,0,0)"}:"translate"===c.positionUsing?{transform:"translate("+e(n)+"%,0)"}:{"margin-left":e(n)+"%"},i.transition="all "+t+"ms "+r,i}function r(n,e){var t="string"==typeof n?n:o(n);return t.indexOf(" "+e+" ")>=0}function i(n,e){var t=o(n),i=t+e;r(t,e)||(n.className=i.substring(1))}function s(n,e){var t,i=o(n);r(n,e)&&(t=i.replace(" "+e+" "," "),n.className=t.substring(1,t.length-1))}function o(n){return(" "+(n.className||"")+" ").replace(/\s+/gi," ")}function a(n){n&&n.parentNode&&n.parentNode.removeChild(n)}var u={};u.version="0.2.0";var c=u.settings={minimum:.08,easing:"ease",positionUsing:"",speed:200,trickle:!0,trickleRate:.02,trickleSpeed:800,showSpinner:!0,barSelector:'[role="bar"]',spinnerSelector:'[role="spinner"]',parent:"body",template:'<div class="bar" role="bar"><div class="peg"></div></div><div class="spinner" role="spinner"><div class="spinner-icon"></div></div>'};u.configure=function(n){var e,t;for(e in n)t=n[e],void 0!==t&&n.hasOwnProperty(e)&&(c[e]=t);return this},u.status=null,u.set=function(e){var r=u.isStarted();e=n(e,c.minimum,1),u.status=1===e?null:e;var i=u.render(!r),s=i.querySelector(c.barSelector),o=c.speed,a=c.easing;return i.offsetWidth,l(function(n){""===c.positionUsing&&(c.positionUsing=u.getPositioningCSS()),f(s,t(e,o,a)),1===e?(f(i,{transition:"none",opacity:1}),i.offsetWidth,setTimeout(function(){f(i,{transition:"all "+o+"ms linear",opacity:0}),setTimeout(function(){u.remove(),n()},o)},o)):setTimeout(n,o)}),this},u.isStarted=function(){return"number"==typeof u.status},u.start=function(){u.status||u.set(0);var n=function(){setTimeout(function(){u.status&&(u.trickle(),n())},c.trickleSpeed)};return c.trickle&&n(),this},u.done=function(n){return n||u.status?u.inc(.3+.5*Math.random()).set(1):this},u.inc=function(e){var t=u.status;return t?("number"!=typeof e&&(e=(1-t)*n(Math.random()*t,.1,.95)),t=n(t+e,0,.994),u.set(t)):u.start()},u.trickle=function(){return u.inc(Math.random()*c.trickleRate)},function(){var n=0,e=0;u.promise=function(t){return t&&"resolved"!==t.state()?(0===e&&u.start(),n++,e++,t.always(function(){e--,0===e?(n=0,u.done()):u.set((n-e)/n)}),this):this}}(),u.render=function(n){if(u.isRendered())return document.getElementById("nprogress");i(document.documentElement,"nprogress-busy");var t=document.createElement("div");t.id="nprogress",t.innerHTML=c.template;var r,s=t.querySelector(c.barSelector),o=n?"-100":e(u.status||0),l=document.querySelector(c.parent);return f(s,{transition:"all 0 linear",transform:"translate3d("+o+"%,0,0)"}),c.showSpinner||(r=t.querySelector(c.spinnerSelector),r&&a(r)),l!=document.body&&i(l,"nprogress-custom-parent"),l.appendChild(t),t},u.remove=function(){s(document.documentElement,"nprogress-busy"),s(document.querySelector(c.parent),"nprogress-custom-parent");var n=document.getElementById("nprogress");n&&a(n)},u.isRendered=function(){return!!document.getElementById("nprogress")},u.getPositioningCSS=function(){var n=document.body.style,e="WebkitTransform"in n?"Webkit":"MozTransform"in n?"Moz":"msTransform"in n?"ms":"OTransform"in n?"O":"";return e+"Perspective"in n?"translate3d":e+"Transform"in n?"translate":"margin"};var l=function(){function n(){var t=e.shift();t&&t(n)}var e=[];return function(t){e.push(t),1==e.length&&n()}}(),f=function(){function n(n){return n.replace(/^-ms-/,"ms-").replace(/-([\da-z])/gi,function(n,e){return e.toUpperCase()})}function e(n){var e=document.body.style;if(n in e)return n;for(var t,r=i.length,s=n.charAt(0).toUpperCase()+n.slice(1);r--;)if(t=i[r]+s,t in e)return t;return n}function t(t){return t=n(t),s[t]||(s[t]=e(t))}function r(n,e,r){e=t(e),n.style[e]=r}var i=["Webkit","O","Moz","ms"],s={};return function(n,e){var t,i,s=arguments;if(2==s.length)for(t in e)i=e[t],void 0!==i&&e.hasOwnProperty(t)&&r(n,t,i);else r(n,s[1],s[2])}}();return u});
|
|
@ -0,0 +1,324 @@
|
|||
(function webpackUniversalModuleDefinition(root, factory) {
|
||||
if(typeof exports === 'object' && typeof module === 'object')
|
||||
module.exports = factory();
|
||||
else if(typeof define === 'function' && define.amd)
|
||||
define([], factory);
|
||||
else if(typeof exports === 'object')
|
||||
exports["POWERMODE"] = factory();
|
||||
else
|
||||
root["POWERMODE"] = factory();
|
||||
})(this, function() {
|
||||
return /******/ (function(modules) { // webpackBootstrap
|
||||
/******/ // The module cache
|
||||
/******/ var installedModules = {};
|
||||
|
||||
/******/ // The require function
|
||||
/******/ function __webpack_require__(moduleId) {
|
||||
|
||||
/******/ // Check if module is in cache
|
||||
/******/ if(installedModules[moduleId])
|
||||
/******/ return installedModules[moduleId].exports;
|
||||
|
||||
/******/ // Create a new module (and put it into the cache)
|
||||
/******/ var module = installedModules[moduleId] = {
|
||||
/******/ exports: {},
|
||||
/******/ id: moduleId,
|
||||
/******/ loaded: false
|
||||
/******/ };
|
||||
|
||||
/******/ // Execute the module function
|
||||
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
||||
|
||||
/******/ // Flag the module as loaded
|
||||
/******/ module.loaded = true;
|
||||
|
||||
/******/ // Return the exports of the module
|
||||
/******/ return module.exports;
|
||||
/******/ }
|
||||
|
||||
|
||||
/******/ // expose the modules object (__webpack_modules__)
|
||||
/******/ __webpack_require__.m = modules;
|
||||
|
||||
/******/ // expose the module cache
|
||||
/******/ __webpack_require__.c = installedModules;
|
||||
|
||||
/******/ // __webpack_public_path__
|
||||
/******/ __webpack_require__.p = "";
|
||||
|
||||
/******/ // Load entry module and return exports
|
||||
/******/ return __webpack_require__(0);
|
||||
/******/ })
|
||||
/************************************************************************/
|
||||
/******/ ([
|
||||
/* 0 */
|
||||
/***/ (function(module, exports, __webpack_require__) {
|
||||
|
||||
'use strict';
|
||||
|
||||
var canvas = document.createElement('canvas');
|
||||
canvas.width = window.innerWidth;
|
||||
canvas.height = window.innerHeight;
|
||||
canvas.style.cssText = 'position:fixed;top:0;left:0;pointer-events:none;z-index:999999';
|
||||
window.addEventListener('resize', function () {
|
||||
canvas.width = window.innerWidth;
|
||||
canvas.height = window.innerHeight;
|
||||
});
|
||||
document.body.appendChild(canvas);
|
||||
var context = canvas.getContext('2d');
|
||||
var particles = [];
|
||||
var particlePointer = 0;
|
||||
var rendering = false;
|
||||
|
||||
POWERMODE.shake = true;
|
||||
|
||||
function getRandom(min, max) {
|
||||
return Math.random() * (max - min) + min;
|
||||
}
|
||||
|
||||
function getColor(el) {
|
||||
if (POWERMODE.colorful) {
|
||||
var u = getRandom(0, 360);
|
||||
return 'hsla(' + getRandom(u - 10, u + 10) + ', 100%, ' + getRandom(50, 80) + '%, ' + 1 + ')';
|
||||
} else {
|
||||
return window.getComputedStyle(el).color;
|
||||
}
|
||||
}
|
||||
|
||||
function getCaret() {
|
||||
var el = document.activeElement;
|
||||
var bcr;
|
||||
if (el.tagName === 'TEXTAREA' ||
|
||||
(el.tagName === 'INPUT' && el.getAttribute('type') === 'text')) {
|
||||
var offset = __webpack_require__(1)(el, el.selectionEnd);
|
||||
bcr = el.getBoundingClientRect();
|
||||
return {
|
||||
x: offset.left + bcr.left,
|
||||
y: offset.top + bcr.top,
|
||||
color: getColor(el)
|
||||
};
|
||||
}
|
||||
var selection = window.getSelection();
|
||||
if (selection.rangeCount) {
|
||||
var range = selection.getRangeAt(0);
|
||||
var startNode = range.startContainer;
|
||||
if (startNode.nodeType === document.TEXT_NODE) {
|
||||
startNode = startNode.parentNode;
|
||||
}
|
||||
bcr = range.getBoundingClientRect();
|
||||
return {
|
||||
x: bcr.left,
|
||||
y: bcr.top,
|
||||
color: getColor(startNode)
|
||||
};
|
||||
}
|
||||
return { x: 0, y: 0, color: 'transparent' };
|
||||
}
|
||||
|
||||
function createParticle(x, y, color) {
|
||||
return {
|
||||
x: x,
|
||||
y: y,
|
||||
alpha: 1,
|
||||
color: color,
|
||||
velocity: {
|
||||
x: -1 + Math.random() * 2,
|
||||
y: -3.5 + Math.random() * 2
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function POWERMODE() {
|
||||
{ // spawn particles
|
||||
var caret = getCaret();
|
||||
var numParticles = 5 + Math.round(Math.random() * 10);
|
||||
while (numParticles--) {
|
||||
particles[particlePointer] = createParticle(caret.x, caret.y, caret.color);
|
||||
particlePointer = (particlePointer + 1) % 500;
|
||||
}
|
||||
}
|
||||
{ // shake screen
|
||||
if (POWERMODE.shake) {
|
||||
var intensity = 1 + 2 * Math.random();
|
||||
var x = intensity * (Math.random() > 0.5 ? -1 : 1);
|
||||
var y = intensity * (Math.random() > 0.5 ? -1 : 1);
|
||||
document.body.style.marginLeft = x + 'px';
|
||||
document.body.style.marginTop = y + 'px';
|
||||
setTimeout(function() {
|
||||
document.body.style.marginLeft = '';
|
||||
document.body.style.marginTop = '';
|
||||
}, 75);
|
||||
}
|
||||
}
|
||||
if(!rendering){
|
||||
requestAnimationFrame(loop);
|
||||
}
|
||||
};
|
||||
POWERMODE.colorful = false;
|
||||
|
||||
function loop() {
|
||||
rendering = true;
|
||||
context.clearRect(0, 0, canvas.width, canvas.height);
|
||||
var rendered = false;
|
||||
var rect = canvas.getBoundingClientRect();
|
||||
for (var i = 0; i < particles.length; ++i) {
|
||||
var particle = particles[i];
|
||||
if (particle.alpha <= 0.1) continue;
|
||||
particle.velocity.y += 0.075;
|
||||
particle.x += particle.velocity.x;
|
||||
particle.y += particle.velocity.y;
|
||||
particle.alpha *= 0.96;
|
||||
context.globalAlpha = particle.alpha;
|
||||
context.fillStyle = particle.color;
|
||||
context.fillRect(
|
||||
Math.round(particle.x - 1.5) - rect.left,
|
||||
Math.round(particle.y - 1.5) - rect.top,
|
||||
3, 3
|
||||
);
|
||||
rendered = true;
|
||||
}
|
||||
if(rendered){
|
||||
requestAnimationFrame(loop);
|
||||
}else{
|
||||
rendering = false;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = POWERMODE;
|
||||
|
||||
|
||||
/***/ }),
|
||||
/* 1 */
|
||||
/***/ (function(module, exports) {
|
||||
|
||||
/* jshint browser: true */
|
||||
|
||||
(function () {
|
||||
|
||||
// The properties that we copy into a mirrored div.
|
||||
// Note that some browsers, such as Firefox,
|
||||
// do not concatenate properties, i.e. padding-top, bottom etc. -> padding,
|
||||
// so we have to do every single property specifically.
|
||||
var properties = [
|
||||
'direction', // RTL support
|
||||
'boxSizing',
|
||||
'width', // on Chrome and IE, exclude the scrollbar, so the mirror div wraps exactly as the textarea does
|
||||
'height',
|
||||
'overflowX',
|
||||
'overflowY', // copy the scrollbar for IE
|
||||
|
||||
'borderTopWidth',
|
||||
'borderRightWidth',
|
||||
'borderBottomWidth',
|
||||
'borderLeftWidth',
|
||||
'borderStyle',
|
||||
|
||||
'paddingTop',
|
||||
'paddingRight',
|
||||
'paddingBottom',
|
||||
'paddingLeft',
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/CSS/font
|
||||
'fontStyle',
|
||||
'fontVariant',
|
||||
'fontWeight',
|
||||
'fontStretch',
|
||||
'fontSize',
|
||||
'fontSizeAdjust',
|
||||
'lineHeight',
|
||||
'fontFamily',
|
||||
|
||||
'textAlign',
|
||||
'textTransform',
|
||||
'textIndent',
|
||||
'textDecoration', // might not make a difference, but better be safe
|
||||
|
||||
'letterSpacing',
|
||||
'wordSpacing',
|
||||
|
||||
'tabSize',
|
||||
'MozTabSize'
|
||||
|
||||
];
|
||||
|
||||
var isFirefox = window.mozInnerScreenX != null;
|
||||
|
||||
function getCaretCoordinates(element, position, options) {
|
||||
|
||||
var debug = options && options.debug || false;
|
||||
if (debug) {
|
||||
var el = document.querySelector('#input-textarea-caret-position-mirror-div');
|
||||
if ( el ) { el.parentNode.removeChild(el); }
|
||||
}
|
||||
|
||||
// mirrored div
|
||||
var div = document.createElement('div');
|
||||
div.id = 'input-textarea-caret-position-mirror-div';
|
||||
document.body.appendChild(div);
|
||||
|
||||
var style = div.style;
|
||||
var computed = window.getComputedStyle? getComputedStyle(element) : element.currentStyle; // currentStyle for IE < 9
|
||||
|
||||
// default textarea styles
|
||||
style.whiteSpace = 'pre-wrap';
|
||||
if (element.nodeName !== 'INPUT')
|
||||
style.wordWrap = 'break-word'; // only for textarea-s
|
||||
|
||||
// position off-screen
|
||||
style.position = 'absolute'; // required to return coordinates properly
|
||||
if (!debug)
|
||||
style.visibility = 'hidden'; // not 'display: none' because we want rendering
|
||||
|
||||
// transfer the element's properties to the div
|
||||
properties.forEach(function (prop) {
|
||||
style[prop] = computed[prop];
|
||||
});
|
||||
|
||||
if (isFirefox) {
|
||||
// Firefox lies about the overflow property for textareas: https://bugzilla.mozilla.org/show_bug.cgi?id=984275
|
||||
if (element.scrollHeight > parseInt(computed.height))
|
||||
style.overflowY = 'scroll';
|
||||
} else {
|
||||
style.overflow = 'hidden'; // for Chrome to not render a scrollbar; IE keeps overflowY = 'scroll'
|
||||
}
|
||||
|
||||
div.textContent = element.value.substring(0, position);
|
||||
// the second special handling for input type="text" vs textarea: spaces need to be replaced with non-breaking spaces - http://stackoverflow.com/a/13402035/1269037
|
||||
if (element.nodeName === 'INPUT')
|
||||
div.textContent = div.textContent.replace(/\s/g, "\u00a0");
|
||||
|
||||
var span = document.createElement('span');
|
||||
// Wrapping must be replicated *exactly*, including when a long word gets
|
||||
// onto the next line, with whitespace at the end of the line before (#7).
|
||||
// The *only* reliable way to do that is to copy the *entire* rest of the
|
||||
// textarea's content into the <span> created at the caret position.
|
||||
// for inputs, just '.' would be enough, but why bother?
|
||||
span.textContent = element.value.substring(position) || '.'; // || because a completely empty faux span doesn't render at all
|
||||
div.appendChild(span);
|
||||
|
||||
var coordinates = {
|
||||
top: span.offsetTop + parseInt(computed['borderTopWidth']),
|
||||
left: span.offsetLeft + parseInt(computed['borderLeftWidth'])
|
||||
};
|
||||
|
||||
if (debug) {
|
||||
span.style.backgroundColor = '#aaa';
|
||||
} else {
|
||||
document.body.removeChild(div);
|
||||
}
|
||||
|
||||
return coordinates;
|
||||
}
|
||||
|
||||
if (typeof module != "undefined" && typeof module.exports != "undefined") {
|
||||
module.exports = getCaretCoordinates;
|
||||
} else {
|
||||
window.getCaretCoordinates = getCaretCoordinates;
|
||||
}
|
||||
|
||||
}());
|
||||
|
||||
/***/ })
|
||||
/******/ ])
|
||||
});
|
||||
;
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,2 @@
|
|||
/*! Lazy Load 2.0.0-beta.2 - MIT license - Copyright 2007-2017 Mika Tuupola */
|
||||
!function(t,e){"object"==typeof exports?module.exports=e(t):"function"==typeof define&&define.amd?define([],e(t)):t.LazyLoad=e(t)}("undefined"!=typeof global?global:this.window||this.global,function(t){"use strict";function e(t,e){this.settings=r(s,e||{}),this.images=t||document.querySelectorAll(this.settings.selector),this.observer=null,this.init()}const s={src:"data-src",srcset:"data-srcset",selector:".lazyload"},r=function(){let t={},e=!1,s=0,o=arguments.length;"[object Boolean]"===Object.prototype.toString.call(arguments[0])&&(e=arguments[0],s++);for(;s<o;s++)!function(s){for(let o in s)Object.prototype.hasOwnProperty.call(s,o)&&(e&&"[object Object]"===Object.prototype.toString.call(s[o])?t[o]=r(!0,t[o],s[o]):t[o]=s[o])}(arguments[s]);return t};if(e.prototype={init:function(){if(!t.IntersectionObserver)return void this.loadImages();let e=this,s={root:null,rootMargin:"0px",threshold:[0]};this.observer=new IntersectionObserver(function(t){t.forEach(function(t){if(t.isIntersecting){e.observer.unobserve(t.target);let s=t.target.getAttribute(e.settings.src),r=t.target.getAttribute(e.settings.srcset);"img"===t.target.tagName.toLowerCase()?(s&&(t.target.src=s),r&&(t.target.srcset=r)):t.target.style.backgroundImage="url("+s+")"}})},s),this.images.forEach(function(t){e.observer.observe(t)})},loadAndDestroy:function(){this.settings&&(this.loadImages(),this.destroy())},loadImages:function(){if(!this.settings)return;let t=this;this.images.forEach(function(e){let s=e.getAttribute(t.settings.src),r=e.getAttribute(t.settings.srcset);"img"===e.tagName.toLowerCase()?(s&&(e.src=s),r&&(e.srcset=r)):e.style.backgroundImage="url("+s+")"})},destroy:function(){this.settings&&(this.observer.disconnect(),this.settings=null)}},t.lazyload=function(t,s){return new e(t,s)},t.jQuery){const s=t.jQuery;s.fn.lazyload=function(t){return t=t||{},t.attribute=t.attribute||"data-src",new e(s.makeArray(this),t),this}}return e});
|
|
@ -0,0 +1,16 @@
|
|||
// Gravatar
|
||||
function get_gravatar(email, size) {
|
||||
|
||||
// MD5 (Message-Digest Algorithm) by WebToolkit
|
||||
//
|
||||
|
||||
var MD5=function(s){function L(k,d){return(k<<d)|(k>>>(32-d))}function K(G,k){var I,d,F,H,x;F=(G&2147483648);H=(k&2147483648);I=(G&1073741824);d=(k&1073741824);x=(G&1073741823)+(k&1073741823);if(I&d){return(x^2147483648^F^H)}if(I|d){if(x&1073741824){return(x^3221225472^F^H)}else{return(x^1073741824^F^H)}}else{return(x^F^H)}}function r(d,F,k){return(d&F)|((~d)&k)}function q(d,F,k){return(d&k)|(F&(~k))}function p(d,F,k){return(d^F^k)}function n(d,F,k){return(F^(d|(~k)))}function u(G,F,aa,Z,k,H,I){G=K(G,K(K(r(F,aa,Z),k),I));return K(L(G,H),F)}function f(G,F,aa,Z,k,H,I){G=K(G,K(K(q(F,aa,Z),k),I));return K(L(G,H),F)}function D(G,F,aa,Z,k,H,I){G=K(G,K(K(p(F,aa,Z),k),I));return K(L(G,H),F)}function t(G,F,aa,Z,k,H,I){G=K(G,K(K(n(F,aa,Z),k),I));return K(L(G,H),F)}function e(G){var Z;var F=G.length;var x=F+8;var k=(x-(x%64))/64;var I=(k+1)*16;var aa=Array(I-1);var d=0;var H=0;while(H<F){Z=(H-(H%4))/4;d=(H%4)*8;aa[Z]=(aa[Z]|(G.charCodeAt(H)<<d));H++}Z=(H-(H%4))/4;d=(H%4)*8;aa[Z]=aa[Z]|(128<<d);aa[I-2]=F<<3;aa[I-1]=F>>>29;return aa}function B(x){var k="",F="",G,d;for(d=0;d<=3;d++){G=(x>>>(d*8))&255;F="0"+G.toString(16);k=k+F.substr(F.length-2,2)}return k}function J(k){k=k.replace(/rn/g,"n");var d="";for(var F=0;F<k.length;F++){var x=k.charCodeAt(F);if(x<128){d+=String.fromCharCode(x)}else{if((x>127)&&(x<2048)){d+=String.fromCharCode((x>>6)|192);d+=String.fromCharCode((x&63)|128)}else{d+=String.fromCharCode((x>>12)|224);d+=String.fromCharCode(((x>>6)&63)|128);d+=String.fromCharCode((x&63)|128)}}}return d}var C=Array();var P,h,E,v,g,Y,X,W,V;var S=7,Q=12,N=17,M=22;var A=5,z=9,y=14,w=20;var o=4,m=11,l=16,j=23;var U=6,T=10,R=15,O=21;s=J(s);C=e(s);Y=1732584193;X=4023233417;W=2562383102;V=271733878;for(P=0;P<C.length;P+=16){h=Y;E=X;v=W;g=V;Y=u(Y,X,W,V,C[P+0],S,3614090360);V=u(V,Y,X,W,C[P+1],Q,3905402710);W=u(W,V,Y,X,C[P+2],N,606105819);X=u(X,W,V,Y,C[P+3],M,3250441966);Y=u(Y,X,W,V,C[P+4],S,4118548399);V=u(V,Y,X,W,C[P+5],Q,1200080426);W=u(W,V,Y,X,C[P+6],N,2821735955);X=u(X,W,V,Y,C[P+7],M,4249261313);Y=u(Y,X,W,V,C[P+8],S,1770035416);V=u(V,Y,X,W,C[P+9],Q,2336552879);W=u(W,V,Y,X,C[P+10],N,4294925233);X=u(X,W,V,Y,C[P+11],M,2304563134);Y=u(Y,X,W,V,C[P+12],S,1804603682);V=u(V,Y,X,W,C[P+13],Q,4254626195);W=u(W,V,Y,X,C[P+14],N,2792965006);X=u(X,W,V,Y,C[P+15],M,1236535329);Y=f(Y,X,W,V,C[P+1],A,4129170786);V=f(V,Y,X,W,C[P+6],z,3225465664);W=f(W,V,Y,X,C[P+11],y,643717713);X=f(X,W,V,Y,C[P+0],w,3921069994);Y=f(Y,X,W,V,C[P+5],A,3593408605);V=f(V,Y,X,W,C[P+10],z,38016083);W=f(W,V,Y,X,C[P+15],y,3634488961);X=f(X,W,V,Y,C[P+4],w,3889429448);Y=f(Y,X,W,V,C[P+9],A,568446438);V=f(V,Y,X,W,C[P+14],z,3275163606);W=f(W,V,Y,X,C[P+3],y,4107603335);X=f(X,W,V,Y,C[P+8],w,1163531501);Y=f(Y,X,W,V,C[P+13],A,2850285829);V=f(V,Y,X,W,C[P+2],z,4243563512);W=f(W,V,Y,X,C[P+7],y,1735328473);X=f(X,W,V,Y,C[P+12],w,2368359562);Y=D(Y,X,W,V,C[P+5],o,4294588738);V=D(V,Y,X,W,C[P+8],m,2272392833);W=D(W,V,Y,X,C[P+11],l,1839030562);X=D(X,W,V,Y,C[P+14],j,4259657740);Y=D(Y,X,W,V,C[P+1],o,2763975236);V=D(V,Y,X,W,C[P+4],m,1272893353);W=D(W,V,Y,X,C[P+7],l,4139469664);X=D(X,W,V,Y,C[P+10],j,3200236656);Y=D(Y,X,W,V,C[P+13],o,681279174);V=D(V,Y,X,W,C[P+0],m,3936430074);W=D(W,V,Y,X,C[P+3],l,3572445317);X=D(X,W,V,Y,C[P+6],j,76029189);Y=D(Y,X,W,V,C[P+9],o,3654602809);V=D(V,Y,X,W,C[P+12],m,3873151461);W=D(W,V,Y,X,C[P+15],l,530742520);X=D(X,W,V,Y,C[P+2],j,3299628645);Y=t(Y,X,W,V,C[P+0],U,4096336452);V=t(V,Y,X,W,C[P+7],T,1126891415);W=t(W,V,Y,X,C[P+14],R,2878612391);X=t(X,W,V,Y,C[P+5],O,4237533241);Y=t(Y,X,W,V,C[P+12],U,1700485571);V=t(V,Y,X,W,C[P+3],T,2399980690);W=t(W,V,Y,X,C[P+10],R,4293915773);X=t(X,W,V,Y,C[P+1],O,2240044497);Y=t(Y,X,W,V,C[P+8],U,1873313359);V=t(V,Y,X,W,C[P+15],T,4264355552);W=t(W,V,Y,X,C[P+6],R,2734768916);X=t(X,W,V,Y,C[P+13],O,1309151649);Y=t(Y,X,W,V,C[P+4],U,4149444226);V=t(V,Y,X,W,C[P+11],T,3174756917);W=t(W,V,Y,X,C[P+2],R,718787259);X=t(X,W,V,Y,C[P+9],O,3951481745);Y=K(Y,h);X=K(X,E);W=K(W,v);V=K(V,g)}var i=B(Y)+B(X)+B(W)+B(V);return i.toLowerCase()};
|
||||
|
||||
var size = size || 80;
|
||||
|
||||
return 'https://' + Poi.gravatar_url + '/' + MD5(email) + '.jpg?s=' + size + '&d=mm';
|
||||
}
|
||||
|
||||
// sync css
|
||||
!function(e){"use strict";var n=function(n,t,o){var l,r=e.document,i=r.createElement("link");if(t)l=t;else{var a=(r.body||r.getElementsByTagName("head")[0]).childNodes;l=a[a.length-1]}var d=r.styleSheets;i.rel="stylesheet",i.href=n,i.media="only x",l.parentNode.insertBefore(i,t?l:l.nextSibling);var f=function(e){for(var n=i.href,t=d.length;t--;)if(d[t].href===n)return e();setTimeout(function(){f(e)})};return i.onloadcssdefined=f,f(function(){i.media=o||"all"}),i};"undefined"!=typeof module?module.exports=n:e.loadCSS=n}("undefined"!=typeof global?global:this);
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,929 @@
|
|||
.entry-content blockquote:before,.entry-content blockquote:after {
|
||||
display: none
|
||||
}
|
||||
|
||||
.entry-content {
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
line-height: 1.5;
|
||||
color: #24292e;
|
||||
/*font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";*/
|
||||
font-size: 16px;
|
||||
line-height: 1.5;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.entry-content .pl-c {
|
||||
color: #6a737d;
|
||||
}
|
||||
|
||||
.entry-content .pl-c1,
|
||||
.entry-content .pl-s .pl-v {
|
||||
color: #005cc5;
|
||||
}
|
||||
|
||||
.entry-content .pl-e,
|
||||
.entry-content .pl-en {
|
||||
color: #6f42c1;
|
||||
}
|
||||
|
||||
.entry-content .pl-smi,
|
||||
.entry-content .pl-s .pl-s1 {
|
||||
color: #24292e;
|
||||
}
|
||||
|
||||
.entry-content .pl-ent {
|
||||
color: #22863a;
|
||||
}
|
||||
|
||||
.entry-content .pl-k {
|
||||
color: #d73a49;
|
||||
}
|
||||
|
||||
.entry-content .pl-s,
|
||||
.entry-content .pl-pds,
|
||||
.entry-content .pl-s .pl-pse .pl-s1,
|
||||
.entry-content .pl-sr,
|
||||
.entry-content .pl-sr .pl-cce,
|
||||
.entry-content .pl-sr .pl-sre,
|
||||
.entry-content .pl-sr .pl-sra {
|
||||
color: #032f62;
|
||||
}
|
||||
|
||||
.entry-content .pl-v,
|
||||
.entry-content .pl-smw {
|
||||
color: #e36209;
|
||||
}
|
||||
|
||||
.entry-content .pl-bu {
|
||||
color: #b31d28;
|
||||
}
|
||||
|
||||
.entry-content .pl-ii {
|
||||
color: #fafbfc;
|
||||
background-color: #b31d28;
|
||||
}
|
||||
|
||||
.entry-content .pl-c2 {
|
||||
color: #fafbfc;
|
||||
background-color: #d73a49;
|
||||
}
|
||||
|
||||
.entry-content .pl-c2::before {
|
||||
content: "^M";
|
||||
}
|
||||
|
||||
.entry-content .pl-sr .pl-cce {
|
||||
font-weight: bold;
|
||||
color: #22863a;
|
||||
}
|
||||
|
||||
.entry-content .pl-ml {
|
||||
color: #735c0f;
|
||||
}
|
||||
|
||||
.entry-content .pl-mh,
|
||||
.entry-content .pl-mh .pl-en,
|
||||
.entry-content .pl-ms {
|
||||
font-weight: bold;
|
||||
color: #005cc5;
|
||||
}
|
||||
|
||||
.entry-content .pl-mi {
|
||||
font-style: italic;
|
||||
color: #24292e;
|
||||
}
|
||||
|
||||
.entry-content .pl-mb {
|
||||
font-weight: bold;
|
||||
color: #24292e;
|
||||
}
|
||||
|
||||
.entry-content .pl-md {
|
||||
color: #b31d28;
|
||||
background-color: #ffeef0;
|
||||
}
|
||||
|
||||
.entry-content .pl-mi1 {
|
||||
color: #22863a;
|
||||
background-color: #f0fff4;
|
||||
}
|
||||
|
||||
.entry-content .pl-mc {
|
||||
color: #e36209;
|
||||
background-color: #ffebda;
|
||||
}
|
||||
|
||||
.entry-content .pl-mi2 {
|
||||
color: #f6f8fa;
|
||||
background-color: #005cc5;
|
||||
}
|
||||
|
||||
.entry-content .pl-mdr {
|
||||
font-weight: bold;
|
||||
color: #6f42c1;
|
||||
}
|
||||
|
||||
.entry-content .pl-ba {
|
||||
color: #586069;
|
||||
}
|
||||
|
||||
.entry-content .pl-sg {
|
||||
color: #959da5;
|
||||
}
|
||||
|
||||
.entry-content .pl-corl {
|
||||
text-decoration: underline;
|
||||
color: #032f62;
|
||||
}
|
||||
|
||||
.entry-content .octicon {
|
||||
display: inline-block;
|
||||
vertical-align: text-top;
|
||||
fill: currentColor;
|
||||
}
|
||||
|
||||
.entry-content a {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.entry-content a:active,
|
||||
.entry-content a:hover {
|
||||
outline-width: 0;
|
||||
}
|
||||
|
||||
.entry-content strong {
|
||||
font-weight: inherit;
|
||||
}
|
||||
|
||||
.entry-content strong {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
.entry-content h1 {
|
||||
font-size: 2em;
|
||||
margin: 0.67em 0;
|
||||
}
|
||||
|
||||
.entry-content img {
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
.entry-content code,
|
||||
.entry-content kbd {
|
||||
font-family: monospace, monospace;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.entry-content hr {
|
||||
box-sizing: content-box;
|
||||
height: 0;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.entry-content input {
|
||||
font: inherit;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.entry-content input {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.entry-content [type="checkbox"] {
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.entry-content * {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.entry-content input {
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
.entry-content a {
|
||||
color: #0366d6;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.entry-content a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.entry-content strong {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.entry-content hr {
|
||||
height: 0;
|
||||
margin: 15px 0;
|
||||
overflow: hidden;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
border-bottom: 1px solid #dfe2e5;
|
||||
}
|
||||
|
||||
.entry-content hr::before {
|
||||
display: table;
|
||||
content: "";
|
||||
}
|
||||
|
||||
.entry-content hr::after {
|
||||
display: table;
|
||||
clear: both;
|
||||
content: "";
|
||||
}
|
||||
|
||||
.entry-content table {
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.entry-content td,
|
||||
.entry-content th {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.entry-content h1,
|
||||
.entry-content h2,
|
||||
.entry-content h3,
|
||||
.entry-content h4,
|
||||
.entry-content h5,
|
||||
.entry-content h6 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.entry-content h1 {
|
||||
font-size: 32px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.entry-content h2 {
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.entry-content h3 {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.entry-content h4 {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.entry-content h5 {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.entry-content h6 {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.entry-content p {
|
||||
margin-top: 0;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.entry-content blockquote {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.entry-content ul,
|
||||
.entry-content ol {
|
||||
padding-left: 0;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.entry-content ol ol,
|
||||
.entry-content ul ol {
|
||||
list-style-type: lower-roman;
|
||||
}
|
||||
|
||||
.entry-content ul ul ol,
|
||||
.entry-content ul ol ol,
|
||||
.entry-content ol ul ol,
|
||||
.entry-content ol ol ol {
|
||||
list-style-type: lower-alpha;
|
||||
}
|
||||
|
||||
.entry-content dd {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.entry-content code {
|
||||
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.entry-content .octicon {
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
|
||||
.entry-content .pl-0 {
|
||||
padding-left: 0 !important;
|
||||
}
|
||||
|
||||
.entry-content .pl-1 {
|
||||
padding-left: 4px !important;
|
||||
}
|
||||
|
||||
.entry-content .pl-2 {
|
||||
padding-left: 8px !important;
|
||||
}
|
||||
|
||||
.entry-content .pl-3 {
|
||||
padding-left: 16px !important;
|
||||
}
|
||||
|
||||
.entry-content .pl-4 {
|
||||
padding-left: 24px !important;
|
||||
}
|
||||
|
||||
.entry-content .pl-5 {
|
||||
padding-left: 32px !important;
|
||||
}
|
||||
|
||||
.entry-content .pl-6 {
|
||||
padding-left: 40px !important;
|
||||
}
|
||||
|
||||
.entry-content::before {
|
||||
display: table;
|
||||
content: "";
|
||||
}
|
||||
|
||||
.entry-content::after {
|
||||
display: table;
|
||||
clear: both;
|
||||
content: "";
|
||||
}
|
||||
|
||||
.entry-content>*:first-child {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
||||
.entry-content>*:last-child {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.entry-content a:not([href]) {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.entry-content .anchor {
|
||||
float: left;
|
||||
padding-right: 4px;
|
||||
margin-left: -20px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.entry-content .anchor:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.entry-content p,
|
||||
.entry-content blockquote,
|
||||
.entry-content ul,
|
||||
.entry-content ol,
|
||||
.entry-content dl,
|
||||
.entry-content table {
|
||||
margin-top: 0;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.entry-content hr {
|
||||
height: 0.25em;
|
||||
padding: 0;
|
||||
margin: 24px 0;
|
||||
background-color: #e1e4e8;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.entry-content blockquote {
|
||||
padding: 0 1em;
|
||||
color: #6a737d;
|
||||
border-left: 0.25em solid #dfe2e5;
|
||||
}
|
||||
|
||||
.entry-content blockquote>:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.entry-content blockquote>:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.entry-content kbd {
|
||||
display: inline-block;
|
||||
padding: 3px 5px;
|
||||
font-size: 11px;
|
||||
line-height: 10px;
|
||||
color: #444d56;
|
||||
vertical-align: middle;
|
||||
background-color: #fafbfc;
|
||||
border: solid 1px #c6cbd1;
|
||||
border-bottom-color: #959da5;
|
||||
border-radius: 3px;
|
||||
box-shadow: inset 0 -1px 0 #959da5;
|
||||
}
|
||||
|
||||
.entry-content h1,
|
||||
.entry-content h2,
|
||||
.entry-content h3,
|
||||
.entry-content h4,
|
||||
.entry-content h5,
|
||||
.entry-content h6 {
|
||||
margin-top: 24px;
|
||||
margin-bottom: 16px;
|
||||
font-weight: 600;
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
.entry-content h1 .octicon-link,
|
||||
.entry-content h2 .octicon-link,
|
||||
.entry-content h3 .octicon-link,
|
||||
.entry-content h4 .octicon-link,
|
||||
.entry-content h5 .octicon-link,
|
||||
.entry-content h6 .octicon-link {
|
||||
color: #1b1f23;
|
||||
vertical-align: middle;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.entry-content h1:hover .anchor,
|
||||
.entry-content h2:hover .anchor,
|
||||
.entry-content h3:hover .anchor,
|
||||
.entry-content h4:hover .anchor,
|
||||
.entry-content h5:hover .anchor,
|
||||
.entry-content h6:hover .anchor {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.entry-content h1:hover .anchor .octicon-link,
|
||||
.entry-content h2:hover .anchor .octicon-link,
|
||||
.entry-content h3:hover .anchor .octicon-link,
|
||||
.entry-content h4:hover .anchor .octicon-link,
|
||||
.entry-content h5:hover .anchor .octicon-link,
|
||||
.entry-content h6:hover .anchor .octicon-link {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.entry-content h1 {
|
||||
padding-bottom: 0.3em;
|
||||
font-size: 2em;
|
||||
border-bottom: 1px solid #eaecef;
|
||||
}
|
||||
|
||||
.entry-content h2 {
|
||||
padding-bottom: 0.3em;
|
||||
font-size: 1.5em;
|
||||
border-bottom: 1px solid #eaecef;
|
||||
}
|
||||
|
||||
.entry-content h3 {
|
||||
font-size: 1.25em;
|
||||
}
|
||||
|
||||
.entry-content h4 {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.entry-content h5 {
|
||||
font-size: 0.875em;
|
||||
}
|
||||
|
||||
.entry-content h6 {
|
||||
font-size: 0.85em;
|
||||
color: #6a737d;
|
||||
}
|
||||
|
||||
.entry-content ul,
|
||||
.entry-content ol {
|
||||
padding-left: 2em;
|
||||
}
|
||||
|
||||
.entry-content ul ul,
|
||||
.entry-content ul ol,
|
||||
.entry-content ol ol,
|
||||
.entry-content ol ul {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.entry-content li {
|
||||
word-wrap: break-all;
|
||||
}
|
||||
|
||||
.entry-content li>p {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.entry-content li+li {
|
||||
margin-top: 0.25em;
|
||||
}
|
||||
|
||||
.entry-content dl {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.entry-content dl dt {
|
||||
padding: 0;
|
||||
margin-top: 16px;
|
||||
font-size: 1em;
|
||||
font-style: italic;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.entry-content dl dd {
|
||||
padding: 0 16px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.entry-content table {
|
||||
display: block;
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.entry-content table th {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.entry-content table th,
|
||||
.entry-content table td {
|
||||
padding: 6px 13px;
|
||||
border: 1px solid #dfe2e5;
|
||||
}
|
||||
|
||||
.entry-content table tr {
|
||||
background-color: #fff;
|
||||
border-top: 1px solid #c6cbd1;
|
||||
}
|
||||
|
||||
.entry-content table tr:nth-child(2n) {
|
||||
background-color: #f6f8fa;
|
||||
}
|
||||
|
||||
.entry-content img {
|
||||
max-width: 100%;
|
||||
box-sizing: content-box;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.entry-content img[align=right] {
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.entry-content img[align=left] {
|
||||
padding-right: 20px;
|
||||
}
|
||||
|
||||
.entry-content code {
|
||||
padding: 0.2em 0.4em;
|
||||
margin: 0;
|
||||
font-size: 85%;
|
||||
background-color: rgba(27,31,35,0.05);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.entry-content .full-commit .btn-outline:not(:disabled):hover {
|
||||
color: #005cc5;
|
||||
border-color: #005cc5;
|
||||
}
|
||||
|
||||
.entry-content kbd {
|
||||
display: inline-block;
|
||||
padding: 3px 5px;
|
||||
font: 11px "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
||||
line-height: 10px;
|
||||
color: #444d56;
|
||||
vertical-align: middle;
|
||||
background-color: #fafbfc;
|
||||
border: solid 1px #d1d5da;
|
||||
border-bottom-color: #c6cbd1;
|
||||
border-radius: 3px;
|
||||
box-shadow: inset 0 -1px 0 #c6cbd1;
|
||||
}
|
||||
|
||||
.entry-content :checked+.radio-label {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
border-color: #0366d6;
|
||||
}
|
||||
|
||||
.entry-content .task-list-item {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
.entry-content .task-list-item+.task-list-item {
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
.entry-content .task-list-item input {
|
||||
margin: 0 0.2em 0.25em -1.6em;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.entry-content hr {
|
||||
border-bottom-color: #eee;
|
||||
}
|
||||
|
||||
/*fix mac code*/
|
||||
.entry-content pre.highlight-wrap {
|
||||
position: relative;
|
||||
background: #21252b;
|
||||
border-radius: 5px;
|
||||
font: 15px/22px "Microsoft YaHei", Arial, Sans-Serif;
|
||||
line-height: 1.6;
|
||||
margin-bottom: 1.6em;
|
||||
max-width: 100%;
|
||||
overflow: auto;
|
||||
text-shadow: none;
|
||||
color: #000;
|
||||
padding-top: 30px;
|
||||
box-shadow: 0 10px 30px 0 rgba(0, 0, 0, .4)
|
||||
}
|
||||
|
||||
.entry-content pre.highlight-wrap:before {
|
||||
content: " ";
|
||||
position: absolute;
|
||||
-webkit-border-radius: 50%;
|
||||
border-radius: 50%;
|
||||
background: #fc625d;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
left: 12px;
|
||||
margin-top: -18px;
|
||||
-webkit-box-shadow: 20px 0 #fdbc40, 40px 0 #35cd4b;
|
||||
box-shadow: 20px 0 #fdbc40, 40px 0 #35cd4b;
|
||||
z-index: 2
|
||||
}
|
||||
|
||||
.entry-content pre.highlight-wrap .copy-code {
|
||||
color: #fff;
|
||||
position: absolute;
|
||||
float: right;
|
||||
right: 10px;
|
||||
top: 0;
|
||||
padding-top: 4px;
|
||||
padding-right: 2px;
|
||||
z-index: 2;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.entry-content pre.highlight-wrap .copy-code:hover {
|
||||
color: rgba(255,255,255,.5);
|
||||
}
|
||||
|
||||
.entry-content pre .hljs-ln-line span::-moz-selection,
|
||||
.entry-content pre .hljs-ln-line::-moz-selection {
|
||||
background: #fff;
|
||||
color: #21252b
|
||||
}
|
||||
|
||||
.entry-content pre .hljs-ln-line span::selection,
|
||||
.entry-content pre .hljs-ln-line::selection {
|
||||
background: #fff;
|
||||
color: #21252b
|
||||
}
|
||||
|
||||
.entry-content pre.highlight-wrap code::-webkit-scrollbar {
|
||||
height: 10x !important;
|
||||
width: 10x !important;
|
||||
background-color: #1d1f21 !important
|
||||
}
|
||||
|
||||
.entry-content pre.highlight-wrap code::-webkit-scrollbar-track {
|
||||
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, .3) !important;
|
||||
border-radius: 10px !important;
|
||||
background-color: #21252b !important
|
||||
}
|
||||
|
||||
.entry-content pre.highlight-wrap code::-webkit-scrollbar-thumb {
|
||||
border-radius: 10px !important;
|
||||
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, .5) !important;
|
||||
background-color: #21252b !important
|
||||
}
|
||||
|
||||
.entry-content pre table.hljs-ln::-webkit-scrollbar {
|
||||
height: 10x !important;
|
||||
width: 10x !important;
|
||||
background-color: #1d1f21 !important;
|
||||
}
|
||||
.entry-content pre table.hljs-ln::-webkit-scrollbar-track {
|
||||
background-color: #41454a;
|
||||
}
|
||||
.entry-content pre table.hljs-ln::-webkit-scrollbar-thumb {
|
||||
border-radius: 10px !important;
|
||||
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, .5) !important;
|
||||
background-color: #21252b !important;
|
||||
}
|
||||
|
||||
.entry-content pre.highlight-wrap code {
|
||||
background: #1d1f21;
|
||||
color: #fff;
|
||||
word-break: break-word;
|
||||
font-family: 'Source Code Pro', monospace, Helvetica, Tahoma, Arial, STXihei, "STHeiti Light", "Microsoft YaHei", sans-serif;
|
||||
padding: 2px;
|
||||
text-shadow: none;
|
||||
border-radius: 0 0 5px 5px;
|
||||
cursor: url(https://cdn.jsdelivr.net/gh/moezx/cdn@3.1.9/img/Sakura/cursor/texto.cur), auto
|
||||
}
|
||||
|
||||
.entry-content pre.highlight-wrap code[data-rel]:before {
|
||||
color: #fff;
|
||||
content: attr(data-rel);
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
background: #21252b;
|
||||
font-size: 16px;
|
||||
position: absolute;
|
||||
margin-top: -30px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
font-family: Ubuntu, sans-serif;
|
||||
font-weight: 700;
|
||||
padding: 0 80px;
|
||||
text-indent: 15px;
|
||||
text-align: center;
|
||||
float: left;
|
||||
z-index: 1;
|
||||
border-radius: 5px 5px 0 0;
|
||||
border-top-left-radius: 5px;
|
||||
border-top-right-radius: 5px;
|
||||
border-bottom-right-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
pointer-events: none
|
||||
}
|
||||
|
||||
.entry-content pre .hljs {
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
padding: .5em;
|
||||
color: #abb2bf;
|
||||
background: rgba(254, 250, 199, .5);
|
||||
border-radius: 10px
|
||||
}
|
||||
|
||||
.entry-content pre .hljs-comment,
|
||||
.entry-content pre .hljs-quote {
|
||||
color: #888f96;
|
||||
font-style: italic
|
||||
}
|
||||
|
||||
.entry-content pre .hljs-doctag,
|
||||
.entry-content pre .hljs-formula,
|
||||
.entry-content pre .hljs-keyword {
|
||||
color: #c678dd
|
||||
}
|
||||
|
||||
.entry-content pre .hljs-deletion,
|
||||
.entry-content pre .hljs-name,
|
||||
.entry-content pre .hljs-section,
|
||||
.entry-content pre .hljs-selector-tag,
|
||||
.entry-content pre .hljs-subst {
|
||||
color: #e06c75
|
||||
}
|
||||
|
||||
.entry-content pre .hljs-literal {
|
||||
color: #56b6c2
|
||||
}
|
||||
|
||||
.entry-content pre .hljs-addition,
|
||||
.entry-content pre .hljs-attribute,
|
||||
.entry-content pre .hljs-meta-string,
|
||||
.entry-content pre .hljs-regexp,
|
||||
.entry-content pre .hljs-string {
|
||||
color: #98c379
|
||||
}
|
||||
|
||||
.entry-content pre .hljs-built_in,
|
||||
.entry-content pre .hljs-class .hljs-title {
|
||||
color: #e6c07b
|
||||
}
|
||||
|
||||
.entry-content pre .hljs-attr,
|
||||
.entry-content pre .hljs-number,
|
||||
.entry-content pre .hljs-selector-attr,
|
||||
.entry-content pre .hljs-selector-class,
|
||||
.entry-content pre .hljs-selector-pseudo,
|
||||
.entry-content pre .hljs-template-variable,
|
||||
.entry-content pre .hljs-type,
|
||||
.entry-content pre .hljs-variable {
|
||||
color: #d19a66
|
||||
}
|
||||
|
||||
.entry-content pre .hljs-bullet,
|
||||
.entry-content pre .hljs-link,
|
||||
.entry-content pre .hljs-meta,
|
||||
.entry-content pre .hljs-selector-id,
|
||||
.entry-content pre .hljs-symbol,
|
||||
.entry-content pre .hljs-title {
|
||||
color: #61aeee
|
||||
}
|
||||
|
||||
.entry-content pre .hljs-emphasis {
|
||||
font-style: italic
|
||||
}
|
||||
|
||||
.entry-content pre .hljs-strong {
|
||||
font-weight: 700
|
||||
}
|
||||
|
||||
.entry-content pre .hljs-link {
|
||||
text-decoration: underline
|
||||
}
|
||||
|
||||
.entry-content pre .hljs-ln {
|
||||
margin: 6px 0 0 0 !important
|
||||
}
|
||||
|
||||
.entry-content pre td .hljs-ln-numbers {
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
text-align: center;
|
||||
color: #888f96;
|
||||
background: #1d1f21;
|
||||
font-family: 'Source Code Pro', monospace, Helvetica, Tahoma, Arial, STXihei, "STHeiti Light", "Microsoft YaHei", sans-serif;
|
||||
vertical-align: top;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: 30px
|
||||
}
|
||||
|
||||
.entry-content pre .hljs-ln-code .hljs-ln-line {
|
||||
margin-left: 22px;
|
||||
}
|
||||
|
||||
.entry-content pre .hljs-ln-code .hljs-ln-line:hover {
|
||||
background-color: rgba(255, 255, 255, .1)
|
||||
}
|
||||
|
||||
.entry-content pre .hljs-ln{border-collapse:collapse}
|
||||
.entry-content pre .hljs-ln td{padding:0}
|
||||
.entry-content pre .hljs-ln-n:before{content:attr(data-line-number)}
|
||||
|
||||
/*fix*/
|
||||
.entry-content pre table tr {
|
||||
background-color: transparent;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.entry-content pre table th, .entry-content pre table td {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.entry-content pre table tr {
|
||||
background-color: transparent;
|
||||
border-top: 0;
|
||||
}
|
||||
|
||||
.entry-content pre table tr:nth-child(2n) {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.code-block-fullscreen {
|
||||
position: fixed !important;
|
||||
top: 0 !important;
|
||||
left: 0 !important;
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
min-width: 100% !important;
|
||||
z-index: 9999999 !important;
|
||||
margin: 0 !important;
|
||||
animation: elastic 1s !important
|
||||
}
|
||||
|
||||
.code-block-fullscreen code {
|
||||
--widthA: 100%;
|
||||
--widthB: calc(var(--widthA) - 30px);
|
||||
height: var(--widthB) !important;
|
||||
min-height: 99% !important;
|
||||
overflow-y: hidden !important;
|
||||
overflow-x: auto !important;
|
||||
height: auto !important
|
||||
}
|
||||
|
||||
.code-block-fullscreen-html-scroll {
|
||||
overflow: hidden !important
|
||||
}
|
||||
|
||||
/*other fix*/
|
||||
.entry-content ol,.entry-content ul {
|
||||
margin: auto !important;
|
||||
}
|
|
@ -0,0 +1,399 @@
|
|||
.entry-content blockquote:before,.entry-content blockquote:after {
|
||||
display: block
|
||||
}
|
||||
|
||||
.entry-content blockquote blockquote:before,.entry-content blockquote blockquote:after {
|
||||
display: none
|
||||
}
|
||||
|
||||
.entry-content .begin,
|
||||
.single-begin {
|
||||
float: left;
|
||||
font-size: 3.6em;
|
||||
line-height: 1em;
|
||||
margin-right: 3px;
|
||||
margin-top: 2px;
|
||||
font-weight: 700
|
||||
}
|
||||
|
||||
@media screen and (max-width:860px) {
|
||||
.entry-content .begin,
|
||||
.single-begin {
|
||||
margin-top: 6px
|
||||
}
|
||||
}
|
||||
|
||||
.entry-content ul {
|
||||
list-style: disc;
|
||||
border: 1px dashed #E4E4E4;
|
||||
padding: 15px 10px 15px 50px;
|
||||
color: #616161;
|
||||
margin-left: 0;
|
||||
border-radius: 10px
|
||||
}
|
||||
|
||||
.entry-content ul ul {
|
||||
border: none;
|
||||
padding: 15px 10px 15px 30px;
|
||||
}
|
||||
|
||||
.entry-content ol {
|
||||
list-style: decimal;
|
||||
border: 1px dashed #E4E4E4;
|
||||
padding: 15px 10px 15px 50px;
|
||||
color: #616161;
|
||||
margin-left: 0;
|
||||
border-radius: 10px
|
||||
}
|
||||
|
||||
.entry-content ol li,
|
||||
.entry-content ul li {
|
||||
padding: 8px 0
|
||||
}
|
||||
|
||||
.entry-content {
|
||||
position: relative
|
||||
}
|
||||
|
||||
.entry-content h3, .entry-content h4, .entry-content h5 {
|
||||
padding-left: 16px;
|
||||
}
|
||||
|
||||
.entry-content h3 {
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 1px dashed #ddd;
|
||||
color: #737373
|
||||
}
|
||||
|
||||
.entry-content h3:after {
|
||||
content: "#";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
color: #FF6D6D
|
||||
}
|
||||
|
||||
.entry-content h4:after {
|
||||
content: ">";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
color: #FF6D6D
|
||||
}
|
||||
|
||||
.entry-content h5:after {
|
||||
content: "?";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
color: #FF6D6D
|
||||
}
|
||||
|
||||
.entry-content code {
|
||||
background: rgba(254, 250, 199, 1);
|
||||
color: #E67474;
|
||||
word-break: break-word;
|
||||
font-family: 'Source Code Pro', monospace, Helvetica, Tahoma, Arial, STXihei, "STHeiti Light", "Microsoft YaHei", sans-serif;
|
||||
padding: 2px;
|
||||
text-shadow: none;
|
||||
border-radius: 5px
|
||||
}
|
||||
|
||||
.entry-content a {
|
||||
color: #e67474;
|
||||
text-decoration: underline dotted rgba(0, 0, 0, .1)
|
||||
}
|
||||
|
||||
.entry-content a:hover {
|
||||
color: orange;
|
||||
text-decoration: underline orange
|
||||
}
|
||||
|
||||
h1.entry-title {
|
||||
font-size: 24px;
|
||||
font-weight: 300
|
||||
}
|
||||
|
||||
.entry-content p {
|
||||
color: #797979
|
||||
}
|
||||
|
||||
.entry-content p {
|
||||
line-height: 30px
|
||||
}
|
||||
|
||||
.entry-content hr {
|
||||
margin-top: 40px;
|
||||
margin-bottom: 40px;
|
||||
display: block;
|
||||
border: 0;
|
||||
text-align: center;
|
||||
background: 0 0
|
||||
}
|
||||
|
||||
.entry-content hr:before {
|
||||
content: '...';
|
||||
display: inline-block;
|
||||
margin-left: .6em;
|
||||
color: rgba(0, 0, 0, .8);
|
||||
position: relative;
|
||||
top: -30px;
|
||||
font-size: 28px;
|
||||
letter-spacing: .6em
|
||||
}
|
||||
|
||||
.entry-content table {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
border-radius: 5px
|
||||
}
|
||||
|
||||
.entry-content th, .entry-content td {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.entry-content tr:nth-child(even){background-color: #f2f2f2}
|
||||
body.dark .entry-content tr:nth-child(even){background-color: unset}
|
||||
|
||||
.entry-content th {
|
||||
color: white;
|
||||
}
|
||||
|
||||
/*fix code block*/
|
||||
.entry-content pre th, .entry-content pre td {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.entry-content pre tr:nth-child(even){
|
||||
background-color: transparent
|
||||
}
|
||||
|
||||
.entry-content pre th {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.highlight-wrap:before {
|
||||
content: " ";
|
||||
position: absolute;
|
||||
-webkit-border-radius: 50%;
|
||||
border-radius: 50%;
|
||||
background: #fc625d;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
left: 12px;
|
||||
margin-top: -18px;
|
||||
-webkit-box-shadow: 20px 0 #fdbc40, 40px 0 #35cd4b;
|
||||
box-shadow: 20px 0 #fdbc40, 40px 0 #35cd4b;
|
||||
z-index: 2
|
||||
}
|
||||
|
||||
.highlight-wrap {
|
||||
position: relative;
|
||||
background: #21252b;
|
||||
border-radius: 5px;
|
||||
font: 15px/22px "Microsoft YaHei", Arial, Sans-Serif;
|
||||
line-height: 1.6;
|
||||
margin-bottom: 1.6em;
|
||||
max-width: 100%;
|
||||
overflow: auto;
|
||||
text-shadow: none;
|
||||
color: #000;
|
||||
padding-top: 30px;
|
||||
box-shadow: 0 10px 30px 0 rgba(0, 0, 0, .4)
|
||||
}
|
||||
|
||||
.highlight-wrap .copy-code {
|
||||
color: #fff;
|
||||
position: absolute;
|
||||
float: right;
|
||||
right: 10px;
|
||||
top: 0;
|
||||
padding-top: 4px;
|
||||
padding-right: 2px;
|
||||
z-index: 2;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.highlight-wrap .copy-code:hover {
|
||||
color: rgba(255,255,255,.5);
|
||||
}
|
||||
|
||||
.hljs-ln-line span::-moz-selection,
|
||||
.hljs-ln-line::-moz-selection {
|
||||
background: #fff;
|
||||
color: #21252b
|
||||
}
|
||||
|
||||
.hljs-ln-line span::selection,
|
||||
.hljs-ln-line::selection {
|
||||
background: #fff;
|
||||
color: #21252b
|
||||
}
|
||||
|
||||
.highlight-wrap code {
|
||||
background: #1d1f21;
|
||||
color: #fff;
|
||||
word-break: break-word;
|
||||
font-family: 'Source Code Pro', monospace, Helvetica, Tahoma, Arial, STXihei, "STHeiti Light", "Microsoft YaHei", sans-serif;
|
||||
padding: 2px;
|
||||
text-shadow: none;
|
||||
border-radius: 0 0 5px 5px;
|
||||
cursor: url(https://cdn.jsdelivr.net/gh/moezx/cdn@3.1.9/img/Sakura/cursor/texto.cur), auto
|
||||
}
|
||||
|
||||
.highlight-wrap code[data-rel]:before {
|
||||
color: #fff;
|
||||
content: attr(data-rel);
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
background: #21252b;
|
||||
font-size: 16px;
|
||||
position: absolute;
|
||||
margin-top: -30px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
font-family: Ubuntu, sans-serif;
|
||||
font-weight: 700;
|
||||
padding: 0 80px;
|
||||
text-indent: 15px;
|
||||
text-align: center;
|
||||
float: left;
|
||||
z-index: 1;
|
||||
border-radius: 5px 5px 0 0;
|
||||
border-top-left-radius: 5px;
|
||||
border-top-right-radius: 5px;
|
||||
border-bottom-right-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
pointer-events: none
|
||||
}
|
||||
|
||||
.hljs {
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
padding: .5em;
|
||||
color: #abb2bf;
|
||||
background: rgba(254, 250, 199, .5);
|
||||
border-radius: 10px
|
||||
}
|
||||
|
||||
.hljs-comment,
|
||||
.hljs-quote {
|
||||
color: #888f96;
|
||||
font-style: italic
|
||||
}
|
||||
|
||||
.hljs-doctag,
|
||||
.hljs-formula,
|
||||
.hljs-keyword {
|
||||
color: #c678dd
|
||||
}
|
||||
|
||||
.hljs-deletion,
|
||||
.hljs-name,
|
||||
.hljs-section,
|
||||
.hljs-selector-tag,
|
||||
.hljs-subst {
|
||||
color: #e06c75
|
||||
}
|
||||
|
||||
.hljs-literal {
|
||||
color: #56b6c2
|
||||
}
|
||||
|
||||
.hljs-addition,
|
||||
.hljs-attribute,
|
||||
.hljs-meta-string,
|
||||
.hljs-regexp,
|
||||
.hljs-string {
|
||||
color: #98c379
|
||||
}
|
||||
|
||||
.hljs-built_in,
|
||||
.hljs-class .hljs-title {
|
||||
color: #e6c07b
|
||||
}
|
||||
|
||||
.hljs-attr,
|
||||
.hljs-number,
|
||||
.hljs-selector-attr,
|
||||
.hljs-selector-class,
|
||||
.hljs-selector-pseudo,
|
||||
.hljs-template-variable,
|
||||
.hljs-type,
|
||||
.hljs-variable {
|
||||
color: #d19a66
|
||||
}
|
||||
|
||||
.hljs-bullet,
|
||||
.hljs-link,
|
||||
.hljs-meta,
|
||||
.hljs-selector-id,
|
||||
.hljs-symbol,
|
||||
.hljs-title {
|
||||
color: #61aeee
|
||||
}
|
||||
|
||||
.hljs-emphasis {
|
||||
font-style: italic
|
||||
}
|
||||
|
||||
.hljs-strong {
|
||||
font-weight: 700
|
||||
}
|
||||
|
||||
.hljs-link {
|
||||
text-decoration: underline
|
||||
}
|
||||
|
||||
.hljs-ln {
|
||||
margin: 6px 0 0 0 !important
|
||||
}
|
||||
|
||||
td.hljs-ln-numbers {
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
text-align: center;
|
||||
color: #888f96;
|
||||
background: #1d1f21;
|
||||
font-family: 'Source Code Pro', monospace, Helvetica, Tahoma, Arial, STXihei, "STHeiti Light", "Microsoft YaHei", sans-serif;
|
||||
vertical-align: top;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: 30px
|
||||
}
|
||||
|
||||
.hljs-ln-code .hljs-ln-line {
|
||||
margin-left: 25px;
|
||||
padding-left: 5px
|
||||
}
|
||||
|
||||
.hljs-ln-code .hljs-ln-line:hover {
|
||||
background-color: rgba(255, 255, 255, .1)
|
||||
}
|
||||
|
||||
.code-block-fullscreen {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-width: 100%;
|
||||
z-index: 9999999;
|
||||
margin: 0;
|
||||
animation: elastic 1s
|
||||
}
|
||||
|
||||
.code-block-fullscreen code {
|
||||
--widthA: 100%;
|
||||
--widthB: calc(var(--widthA) - 30px);
|
||||
height: var(--widthB);
|
||||
min-height: 99%;
|
||||
overflow-y: hidden;
|
||||
overflow-x: auto;
|
||||
height: auto
|
||||
}
|
||||
|
||||
.code-block-fullscreen-html-scroll {
|
||||
overflow: hidden
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue