127 Commits
v1.2.0 ... dev

Author SHA1 Message Date
fen
6df1b433ee improve: show site description in homepage title 2024-01-04 22:13:41 +08:00
fen
2650bb6654 fix: search result 2024-01-04 16:58:44 +08:00
fen
316cf1da39 improve: comment style 2024-01-04 16:58:44 +08:00
joyqi
be12409358 Merge commit 'f3299ecb8a6d7a4283f81905c4c8b079e85339ee' into dev 2024-01-01 23:47:24 +08:00
LibXZR
f3299ecb8a Fix broken link when paging by category or tags (#1673) 2024-01-01 18:34:20 +08:00
joyqi
b88a733dc0 Dev (#1670)
* Add feed widget

* add feed render

* Add CommentPage widget

* New theme (#1390)

* 调整忽略目录

* add theme

* fix theme scss build

Co-authored-by: fen <f3nb0x@gmail.com>

* s/is_writeable/is_writable/g

* New upgrade method

* merge new fixes from master

* add pgsql ssl mode support (ref #1600) (#1623)

* Feat/code refactor (#1626)

* remove all magic methods, add type for class properties

* refactor codes

* fix all

* refactor code

* fix type

* fix all

* fix request is method

* fix all

* fix router

* fix get page

* fix 1.3.0 upgrade

* [feat] support high resolution avatar

* fix types in i18n component

* Implement Ctrl+S or Command+S for save draft (#1628)

* Implement Ctrl+S or Command+S for save draft

* rename

* add Typecho.savePost

* fix upload file size

* add new uploader

* replace new uploader

* fix textarea change

* fix preview

* refactor post edit

* fix issue

* fix page edit

---------

Co-authored-by: joyqi <joyqi@segmentfault.com>
Co-authored-by: joyqi <magike.net@gmail.com>

* fix #1632

* Add svg to image types

* Feat/tree pages (#1646)

* add tree trait

* finish category tree trait

* support select fields

* fix select fields

* refactor admin trait

* fix draft status

* Add new contents type "revision"

* minor refactor

* add more tree view abstracts

* add tree trait to pages

* get ready for tree view pages

* improve page edit

* fix revision

* fix slug

* add router params delegate

* fix params delegate

* fix

* fix

* fix all

* fix all

* fix tree

* fix page link

* fix feed

* fix page

* fix permalink

* fix permalink input

* fix offset query

* Support IDN (#1629)

* Support IDN

* use js

* Optimize code

* Optimize code

* fix URL script

* remove unnecessary use

---------

Co-authored-by: joyqi <joyqi@segmentfault.com>

* fix input element

* fix #1651, close #1653

* Use json instead of serialize (#1624)

* Use json instead of serialize

* Fix Upgrade code

* add tree trait

* finish category tree trait

* support select fields

* fix select fields

* refactor admin trait

* fix draft status

* Add new contents type "revision"

* minor refactor

* add more tree view abstracts

* add tree trait to pages

* get ready for tree view pages

* improve page edit

* fix revision

* fix slug

* add router params delegate

* fix params delegate

* fix

* fix

* fix all

* fix all

* fix tree

* fix page link

* fix feed

* fix page

* fix permalink

* fix permalink input

* fix offset query

* Fix typo

* remove proxy methods

* remove unnecessary useage

---------

Co-authored-by: joyqi <joyqi@segmentfault.com>
Co-authored-by: joyqi <magike.net@gmail.com>

* Fix Prevent XSS vulnerability in default theme (#1654)

* Fix Prevent XSS vulnerability in default theme

* Update var/Typecho/Db/Adapter/Pdo.php

* fix the getter

---------

Co-authored-by: joyqi <joyqi@segmentfault.com>

* add throwCallback to widget response

* fix: cut down fields when selecting recent posts

* fix typo errors

* fix typo errors

* fix http client cookie

* add throw finish

* fix theme lang

* fix default theme

* fix query

* add open graph and twitter card support
add canonical link

* fix canonical link meta

* fix theme classic-22

* remove unnecessary scss file when packaging

* init plugin signal

* improve: remove feather-icon js file

* fix: typo

* improve: post detail layout

* fix tags saving

* improve: nav search

* fix: theme screenshot

* fix: theme page layout

* remove php 7.2/7.3 env

* feat: pull request auto merge

* fix permission

---------

Co-authored-by: fen <f3nb0x@gmail.com>
Co-authored-by: Lu Fei <52o@qq52o.cn>
2023-12-31 17:13:56 +08:00
joyqi
2a1a692195 fix permission 2023-12-31 17:13:07 +08:00
joyqi
8b4118a2ce Merge commit '746667a8e602aece11bc8e6ec8d0daf20999aff5' into dev 2023-12-31 17:12:55 +08:00
jrotty
746667a8e6 删除多余无用js (#1668)
看了下默认主题没有引用任何js,这个应该是多余的
2023-12-31 17:05:45 +08:00
joyqi
6232de74e9 Merge pull request branch automatically (#1669)
* Add feed widget

* add feed render

* Add CommentPage widget

* New theme (#1390)

* 调整忽略目录

* add theme

* fix theme scss build

Co-authored-by: fen <f3nb0x@gmail.com>

* s/is_writeable/is_writable/g

* New upgrade method

* merge new fixes from master

* add pgsql ssl mode support (ref #1600) (#1623)

* Feat/code refactor (#1626)

* remove all magic methods, add type for class properties

* refactor codes

* fix all

* refactor code

* fix type

* fix all

* fix request is method

* fix all

* fix router

* fix get page

* fix 1.3.0 upgrade

* [feat] support high resolution avatar

* fix types in i18n component

* Implement Ctrl+S or Command+S for save draft (#1628)

* Implement Ctrl+S or Command+S for save draft

* rename

* add Typecho.savePost

* fix upload file size

* add new uploader

* replace new uploader

* fix textarea change

* fix preview

* refactor post edit

* fix issue

* fix page edit

---------

Co-authored-by: joyqi <joyqi@segmentfault.com>
Co-authored-by: joyqi <magike.net@gmail.com>

* fix #1632

* Add svg to image types

* Feat/tree pages (#1646)

* add tree trait

* finish category tree trait

* support select fields

* fix select fields

* refactor admin trait

* fix draft status

* Add new contents type "revision"

* minor refactor

* add more tree view abstracts

* add tree trait to pages

* get ready for tree view pages

* improve page edit

* fix revision

* fix slug

* add router params delegate

* fix params delegate

* fix

* fix

* fix all

* fix all

* fix tree

* fix page link

* fix feed

* fix page

* fix permalink

* fix permalink input

* fix offset query

* Support IDN (#1629)

* Support IDN

* use js

* Optimize code

* Optimize code

* fix URL script

* remove unnecessary use

---------

Co-authored-by: joyqi <joyqi@segmentfault.com>

* fix input element

* fix #1651, close #1653

* Use json instead of serialize (#1624)

* Use json instead of serialize

* Fix Upgrade code

* add tree trait

* finish category tree trait

* support select fields

* fix select fields

* refactor admin trait

* fix draft status

* Add new contents type "revision"

* minor refactor

* add more tree view abstracts

* add tree trait to pages

* get ready for tree view pages

* improve page edit

* fix revision

* fix slug

* add router params delegate

* fix params delegate

* fix

* fix

* fix all

* fix all

* fix tree

* fix page link

* fix feed

* fix page

* fix permalink

* fix permalink input

* fix offset query

* Fix typo

* remove proxy methods

* remove unnecessary useage

---------

Co-authored-by: joyqi <joyqi@segmentfault.com>
Co-authored-by: joyqi <magike.net@gmail.com>

* Fix Prevent XSS vulnerability in default theme (#1654)

* Fix Prevent XSS vulnerability in default theme

* Update var/Typecho/Db/Adapter/Pdo.php

* fix the getter

---------

Co-authored-by: joyqi <joyqi@segmentfault.com>

* add throwCallback to widget response

* fix: cut down fields when selecting recent posts

* fix typo errors

* fix typo errors

* fix http client cookie

* add throw finish

* fix theme lang

* fix default theme

* fix query

* add open graph and twitter card support
add canonical link

* fix canonical link meta

* fix theme classic-22

* remove unnecessary scss file when packaging

* init plugin signal

* improve: remove feather-icon js file

* fix: typo

* improve: post detail layout

* fix tags saving

* improve: nav search

* fix: theme screenshot

* fix: theme page layout

* remove php 7.2/7.3 env

* feat: pull request auto merge

---------

Co-authored-by: fen <f3nb0x@gmail.com>
Co-authored-by: Lu Fei <52o@qq52o.cn>
2023-12-31 17:04:45 +08:00
joyqi
f209fd78fe Merge branch 'master' into dev
# Conflicts:
#	var/Widget/Options.php
2023-12-31 17:02:20 +08:00
joyqi
0265a50100 feat: pull request auto merge 2023-12-31 16:57:59 +08:00
Lu Fei
e306960db4 Fix installation failure (#1664)
* Fix installation failure

* fix missing secret

* Apply suggestions from code review
2023-12-31 16:10:05 +08:00
joyqi
3caebb3b20 v1.3.0 (#1661)
* Add feed widget

* add feed render

* Add CommentPage widget

* New theme (#1390)

* 调整忽略目录

* add theme

* fix theme scss build

Co-authored-by: fen <f3nb0x@gmail.com>

* s/is_writeable/is_writable/g

* New upgrade method

* merge new fixes from master

* add pgsql ssl mode support (ref #1600) (#1623)

* Feat/code refactor (#1626)

* remove all magic methods, add type for class properties

* refactor codes

* fix all

* refactor code

* fix type

* fix all

* fix request is method

* fix all

* fix router

* fix get page

* fix 1.3.0 upgrade

* [feat] support high resolution avatar

* fix types in i18n component

* Implement Ctrl+S or Command+S for save draft (#1628)

* Implement Ctrl+S or Command+S for save draft

* rename

* add Typecho.savePost

* fix upload file size

* add new uploader

* replace new uploader

* fix textarea change

* fix preview

* refactor post edit

* fix issue

* fix page edit

---------

Co-authored-by: joyqi <joyqi@segmentfault.com>
Co-authored-by: joyqi <magike.net@gmail.com>

* fix #1632

* Add svg to image types

* Feat/tree pages (#1646)

* add tree trait

* finish category tree trait

* support select fields

* fix select fields

* refactor admin trait

* fix draft status

* Add new contents type "revision"

* minor refactor

* add more tree view abstracts

* add tree trait to pages

* get ready for tree view pages

* improve page edit

* fix revision

* fix slug

* add router params delegate

* fix params delegate

* fix

* fix

* fix all

* fix all

* fix tree

* fix page link

* fix feed

* fix page

* fix permalink

* fix permalink input

* fix offset query

* Support IDN (#1629)

* Support IDN

* use js

* Optimize code

* Optimize code

* fix URL script

* remove unnecessary use

---------

Co-authored-by: joyqi <joyqi@segmentfault.com>

* fix input element

* fix #1651, close #1653

* Use json instead of serialize (#1624)

* Use json instead of serialize

* Fix Upgrade code

* add tree trait

* finish category tree trait

* support select fields

* fix select fields

* refactor admin trait

* fix draft status

* Add new contents type "revision"

* minor refactor

* add more tree view abstracts

* add tree trait to pages

* get ready for tree view pages

* improve page edit

* fix revision

* fix slug

* add router params delegate

* fix params delegate

* fix

* fix

* fix all

* fix all

* fix tree

* fix page link

* fix feed

* fix page

* fix permalink

* fix permalink input

* fix offset query

* Fix typo

* remove proxy methods

* remove unnecessary useage

---------

Co-authored-by: joyqi <joyqi@segmentfault.com>
Co-authored-by: joyqi <magike.net@gmail.com>

* Fix Prevent XSS vulnerability in default theme (#1654)

* Fix Prevent XSS vulnerability in default theme

* Update var/Typecho/Db/Adapter/Pdo.php

* fix the getter

---------

Co-authored-by: joyqi <joyqi@segmentfault.com>

* add throwCallback to widget response

* fix: cut down fields when selecting recent posts

* fix typo errors

* fix typo errors

* fix http client cookie

* add throw finish

* fix theme lang

* fix default theme

* fix query

* add open graph and twitter card support
add canonical link

* fix canonical link meta

* fix theme classic-22

* remove unnecessary scss file when packaging

* init plugin signal

* improve: remove feather-icon js file

* fix: typo

* improve: post detail layout

* fix tags saving

* improve: nav search

* fix: theme screenshot

* fix: theme page layout

* remove php 7.2/7.3 env

---------

Co-authored-by: fen <f3nb0x@gmail.com>
Co-authored-by: Lu Fei <52o@qq52o.cn>
2023-12-30 23:02:25 +08:00
joyqi
6e0bbe885d remove php 7.2/7.3 env 2023-12-30 23:01:18 +08:00
fen
fc5ac7969c fix: theme page layout 2023-12-30 22:52:11 +08:00
fen
edc73ccbc8 fix: theme screenshot 2023-12-30 22:50:04 +08:00
fen
752eed6890 improve: nav search 2023-12-30 22:29:12 +08:00
joyqi
90c0a70252 fix tags saving 2023-12-30 21:21:43 +08:00
fen
d7465f1cff improve: post detail layout 2023-12-30 20:34:04 +08:00
fen
fef2ec2377 fix: typo 2023-12-30 00:13:02 +08:00
fen
dde84fe0aa improve: remove feather-icon js file 2023-12-30 00:11:59 +08:00
joyqi
878b2b3d11 init plugin signal 2023-12-29 18:03:45 +08:00
joyqi
dd88938aa1 remove unnecessary scss file when packaging 2023-12-29 16:56:14 +08:00
joyqi
7415b5ba76 fix theme classic-22 2023-12-29 16:49:42 +08:00
joyqi
fd013a7508 fix canonical link meta 2023-12-29 14:34:24 +08:00
joyqi
005951ee4d add open graph and twitter card support
add canonical link
2023-12-29 14:31:39 +08:00
joyqi
7edd3f9659 fix query 2023-12-29 12:59:33 +08:00
joyqi
6b2c5b19e1 fix default theme 2023-12-29 11:50:38 +08:00
joyqi
f1937a3a7c fix theme lang 2023-12-28 18:26:14 +08:00
joyqi
0595d1126e add throw finish 2023-12-27 18:45:42 +08:00
joyqi
4c4b14020d fix http client cookie 2023-12-27 18:10:17 +08:00
joyqi
56d7e7eec8 fix typo errors 2023-12-26 23:33:01 +08:00
joyqi
144bbee912 fix typo errors 2023-12-18 15:50:53 +08:00
joyqi
a41fd2dc7c fix: cut down fields when selecting recent posts 2023-12-18 15:48:00 +08:00
joyqi
06fda5b1a6 add throwCallback to widget response 2023-12-18 15:44:41 +08:00
Lu Fei
9df0256e8c Fix Prevent XSS vulnerability in default theme (#1654)
* Fix Prevent XSS vulnerability in default theme

* Update var/Typecho/Db/Adapter/Pdo.php

* fix the getter

---------

Co-authored-by: joyqi <joyqi@segmentfault.com>
2023-12-06 18:03:23 +08:00
Lu Fei
fbc7696ae8 Use json instead of serialize (#1624)
* Use json instead of serialize

* Fix Upgrade code

* add tree trait

* finish category tree trait

* support select fields

* fix select fields

* refactor admin trait

* fix draft status

* Add new contents type "revision"

* minor refactor

* add more tree view abstracts

* add tree trait to pages

* get ready for tree view pages

* improve page edit

* fix revision

* fix slug

* add router params delegate

* fix params delegate

* fix

* fix

* fix all

* fix all

* fix tree

* fix page link

* fix feed

* fix page

* fix permalink

* fix permalink input

* fix offset query

* Fix typo

* remove proxy methods

* remove unnecessary useage

---------

Co-authored-by: joyqi <joyqi@segmentfault.com>
Co-authored-by: joyqi <magike.net@gmail.com>
2023-12-06 15:52:19 +08:00
joyqi
c9aba55949 fix #1651, close #1653 2023-12-04 17:56:17 +08:00
joyqi
a2c1fbf4a8 fix input element 2023-12-04 17:23:06 +08:00
Lu Fei
a1f62e1bcc Support IDN (#1629)
* Support IDN

* use js

* Optimize code

* Optimize code

* fix URL script

* remove unnecessary use

---------

Co-authored-by: joyqi <joyqi@segmentfault.com>
2023-12-04 14:07:20 +08:00
joyqi
e89b1bbcf6 Feat/tree pages (#1646)
* add tree trait

* finish category tree trait

* support select fields

* fix select fields

* refactor admin trait

* fix draft status

* Add new contents type "revision"

* minor refactor

* add more tree view abstracts

* add tree trait to pages

* get ready for tree view pages

* improve page edit

* fix revision

* fix slug

* add router params delegate

* fix params delegate

* fix

* fix

* fix all

* fix all

* fix tree

* fix page link

* fix feed

* fix page

* fix permalink

* fix permalink input

* fix offset query
2023-11-27 21:57:18 -08:00
insomnux
43c54328f7 gettext for installation comment (#1643)
Co-authored-by: insomnux <insomnux@insomnus.info>
2023-10-31 11:30:54 +08:00
joyqi
4c1c42ad40 Add svg to image types 2023-10-23 18:38:40 +08:00
joyqi
b28d5b7bab fix #1632 2023-10-04 15:58:30 +08:00
joyqi
b00a0ae06f Merge commit '99212ec78743317bf52063fb165b90fceb70de5e' into dev
# Conflicts:
#	admin/login.php
2023-10-03 11:16:04 +08:00
joyqi
99212ec787 fix #1635 (#1636) 2023-10-03 11:14:04 +08:00
Lu Fei
5f52c1e25b Fix null argument issue (#1633) 2023-10-03 11:12:46 +08:00
Lu Fei
438ac35487 Implement Ctrl+S or Command+S for save draft (#1628)
* Implement Ctrl+S or Command+S for save draft

* rename

* add Typecho.savePost

* fix upload file size

* add new uploader

* replace new uploader

* fix textarea change

* fix preview

* refactor post edit

* fix issue

* fix page edit

---------

Co-authored-by: joyqi <joyqi@segmentfault.com>
Co-authored-by: joyqi <magike.net@gmail.com>
2023-10-01 16:51:09 +08:00
jrotty
272fc8b3e1 增加邮箱也可以登陆的提示 (#1631)
😭用了八年,今天翻代码才知道也可以用邮箱登陆
2023-09-29 15:12:11 +08:00
joyqi
ff1fde5c4b fix types in i18n component 2023-09-24 23:15:55 +08:00
joyqi
3296151409 [feat] support high resolution avatar 2023-09-24 17:31:35 +08:00
joyqi
157de39b54 fix 1.3.0 upgrade 2023-09-24 16:25:01 +08:00
joyqi
4c8c64c79e Feat/code refactor (#1626)
* remove all magic methods, add type for class properties

* refactor codes

* fix all

* refactor code

* fix type

* fix all

* fix request is method

* fix all

* fix router

* fix get page
2023-09-24 16:21:32 +08:00
joyqi
9b107027ed add pgsql ssl mode support (ref #1600) (#1623) 2023-09-22 13:51:35 +08:00
joyqi
b73187f12c merge new fixes from master 2023-09-22 11:09:34 +08:00
joyqi
f206d852bd Merge commit 'e143be0036b91a6ec4bfc5e8d3ad7c19edbfa6e8' into dev 2023-09-22 11:08:55 +08:00
Losses Don
e143be0036 fix: Fix #1597 (#1598) 2023-09-22 10:54:38 +08:00
joyqi
91ae56484d fix the source to get content type (#1622) 2023-09-22 10:50:39 +08:00
Lu Fei
9910a9cddc Optimize checkVersion,feed code (#1605) 2023-09-22 10:49:51 +08:00
Jealous
666619538a Fix typo (#1612) 2023-09-21 22:48:27 +08:00
joyqi
38562bab48 Merge commit '9d1b01a8736ab1ce39e9e2e666a2f992eba28b0f' into dev 2023-07-07 16:56:26 +08:00
Kent Liao
9d1b01a873 fix: adding checkbox options after theme initialization cannot be saved. (#1591)
* fix: adding checkbox options after theme initialization cannot be saved.

* chore: Use isset to determine if an option exists
2023-06-14 08:58:27 +08:00
logdd
206880ba71 重复执行判断的优化 (#1586)
使用$isNamespace变量,避免重复判断
2023-06-05 15:15:24 +08:00
joyqi
c1753aa04e improve release ci, upload built asset after new release published. (#1576) 2023-05-17 11:35:18 +08:00
joyqi
6f19a24aa3 fix #1574 (#1575)
* split multiple values

* add a new field type 'json' to handle complex situation

* fix json input display
2023-05-16 21:45:41 +08:00
沈唁
c725fec12e Add a prompt message for manual database creation (#1348)
* Optimize for no database during install

* change tips
2023-05-16 14:33:26 +08:00
joyqi
596d117210 fix: when setting CheckBox's default value to null [ref #1568] 2023-05-16 12:33:49 +08:00
joyqi
0433a11c0a escape mail string before output 2023-05-15 22:35:25 +08:00
joyqi
98e4c1d16d fix url validate 2023-05-15 21:44:12 +08:00
joyqi
7a41f0d013 fix email validate 2023-05-15 19:55:36 +08:00
Ryan Lieu
c9de1b3b01 fix php 8.1 Deprecated: htmlspecialchars(): Passing null to parameter #1 (#1570)
* Fix multiple calls returning the same object

* fix: strtolower() passing null to parameter #1 ($string) of type string is deprecated

* fix: php 8.1 Deprecated: htmlspecialchars(): Passing null to parameter #1 ($string) of type string is deprecated
2023-05-15 18:30:44 +08:00
Patrick SAMA
83d4d020ed Fix an XSS vulnerability in v1.2.1-rc (#1561)
* fix #1560

* Update var/Typecho/Validate.php

Co-authored-by: 沈唁 <52o@qq52o.cn>

---------

Co-authored-by: joyqi <joyqi@users.noreply.github.com>
Co-authored-by: 沈唁 <52o@qq52o.cn>
2023-05-15 18:29:47 +08:00
Ryan Lieu
01100c9a4a Fix: php 8.1 strtolower not allow null value (#1559) 2023-04-14 11:45:09 +08:00
joyqi
6de71129a4 Merge commit 'daef17d7eb250419ff84f499e87d25ee71daac87' into dev
# Conflicts:
#	var/Utils/Upgrade.php
2023-03-29 16:20:01 +08:00
沈唁
daef17d7eb Support ssl for pdo_mysql and mysqli (#1525)
* Support ssl for pdo_mysql and mysqli

* Improve config name for mysql ssl mode, and fix some minor bugs.

* Fix typo

---------

Co-authored-by: joyqi <joyqi@segmentfault.com>
2023-03-29 14:33:23 +08:00
joyqi
65f5974e17 Replace the protocol of backend remote checking url from http to https. 2023-03-28 12:07:33 +08:00
Zero King
f6e1232db8 Use https links (#1280) 2023-03-28 11:57:45 +08:00
joyqi
b989459d87 fix #1545 and close #1547 2023-03-28 11:36:01 +08:00
joyqi
a609b149e9 fix #1539 2023-03-03 16:37:32 +08:00
joyqi
f9ede542c9 fix #1535 2023-02-21 17:43:20 +08:00
joyqi
d4a5f765a3 Merge branch 'master' into dev
# Conflicts:
#	admin/css/style.css
#	var/Widget/Archive.php
2023-01-29 14:28:43 +08:00
沈唁
16d21f03ef Fix htmlspecialchars error for feed (#1522) 2023-01-11 00:45:28 +08:00
Zero King
8437eac420 Fix unsafe use of jQuery .html() (#1382) 2022-10-29 23:54:13 +08:00
joyqi
f0bf9d770d update readme 2022-10-25 14:53:09 +08:00
沈唁
e05ebe442e Fix #1495 (#1496)
Argument 1 passed to Utils\AutoP::parse() must be of the type string, null given
2022-09-22 10:25:18 +08:00
沈唁
17d9dcfa17 Fix comments feed jump error (#1491) 2022-08-15 07:24:43 +08:00
沈唁
2014be4cd3 Adjust style of edit comments (#1483)
* Adjust style of edit comments

Fix #1481

* update

* update
2022-08-01 14:56:22 +08:00
沈唁
d15fc14463 Fix use SQLite error of windows install (#1471) 2022-07-20 00:20:25 +08:00
Ryan Lieu
f07b57fe20 Fix multiple calls returning the same object (#1478) 2022-07-15 11:19:18 +08:00
沈唁
c03ee2c8be Fix the error of getting request parameters (#1464) 2022-06-21 13:59:53 +08:00
Kane
4095850140 Minor update (#1460)
- 后台上传设置增加 avif 类型
- 后台 Avatar 头像支持原生懒加载
2022-06-14 18:57:07 +08:00
Kane
7f7b24d28f Minor update (#1451)
* Update

- 更新 Windows 和 Linux 系统中文本编辑器样式问题(为代码块中添加中文后备字体修正样式)

* Update

- 缩略图支持识别 avif 图片(具体可参考https://en.wikipedia.org/wiki/AVIF
2022-06-07 18:08:24 +08:00
joyqi
1d0e253281 Fix page draft publish 2022-06-01 23:50:36 +08:00
沈唁
88c3bfe13f Fix #1449 (#1450) 2022-05-30 11:11:44 +08:00
沈唁
59a5c8d14d Fix category creation error when using xmlrpc (#1443)
* Fix category creation error when using xmlrpc

* Add use Typecho\Request
2022-05-23 10:44:59 +08:00
joyqi
3119c05e2c fix #1441, fix #1442 2022-05-17 10:24:56 +08:00
joyqi
05e20c0ae5 Fix themeUrl format 2022-05-13 00:46:12 +08:00
沈唁
7279d4832d Fix missing change themeUrl (#1431)
* Fix missing change themeUrl

* Use options themeUrl method
2022-05-13 00:26:10 +08:00
沈唁
ac33000ad0 Add admin/footer.php begin plugin (#1426) 2022-05-07 16:33:00 +08:00
MBRjun Duplicate
02937dc51c Fix QUIC/https Mixed Content (#1423) 2022-05-04 09:31:59 +08:00
jrotty
437d296af5 修复管理员进入其他用户文章列表时显示所有文章的bug (#1415)
* 修复管理员进入其他用户文章列表时显示所有文章的bug

bug描述:当管理员在文章管理页面,点击所有查看所有文章后,再通过这个页面进入作者文章管理页面时,仍会显示所有文章而不是当前作者的文章

* Update manage-users.php

* Fix missing manage-posts

Co-authored-by: sy-records <52o@qq52o.cn>
2022-04-29 10:53:05 +08:00
沈唁
f31e6daf7b Fix notice not clear (#1416) 2022-04-26 10:29:26 +08:00
jrotty
f8a9d95e43 修正注释 (#1411)
* 修正注释

* 修正注释
2022-04-23 18:00:02 +08:00
jrotty
0fbb1aaea5 模板缩略图支持识别webp图片后缀 (#1403)
* 模板缩略图支持识别webp图片后缀

* Update Contents.php

Co-authored-by: 沈唁 <52o@qq52o.cn>
2022-04-15 13:51:06 +08:00
Valpha
9fd02529b1 Update write-js.php (#1400)
Add 'allow-same-origin' into sandbox's attrs to fix that the article preview page does not match the real page.
2022-04-15 13:50:13 +08:00
沈唁
3512fd41bf Enhancement of Typecho\Cookie (#1399) 2022-04-14 15:49:04 +08:00
joyqi
bec905274a New upgrade method 2022-04-08 15:11:09 +08:00
joyqi
53eda2cf75 s/is_writeable/is_writable/g 2022-04-07 17:31:32 +08:00
joyqi
bad3ef651d New theme (#1390)
* 调整忽略目录

* add theme

* fix theme scss build

Co-authored-by: fen <f3nb0x@gmail.com>
2022-04-07 14:20:59 +08:00
joyqi
a74206a89e Add CommentPage widget 2022-04-07 12:55:19 +08:00
joyqi
997aa607ac fix words 2022-04-07 11:28:28 +08:00
沈唁
3b03e0267b Update admin welcome tip (#1389) 2022-04-07 11:26:02 +08:00
joyqi
22a8ad362e add feed render 2022-04-07 01:53:33 +08:00
joyqi
f49564db23 Add feed widget 2022-04-06 18:26:15 +08:00
joyqi
61606a9069 fix #1380 2022-04-05 22:53:39 +08:00
joyqi
34e5bf2861 fix #1375 2022-04-04 00:01:33 +08:00
沈唁
c78f7fda68 Fix pgsql reset id error (#1369) 2022-04-02 21:27:31 +08:00
joyqi
7ebfe82de1 fix #1361 2022-04-02 18:10:28 +08:00
joyqi
004db7c056 Move language build trigger from workflows/dev to workflows/release. 2022-04-02 16:41:37 +08:00
joyqi
d4068b1661 fix #1363, close #1364
Add json request & response. Perform async service via json request.
2022-04-02 15:33:17 +08:00
joyqi
d77a1ecad7 Delete config.inc.sqlite.php 2022-04-01 16:55:08 +08:00
joyqi
ded268ef59 Pr/1344 (#1360)
* Add missing theme action

* Fix typo

* Optimize code

* Optimize code

* Update themes.php

* Simpler missing theme judgement

Co-authored-by: sy-records <52o@qq52o.cn>
2022-04-01 16:50:23 +08:00
joyqi
142a615feb Merge branch 'master' of github.com:typecho/typecho 2022-04-01 15:25:28 +08:00
joyqi
c30b67d18d Update .gitignore
update gitignore
2022-04-01 15:25:10 +08:00
毛线
2db893e802 Update install.php (#1357)
修复宝塔面板的网站目录带.导致db路径校验不通过的问题
2022-04-01 14:07:08 +08:00
沈唁
2f3e15dfb8 Fix checkVersion (#1356) 2022-04-01 11:12:54 +08:00
229 changed files with 9169 additions and 27059 deletions

View File

@@ -12,11 +12,11 @@ jobs:
php:
name: PHP ${{ matrix.php }} Tests
runs-on: ubuntu-latest
if: "!contains(github.event.head_commit.message, 'skip ci')"
if: ${{ !contains(github.event.head_commit.message, 'skip ci') }}
strategy:
fail-fast: false
matrix:
php: ['7.2', '7.3', '7.4', '8.0', '8.1']
php: ['7.4', '8.0', '8.1', '8.2']
steps:
- name: Checkout code
uses: actions/checkout@v2
@@ -30,7 +30,7 @@ jobs:
build:
name: Typecho Build
runs-on: ubuntu-latest
if: "!contains(github.event.head_commit.message, 'skip ci') && github.event_name != 'pull_request'"
if: ${{ !contains(github.event.head_commit.message, 'skip ci') && github.event_name != 'pull_request' }}
needs:
- php
steps:
@@ -43,6 +43,7 @@ jobs:
mkdir build/usr/uploads/
chmod 755 build/usr/uploads/
rm -rf build/admin/src
rm -rf build/usr/themes/classic-22/static/scss
cd build && zip -q -r typecho.zip * && mv typecho.zip ../ && cd -
- name: Upload a Build Artifact
uses: WebFreak001/deploy-nightly@v1.1.0
@@ -55,10 +56,3 @@ jobs:
asset_name: typecho.zip
asset_content_type: application/zip
max_releases: 1
- name: Trigger build
run: |
curl -XPOST -H "Authorization: token ${{ secrets.WORKFLOW_TOKEN }}" \
-H "Accept: application/vnd.github.everest-preview+json" \
-H "Content-Type: application/json" \
https://api.github.com/repos/typecho/languages/actions/workflows/update.yml/dispatches --data '{"ref": "master"}'

View File

@@ -0,0 +1,36 @@
name: Typecho Hotfix Merge
on:
pull_request:
types:
- closed
- labeled
branches:
- master
jobs:
auto-merge:
if: github.event.action == 'closed' && github.event.pull_request.merged == true && startsWith(github.event.pull_request.head.ref, 'fix/')
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Merge to dev branch
uses: devmasx/merge-branch@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
from_branch: ${{ github.event.pull_request.head.ref }}
target_branch: dev
label-merge:
if: github.event.action == 'labeled' && !startsWith(github.event.pull_request.head.ref, 'fix/')
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Merge to dev branch
uses: devmasx/merge-branch@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
label_name: 'merge-to-dev'
target_branch: dev

View File

@@ -1,14 +1,14 @@
name: Typecho Build Release Ci
on:
push:
tags:
- 'v*'
release:
types: [published]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Build
run: |
mkdir build
@@ -16,24 +16,18 @@ jobs:
mkdir build/usr/uploads/
chmod 755 build/usr/uploads/
rm -rf build/admin/src
rm -rf build/usr/themes/classic-22/static/scss
cd build && zip -q -r typecho.zip * && mv typecho.zip ../ && cd -
- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: ${{ github.ref }}
draft: true
prerelease: false
- name: Upload Release Asset
id: upload-release-asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
uses: shogo82148/actions-upload-release-asset@v1
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
upload_url: ${{ github.event.release.upload_url }}
asset_path: ./typecho.zip
asset_name: typecho.zip
asset_content_type: application/zip
- name: Trigger language build
run: |
curl -XPOST -H "Authorization: token ${{ secrets.WORKFLOW_TOKEN }}" \
-H "Accept: application/vnd.github.everest-preview+json" \
-H "Content-Type: application/json" \
https://api.github.com/repos/typecho/languages/actions/workflows/update.yml/dispatches --data '{"ref": "master"}'

17
.gitignore vendored
View File

@@ -25,12 +25,13 @@
.sass-cache
config.rb
prepros.config
/config.inc.php
/usr/uploads/
/usr/*.db
/usr/plugins/
!/usr/plugins/HelloWorld
/usr/themes/
!/usr/themes/default
config.inc.*
usr/uploads/
usr/*.db
usr/plugins/
!usr/plugins/HelloWorld
usr/themes/*
!usr/themes/default
!usr/themes/classic-22
node_modules/
/tools/tmp/
tools/tmp/

37
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,37 @@
Contributing to Typecho
=======================
Thanks for considering contributing to Typecho! There are many ways to contribute to Typecho, and we appreciate all of them.
## Reporting Bugs
If you find a bug in the source code, you can help us by [submitting an issue](https://github.com/typecho/typecho/issues)
to our [GitHub Repository](https://github.com/typecho/typecho). Even better, you can submit a Pull Request with a fix.
## Contributing Code
If you would like to contribute code to Typecho, please read the following guidelines:
* [Code of Conduct](CODE_OF_CONDUCT.md)
* [Contributing Guide](CONTRIBUTING.md)
* [Coding Style Guide](CODING_STYLE.md)
## Translations
Please see [TRANSLATION](https://github.com/typecho/languages) for details.
## Plugin Development
Please see [Plugin Development](http://docs.typecho.org/plugins) for details.
## Theme Development
Please see [Theme Development](http://docs.typecho.org/themes) for details.
## Community
* [Telegram Channel](https://t.me/typechodev)
* [Homepage](http://typecho.org/)
* [Documents](http://docs.typecho.org/)
* [Community](http://forum.typecho.org/)
* [Download](http://typecho.org/download)

View File

@@ -1,19 +1,30 @@
Typecho Blogging Platform
=========================
Typecho is a PHP Blogging Platform. Simple and Powerful.
Typecho is a PHP-based blog software and is designed to be the most powerful blog engine in the world.
Typecho is released under the GNU General Public License 2.0.
#### Telegram Channel
https://t.me/typechodev
## Main Features
#### Homepage
http://typecho.org/
* Multiple databases support (MySQL, SQLite, PostgreSQL)
* Markdown Support
* Plugin Support
* Theme Support
* Custom Fields
* Custom Pages
#### Documents
http://docs.typecho.org/
## Requirements
#### Community
http://forum.typecho.org/
* PHP 7.2.0 or higher
* Database (MySQL, SQLite, PostgreSQL)
* MySQL 5.5.3 or higher
* SQLite 3.7.11 or higher
* PostgreSQL 9.1 or higher
#### Download
http://typecho.org/download
## Screenshots
![Typecho](https://typecho.org/usr/themes/bluecode/img/screenshot/st1.png)
## Contributing
Please see [CONTRIBUTING](CONTRIBUTING.md) for details.

View File

@@ -84,6 +84,7 @@ $backupFiles = \Widget\Backup::alloc()->listFiles();
<?php
include 'copyright.php';
include 'common-js.php';
include 'form-js.php';
?>
<script>
$('#backup-secondary .typecho-option-tabs li').click(function() {

View File

@@ -13,7 +13,9 @@
noticeType : $.cookie(prefix + '__typecho_notice_type'),
highlight : $.cookie(prefix + '__typecho_notice_highlight')
},
path = '<?php echo \Typecho\Cookie::getPath(); ?>';
path = '<?php echo \Typecho\Cookie::getPath(); ?>',
domain = '<?php echo \Typecho\Cookie::getDomain(); ?>',
secure = <?php echo json_encode(\Typecho\Cookie::getSecure()); ?>;
if (!!cookies.notice && 'success|notice|error'.indexOf(cookies.noticeType) >= 0) {
var head = $('.typecho-head-nav'),
@@ -63,14 +65,13 @@
});
});
$.cookie(prefix + '__typecho_notice', null, {path : path});
$.cookie(prefix + '__typecho_notice_type', null, {path : path});
$.cookie(prefix + '__typecho_notice', null, {path : path, domain: domain, secure: secure});
$.cookie(prefix + '__typecho_notice_type', null, {path : path, domain: domain, secure: secure});
}
if (cookies.highlight) {
$('#' + cookies.highlight).effect('highlight', 1000);
$.cookie(prefix + '__typecho_notice_highlight', null, {path : path});
$.cookie(prefix + '__typecho_notice_highlight', null, {path : path, domain: domain, secure: secure});
}
})();
@@ -91,6 +92,7 @@
$('#typecho-nav-list ul.root').each(function () {
const ul = $(this), nav = ul.parent();
let focused = false;
ul.on('click touchend', '.parent a', function (e) {
nav.removeClass('noexpanded').addClass('expanded');
@@ -102,6 +104,19 @@
nav.removeClass('expanded').addClass('noexpanded');
return false;
}));
$('a', ul).focus(function () {
ul.addClass('expanded');
focused = true;
}).blur(function () {
focused = false;
setTimeout(function () {
if (!focused) {
ul.removeClass('expanded');
}
});
});
});
if ($('.typecho-login').length == 0) {
@@ -118,10 +133,6 @@
.attr('rel', 'noopener noreferrer');
});
}
$('.main form').submit(function () {
$('button[type=submit]', this).attr('disabled', 'disabled');
});
});
})();
</script>

View File

@@ -15,7 +15,7 @@ if (!defined('__TYPECHO_ROOT_DIR__') && !@include_once __DIR__ . '/../config.inc
\Widget\Init::alloc();
/** 注册一个初始化插件 */
\Typecho\Plugin::factory('admin/common.php')->begin();
\Typecho\Plugin::factory('admin/common.php')->call('begin');
\Widget\Options::alloc()->to($options);
\Widget\User::alloc()->to($user);

View File

@@ -1,13 +1,13 @@
<?php if(!defined('__TYPECHO_ADMIN__')) exit; ?>
<div class="typecho-foot" role="contentinfo">
<div class="copyright">
<a href="http://typecho.org" class="i-logo-s">Typecho</a>
<p><?php _e('由 <a href="http://typecho.org">%s</a> 强力驱动, 版本 %s', $options->software, $options->version); ?></p>
<a href="https://typecho.org" class="i-logo-s">Typecho</a>
<p><?php _e('由 <a href="https://typecho.org">%s</a> 强力驱动, 版本 %s', $options->software, $options->version); ?></p>
</div>
<nav class="resource">
<a href="http://docs.typecho.org"><?php _e('帮助文档'); ?></a> &bull;
<a href="http://forum.typecho.org"><?php _e('支持论坛'); ?></a> &bull;
<a href="https://docs.typecho.org"><?php _e('帮助文档'); ?></a> &bull;
<a href="https://forum.typecho.org"><?php _e('支持论坛'); ?></a> &bull;
<a href="https://github.com/typecho/typecho/issues"><?php _e('报告错误'); ?></a> &bull;
<a href="http://typecho.org/download"><?php _e('资源下载'); ?></a>
<a href="https://typecho.org/download"><?php _e('资源下载'); ?></a>
</nav>
</div>

File diff suppressed because one or more lines are too long

View File

@@ -1,24 +1 @@
h1 { text-align: center; }
details summary { cursor: pointer; }
@keyframes fadein { from { opacity: 0; }
to { opacity: 1; } }
.fresh .keep-word { display: none; }
.keep .fresh-word { display: none; }
form > .message { display: none; padding: 20px; border-radius: 5px; }
.message textarea { width: 100%; height: 200px; resize: none; margin: 10px 0; }
.message.fade { display: block; animation: fadein .5s linear; }
.message *:last-child { margin-bottom: 0; }
.message p { margin-top: 10px; }
.message p button { margin-left: 5px; }
.message p button:first-child { margin-left: 0; }
h1{text-align:center}details summary{cursor:pointer}@keyframes fadein{from{opacity:0}to{opacity:1}}.fresh .keep-word{display:none}.keep .fresh-word{display:none}form>.message{display:none;padding:20px;border-radius:5px}.message textarea{width:100%;height:200px;resize:none;margin:10px 0}.message.fade{display:block;animation:fadein .5s linear}.message *:last-child{margin-bottom:0}.message p{margin-top:10px}.message p button{margin-left:5px}.message p button:first-child{margin-left:0}

File diff suppressed because one or more lines are too long

View File

@@ -20,7 +20,7 @@ $(document).ready(function () {
$(this).remove();
});
$(this).parents('form').trigger('field');
$(this).parents('form').trigger('change');
}
});
}
@@ -30,7 +30,7 @@ $(document).ready(function () {
});
$('#custom-field button.operate-add').click(function () {
var html = '<tr><td><input type="text" name="fieldNames[]" placeholder="<?php _e('字段名称'); ?>" class="text-s w-100"></td>'
var html = '<tr><td><input type="text" name="fieldNames[]" placeholder="<?php _e('字段名称'); ?>" pattern="^[_a-zA-Z][_a-zA-Z0-9]*$" oninput="this.reportValidity()" class="text-s w-100"></td>'
+ '<td><select name="fieldTypes[]" id="">'
+ '<option value="str"><?php _e('字符'); ?></option>'
+ '<option value="int"><?php _e('整数'); ?></option>'
@@ -40,10 +40,6 @@ $(document).ready(function () {
+ '<td><button type="button" class="btn btn-xs"><?php _e('删除'); ?></button></td></tr>',
el = $(html).hide().appendTo('#custom-field table tbody').fadeIn();
$(':input', el).bind('input change', function () {
$(this).parents('form').trigger('field');
});
attachDeleteEvent(el);
});
});

View File

@@ -9,8 +9,8 @@ $defaultFields = isset($post) ? $post->getDefaultFieldItems() : $page->getDefaul
class="i-caret-right"></i> <?php _e('自定义字段'); ?></a></label>
<table class="typecho-list-table mono">
<colgroup>
<col width="25%"/>
<col width="10%"/>
<col width="20%"/>
<col width="15%"/>
<col width="55%"/>
<col width="10%"/>
</colgroup>
@@ -26,7 +26,7 @@ $defaultFields = isset($post) ? $post->getDefaultFieldItems() : $page->getDefaul
<td>
<label for="fieldname" class="sr-only"><?php _e('字段名称'); ?></label>
<input type="text" name="fieldNames[]" value="<?php echo htmlspecialchars($field['name']); ?>"
id="fieldname" class="text-s w-100">
id="fieldname" pattern="^[_a-zA-Z][_a-zA-Z0-9]*$" oninput="this.reportValidity()" class="text-s w-100">
</td>
<td>
<label for="fieldtype" class="sr-only"><?php _e('字段类型'); ?></label>
@@ -37,12 +37,14 @@ $defaultFields = isset($post) ? $post->getDefaultFieldItems() : $page->getDefaul
value="int"<?php if ('int' == $field['type']): ?> selected<?php endif; ?>><?php _e('整数'); ?></option>
<option
value="float"<?php if ('float' == $field['type']): ?> selected<?php endif; ?>><?php _e('小数'); ?></option>
<option
value="json"<?php if ('json' == $field['type']): ?> selected<?php endif; ?>><?php _e('JSON 结构'); ?></option>
</select>
</td>
<td>
<label for="fieldvalue" class="sr-only"><?php _e('字段值'); ?></label>
<textarea name="fieldValues[]" id="fieldvalue" class="text-s w-100"
rows="2"><?php echo htmlspecialchars($field[$field['type'] . '_value']); ?></textarea>
rows="2"><?php echo htmlspecialchars($field[($field['type'] == 'json' ? 'str' : $field['type']) . '_value']); ?></textarea>
</td>
<td>
<button type="button" class="btn btn-xs"><?php _e('删除'); ?></button>
@@ -54,7 +56,7 @@ $defaultFields = isset($post) ? $post->getDefaultFieldItems() : $page->getDefaul
<td>
<label for="fieldname" class="sr-only"><?php _e('字段名称'); ?></label>
<input type="text" name="fieldNames[]" placeholder="<?php _e('字段名称'); ?>" id="fieldname"
class="text-s w-100">
class="text-s w-100" pattern="^[_a-zA-Z][_a-zA-Z0-9]*$" oninput="this.reportValidity()">
</td>
<td>
<label for="fieldtype" class="sr-only"><?php _e('字段类型'); ?></label>
@@ -77,6 +79,6 @@ $defaultFields = isset($post) ? $post->getDefaultFieldItems() : $page->getDefaul
</table>
<div class="description clearfix">
<button type="button" class="btn btn-xs operate-add"><?php _e('+添加字段'); ?></button>
<?php _e('自定义字段可以扩展你的模板功能, 使用方法参见 <a href="http://docs.typecho.org/help/custom-fields">帮助文档</a>'); ?>
<?php _e('自定义字段可以扩展你的模板功能, 使用方法参见 <a href="https://docs.typecho.org/help/custom-fields">帮助文档</a>'); ?>
</div>
</section>

View File

@@ -1,17 +1,44 @@
<?php if(!defined('__TYPECHO_ADMIN__')) exit; ?>
<?php $content = !empty($post) ? $post : $page; if ($options->markdown): ?>
<?php $content = !empty($post) ? $post : $page; ?>
<script>
(function () {
$('#text').on('change', function (e) {
e.preventDefault();
e.stopPropagation();
}).on('input', function () {
$(this).parents('form').trigger('write');
});
})();
</script>
<?php if (!$options->markdown): ?>
<script>
(function () {
const textarea = $('#text');
// 原始的插入图片和文件
Typecho.insertFileToEditor = function (file, url, isImage) {
const sel = textarea.getSelection(),
html = isImage ? '<img src="' + url + '" alt="' + file + '" />'
: '<a href="' + url + '">' + file + '</a>',
offset = (sel ? sel.start : 0) + html.length;
textarea.replaceSelection(html);
textarea.setSelection(offset, offset);
};
})();
</script>
<?php else: ?>
<script src="<?php $options->adminStaticUrl('js', 'hyperdown.js'); ?>"></script>
<script src="<?php $options->adminStaticUrl('js', 'pagedown.js'); ?>"></script>
<script src="<?php $options->adminStaticUrl('js', 'paste.js'); ?>"></script>
<script src="<?php $options->adminStaticUrl('js', 'purify.js'); ?>"></script>
<script>
$(document).ready(function () {
var textarea = $('#text'),
isFullScreen = false,
const textarea = $('#text'),
toolbar = $('<div class="editor" id="wmd-button-bar" />').insertBefore(textarea.parent()),
preview = $('<div id="wmd-preview" class="wmd-hidetab" />').insertAfter('.editor');
let isFullScreen = false;
var options = {}, isMarkdown = <?php echo intval($content->isMarkdown || !$content->have()); ?>;
const options = {}, isMarkdown = <?php echo intval($content->isMarkdown || !$content->have()); ?>;
options.strings = {
bold: '<?php _e('加粗'); ?> <strong> Ctrl+B',
@@ -59,13 +86,13 @@ $(document).ready(function () {
help: '<?php _e('Markdown语法帮助'); ?>'
};
var converter = new HyperDown(),
const converter = new HyperDown(),
editor = new Markdown.Editor(converter, '', options);
// 自动跟随
converter.enableHtml(true);
converter.enableLine(true);
reloadScroll = scrollableEditor(textarea, preview);
const reloadScroll = scrollableEditor(textarea, preview);
// 修正白名单
converter.hook('makeHtml', function (html) {
@@ -82,7 +109,7 @@ $(document).ready(function () {
// 替换block
html = html.replace(/<(iframe|embed)\s+([^>]*)>/ig, function (all, tag, src) {
if (src[src.length - 1] == '/') {
if (src[src.length - 1] === '/') {
src = src.substring(0, src.length - 1);
}
@@ -94,25 +121,26 @@ $(document).ready(function () {
});
editor.hooks.chain('onPreviewRefresh', function () {
var images = $('img', preview), count = images.length;
const images = $('img', preview);
let count = images.length;
if (count == 0) {
if (count === 0) {
reloadScroll(true);
} else {
images.bind('load error', function () {
count --;
if (count == 0) {
if (count === 0) {
reloadScroll(true);
}
});
}
});
<?php \Typecho\Plugin::factory('admin/editor-js.php')->markdownEditor($content); ?>
<?php \Typecho\Plugin::factory('admin/editor-js.php')->call('markdownEditor', $content); ?>
var th = textarea.height(), ph = preview.height(),
uploadBtn = $('<button type="button" id="btn-fullscreen-upload" class="btn btn-link">'
let th = textarea.height(), ph = preview.height();
const uploadBtn = $('<button type="button" id="btn-fullscreen-upload" class="btn btn-link">'
+ '<i class="i-upload"><?php _e('附件'); ?></i></button>')
.prependTo('.submit .right')
.click(function() {
@@ -129,7 +157,7 @@ $(document).ready(function () {
th = textarea.height();
ph = preview.height();
$(document.body).addClass('fullscreen');
var h = $(window).height() - toolbar.outerHeight();
const h = $(window).height() - toolbar.outerHeight();
textarea.css('height', h);
preview.css('height', h);
@@ -139,7 +167,7 @@ $(document).ready(function () {
editor.hooks.chain('enterFullScreen', function () {
$(document.body).addClass('fullscreen');
var h = window.screen.height - toolbar.outerHeight();
const h = window.screen.height - toolbar.outerHeight();
textarea.css('height', h);
preview.css('height', h);
isFullScreen = true;
@@ -156,19 +184,23 @@ $(document).ready(function () {
textarea.trigger('input');
});
editor.hooks.chain('save', function () {
Typecho.savePost();
});
function initMarkdown() {
editor.run();
var imageButton = $('#wmd-image-button'),
const imageButton = $('#wmd-image-button'),
linkButton = $('#wmd-link-button');
Typecho.insertFileToEditor = function (file, url, isImage) {
var button = isImage ? imageButton : linkButton;
const button = isImage ? imageButton : linkButton;
options.strings[isImage ? 'imagename' : 'linkname'] = file;
button.trigger('click');
var checkDialog = setInterval(function () {
let checkDialog = setInterval(function () {
if ($('.wmd-prompt-dialog').length > 0) {
$('.wmd-prompt-dialog input').val(url).select();
clearInterval(checkDialog);
@@ -177,12 +209,12 @@ $(document).ready(function () {
}, 10);
};
Typecho.uploadComplete = function (file) {
Typecho.insertFileToEditor(file.title, file.url, file.isImage);
Typecho.uploadComplete = function (attachment) {
Typecho.insertFileToEditor(attachment.title, attachment.url, attachment.isImage);
};
// 编辑预览切换
var edittab = $('.editor').prepend('<div class="wmd-edittab"><a href="#wmd-editarea" class="active"><?php _e('撰写'); ?></a><a href="#wmd-preview"><?php _e('预览'); ?></a></div>'),
const edittab = $('.editor').prepend('<div class="wmd-edittab"><a href="#wmd-editarea" class="active"><?php _e('撰写'); ?></a><a href="#wmd-preview"><?php _e('预览'); ?></a></div>'),
editarea = $(textarea.parent()).attr("id", "wmd-editarea");
$(".wmd-edittab a").click(function() {
@@ -190,11 +222,11 @@ $(document).ready(function () {
$(this).addClass("active");
$("#wmd-editarea, #wmd-preview").addClass("wmd-hidetab");
var selected_tab = $(this).attr("href"),
const selected_tab = $(this).attr("href"),
selected_el = $(selected_tab).removeClass("wmd-hidetab");
// 预览时隐藏编辑器按钮
if (selected_tab == "#wmd-preview") {
if (selected_tab === "#wmd-preview") {
$("#wmd-button-row").addClass("wmd-visualhide");
} else {
$("#wmd-button-row").removeClass("wmd-visualhide");
@@ -207,21 +239,30 @@ $(document).ready(function () {
});
// 剪贴板复制图片
textarea.pastableTextarea().on('pasteImage', function (e, data) {
var name = data.name ? data.name.replace(/[\(\)\[\]\*#!]/g, '') : (new Date()).toISOString().replace(/\..+$/, '');
if (!name.match(/\.[a-z0-9]{2,}$/i)) {
var ext = data.blob.type.split('/').pop();
name += '.' + ext;
}
textarea.bind('paste', function (e) {
const items = (e.clipboardData || e.originalEvent.clipboardData).items;
Typecho.uploadFile(new File([data.blob], name), name);
for (const item of items) {
if (item.kind === 'file') {
const file = item.getAsFile();
if (file.size > 0) {
if (!file.name) {
file.name = (new Date()).toISOString().replace(/\..+$/, '')
+ '.' + file.type.split('/').pop();
}
Typecho.uploadFile(file);
}
}
}
});
}
if (isMarkdown) {
initMarkdown();
} else {
var notice = $('<div class="message notice"><?php _e('这篇文章不是由Markdown语法创建的, 继续使用Markdown编辑它吗?'); ?> '
const notice = $('<div class="message notice"><?php _e('这篇文章不是由Markdown语法创建的, 继续使用Markdown编辑它吗?'); ?> '
+ '<button class="btn btn-xs primary yes"><?php _e('是'); ?></button> '
+ '<button class="btn btn-xs no"><?php _e('否'); ?></button></div>')
.hide().insertBefore(textarea).slideDown();

View File

@@ -3,7 +3,7 @@
include 'common.php';
$panel = $request->get('panel');
$panelTable = unserialize($options->panelTable);
$panelTable = $options->panelTable;
if (!isset($panelTable['file']) || !in_array(urlencode($panel), $panelTable['file'])) {
throw new \Typecho\Plugin\Exception(_t('页面不存在'), 404);

View File

@@ -1,23 +1,18 @@
<?php if(!defined('__TYPECHO_ADMIN__')) exit; ?>
<?php
if (isset($post) && $post instanceof \Typecho\Widget && $post->have()) {
$fileParentContent = $post;
} elseif (isset($page) && $page instanceof \Typecho\Widget && $page->have()) {
$fileParentContent = $page;
}
$phpMaxFilesize = function_exists('ini_get') ? trim(ini_get('upload_max_filesize')) : '0';
$phpMaxFilesize = function_exists('ini_get') ? trim(ini_get('upload_max_filesize')) : 0;
if (preg_match("/^([0-9]+)([a-z]{1,2})?$/i", $phpMaxFilesize, $matches)) {
$size = intval($matches[1]);
$unit = $matches[2] ?? 'b';
if (preg_match("/^([0-9]+)([a-z]{1,2})$/i", $phpMaxFilesize, $matches)) {
$phpMaxFilesize = strtolower($matches[1] . $matches[2] . (1 == strlen($matches[2]) ? 'b' : ''));
$phpMaxFilesize = round($size * pow(1024, stripos('bkmgtpezy', $unit[0])));
}
?>
<script src="<?php $options->adminStaticUrl('js', 'moxie.js'); ?>"></script>
<script src="<?php $options->adminStaticUrl('js', 'plupload.js'); ?>"></script>
<script>
$(document).ready(function() {
function updateAttacmentNumber () {
function updateAttachmentNumber () {
var btn = $('#tab-files-btn'),
balloon = $('.balloon', btn),
count = $('#file-list li .insert').length;
@@ -29,24 +24,40 @@ $(document).ready(function() {
}
balloon.html(count);
} else if (0 == count && balloon.length > 0) {
} else if (0 === count && balloon.length > 0) {
balloon.remove();
}
}
$('.upload-area').bind({
dragenter : function () {
updateAttachmentNumber();
const uploadUrl = $('.upload-area').bind({
dragenter : function (e) {
$(this).parent().addClass('drag');
},
dragover : function (e) {
e.stopPropagation();
e.preventDefault();
$(this).parent().addClass('drag');
},
drop : function () {
drop : function (e) {
e.stopPropagation();
e.preventDefault();
$(this).parent().removeClass('drag');
const files = e.originalEvent.dataTransfer.files;
if (files.length === 0) {
return;
}
for (const file of files) {
Typecho.uploadFile(file);
}
},
dragend : function () {
$(this).parent().removeClass('drag');
},
@@ -54,31 +65,44 @@ $(document).ready(function() {
dragleave : function () {
$(this).parent().removeClass('drag');
}
}).data('url');
const btn = $('.upload-file');
const fileInput = $('<input type="file" name="file" />').hide().insertAfter(btn);
btn.click(function () {
fileInput.click();
return false;
});
updateAttacmentNumber();
fileInput.change(function () {
if (this.files.length === 0) {
return;
}
Typecho.uploadFile(this.files[0]);
});
function fileUploadStart (file) {
$('<li id="' + file.id + '" class="loading">'
+ file.name + '</li>').appendTo('#file-list');
}
function fileUploadError (error) {
var file = error.file, code = error.code, word;
function fileUploadError (type, file) {
let word = '<?php _e('上传出现错误'); ?>';
switch (code) {
case plupload.FILE_SIZE_ERROR:
switch (type) {
case 'size':
word = '<?php _e('文件大小超过限制'); ?>';
break;
case plupload.FILE_EXTENSION_ERROR:
case 'type':
word = '<?php _e('文件扩展名不被支持'); ?>';
break;
case plupload.FILE_DUPLICATE_ERROR:
case 'duplicate':
word = '<?php _e('文件已经上传过'); ?>';
break;
case plupload.HTTP_ERROR:
case 'network':
default:
word = '<?php _e('上传出现错误'); ?>';
break;
}
@@ -94,104 +118,91 @@ $(document).ready(function() {
li.effect('highlight', {color : '#FBC2C4'}, 2000, function () {
$(this).remove();
});
// fix issue #341
this.removeFile(file);
}
var completeFile = null;
function fileUploadComplete (id, url, data) {
var li = $('#' + id).removeClass('loading').data('cid', data.cid)
.data('url', data.url)
.data('image', data.isImage)
.html('<input type="hidden" name="attachment[]" value="' + data.cid + '" />'
+ '<a class="insert" target="_blank" href="###" title="<?php _e('点击插入文件'); ?>">' + data.title + '</a><div class="info">' + data.bytes
function fileUploadComplete (file, attachment) {
const li = $('#' + file.id).removeClass('loading').data('cid', attachment.cid)
.data('url', attachment.url)
.data('image', attachment.isImage)
.html('<input type="hidden" name="attachment[]" value="' + attachment.cid + '" />'
+ '<a class="insert" target="_blank" href="###" title="<?php _e('点击插入文件'); ?>">'
+ attachment.title + '</a><div class="info">' + attachment.bytes
+ ' <a class="file" target="_blank" href="<?php $options->adminUrl('media.php'); ?>?cid='
+ data.cid + '" title="<?php _e('编辑'); ?>"><i class="i-edit"></i></a>'
+ attachment.cid + '" title="<?php _e('编辑'); ?>"><i class="i-edit"></i></a>'
+ ' <a class="delete" href="###" title="<?php _e('删除'); ?>"><i class="i-delete"></i></a></div>')
.effect('highlight', 1000);
attachInsertEvent(li);
attachDeleteEvent(li);
updateAttacmentNumber();
updateAttachmentNumber();
if (!completeFile) {
completeFile = data;
}
Typecho.uploadComplete(attachment);
}
var uploader = null, tabFilesEl = $('#tab-files').bind('init', function () {
uploader = new plupload.Uploader({
browse_button : $('.upload-file').get(0),
url : '<?php $security->index('/action/upload'
. (isset($fileParentContent) ? '?cid=' . $fileParentContent->cid : '')); ?>',
runtimes : 'html5,flash,html4',
flash_swf_url : '<?php $options->adminStaticUrl('js', 'Moxie.swf'); ?>',
drop_element : $('.upload-area').get(0),
filters : {
max_file_size : '<?php echo $phpMaxFilesize ?>',
mime_types : [{'title' : '<?php _e('允许上传的文件'); ?>', 'extensions' : '<?php echo implode(',', $options->allowedAttachmentTypes); ?>'}],
prevent_duplicates : true
},
Typecho.uploadFile = (function () {
const types = '<?php echo json_encode($options->allowedAttachmentTypes); ?>';
const maxSize = <?php echo $phpMaxFilesize ?>;
const queue = [];
let index = 0;
init : {
FilesAdded : function (up, files) {
for (var i = 0; i < files.length; i ++) {
fileUploadStart(files[i]);
}
const getUrl = function () {
const url = new URL(uploadUrl);
const cid = $('input[name=cid]').val();
completeFile = null;
uploader.start();
},
url.searchParams.append('cid', cid);
return url.toString();
};
UploadComplete : function () {
if (completeFile) {
Typecho.uploadComplete(completeFile);
}
},
const upload = function () {
const file = queue.shift();
FileUploaded : function (up, file, result) {
if (200 == result.status) {
var data = $.parseJSON(result.response);
if (data) {
fileUploadComplete(file.id, data[0], data[1]);
uploader.removeFile(file);
return;
}
}
fileUploadError.call(uploader, {
code : plupload.HTTP_ERROR,
file : file
});
},
Error : function (up, error) {
fileUploadError.call(uploader, error);
}
}
});
uploader.init();
});
Typecho.uploadFile = function (file, name) {
if (!uploader) {
$('#tab-files-btn').parent().trigger('click');
}
var timer = setInterval(function () {
if (!uploader) {
if (!file) {
return;
}
clearInterval(timer);
timer = null;
const data = new FormData();
data.append('file', file);
uploader.addFile(file, name);
}, 50);
};
fetch(getUrl(), {
method: 'POST',
body: data
}).then(function (response) {
if (response.ok) {
return response.json();
} else {
throw new Error(response.statusText);
}
}).then(function (data) {
if (data) {
const [_, attachment] = data;
fileUploadComplete(file, attachment);
upload();
} else {
throw new Error('no data');
}
}).catch(function (error) {
fileUploadError('network', file);
upload();
});
};
return function (file) {
file.id = 'upload-' + (index++);
if (file.size > maxSize) {
return fileUploadError('size', file);
}
const match = file.name.match(/\.([a-z0-9]+)$/i);
if (!match || types.indexOf(match[1].toLowerCase()) < 0) {
return fileUploadError('type', file);
}
queue.push(file);
fileUploadStart(file);
upload();
};
})();
function attachInsertEvent (el) {
$('.insert', el).click(function () {
@@ -211,7 +222,7 @@ $(document).ready(function() {
function () {
$(el).fadeOut(function () {
$(this).remove();
updateAttacmentNumber();
updateAttachmentNumber();
});
});
}

View File

@@ -13,7 +13,9 @@ if (isset($post) || isset($page)) {
?>
<div id="upload-panel" class="p">
<div class="upload-area" draggable="true"><?php _e('拖放文件到这里<br>或者 %s选择文件上传%s', '<a href="###" class="upload-file">', '</a>'); ?></div>
<div class="upload-area" data-url="<?php $security->index('/action/upload'); ?>">
<?php _e('拖放文件到这里<br>或者 %s选择文件上传%s', '<a href="###" class="upload-file">', '</a>'); ?>
</div>
<ul id="file-list">
<?php while ($attachment->next()): ?>
<li data-cid="<?php $attachment->cid(); ?>" data-url="<?php echo $attachment->attachment->url; ?>" data-image="<?php echo $attachment->attachment->isImage ? 1 : 0; ?>"><input type="hidden" name="attachment[]" value="<?php $attachment->cid(); ?>" />

View File

@@ -1,6 +1,7 @@
<?php if(!defined('__TYPECHO_ADMIN__')) exit; ?>
<?php \Typecho\Plugin::factory('admin/footer.php')->call('begin'); ?>
</body>
</html>
<?php
/** 注册一个结束插件 */
\Typecho\Plugin::factory('admin/footer.php')->end();
\Typecho\Plugin::factory('admin/footer.php')->call('end');

View File

@@ -2,25 +2,50 @@
<script>
(function () {
$(document).ready(function () {
var error = $('.typecho-option .error:first');
const error = $('.typecho-option .error:first');
if (error.length > 0) {
$('html,body').scrollTop(error.parents('.typecho-option').offset().top);
}
$('form').submit(function () {
if (this.submitted) {
$('.main form').submit(function () {
const self = $(this);
if (self.hasClass('submitting')) {
return false;
} else {
this.submitted = true;
$('button[type=submit]', this).attr('disabled', 'disabled');
self.addClass('submitting');
}
}).on('submitted', function () {
$('button[type=submit]', this).removeAttr('disabled');
$(this).removeClass('submitting');
});
$('label input[type=text]').click(function (e) {
var check = $('#' + $(this).parents('label').attr('for'));
const check = $('#' + $(this).parents('label').attr('for'));
check.prop('checked', true);
return false;
});
$('.main form input[type="url"]').each(function () {
const self = $(this);
const input = $('<input type="hidden" />').attr('name', self.attr('name'));
function setInput() {
const url = self.val();
try {
const urlObj = new URL(url);
input.val(urlObj.toString());
} catch {
// ignore
}
}
self.removeAttr('name').after(input).on('input', setInput);
setInput();
});
});
})();
</script>

View File

@@ -8,7 +8,7 @@ $header = '<link rel="stylesheet" href="' . $options->adminStaticUrl('css', 'nor
<link rel="stylesheet" href="' . $options->adminStaticUrl('css', 'style.css', true) . '">';
/** 注册一个初始化插件 */
$header = \Typecho\Plugin::factory('admin/header.php')->header($header);
$header = \Typecho\Plugin::factory('admin/header.php')->call('header', $header);
?><!DOCTYPE HTML>
<html>

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

2
admin/js/jquery.js vendored

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

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

View File

@@ -13,19 +13,19 @@ include 'header.php';
?>
<div class="typecho-login-wrap">
<div class="typecho-login">
<h1><a href="http://typecho.org" class="i-logo">Typecho</a></h1>
<h1><a href="https://typecho.org" class="i-logo">Typecho</a></h1>
<form action="<?php $options->loginAction(); ?>" method="post" name="login" role="form">
<p>
<label for="name" class="sr-only"><?php _e('用户名'); ?></label>
<input type="text" id="name" name="name" value="<?php echo $rememberName; ?>" placeholder="<?php _e('用户名'); ?>" class="text-l w-100" autofocus />
<label for="name" class="sr-only"><?php _e('用户名或邮箱'); ?></label>
<input type="text" id="name" name="name" value="<?php echo $rememberName; ?>" placeholder="<?php _e('用户名或邮箱'); ?>" class="text-l w-100" autofocus />
</p>
<p>
<label for="password" class="sr-only"><?php _e('密码'); ?></label>
<input type="password" id="password" name="password" class="text-l w-100" placeholder="<?php _e('密码'); ?>" />
<input type="password" id="password" name="password" class="text-l w-100" placeholder="<?php _e('密码'); ?>" required />
</p>
<p class="submit">
<button type="submit" class="btn btn-l w-100 primary"><?php _e('登录'); ?></button>
<input type="hidden" name="referer" value="<?php echo htmlspecialchars($request->get('referer') ?? ''); ?>" />
<input type="hidden" name="referer" value="<?php echo $request->filter('html')->get('referer'); ?>" />
</p>
<p>
<label for="remember">

View File

@@ -21,9 +21,9 @@ $isAllComments = ('on' == $request->get('__typecho_all_comments') || 'on' == \Ty
</ul>
<ul class="typecho-option-tabs">
<li<?php if(!isset($request->status) || 'approved' == $request->get('status')): ?> class="current"<?php endif; ?>><a href="<?php $options->adminUrl('manage-comments.php'
. (isset($request->cid) ? '?cid=' . $request->cid : '')); ?>"><?php _e('已通过'); ?></a></li>
. (isset($request->cid) ? '?cid=' . $request->filter('encode')->cid : '')); ?>"><?php _e('已通过'); ?></a></li>
<li<?php if('waiting' == $request->get('status')): ?> class="current"<?php endif; ?>><a href="<?php $options->adminUrl('manage-comments.php?status=waiting'
. (isset($request->cid) ? '&cid=' . $request->cid : '')); ?>"><?php _e('待审核'); ?>
. (isset($request->cid) ? '&cid=' . $request->filter('encode')->cid : '')); ?>"><?php _e('待审核'); ?>
<?php if(!$isAllComments && $stat->myWaitingCommentsNum > 0 && !isset($request->cid)): ?>
<span class="balloon"><?php $stat->myWaitingCommentsNum(); ?></span>
<?php elseif($isAllComments && $stat->waitingCommentsNum > 0 && !isset($request->cid)): ?>
@@ -33,7 +33,7 @@ $isAllComments = ('on' == $request->get('__typecho_all_comments') || 'on' == \Ty
<?php endif; ?>
</a></li>
<li<?php if('spam' == $request->get('status')): ?> class="current"<?php endif; ?>><a href="<?php $options->adminUrl('manage-comments.php?status=spam'
. (isset($request->cid) ? '&cid=' . $request->cid : '')); ?>"><?php _e('垃圾'); ?>
. (isset($request->cid) ? '&cid=' . $request->filter('encode')->cid : '')); ?>"><?php _e('垃圾'); ?>
<?php if(!$isAllComments && $stat->mySpamCommentsNum > 0 && !isset($request->cid)): ?>
<span class="balloon"><?php $stat->mySpamCommentsNum(); ?></span>
<?php elseif($isAllComments && $stat->spamCommentsNum > 0 && !isset($request->cid)): ?>
@@ -66,15 +66,15 @@ $isAllComments = ('on' == $request->get('__typecho_all_comments') || 'on' == \Ty
<?php if ('' != $request->keywords || '' != $request->category): ?>
<a href="<?php $options->adminUrl('manage-comments.php'
. (isset($request->status) || isset($request->cid) ? '?' .
(isset($request->status) ? 'status=' . htmlspecialchars($request->get('status')) : '') .
(isset($request->cid) ? (isset($request->status) ? '&' : '') . 'cid=' . htmlspecialchars($request->get('cid')) : '') : '')); ?>"><?php _e('&laquo; 取消筛选'); ?></a>
(isset($request->status) ? 'status=' . $request->filter('encode')->status : '') .
(isset($request->cid) ? (isset($request->status) ? '&' : '') . 'cid=' . $request->filter('encode')->cid : '') : '')); ?>"><?php _e('&laquo; 取消筛选'); ?></a>
<?php endif; ?>
<input type="text" class="text-s" placeholder="<?php _e('请输入关键字'); ?>" value="<?php echo htmlspecialchars($request->keywords ?? ''); ?>"<?php if ('' == $request->keywords): ?> onclick="value='';name='keywords';" <?php else: ?> name="keywords"<?php endif; ?>/>
<input type="text" class="text-s" placeholder="<?php _e('请输入关键字'); ?>" value="<?php echo $request->filter('html')->keywords; ?>"<?php if ('' == $request->keywords): ?> onclick="value='';name='keywords';" <?php else: ?> name="keywords"<?php endif; ?>/>
<?php if(isset($request->status)): ?>
<input type="hidden" value="<?php echo htmlspecialchars($request->get('status')); ?>" name="status" />
<input type="hidden" value="<?php echo $request->filter('html')->status; ?>" name="status" />
<?php endif; ?>
<?php if(isset($request->cid)): ?>
<input type="hidden" value="<?php echo htmlspecialchars($request->get('cid')); ?>" name="cid" />
<input type="hidden" value="<?php echo $request->filter('html')->cid; ?>" name="cid" />
<?php endif; ?>
<button type="submit" class="btn btn-s"><?php _e('筛选'); ?></button>
</div>
@@ -120,7 +120,7 @@ $isAllComments = ('on' == $request->get('__typecho_all_comments') || 'on' == \Ty
<td valign="top" class="kit-hidden-mb">
<div class="comment-avatar">
<?php if ('comment' == $comments->type): ?>
<?php $comments->gravatar(40); ?>
<?php $comments->gravatar(40, null, true); ?>
<?php endif; ?>
<?php if ('comment' != $comments->type): ?>
<?php _e('引用'); ?>
@@ -131,7 +131,7 @@ $isAllComments = ('on' == $request->get('__typecho_all_comments') || 'on' == \Ty
<div class="comment-meta">
<strong class="comment-author"><?php $comments->author(true); ?></strong>
<?php if($comments->mail): ?>
<br /><span><a href="mailto:<?php $comments->mail(); ?>"><?php $comments->mail(); ?></a></span>
<br /><span><a href="<?php $comments->mail(true); ?>"><?php $comments->mail(); ?></a></span>
<?php endif; ?>
<?php if($comments->ip): ?>
<br /><span><?php $comments->ip(); ?></span>
@@ -183,7 +183,7 @@ $isAllComments = ('on' == $request->get('__typecho_all_comments') || 'on' == \Ty
</div><!-- end .typecho-table-wrap -->
<?php if(isset($request->cid)): ?>
<input type="hidden" value="<?php echo htmlspecialchars($request->get('cid')); ?>" name="cid" />
<input type="hidden" value="<?php echo $request->filter('html')->cid; ?>" name="cid" />
<?php endif; ?>
</form><!-- end .operate-form -->
@@ -279,10 +279,12 @@ $(document).ready(function () {
form.submit(function () {
var t = $(this), tr = t.parents('tr'),
reply = $('<div class="comment-reply-content"></div>').insertAfter($('.comment-content', tr));
reply.html('<p>' + textarea.val() + '</p>');
var html = DOMPurify.sanitize(textarea.val(), {USE_PROFILES: {html: true}});
reply.html('<p>' + html + '</p>');
$.post(t.attr('action'), t.serialize(), function (o) {
reply.html(o.comment.content)
var html = DOMPurify.sanitize(o.comment.content, {USE_PROFILES: {html: true}});
reply.html(html)
.effect('highlight');
}, 'json');
@@ -340,7 +342,7 @@ $(document).ready(function () {
}
});
var html = '<strong class="comment-author">'
var unsafeHTML = '<strong class="comment-author">'
+ (comment.url ? '<a target="_blank" href="' + comment.url + '">'
+ comment.author + '</a>' : comment.author) + '</strong>'
+ ('comment' != comment.type ? '<small><?php _e('引用'); ?></small>' : '')
@@ -348,13 +350,16 @@ $(document).ready(function () {
+ comment.mail + '</a></span>' : '')
+ (comment.ip ? '<br /><span>' + comment.ip + '</span>' : '');
var html = DOMPurify.sanitize(unsafeHTML, {USE_PROFILES: {html: true}});
var content = DOMPurify.sanitize(comment.text, {USE_PROFILES: {html: true}});
$('.comment-meta', oldTr).html(html)
.effect('highlight');
$('.comment-content', oldTr).html('<p>' + comment.text + '</p>');
$('.comment-content', oldTr).html('<p>' + content + '</p>');
oldTr.data('comment', comment);
$.post(t.attr('action'), comment, function (o) {
$('.comment-content', oldTr).html(o.comment.content)
var content = DOMPurify.sanitize(o.comment.content, {USE_PROFILES: {html: true}});
$('.comment-content', oldTr).html('<p>' + content + '</p>')
.effect('highlight');
}, 'json');

View File

@@ -36,7 +36,7 @@ $attachments = \Widget\Contents\Attachment\Admin::alloc();
<a href="<?php $options->adminUrl('manage-medias.php'); ?>"><?php _e('&laquo; 取消筛选'); ?></a>
<?php endif; ?>
<input type="text" class="text-s" placeholder="<?php _e('请输入关键字'); ?>"
value="<?php echo htmlspecialchars($request->keywords ?? ''); ?>"<?php if ('' == $request->keywords): ?> onclick="value='';name='keywords';" <?php else: ?> name="keywords"<?php endif; ?>/>
value="<?php echo $request->filter('html')->keywords; ?>"<?php if ('' == $request->keywords): ?> onclick="value='';name='keywords';" <?php else: ?> name="keywords"<?php endif; ?>/>
<button type="submit" class="btn btn-s"><?php _e('筛选'); ?></button>
</div>
</form>

View File

@@ -35,11 +35,12 @@ $pages = \Widget\Contents\Page\Admin::alloc();
</div>
<div class="search" role="search">
<?php $pages->backLink(); ?>
<?php if ('' != $request->keywords): ?>
<a href="<?php $options->adminUrl('manage-pages.php'); ?>"><?php _e('&laquo; 取消筛选'); ?></a>
<?php endif; ?>
<input type="text" class="text-s" placeholder="<?php _e('请输入关键字'); ?>"
value="<?php echo htmlspecialchars($request->keywords ?? ''); ?>" name="keywords"/>
value="<?php echo $request->filter('html')->keywords; ?>" name="keywords"/>
<button type="submit" class="btn btn-s"><?php _e('筛选'); ?></button>
</div>
</form>
@@ -61,7 +62,7 @@ $pages = \Widget\Contents\Page\Admin::alloc();
<th class="kit-hidden-mb"></th>
<th class="kit-hidden-mb"></th>
<th><?php _e('标题'); ?></th>
<th><?php _e('缩略名'); ?></th>
<th><?php _e('子页面'); ?></th>
<th class="kit-hidden-mb"><?php _e('作者'); ?></th>
<th><?php _e('日期'); ?></th>
</tr>
@@ -80,8 +81,10 @@ $pages = \Widget\Contents\Page\Admin::alloc();
<td>
<a href="<?php $options->adminUrl('write-page.php?cid=' . $pages->cid); ?>"><?php $pages->title(); ?></a>
<?php
if ($pages->hasSaved || 'page_draft' == $pages->type) {
if ('page_draft' == $pages->type) {
echo '<em class="status">' . _t('草稿') . '</em>';
} elseif ($pages->revision) {
echo '<em class="status">' . _t('有修订版') . '</em>';
}
if ('hidden' == $pages->status) {
@@ -97,12 +100,18 @@ $pages = \Widget\Contents\Page\Admin::alloc();
class="i-exlink"></i></a>
<?php endif; ?>
</td>
<td><?php $pages->slug(); ?></td>
<td>
<?php if (count($pages->children) > 0): ?>
<a href="<?php $options->adminUrl('manage-pages.php?parent=' . $pages->cid); ?>"><?php echo _n('一个页面', '%d个页面', count($pages->children)); ?></a>
<?php else: ?>
<a href="<?php $options->adminUrl('write-page.php?parent=' . $pages->cid); ?>"><?php echo _e('新增'); ?></a>
<?php endif; ?>
</td>
<td class="kit-hidden-mb"><?php $pages->author(); ?></td>
<td>
<?php if ($pages->hasSaved): ?>
<?php if ('page_draft' == $pages->type || $pages->revision): ?>
<span class="description">
<?php $modifyDate = new \Typecho\Date($pages->modified); ?>
<?php $modifyDate = new \Typecho\Date($pages->revision ? $pages->revision['modified'] : $pages->modified); ?>
<?php _e('保存于 %s', $modifyDate->word()); ?>
</span>
<?php else: ?>
@@ -132,7 +141,7 @@ include 'common-js.php';
include 'table-js.php';
?>
<?php if (!isset($request->status) || 'publish' == $request->get('status')): ?>
<?php if (!$request->is('keywords')): ?>
<script type="text/javascript">
(function () {
$(document).ready(function () {

View File

@@ -26,11 +26,11 @@ $isAllPosts = ('on' == $request->get('__typecho_all_posts') || 'on' == \Typecho\
<ul class="typecho-option-tabs">
<li<?php if (!isset($request->status) || 'all' == $request->get('status')): ?> class="current"<?php endif; ?>>
<a href="<?php $options->adminUrl('manage-posts.php'
. (isset($request->uid) ? '?uid=' . $request->uid : '')); ?>"><?php _e('可用'); ?></a>
. (isset($request->uid) ? '?uid=' . $request->filter('encode')->uid : '')); ?>"><?php _e('可用'); ?></a>
</li>
<li<?php if ('waiting' == $request->get('status')): ?> class="current"<?php endif; ?>><a
href="<?php $options->adminUrl('manage-posts.php?status=waiting'
. (isset($request->uid) ? '&uid=' . $request->uid : '')); ?>"><?php _e('待审核'); ?>
. (isset($request->uid) ? '&uid=' . $request->filter('encode')->uid : '')); ?>"><?php _e('待审核'); ?>
<?php if (!$isAllPosts && $stat->myWaitingPostsNum > 0 && !isset($request->uid)): ?>
<span class="balloon"><?php $stat->myWaitingPostsNum(); ?></span>
<?php elseif ($isAllPosts && $stat->waitingPostsNum > 0 && !isset($request->uid)): ?>
@@ -41,7 +41,7 @@ $isAllPosts = ('on' == $request->get('__typecho_all_posts') || 'on' == \Typecho\
</a></li>
<li<?php if ('draft' == $request->get('status')): ?> class="current"<?php endif; ?>><a
href="<?php $options->adminUrl('manage-posts.php?status=draft'
. (isset($request->uid) ? '&uid=' . $request->uid : '')); ?>"><?php _e('草稿'); ?>
. (isset($request->uid) ? '&uid=' . $request->filter('encode')->uid : '')); ?>"><?php _e('草稿'); ?>
<?php if (!$isAllPosts && $stat->myDraftPostsNum > 0 && !isset($request->uid)): ?>
<span class="balloon"><?php $stat->myDraftPostsNum(); ?></span>
<?php elseif ($isAllPosts && $stat->draftPostsNum > 0 && !isset($request->uid)): ?>
@@ -87,11 +87,11 @@ $isAllPosts = ('on' == $request->get('__typecho_all_posts') || 'on' == \Typecho\
<?php if ('' != $request->keywords || '' != $request->category): ?>
<a href="<?php $options->adminUrl('manage-posts.php'
. (isset($request->status) || isset($request->uid) ? '?' .
(isset($request->status) ? 'status=' . htmlspecialchars($request->get('status')) : '') .
(isset($request->uid) ? '?uid=' . htmlspecialchars($request->get('uid')) : '') : '')); ?>"><?php _e('&laquo; 取消筛选'); ?></a>
(isset($request->status) ? 'status=' . $request->filter('encode')->status : '') .
(isset($request->uid) ? (isset($request->status) ? '&' : '') . 'uid=' . $request->filter('encode')->uid : '') : '')); ?>"><?php _e('&laquo; 取消筛选'); ?></a>
<?php endif; ?>
<input type="text" class="text-s" placeholder="<?php _e('请输入关键字'); ?>"
value="<?php echo htmlspecialchars($request->keywords ?? ''); ?>" name="keywords"/>
value="<?php echo $request->filter('html')->keywords; ?>" name="keywords"/>
<select name="category">
<option value=""><?php _e('所有分类'); ?></option>
<?php \Widget\Metas\Category\Rows::alloc()->to($category); ?>
@@ -102,11 +102,11 @@ $isAllPosts = ('on' == $request->get('__typecho_all_posts') || 'on' == \Typecho\
</select>
<button type="submit" class="btn btn-s"><?php _e('筛选'); ?></button>
<?php if (isset($request->uid)): ?>
<input type="hidden" value="<?php echo htmlspecialchars($request->get('uid')); ?>"
<input type="hidden" value="<?php echo $request->filter('html')->uid; ?>"
name="uid"/>
<?php endif; ?>
<?php if (isset($request->status)): ?>
<input type="hidden" value="<?php echo htmlspecialchars($request->get('status')); ?>"
<input type="hidden" value="<?php echo $request->filter('html')->status; ?>"
name="status"/>
<?php endif; ?>
</div>
@@ -148,8 +148,10 @@ $isAllPosts = ('on' == $request->get('__typecho_all_posts') || 'on' == \Typecho\
<td>
<a href="<?php $options->adminUrl('write-post.php?cid=' . $posts->cid); ?>"><?php $posts->title(); ?></a>
<?php
if ($posts->hasSaved || 'post_draft' == $posts->type) {
if ('post_draft' == $posts->type) {
echo '<em class="status">' . _t('草稿') . '</em>';
} elseif ($posts->revision) {
echo '<em class="status">' . _t('有修订版') . '</em>';
}
if ('hidden' == $posts->status) {
@@ -172,22 +174,21 @@ $isAllPosts = ('on' == $request->get('__typecho_all_posts') || 'on' == \Typecho\
<?php endif; ?>
</td>
<td class="kit-hidden-mb"><a
href="<?php $options->adminUrl('manage-posts.php?uid=' . $posts->author->uid); ?>"><?php $posts->author(); ?></a>
href="<?php $options->adminUrl('manage-posts.php?__typecho_all_posts=off&uid=' . $posts->author->uid); ?>"><?php $posts->author(); ?></a>
</td>
<td class="kit-hidden-mb"><?php $categories = $posts->categories;
$length = count($categories); ?>
<?php foreach ($categories as $key => $val): ?>
while ($categories->next()): ?>
<?php echo '<a href="';
$options->adminUrl('manage-posts.php?category=' . $val['mid']
. (isset($request->uid) ? '&uid=' . $request->uid : '')
. (isset($request->status) ? '&status=' . $request->status : ''));
echo '">' . $val['name'] . '</a>' . ($key < $length - 1 ? ', ' : ''); ?>
<?php endforeach; ?>
$options->adminUrl('manage-posts.php?category=' . $categories->mid
. (isset($request->uid) ? '&uid=' . $request->filter('encode')->uid : '')
. (isset($request->status) ? '&status=' . $request->filter('encode')->status : ''));
echo '">' . $categories->name . '</a>' . ($categories->sequence < $categories->length - 1 ? ', ' : ''); ?>
<?php endwhile; ?>
</td>
<td>
<?php if ($posts->hasSaved): ?>
<?php if ('post_draft' == $posts->type || $posts->revision): ?>
<span class="description">
<?php $modifyDate = new \Typecho\Date($posts->modified); ?>
<?php $modifyDate = new \Typecho\Date($posts->revision ? $posts->revision['modified'] : $posts->modified); ?>
<?php _e('保存于 %s', $modifyDate->word()); ?>
</span>
<?php else: ?>

View File

@@ -31,7 +31,7 @@ $users = \Widget\Users\Admin::alloc();
<a href="<?php $options->adminUrl('manage-users.php'); ?>"><?php _e('&laquo; 取消筛选'); ?></a>
<?php endif; ?>
<input type="text" class="text-s" placeholder="<?php _e('请输入关键字'); ?>"
value="<?php echo htmlspecialchars($request->keywords ?? ''); ?>" name="keywords"/>
value="<?php echo $request->filter('html')->keywords; ?>" name="keywords"/>
<button type="submit" class="btn btn-s"><?php _e('筛选'); ?></button>
</div>
</form>
@@ -64,7 +64,7 @@ $users = \Widget\Users\Admin::alloc();
<td class="kit-hidden-mb"><input type="checkbox" value="<?php $users->uid(); ?>"
name="uid[]"/></td>
<td class="kit-hidden-mb"><a
href="<?php $options->adminUrl('manage-posts.php?uid=' . $users->uid); ?>"
href="<?php $options->adminUrl('manage-posts.php?__typecho_all_posts=off&uid=' . $users->uid); ?>"
class="balloon-button left size-<?php echo \Typecho\Common::splitByCount($users->postsNum, 1, 10, 20, 50, 100); ?>"><?php $users->postsNum(); ?></a>
</td>
<td>

View File

@@ -3,13 +3,7 @@ include 'common.php';
include 'header.php';
include 'menu.php';
$phpMaxFilesize = function_exists('ini_get') ? trim(ini_get('upload_max_filesize')) : 0;
if (preg_match("/^([0-9]+)([a-z]{1,2})$/i", $phpMaxFilesize, $matches)) {
$phpMaxFilesize = strtolower($matches[1] . $matches[2] . (1 == strlen($matches[2]) ? 'b' : ''));
}
$attachment = \Widget\Contents\Attachment\Edit::alloc();
\Widget\Contents\Attachment\Edit::alloc()->prepare()->to($attachment);
?>
<div class="main">
@@ -35,8 +29,9 @@ $attachment = \Widget\Contents\Attachment\Edit::alloc();
</p>
<div id="upload-panel" class="p">
<div class="upload-area"
draggable="true"><?php _e('拖放文件到这里<br>或者 %s选择文件上传%s', '<a href="###" class="upload-file">', '</a>'); ?></div>
<div class="upload-area" data-url="<?php $security->index('/action/upload?do=modify'); ?>">
<?php _e('拖放文件到这里<br>或者 %s选择文件上传%s', '<a href="###" class="upload-file">', '</a>'); ?>
</div>
<ul id="file-list"></ul>
</div>
</div>
@@ -50,9 +45,8 @@ $attachment = \Widget\Contents\Attachment\Edit::alloc();
<?php
include 'copyright.php';
include 'common-js.php';
include 'file-upload-js.php';
?>
<script src="<?php $options->adminStaticUrl('js', 'moxie.js'); ?>"></script>
<script src="<?php $options->adminStaticUrl('js', 'plupload.js'); ?>"></script>
<script type="text/javascript">
$(document).ready(function () {
$('#attachment-url').click(function () {
@@ -69,130 +63,16 @@ include 'common-js.php';
return false;
});
$('.upload-area').bind({
dragenter: function () {
$(this).parent().addClass('drag');
},
dragover: function (e) {
$(this).parent().addClass('drag');
},
drop: function () {
$(this).parent().removeClass('drag');
},
dragend: function () {
$(this).parent().removeClass('drag');
},
dragleave: function () {
$(this).parent().removeClass('drag');
}
});
function fileUploadStart(file) {
$('<ul id="file-list"></ul>').appendTo('#upload-panel');
$('<li id="' + file.id + '" class="loading">'
+ file.name + '</li>').prependTo('#file-list');
}
function fileUploadError(error) {
var file = error.file, code = error.code, word;
switch (code) {
case plupload.FILE_SIZE_ERROR:
word = '<?php _e('文件大小超过限制'); ?>';
break;
case plupload.FILE_EXTENSION_ERROR:
word = '<?php _e('文件扩展名不被支持'); ?>';
break;
case plupload.FILE_DUPLICATE_ERROR:
word = '<?php _e('文件已经上传过'); ?>';
break;
case plupload.HTTP_ERROR:
default:
word = '<?php _e('上传出现错误'); ?>';
break;
Typecho.uploadComplete = function (attachment) {
if (attachment.isImage) {
$('.typecho-attachment-photo').attr('src', attachment.url + '?' + Math.random());
}
var fileError = '<?php _e('%s 上传失败'); ?>'.replace('%s', file.name),
li, exist = $('#' + file.id);
if (exist.length > 0) {
li = exist.removeClass('loading').html(fileError);
} else {
$('<ul id="file-list"></ul>').appendTo('#upload-panel');
li = $('<li>' + fileError + '<br />' + word + '</li>').prependTo('#file-list');
}
li.effect('highlight', {color: '#FBC2C4'}, 2000, function () {
$(this).remove();
});
}
function fileUploadComplete(id, url, data) {
var img = $('.typecho-attachment-photo');
if (img.length > 0) {
img.get(0).src = '<?php $attachment->attachment->url(); ?>?' + Math.random();
}
$('#' + id).html('<?php _e('文件 %s 已经替换'); ?>'.replace('%s', data.title))
$('#file-list li').text('<?php _e('文件 %s 已经替换'); ?>'.replace('%s', attachment.title))
.effect('highlight', 1000, function () {
$(this).remove();
$('#file-list').remove();
});
}
var uploader = new plupload.Uploader({
browse_button: $('.upload-file').get(0),
url: '<?php $security->index('/action/upload?do=modify&cid=' . $attachment->cid); ?>',
runtimes: 'html5,flash,html4',
flash_swf_url: '<?php $options->adminStaticUrl('js', 'Moxie.swf'); ?>',
drop_element: $('.upload-area').get(0),
filters: {
max_file_size: '<?php echo $phpMaxFilesize ?>',
mime_types: [{
'title': '<?php _e('允许上传的文件'); ?>',
'extensions': '<?php $attachment->attachment->type(); ?>'
}],
prevent_duplicates: true
},
multi_selection: false,
init: {
FilesAdded: function (up, files) {
plupload.each(files, function (file) {
fileUploadStart(file);
});
uploader.start();
},
FileUploaded: function (up, file, result) {
if (200 == result.status) {
var data = $.parseJSON(result.response);
if (data) {
fileUploadComplete(file.id, data[0], data[1]);
return;
}
}
fileUploadError({
code: plupload.HTTP_ERROR,
file: file
});
},
Error: function (up, error) {
fileUploadError(error);
}
}
});
uploader.init();
};
});
</script>
<?php

View File

@@ -5,7 +5,7 @@
<?php $menu->output(); ?>
</nav>
<div class="operate">
<?php \Typecho\Plugin::factory('admin/menu.php')->navBar(); ?><a title="<?php
<?php \Typecho\Plugin::factory('admin/menu.php')->call('navBar'); ?><a title="<?php
if ($user->logged > 0) {
$logged = new \Typecho\Date($user->logged);
_e('最后登录: %s', $logged->word());

View File

@@ -11,7 +11,7 @@ $stat = \Widget\Stat::alloc();
<?php include 'page-title.php'; ?>
<div class="row typecho-page-main">
<div class="col-mb-12 col-tb-3">
<p><a href="https://gravatar.com/emails/"
<p><a href="https://gravatar.com/"
title="<?php _e('在 Gravatar 上修改头像'); ?>"><?php echo '<img class="profile-avatar" src="' . \Typecho\Common::gravatarUrl($user->mail, 220, 'X', 'mm', $request->isSecure()) . '" alt="' . $user->screenName . '" />'; ?></a>
</p>
<h2><?php $user->screenName(); ?></h2>
@@ -57,6 +57,6 @@ $stat = \Widget\Stat::alloc();
include 'copyright.php';
include 'common-js.php';
include 'form-js.php';
\Typecho\Plugin::factory('admin/profile.php')->bottom();
\Typecho\Plugin::factory('admin/profile.php')->call('bottom');
include 'footer.php';
?>

View File

@@ -4,8 +4,8 @@ include 'common.php';
if ($user->hasLogin() || !$options->allowRegister) {
$response->redirect($options->siteUrl);
}
$rememberName = htmlspecialchars(\Typecho\Cookie::get('__typecho_remember_name'));
$rememberMail = htmlspecialchars(\Typecho\Cookie::get('__typecho_remember_mail'));
$rememberName = htmlspecialchars(\Typecho\Cookie::get('__typecho_remember_name', ''));
$rememberMail = htmlspecialchars(\Typecho\Cookie::get('__typecho_remember_mail', ''));
\Typecho\Cookie::delete('__typecho_remember_name');
\Typecho\Cookie::delete('__typecho_remember_mail');
@@ -15,7 +15,7 @@ include 'header.php';
?>
<div class="typecho-login-wrap">
<div class="typecho-login">
<h1><a href="http://typecho.org" class="i-logo">Typecho</a></h1>
<h1><a href="https://typecho.org" class="i-logo">Typecho</a></h1>
<form action="<?php $options->registerAction(); ?>" method="post" name="register" role="form">
<p>
<label for="name" class="sr-only"><?php _e('用户名'); ?></label>

File diff suppressed because it is too large Load Diff

View File

@@ -1700,8 +1700,8 @@ else
// The default text that appears in the dialog input box when entering
// links.
var imageDefaultText = "http://";
var linkDefaultText = "http://";
var imageDefaultText = "https://";
var linkDefaultText = "https://";
// -------------------------------------------------------------------
// END OF YOUR CHANGES
@@ -1767,6 +1767,8 @@ else
hooks.addNoop("enterFakeFullScreen");
hooks.addNoop("exitFullScreen");
hooks.addNoop("save");
this.getConverter = function () { return markdownConverter; }
var that = this,
@@ -3082,11 +3084,13 @@ else
doClick(buttons.undo);
}
break;
case "s":
hooks.save();
break;
default:
return;
}
if (key.preventDefault) {
key.preventDefault();
}

View File

@@ -1,443 +0,0 @@
// Generated by CoffeeScript 1.12.7
/*
paste.js is an interface to read data ( text / image ) from clipboard in different browsers. It also contains several hacks.
https://github.com/layerssss/paste.js
*/
(function() {
var $, Paste, createHiddenEditable, dataURLtoBlob, isFocusable;
$ = window.jQuery;
$.paste = function(pasteContainer) {
var pm;
if (typeof console !== "undefined" && console !== null) {
console.log("DEPRECATED: This method is deprecated. Please use $.fn.pastableNonInputable() instead.");
}
pm = Paste.mountNonInputable(pasteContainer);
return pm._container;
};
$.fn.pastableNonInputable = function() {
var el, j, len, ref;
ref = this;
for (j = 0, len = ref.length; j < len; j++) {
el = ref[j];
if (el._pastable || $(el).is('textarea, input:text, [contenteditable]')) {
continue;
}
Paste.mountNonInputable(el);
el._pastable = true;
}
return this;
};
$.fn.pastableTextarea = function() {
var el, j, len, ref;
ref = this;
for (j = 0, len = ref.length; j < len; j++) {
el = ref[j];
if (el._pastable || $(el).is(':not(textarea, input:text)')) {
continue;
}
Paste.mountTextarea(el);
el._pastable = true;
}
return this;
};
$.fn.pastableContenteditable = function() {
var el, j, len, ref;
ref = this;
for (j = 0, len = ref.length; j < len; j++) {
el = ref[j];
if (el._pastable || $(el).is(':not([contenteditable])')) {
continue;
}
Paste.mountContenteditable(el);
el._pastable = true;
}
return this;
};
dataURLtoBlob = function(dataURL, sliceSize) {
var b64Data, byteArray, byteArrays, byteCharacters, byteNumbers, contentType, i, m, offset, ref, slice;
if (sliceSize == null) {
sliceSize = 512;
}
if (!(m = dataURL.match(/^data\:([^\;]+)\;base64\,(.+)$/))) {
return null;
}
ref = m, m = ref[0], contentType = ref[1], b64Data = ref[2];
byteCharacters = atob(b64Data);
byteArrays = [];
offset = 0;
while (offset < byteCharacters.length) {
slice = byteCharacters.slice(offset, offset + sliceSize);
byteNumbers = new Array(slice.length);
i = 0;
while (i < slice.length) {
byteNumbers[i] = slice.charCodeAt(i);
i++;
}
byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
offset += sliceSize;
}
return new Blob(byteArrays, {
type: contentType
});
};
createHiddenEditable = function() {
return $(document.createElement('div')).attr('contenteditable', true).attr('aria-hidden', true).attr('tabindex', -1).css({
width: 1,
height: 1,
position: 'fixed',
left: -100,
overflow: 'hidden',
opacity: 1e-17
});
};
isFocusable = function(element, hasTabindex) {
var fieldset, focusableIfVisible, img, map, mapName, nodeName;
map = void 0;
mapName = void 0;
img = void 0;
focusableIfVisible = void 0;
fieldset = void 0;
nodeName = element.nodeName.toLowerCase();
if ('area' === nodeName) {
map = element.parentNode;
mapName = map.name;
if (!element.href || !mapName || map.nodeName.toLowerCase() !== 'map') {
return false;
}
img = $('img[usemap=\'#' + mapName + '\']');
return img.length > 0 && img.is(':visible');
}
if (/^(input|select|textarea|button|object)$/.test(nodeName)) {
focusableIfVisible = !element.disabled;
if (focusableIfVisible) {
fieldset = $(element).closest('fieldset')[0];
if (fieldset) {
focusableIfVisible = !fieldset.disabled;
}
}
} else if ('a' === nodeName) {
focusableIfVisible = element.href || hasTabindex;
} else {
focusableIfVisible = hasTabindex;
}
focusableIfVisible = focusableIfVisible || $(element).is('[contenteditable]');
return focusableIfVisible && $(element).is(':visible');
};
Paste = (function() {
Paste.prototype._target = null;
Paste.prototype._container = null;
Paste.mountNonInputable = function(nonInputable) {
var paste;
paste = new Paste(createHiddenEditable().appendTo(nonInputable), nonInputable);
$(nonInputable).on('click', (function(_this) {
return function(ev) {
if (!(isFocusable(ev.target, false) || window.getSelection().toString())) {
return paste._container.focus();
}
};
})(this));
paste._container.on('focus', (function(_this) {
return function() {
return $(nonInputable).addClass('pastable-focus');
};
})(this));
return paste._container.on('blur', (function(_this) {
return function() {
return $(nonInputable).removeClass('pastable-focus');
};
})(this));
};
Paste.mountTextarea = function(textarea) {
var ctlDown, paste, ref, ref1;
if ((typeof DataTransfer !== "undefined" && DataTransfer !== null ? DataTransfer.prototype : void 0) && ((ref = Object.getOwnPropertyDescriptor) != null ? (ref1 = ref.call(Object, DataTransfer.prototype, 'items')) != null ? ref1.get : void 0 : void 0)) {
return this.mountContenteditable(textarea);
}
paste = new Paste(createHiddenEditable().insertBefore(textarea), textarea);
ctlDown = false;
$(textarea).on('keyup', function(ev) {
var ref2;
if ((ref2 = ev.keyCode) === 17 || ref2 === 224) {
ctlDown = false;
}
return null;
});
$(textarea).on('keydown', function(ev) {
var ref2;
if ((ref2 = ev.keyCode) === 17 || ref2 === 224) {
ctlDown = true;
}
if ((ev.ctrlKey != null) && (ev.metaKey != null)) {
ctlDown = ev.ctrlKey || ev.metaKey;
}
if (ctlDown && ev.keyCode === 86) {
paste._textarea_focus_stolen = true;
paste._container.focus();
paste._paste_event_fired = false;
setTimeout((function(_this) {
return function() {
if (!paste._paste_event_fired) {
$(textarea).focus();
return paste._textarea_focus_stolen = false;
}
};
})(this), 1);
}
return null;
});
$(textarea).on('paste', (function(_this) {
return function() {};
})(this));
$(textarea).on('focus', (function(_this) {
return function() {
if (!paste._textarea_focus_stolen) {
return $(textarea).addClass('pastable-focus');
}
};
})(this));
$(textarea).on('blur', (function(_this) {
return function() {
if (!paste._textarea_focus_stolen) {
return $(textarea).removeClass('pastable-focus');
}
};
})(this));
$(paste._target).on('_pasteCheckContainerDone', (function(_this) {
return function() {
$(textarea).focus();
return paste._textarea_focus_stolen = false;
};
})(this));
return $(paste._target).on('pasteText', (function(_this) {
return function(ev, data) {
var content, curEnd, curStart;
curStart = $(textarea).prop('selectionStart');
curEnd = $(textarea).prop('selectionEnd');
content = $(textarea).val();
$(textarea).val("" + content.slice(0, curStart) + data.text + content.slice(curEnd));
$(textarea)[0].setSelectionRange(curStart + data.text.length, curStart + data.text.length);
return $(textarea).trigger('change');
};
})(this));
};
Paste.mountContenteditable = function(contenteditable) {
var paste;
paste = new Paste(contenteditable, contenteditable);
$(contenteditable).on('focus', (function(_this) {
return function() {
return $(contenteditable).addClass('pastable-focus');
};
})(this));
return $(contenteditable).on('blur', (function(_this) {
return function() {
return $(contenteditable).removeClass('pastable-focus');
};
})(this));
};
function Paste(_container, _target) {
this._container = _container;
this._target = _target;
this._container = $(this._container);
this._target = $(this._target).addClass('pastable');
this._container.on('paste', (function(_this) {
return function(ev) {
var _i, clipboardData, file, fileType, item, j, k, l, len, len1, len2, pastedFilename, reader, ref, ref1, ref2, ref3, ref4, stringIsFilename, text;
_this.originalEvent = (ev.originalEvent !== null ? ev.originalEvent : null);
_this._paste_event_fired = true;
if (((ref = ev.originalEvent) != null ? ref.clipboardData : void 0) != null) {
clipboardData = ev.originalEvent.clipboardData;
if (clipboardData.items) {
pastedFilename = null;
_this.originalEvent.pastedTypes = [];
ref1 = clipboardData.items;
for (j = 0, len = ref1.length; j < len; j++) {
item = ref1[j];
if (item.type.match(/^text\/(plain|rtf|html)/)) {
_this.originalEvent.pastedTypes.push(item.type);
}
}
ref2 = clipboardData.items;
for (_i = k = 0, len1 = ref2.length; k < len1; _i = ++k) {
item = ref2[_i];
if (item.type.match(/^image\//)) {
reader = new FileReader();
reader.onload = function(event) {
return _this._handleImage(event.target.result, _this.originalEvent, pastedFilename);
};
try {
reader.readAsDataURL(item.getAsFile());
} catch (error) {}
ev.preventDefault();
break;
}
if (item.type === 'text/plain') {
if (_i === 0 && clipboardData.items.length > 1 && clipboardData.items[1].type.match(/^image\//)) {
stringIsFilename = true;
fileType = clipboardData.items[1].type;
}
item.getAsString(function(string) {
if (stringIsFilename) {
pastedFilename = string;
return _this._target.trigger('pasteText', {
text: string,
isFilename: true,
fileType: fileType,
originalEvent: _this.originalEvent
});
} else {
return _this._target.trigger('pasteText', {
text: string,
originalEvent: _this.originalEvent
});
}
});
}
if (item.type === 'text/rtf') {
item.getAsString(function(string) {
return _this._target.trigger('pasteTextRich', {
text: string,
originalEvent: _this.originalEvent
});
});
}
if (item.type === 'text/html') {
item.getAsString(function(string) {
return _this._target.trigger('pasteTextHtml', {
text: string,
originalEvent: _this.originalEvent
});
});
}
}
} else {
if (-1 !== Array.prototype.indexOf.call(clipboardData.types, 'text/plain')) {
text = clipboardData.getData('Text');
setTimeout(function() {
return _this._target.trigger('pasteText', {
text: text,
originalEvent: _this.originalEvent
});
}, 1);
}
_this._checkImagesInContainer(function(src) {
return _this._handleImage(src, _this.originalEvent);
});
}
}
if (clipboardData = window.clipboardData) {
if ((ref3 = (text = clipboardData.getData('Text'))) != null ? ref3.length : void 0) {
setTimeout(function() {
_this._target.trigger('pasteText', {
text: text,
originalEvent: _this.originalEvent
});
return _this._target.trigger('_pasteCheckContainerDone');
}, 1);
} else {
ref4 = clipboardData.files;
for (l = 0, len2 = ref4.length; l < len2; l++) {
file = ref4[l];
_this._handleImage(URL.createObjectURL(file), _this.originalEvent);
}
_this._checkImagesInContainer(function(src) {});
}
}
return null;
};
})(this));
}
Paste.prototype._handleImage = function(src, e, name) {
var loader;
if (src.match(/^webkit\-fake\-url\:\/\//)) {
return this._target.trigger('pasteImageError', {
message: "You are trying to paste an image in Safari, however we are unable to retieve its data."
});
}
this._target.trigger('pasteImageStart');
loader = new Image();
loader.crossOrigin = "anonymous";
loader.onload = (function(_this) {
return function() {
var blob, canvas, ctx, dataURL;
canvas = document.createElement('canvas');
canvas.width = loader.width;
canvas.height = loader.height;
ctx = canvas.getContext('2d');
ctx.drawImage(loader, 0, 0, canvas.width, canvas.height);
dataURL = null;
try {
dataURL = canvas.toDataURL('image/png');
blob = dataURLtoBlob(dataURL);
} catch (error) {}
if (dataURL) {
_this._target.trigger('pasteImage', {
blob: blob,
dataURL: dataURL,
width: loader.width,
height: loader.height,
originalEvent: e,
name: name
});
}
return _this._target.trigger('pasteImageEnd');
};
})(this);
loader.onerror = (function(_this) {
return function() {
_this._target.trigger('pasteImageError', {
message: "Failed to get image from: " + src,
url: src
});
return _this._target.trigger('pasteImageEnd');
};
})(this);
return loader.src = src;
};
Paste.prototype._checkImagesInContainer = function(cb) {
var img, j, len, ref, timespan;
timespan = Math.floor(1000 * Math.random());
ref = this._container.find('img');
for (j = 0, len = ref.length; j < len; j++) {
img = ref[j];
img["_paste_marked_" + timespan] = true;
}
return setTimeout((function(_this) {
return function() {
var k, len1, ref1;
ref1 = _this._container.find('img');
for (k = 0, len1 = ref1.length; k < len1; k++) {
img = ref1[k];
if (!img["_paste_marked_" + timespan]) {
cb(img.src);
$(img).remove();
}
}
return _this._target.trigger('_pasteCheckContainerDone');
};
})(this), 1);
};
return Paste;
})();
}).call(this);

File diff suppressed because it is too large Load Diff

View File

@@ -10,7 +10,8 @@
}
})
},
uploadComplete : function (file) {}
uploadComplete : function (attachment) {},
savePost : function (cb) {},
};
})(window);

View File

@@ -2,7 +2,7 @@
* Forms
*/
input[type=text], input[type=password], input[type=email],
input[type=text], input[type=url], input[type=password], input[type=email],
textarea {
background: #FFF;
border: 1px solid #D9D9D6;

View File

@@ -100,7 +100,7 @@ $color-nav-child-focus: #6DA1BB;
font-weight: bold;
}
&.root:hover .child {
&.root:hover .child, &.root.expanded .child {
display: block;
}
}

View File

@@ -504,6 +504,14 @@ a.operate-reply {
max-width: 100%;
}
@media (max-width: $screen-phone - 1px) {
.comment-edit {
display: flex;
flex-direction: column;
width: 90vw;
}
.comment-edit td:first-child { display: none; }
}
/**
* 评论回复

View File

@@ -1,4 +1,5 @@
<?php if(!defined('__TYPECHO_ADMIN__')) exit; ?>
<script src="<?php $options->adminStaticUrl('js', 'purify.js'); ?>"></script>
<script>
(function () {
$(document).ready(function () {

View File

@@ -60,6 +60,6 @@ include 'menu.php';
<?php
include 'copyright.php';
include 'common-js.php';
\Typecho\Plugin::factory('admin/theme-editor.php')->bottom($files);
\Typecho\Plugin::factory('admin/theme-editor.php')->call('bottom', $files);
include 'footer.php';
?>

View File

@@ -12,7 +12,7 @@ include 'menu.php';
<ul class="typecho-option-tabs fix-tabs clearfix">
<li class="current"><a href="<?php $options->adminUrl('themes.php'); ?>"><?php _e('可以使用的外观'); ?></a>
</li>
<?php if (!defined('__TYPECHO_THEME_WRITEABLE__') || __TYPECHO_THEME_WRITEABLE__): ?>
<?php if (\Widget\Themes\Files::isWriteable()): ?>
<li><a href="<?php $options->adminUrl('theme-editor.php'); ?>"><?php _e('编辑当前外观'); ?></a></li>
<?php endif; ?>
<?php if (\Widget\Themes\Config::isExists()): ?>
@@ -33,10 +33,21 @@ include 'menu.php';
</thead>
<tbody>
<?php if ($options->missingTheme): ?>
<tr id="theme-<?php $options->missingTheme; ?>" class="current">
<td colspan="2" class="warning">
<p><strong><?php _e('检测到您之前使用的 "%s" 外观文件不存在,您可以重新上传此外观或者启用其他外观。', $options->missingTheme); ?></strong></p>
<ul>
<li><?php _e('重新上传此外观后刷新当前页面,此提示将会消失。'); ?></li>
<li><?php _e('启用新外观后,当前外观的设置数据将被删除。'); ?></li>
</ul>
</td>
</tr>
<?php endif; ?>
<?php \Widget\Themes\Rows::alloc()->to($themes); ?>
<?php while ($themes->next()): ?>
<tr id="theme-<?php $themes->name(); ?>"
class="<?php if ($themes->activated): ?>current<?php endif; ?>">
class="<?php if ($themes->activated && !$options->missingTheme): ?>current<?php endif; ?>">
<td valign="top"><img src="<?php $themes->screen(); ?>"
alt="<?php $themes->name(); ?>"/></td>
<td valign="top">
@@ -46,9 +57,9 @@ include 'menu.php';
<?php if ($themes->version): ?><?php _e('版本'); ?>: <?php $themes->version() ?><?php endif; ?>
</cite>
<p><?php echo nl2br($themes->description); ?></p>
<?php if ($options->theme != $themes->name): ?>
<?php if ($options->theme != $themes->name || $options->missingTheme): ?>
<p>
<?php if (!defined('__TYPECHO_THEME_WRITEABLE__') || __TYPECHO_THEME_WRITEABLE__): ?>
<?php if (\Widget\Themes\Files::isWriteable()): ?>
<a class="edit"
href="<?php $options->adminUrl('theme-editor.php?theme=' . $themes->name); ?>"><?php _e('编辑'); ?></a> &nbsp;
<?php endif; ?>

View File

@@ -16,9 +16,9 @@ include 'menu.php';
<li><a class="operate-delete" href="<?php $options->adminUrl('profile.php#change-password'); ?>"><?php _e('强烈建议更改你的默认密码'); ?></a></li>
<?php if($user->pass('contributor', true)): ?>
<li><a href="<?php $options->adminUrl('write-post.php'); ?>"><?php _e('撰写第一篇日志'); ?></a></li>
<li><a href="<?php $options->siteUrl(); ?>"><?php _e('查看我的站点'); ?></a></li>
<li><a href="<?php $options->siteUrl(); ?>"><?php $user->pass('administrator', true) ? _e('查看我的站点') : _e('查看网站'); ?></a></li>
<?php else: ?>
<li><a href="<?php $options->siteUrl(); ?>"><?php _e('查看我的站点'); ?></a></li>
<li><a href="<?php $options->siteUrl(); ?>"><?php _e('查看网站'); ?></a></li>
<?php endif; ?>
</ol>
<p><button type="submit" class="btn primary"><?php _e('让我直接开始使用吧 &raquo;'); ?></button></p>

View File

@@ -1,5 +1,5 @@
<?php if(!defined('__TYPECHO_ADMIN__')) exit; ?>
<?php \Typecho\Plugin::factory('admin/write-js.php')->write(); ?>
<?php \Typecho\Plugin::factory('admin/write-js.php')->call('write'); ?>
<?php \Widget\Metas\Tag\Cloud::alloc('sort=count&desc=1&limit=200')->to($tags); ?>
<script src="<?php $options->adminStaticUrl('js', 'timepicker.js'); ?>"></script>
@@ -42,12 +42,12 @@ $(document).ready(function() {
Typecho.editorResize('text', '<?php $security->index('/action/ajax?do=editorResize'); ?>');
// tag autocomplete 提示
var tags = $('#tags'), tagsPre = [];
const tags = $('#tags'), tagsPre = [];
if (tags.length > 0) {
var items = tags.val().split(','), result = [];
for (var i = 0; i < items.length; i ++) {
var tag = items[i];
const items = tags.val().split(',');
for (let i = 0; i < items.length; i ++) {
const tag = items[i];
if (!tag) {
continue;
@@ -87,7 +87,7 @@ $(document).ready(function() {
result = [];
}
if (!result[0] || result[0]['id'] != query) {
if (!result[0] || result[0]['id'] !== query) {
result.unshift({
id : val,
tags : val
@@ -100,17 +100,17 @@ $(document).ready(function() {
// tag autocomplete 提示宽度设置
$('#token-input-tags').focus(function() {
var t = $('.token-input-dropdown'),
const t = $('.token-input-dropdown'),
offset = t.outerWidth() - t.width();
t.width($('.token-input-list').outerWidth() - offset);
});
}
// 缩略名自适应宽度
var slug = $('#slug');
const slug = $('#slug');
if (slug.length > 0) {
var wrap = $('<div />').css({
const wrap = $('<div />').css({
'position' : 'relative',
'display' : 'inline-block'
}),
@@ -126,10 +126,10 @@ $(document).ready(function() {
'minWidth' : '5px',
'position' : 'absolute',
'width' : '100%'
})), originalWidth = slug.width();
}));
function justifySlugWidth() {
var val = slug.val();
const val = slug.val();
justifySlug.text(val.length > 0 ? val : ' ');
}
@@ -137,91 +137,111 @@ $(document).ready(function() {
justifySlugWidth();
}
// 原始的插入图片和文件
Typecho.insertFileToEditor = function (file, url, isImage) {
var textarea = $('#text'), sel = textarea.getSelection(),
html = isImage ? '<img src="' + url + '" alt="' + file + '" />'
: '<a href="' + url + '">' + file + '</a>',
offset = (sel ? sel.start : 0) + html.length;
textarea.replaceSelection(html);
textarea.setSelection(offset, offset);
};
var submitted = false, form = $('form[name=write_post],form[name=write_page]').submit(function () {
submitted = true;
}), formAction = form.attr('action'),
// 处理保存文章的逻辑
const form = $('form[name=write_post],form[name=write_page]'),
idInput = $('input[name=cid]'),
cid = idInput.val(),
draft = $('input[name=draft]'),
draftId = draft.length > 0 ? draft.val() : 0,
btnSave = $('#btn-save').removeAttr('name').removeAttr('value'),
btnSubmit = $('#btn-submit').removeAttr('name').removeAttr('value'),
btnPreview = $('#btn-preview'),
doAction = $('<input type="hidden" name="do" value="publish" />').appendTo(form),
locked = false,
autoSave = $('<span id="auto-save-message" class="left"></span>').prependTo('.submit');
let cid = idInput.val(),
draftId = draft.length > 0 ? draft.val() : 0,
changed = false,
autoSave = $('<span id="auto-save-message" class="left"></span>').prependTo('.submit'),
written = false,
lastSaveTime = null;
$(':input', form).bind('input change', function (e) {
var tagName = $(this).prop('tagName');
if (tagName.match(/(input|textarea)/i) && e.type == 'change') {
return;
}
changed = true;
form.on('write', function () {
written = true;
form.trigger('datachange');
});
form.bind('field', function () {
changed = true;
form.on('change', function () {
if (written) {
form.trigger('datachange');
}
});
$('button[name=do]').click(function () {
$('input[name=do]').val($(this).val());
});
// 自动检测离开页
$(window).bind('beforeunload', function () {
if (changed && !form.hasClass('submitting')) {
return '<?php _e('内容已经改变尚未保存, 您确认要离开此页面吗?'); ?>';
}
});
// 发送保存请求
function saveData(cb) {
function callback(o) {
Typecho.savePost = function(cb) {
if (!changed) {
cb && cb();
return;
}
const callback = function (o) {
lastSaveTime = o.time;
cid = o.cid;
draftId = o.draftId;
idInput.val(cid);
autoSave.text('<?php _e('已保存'); ?>' + ' (' + o.time + ')').effect('highlight', 1000);
locked = false;
btnSave.removeAttr('disabled');
btnPreview.removeAttr('disabled');
if (!!cb) {
cb(o)
}
}
cb && cb();
};
changed = false;
btnSave.attr('disabled', 'disabled');
btnPreview.attr('disabled', 'disabled');
autoSave.text('<?php _e('正在保存'); ?>');
if (typeof FormData !== 'undefined') {
var data = new FormData(form.get(0));
data.append('do', 'save');
const data = new FormData(form.get(0));
data.append('do', 'save');
form.triggerHandler('submit');
$.ajax({
url: formAction,
processData: false,
contentType: false,
type: 'POST',
data: data,
success: callback
});
} else {
var data = form.serialize() + '&do=save';
$.post(formAction, data, callback, 'json');
$.ajax({
url: form.attr('action'),
processData: false,
contentType: false,
type: 'POST',
data: data,
success: callback,
error: function () {
autoSave.text('<?php _e('保存失败, 请重试'); ?>');
},
complete: function () {
form.trigger('submitted');
}
});
};
<?php if ($options->autoSave): ?>
// 自动保存
let saveTimer = null;
let stopAutoSave = false;
form.on('datachange', function () {
changed = true;
autoSave.text('<?php _e('尚未保存'); ?>' + (lastSaveTime ? ' (<?php _e('上次保存时间'); ?>: ' + lastSaveTime + ')' : ''));
if (saveTimer) {
clearTimeout(saveTimer);
}
}
saveTimer = setTimeout(function () {
!stopAutoSave && Typecho.savePost();
}, 3000);
}).on('submit', function () {
stopAutoSave = true;
}).on('submitted', function () {
stopAutoSave = false;
});
<?php else: ?>
form.on('datachange', function () {
changed = true;
});
<?php endif; ?>
// 计算夏令时偏移
var dstOffset = (function () {
var d = new Date(),
const dstOffset = (function () {
const d = new Date(),
jan = new Date(d.getFullYear(), 0, 1),
jul = new Date(d.getFullYear(), 6, 1),
stdOffset = Math.max(jan.getTimezoneOffset(), jul.getTimezoneOffset());
@@ -236,52 +256,16 @@ $(document).ready(function() {
// 时区
$('<input name="timezone" type="hidden" />').appendTo(form).val(- (new Date).getTimezoneOffset() * 60);
// 自动保存
<?php if ($options->autoSave): ?>
var autoSaveOnce = !!cid;
function autoSaveListener () {
setInterval(function () {
if (changed && !locked) {
locked = true;
saveData();
}
}, 10000);
}
if (autoSaveOnce) {
autoSaveListener();
}
$('#text').bind('input propertychange', function () {
if (!locked) {
autoSave.text('<?php _e('尚未保存'); ?>' + (lastSaveTime ? ' (<?php _e('上次保存时间'); ?>: ' + lastSaveTime + ')' : ''));
}
if (!autoSaveOnce) {
autoSaveOnce = true;
autoSaveListener();
}
});
<?php endif; ?>
// 自动检测离开页
$(window).bind('beforeunload', function () {
if (changed && !submitted) {
return '<?php _e('内容已经改变尚未保存, 您确认要离开此页面吗?'); ?>';
}
});
// 预览功能
var isFullScreen = false;
let isFullScreen = false;
function previewData(cid) {
isFullScreen = $(document.body).hasClass('fullscreen');
$(document.body).addClass('fullscreen preview');
var frame = $('<iframe frameborder="0" class="preview-frame preview-loading"></iframe>')
const frame = $('<iframe frameborder="0" class="preview-frame preview-loading"></iframe>')
.attr('src', './preview.php?cid=' + cid)
.attr('sandbox', 'allow-scripts')
.attr('sandbox', 'allow-same-origin allow-scripts')
.appendTo(document.body);
frame.load(function () {
@@ -292,36 +276,28 @@ $(document).ready(function() {
}
function cancelPreview() {
if (submitted) {
return;
}
if (!isFullScreen) {
$(document.body).removeClass('fullscreen');
}
$(document.body).removeClass('preview');
$('.preview-frame').remove();
};
}
$('#btn-cancel-preview').click(cancelPreview);
$(window).bind('message', function (e) {
if (e.originalEvent.data == 'cancelPreview') {
if (e.originalEvent.data === 'cancelPreview') {
cancelPreview();
}
});
btnPreview.click(function () {
if (changed) {
locked = true;
if (confirm('<?php _e('修改后的内容需要保存后才能预览, 是否保存?'); ?>')) {
saveData(function (o) {
previewData(o.draftId);
Typecho.savePost(function () {
previewData(draftId);
});
} else {
locked = false;
}
} else if (!!draftId) {
previewData(draftId);
@@ -330,28 +306,13 @@ $(document).ready(function() {
}
});
btnSave.click(function () {
doAction.attr('value', 'save');
});
btnSubmit.click(function () {
doAction.attr('value', 'publish');
});
// 控制选项和附件的切换
var fileUploadInit = false;
$('#edit-secondary .typecho-option-tabs li').click(function() {
$('#edit-secondary .typecho-option-tabs li').removeClass('active');
$(this).addClass('active');
$(this).parents('#edit-secondary').find('.tab-content').addClass('hidden');
var selected_tab = $(this).find('a').attr('href'),
selected_el = $(selected_tab).removeClass('hidden');
$('#edit-secondary .typecho-option-tabs li.active').removeClass('active');
$('#edit-secondary .tab-content').addClass('hidden');
if (!fileUploadInit) {
selected_el.trigger('init');
fileUploadInit = true;
}
const activeTab = $(this).addClass('active').find('a').attr('href');
$(activeTab).removeClass('hidden');
return false;
});
@@ -364,9 +325,9 @@ $(document).ready(function() {
// 自动隐藏密码框
$('#visibility').change(function () {
var val = $(this).val(), password = $('#post-password');
const val = $(this).val(), password = $('#post-password');
if ('password' == val) {
if ('password' === val) {
password.removeClass('hidden');
} else {
password.addClass('hidden');

View File

@@ -2,7 +2,19 @@
include 'common.php';
include 'header.php';
include 'menu.php';
\Widget\Contents\Page\Edit::alloc()->to($page);
$page = \Widget\Contents\Page\Edit::alloc()->prepare();
$parentPageId = $page->getParent();
$parentPages = [0 => _t('不选择')];
$parents = \Widget\Contents\Page\Admin::allocWithAlias(
'options',
'ignoreRequest=1' . ($request->is('cid') ? '&ignore=' . $request->get('cid') : '')
);
while ($parents->next()) {
$parentPages[$parents->cid] = str_repeat('&nbsp;&nbsp;&nbsp;&nbsp;', $parents->levels) . $parents->title;
}
?>
<div class="main">
<div class="body container">
@@ -14,7 +26,7 @@ include 'menu.php';
<?php if ($page->draft['cid'] != $page->cid): ?>
<?php $pageModifyDate = new \Typecho\Date($page->draft['modified']); ?>
<cite
class="edit-draft-notice"><?php _e('当前正在编辑的是保存于%s的草稿, 你可以<a href="%s">删除它</a>', $pageModifyDate->word(),
class="edit-draft-notice"><?php _e('正在编辑的是保存于 %s 的修订版, 你可以 <a href="%s">删除它</a>', $pageModifyDate->word(),
$security->getIndex('/action/contents-page-edit?do=deleteDraft&cid=' . $page->cid)); ?></cite>
<?php else: ?>
<cite class="edit-draft-notice"><?php _e('当前正在编辑的是未发布的草稿'); ?></cite>
@@ -38,12 +50,18 @@ include 'menu.php';
?>
<p class="mono url-slug">
<label for="slug" class="sr-only"><?php _e('网址缩略名'); ?></label>
<?php echo preg_replace("/\{slug\}/i", $input, $permalink); ?>
<?php echo preg_replace_callback("/\{(slug|directory)\}/i", function ($matches) use ($input) {
if ($matches[1] == 'slug') {
return $input;
} else {
return '{directory/' . $input . '}';
}
}, $permalink); ?>
</p>
<p>
<label for="text" class="sr-only"><?php _e('页面内容'); ?></label>
<textarea style="height: <?php $options->editorSize(); ?>px" autocomplete="off" id="text"
name="text" class="w-100 mono"><?php echo htmlspecialchars($page->text ?? ''); ?></textarea>
name="text" class="w-100 mono"><?php echo htmlspecialchars($page->text); ?></textarea>
</p>
<?php include 'custom-fields.php'; ?>
@@ -53,6 +71,7 @@ include 'menu.php';
class="i-caret-left"></i> <?php _e('取消预览'); ?></button>
</span>
<span class="right">
<input type="hidden" name="do" value="publish" />
<input type="hidden" name="cid" value="<?php $page->cid(); ?>"/>
<button type="button" id="btn-preview" class="btn"><i
class="i-exlink"></i> <?php _e('预览页面'); ?></button>
@@ -66,7 +85,7 @@ include 'menu.php';
</span>
</p>
<?php \Typecho\Plugin::factory('admin/write-page.php')->content($page); ?>
<?php \Typecho\Plugin::factory('admin/write-page.php')->call('content', $page); ?>
</div>
<div id="edit-secondary" class="col-mb-12 col-tb-3" role="complementary">
<ul class="typecho-option-tabs clearfix">
@@ -104,7 +123,20 @@ include 'menu.php';
<p class="description"><?php _e('如果你为此页面选择了一个自定义模板, 系统将按照你选择的模板文件展现它'); ?></p>
</section>
<?php \Typecho\Plugin::factory('admin/write-page.php')->option($page); ?>
<section class="typecho-post-option">
<label for="parent" class="typecho-label"><?php _e('父级页面'); ?></label>
<p>
<select name="parent" id="parent">
<?php foreach ($parentPages as $pageId => $pageTitle): ?>
<option
value="<?php echo $pageId; ?>"<?php if ($pageId == ($page->parent ?? $parentPageId)): ?> selected="true"<?php endif; ?>><?php echo $pageTitle; ?></option>
<?php endforeach; ?>
</select>
</p>
<p class="description"><?php _e('如果你设定了父级页面, 此页面将作为子页面呈现'); ?></p>
</section>
<?php \Typecho\Plugin::factory('admin/write-page.php')->call('option', $page); ?>
<button type="button" id="advance-panel-btn" class="btn btn-xs"><?php _e('高级选项'); ?> <i
class="i-caret-down"></i></button>
@@ -136,7 +168,7 @@ include 'menu.php';
</ul>
</section>
<?php \Typecho\Plugin::factory('admin/write-page.php')->advanceOption($page); ?>
<?php \Typecho\Plugin::factory('admin/write-page.php')->call('advanceOption', $page); ?>
</div>
<?php if ($page->have()): ?>
<?php $modified = new \Typecho\Date($page->modified); ?>
@@ -167,7 +199,7 @@ include 'common-js.php';
include 'form-js.php';
include 'write-js.php';
\Typecho\Plugin::factory('admin/write-page.php')->trigger($plugged)->richEditor($page);
\Typecho\Plugin::factory('admin/write-page.php')->trigger($plugged)->call('richEditor', $page);
if (!$plugged) {
include 'editor-js.php';
}

View File

@@ -2,7 +2,8 @@
include 'common.php';
include 'header.php';
include 'menu.php';
\Widget\Contents\Post\Edit::alloc()->to($post);
$post = \Widget\Contents\Post\Edit::alloc()->prepare();
?>
<div class="main">
<div class="body container">
@@ -14,7 +15,7 @@ include 'menu.php';
<?php if ($post->draft['cid'] != $post->cid): ?>
<?php $postModifyDate = new \Typecho\Date($post->draft['modified']); ?>
<cite
class="edit-draft-notice"><?php _e('你正在编辑的是保存于 %s 的草稿, 你也可以 <a href="%s">删除它</a>', $postModifyDate->word(),
class="edit-draft-notice"><?php _e('你正在编辑的是保存于 %s 的修订版, 你也可以 <a href="%s">删除它</a>', $postModifyDate->word(),
$security->getIndex('/action/contents-post-edit?do=deleteDraft&cid=' . $post->cid)); ?></cite>
<?php else: ?>
<cite class="edit-draft-notice"><?php _e('当前正在编辑的是未发布的草稿'); ?></cite>
@@ -47,7 +48,7 @@ include 'menu.php';
<p>
<label for="text" class="sr-only"><?php _e('文章内容'); ?></label>
<textarea style="height: <?php $options->editorSize(); ?>px" autocomplete="off" id="text"
name="text" class="w-100 mono"><?php echo htmlspecialchars($post->text ?? ''); ?></textarea>
name="text" class="w-100 mono"><?php echo htmlspecialchars($post->text); ?></textarea>
</p>
<?php include 'custom-fields.php'; ?>
@@ -58,6 +59,7 @@ include 'menu.php';
class="i-caret-left"></i> <?php _e('取消预览'); ?></button>
</span>
<span class="right">
<input type="hidden" name="do" value="publish" />
<input type="hidden" name="cid" value="<?php $post->cid(); ?>"/>
<button type="button" id="btn-preview" class="btn"><i
class="i-exlink"></i> <?php _e('预览文章'); ?></button>
@@ -71,7 +73,7 @@ include 'menu.php';
</span>
</p>
<?php \Typecho\Plugin::factory('admin/write-post.php')->content($post); ?>
<?php \Typecho\Plugin::factory('admin/write-post.php')->call('content', $post); ?>
</div>
<div id="edit-secondary" class="col-mb-12 col-tb-3" role="complementary">
@@ -93,13 +95,7 @@ include 'menu.php';
<label class="typecho-label"><?php _e('分类'); ?></label>
<?php \Widget\Metas\Category\Rows::alloc()->to($category); ?>
<ul>
<?php
if ($post->have()) {
$categories = array_column($post->categories, 'mid');
} else {
$categories = [];
}
?>
<?php $categories = $post->categories->toArray('mid'); ?>
<?php while ($category->next()): ?>
<li><?php echo str_repeat('&nbsp;&nbsp;&nbsp;&nbsp;', $category->levels); ?><input
type="checkbox" id="category-<?php $category->mid(); ?>"
@@ -114,11 +110,11 @@ include 'menu.php';
<section class="typecho-post-option">
<label for="token-input-tags" class="typecho-label"><?php _e('标签'); ?></label>
<p><input id="tags" name="tags" type="text" value="<?php $post->tags(',', false); ?>"
<p><input id="tags" name="tags" type="text" value="<?php $post->have() ? $post->tags(',', false) : ''; ?>"
class="w-100 text"/></p>
</section>
<?php \Typecho\Plugin::factory('admin/write-post.php')->option($post); ?>
<?php \Typecho\Plugin::factory('admin/write-post.php')->call('option', $post); ?>
<button type="button" id="advance-panel-btn" class="btn btn-xs"><?php _e('高级选项'); ?> <i
class="i-caret-down"></i></button>
@@ -172,7 +168,7 @@ include 'menu.php';
<p class="description"><?php _e('每一行一个引用地址, 用回车隔开'); ?></p>
</section>
<?php \Typecho\Plugin::factory('admin/write-post.php')->advanceOption($post); ?>
<?php \Typecho\Plugin::factory('admin/write-post.php')->call('advanceOption', $post); ?>
</div><!-- end #advance-panel -->
<?php if ($post->have()): ?>
@@ -204,13 +200,13 @@ include 'common-js.php';
include 'form-js.php';
include 'write-js.php';
\Typecho\Plugin::factory('admin/write-post.php')->trigger($plugged)->richEditor($post);
\Typecho\Plugin::factory('admin/write-post.php')->trigger($plugged)->call('richEditor', $post);
if (!$plugged) {
include 'editor-js.php';
}
include 'file-upload-js.php';
include 'custom-fields-js.php';
\Typecho\Plugin::factory('admin/write-post.php')->bottom($post);
\Typecho\Plugin::factory('admin/write-post.php')->call('bottom', $post);
include 'footer.php';
?>

View File

@@ -205,14 +205,14 @@ function install_get_default_routers(): array
'comment_page' =>
[
'url' => '[permalink:string]/comment-page-[commentPage:digital]',
'widget' => '\Widget\Archive',
'action' => 'render',
'widget' => '\Widget\CommentPage',
'action' => 'action',
],
'feed' =>
[
'url' => '/feed[feed:string:0]',
'widget' => '\Widget\Archive',
'action' => 'feed',
'widget' => '\Widget\Feed',
'action' => 'render',
],
'feedback' =>
[
@@ -241,7 +241,16 @@ function install_get_default_options(): array
if (empty($options)) {
$options = [
'theme' => 'default',
'theme:default' => 'a:2:{s:7:"logoUrl";N;s:12:"sidebarBlock";a:5:{i:0;s:15:"ShowRecentPosts";i:1;s:18:"ShowRecentComments";i:2;s:12:"ShowCategory";i:3;s:11:"ShowArchive";i:4;s:9:"ShowOther";}}',
'theme:default' => json_encode([
'logoUrl' => '',
'sidebarBlock' => [
'ShowRecentPosts',
'ShowRecentComments',
'ShowCategory',
'ShowArchive',
'ShowOther'
]
]),
'timezone' => '28800',
'lang' => install_get_lang(),
'charset' => 'UTF-8',
@@ -256,7 +265,7 @@ function install_get_default_options(): array
'frontArchive' => 0,
'commentsRequireMail' => 1,
'commentsWhitelist' => 0,
'commentsRequireURL' => 0,
'commentsRequireUrl' => 0,
'commentsRequireModeration' => 0,
'plugins' => 'a:0:{}',
'commentDateFormat' => 'F jS, Y \a\t h:i a',
@@ -294,9 +303,9 @@ function install_get_default_options(): array
'commentsAvatar' => 1,
'commentsAvatarRating' => 'G',
'commentsAntiSpam' => 1,
'routingTable' => serialize(install_get_default_routers()),
'actionTable' => 'a:0:{}',
'panelTable' => 'a:0:{}',
'routingTable' => json_encode(install_get_default_routers()),
'actionTable' => json_encode([]),
'panelTable' => json_encode([]),
'attachmentTypes' => '@image@',
'secret' => \Typecho\Common::randString(32, true),
'installed' => 0,
@@ -705,7 +714,7 @@ function install_step_1()
</p>
<h3><?php _e('许可及协议'); ?></h3>
<ul>
<li><?php _e('Typecho 基于 <a href="http://www.gnu.org/copyleft/gpl.html">GPL</a> 协议发布, 我们允许用户在 GPL 协议许可的范围内使用, 拷贝, 修改和分发此程序.'); ?>
<li><?php _e('Typecho 基于 <a href="https://www.gnu.org/copyleft/gpl.html">GPL</a> 协议发布, 我们允许用户在 GPL 协议许可的范围内使用, 拷贝, 修改和分发此程序.'); ?>
<?php _e('在GPL许可的范围内, 您可以自由地将其用于商业以及非商业用途.'); ?></li>
<li><?php _e('Typecho 软件由其社区提供支持, 核心开发团队负责维护程序日常开发工作以及新特性的制定.'); ?>
<?php _e('如果您遇到使用上的问题, 程序中的 BUG, 以及期许的新功能, 欢迎您在社区中交流或者直接向我们贡献代码.'); ?>
@@ -759,7 +768,7 @@ function install_step_1_perform()
$realUploadDir = \Typecho\Common::url($uploadDir, __TYPECHO_ROOT_DIR__);
$writeable = true;
if (is_dir($realUploadDir)) {
if (!is_writeable($realUploadDir) || !is_readable($realUploadDir)) {
if (!is_writable($realUploadDir) || !is_readable($realUploadDir)) {
if (!@chmod($realUploadDir, 0755)) {
$writeable = false;
}
@@ -924,7 +933,9 @@ function install_step_2_perform()
'dbPassword' => null,
'dbCharset' => 'utf8mb4',
'dbDatabase' => null,
'dbEngine' => 'InnoDB'
'dbEngine' => 'InnoDB',
'dbSslCa' => null,
'dbSslVerify' => 'off',
],
'Pgsql' => [
'dbHost' => 'localhost',
@@ -933,6 +944,7 @@ function install_step_2_perform()
'dbPassword' => null,
'dbCharset' => 'utf8',
'dbDatabase' => null,
'dbSslVerify' => 'off',
],
'SQLite' => [
'dbFile' => __TYPECHO_ROOT_DIR__ . '/usr/' . uniqid() . '.db'
@@ -952,7 +964,9 @@ function install_step_2_perform()
'dbEngine' => $request->getServer('TYPECHO_DB_ENGINE'),
'dbPrefix' => $request->getServer('TYPECHO_DB_PREFIX', 'typecho_'),
'dbAdapter' => $request->getServer('TYPECHO_DB_ADAPTER', install_get_current_db_driver()),
'dbNext' => $request->getServer('TYPECHO_DB_NEXT', 'none')
'dbNext' => $request->getServer('TYPECHO_DB_NEXT', 'none'),
'dbSslCa' => $request->getServer('TYPECHO_DB_SSL_CA'),
'dbSslVerify' => $request->getServer('TYPECHO_DB_SSL_VERIFY', 'off'),
];
} else {
$config = $request->from([
@@ -967,7 +981,9 @@ function install_step_2_perform()
'dbEngine',
'dbPrefix',
'dbAdapter',
'dbNext'
'dbNext',
'dbSslCa',
'dbSslVerify',
]);
}
@@ -1005,6 +1021,8 @@ function install_step_2_perform()
->addRule('dbDatabase', 'required', _t('确认您的配置'))
->addRule('dbEngine', 'required', _t('确认您的配置'))
->addRule('dbEngine', 'enum', _t('确认您的配置'), ['InnoDB', 'MyISAM'])
->addRule('dbSslCa', 'file_exists', _t('确认您的配置'))
->addRule('dbSslVerify', 'enum', _t('确认您的配置'), ['on', 'off'])
->run($config);
break;
case 'Pgsql':
@@ -1016,13 +1034,18 @@ function install_step_2_perform()
->addRule('dbCharset', 'required', _t('确认您的配置'))
->addRule('dbCharset', 'enum', _t('确认您的配置'), ['utf8'])
->addRule('dbDatabase', 'required', _t('确认您的配置'))
->addRule('dbSslVerify', 'enum', _t('确认您的配置'), ['on', 'off'])
->run($config);
break;
case 'SQLite':
$error = (new \Typecho\Validate())
->addRule('dbFile', 'required', _t('确认您的配置'))
->addRule('dbFile', function (string $path) {
return !!preg_match("/^(\/[_a-z0-9-]+)*[a-z0-9]+\.[a-z0-9]{2,}$/i", $path);
$pattern = "/^(\/[._a-z0-9-]+)*[a-z0-9]+\.[a-z0-9]{2,}$/i";
if (strstr(PHP_OS, 'WIN')) {
$pattern = "/(\/[._a-z0-9-]+)*[a-z0-9]+\.[a-z0-9]{2,}$/i";
}
return !!preg_match($pattern, $path);
}, _t('确认您的配置'))
->run($config);
break;
@@ -1036,7 +1059,7 @@ function install_step_2_perform()
}
foreach ($configMap[$type] as $key => $value) {
$dbConfig[strtolower(substr($key, 2))] = $config[$key];
$dbConfig[lcfirst(substr($key, 2))] = $config[$key];
}
// intval port number
@@ -1044,6 +1067,11 @@ function install_step_2_perform()
$dbConfig['port'] = intval($dbConfig['port']);
}
// bool ssl verify
if (isset($dbConfig['sslVerify'])) {
$dbConfig['sslVerify'] = $dbConfig['sslVerify'] == 'on' || !empty($dbConfig['sslCa']);
}
if (isset($dbConfig['file']) && preg_match("/^[a-z0-9]+\.[a-z0-9]{2,}$/i", $dbConfig['file'])) {
$dbConfig['file'] = __DIR__ . '/usr/' . $dbConfig['file'];
}
@@ -1059,7 +1087,12 @@ function install_step_2_perform()
$installDb->addServer($dbConfig, \Typecho\Db::READ | \Typecho\Db::WRITE);
$installDb->query('SELECT 1=1');
} catch (\Typecho\Db\Adapter\ConnectionException $e) {
install_raise_error(_t('对不起, 无法连接数据库, 请先检查数据库配置再继续进行安装'));
$code = $e->getCode();
if (('Mysql' == $type && 1049 == $code) || ('Pgsql' == $type && 7 == $code)) {
install_raise_error(_t('数据库: "%s"不存在,请手动创建后重试', $config['dbDatabase']));
} else {
install_raise_error(_t('对不起, 无法连接数据库, 请先检查数据库配置再继续进行安装: "%s"', $e->getMessage()));
}
} catch (\Typecho\Db\Exception $e) {
install_raise_error(_t('安装程序捕捉到以下错误: "%s". 程序被终止, 请检查您的配置信息.', $e->getMessage()));
}
@@ -1333,7 +1366,7 @@ function install_step_3_perform()
'url' => 'https://typecho.org',
'ip' => '127.0.0.1',
'agent' => $options->generator,
'text' => '欢迎加入 Typecho 大家族',
'text' => _t('欢迎加入 Typecho 大家族'),
'type' => 'comment',
'status' => 'approved',
'parent' => 0
@@ -1455,7 +1488,7 @@ function install_dispatch()
</head>
<body>
<div class="body container">
<h1><a href="http://typecho.org" target="_blank" class="i-logo">Typecho</a></h1>
<h1><a href="https://typecho.org" target="_blank" class="i-logo">Typecho</a></h1>
<?php $method(); ?>
</div>
</body>

View File

@@ -63,4 +63,22 @@
</select>
</li>
</ul>
</details>
<ul class="typecho-option">
<li>
<label class="typecho-label" for="dbSslCa"><?php _e('数据库 SSL 证书'); ?></label>
<input type="text" class="text" name="dbSslCa" id="dbSslCa"/>
<p class="description"><?php _e('如果您的数据库启用了 SSL请填写 CA 证书路径,否则请留空'); ?></p>
</li>
</ul>
<ul class="typecho-option">
<li>
<label class="typecho-label" for="dbSslVerify"><?php _e('启用数据库 SSL 服务端证书验证'); ?></label>
<select name="dbSslVerify" id="dbSslVerify">
<option value="off"><?php _e('不启用'); ?></option>
<option value="on"><?php _e('启用'); ?></option>
</select>
</li>
</ul>
</details>

View File

@@ -6,13 +6,6 @@
<p class="description"><?php _e('您可能会使用 "%s"', 'localhost'); ?></p>
</li>
</ul>
<ul class="typecho-option">
<li>
<label class="typecho-label" for="dbPort"><?php _e('数据库端口'); ?></label>
<input type="text" class="text" name="dbPort" id="dbPort" value="5432"/>
<p class="description"><?php _e('如果您不知道此选项的意义, 请保留默认设置'); ?></p>
</li>
</ul>
<ul class="typecho-option">
<li>
<label class="typecho-label" for="dbUser"><?php _e('数据库用户名'); ?></label>
@@ -34,4 +27,28 @@
</li
</ul>
<input type="hidden" name="dbCharset" value="utf8" />
<details>
<summary>
<strong><?php _e('高级选项'); ?></strong>
</summary>
<ul class="typecho-option">
<li>
<label class="typecho-label" for="dbPort"><?php _e('数据库端口'); ?></label>
<input type="text" class="text" name="dbPort" id="dbPort" value="5432"/>
<p class="description"><?php _e('如果您不知道此选项的意义, 请保留默认设置'); ?></p>
</li>
</ul>
<input type="hidden" name="dbCharset" value="utf8" />
<ul class="typecho-option">
<li>
<label class="typecho-label" for="dbSslVerify"><?php _e('启用数据库 SSL 服务端证书验证'); ?></label>
<select name="dbSslVerify" id="dbSslVerify">
<option value="off"><?php _e('不启用'); ?></option>
<option value="on"><?php _e('启用'); ?></option>
</select>
</li>
</ul>
</details>

View File

@@ -5,6 +5,7 @@ const sass = require('node-sass'),
UglifyJS = require("uglify-js"),
srcDir = __dirname + '/../admin/src',
distDir = __dirname + '/../admin',
themeDir = __dirname + '/../usr/themes/classic-22',
action = process.argv.pop();
let spriteImporter = SpriteMagicImporter({
@@ -29,16 +30,16 @@ let spriteImporter = SpriteMagicImporter({
}
});
function buildSass(file) {
let outFile = distDir + '/css/' + file.split('.')[0] + '.css',
sassDir = srcDir + '/scss';
function buildSass(file, dist, sassDir)
{
let outFile = dist + '/' + file.split('.')[0] + '.css';
console.log(color.green('processing ' + file));
sass.render({
file: sassDir + '/' + file,
outFile: outFile,
includePaths: [sassDir],
outputStyle: 'compact',
outputStyle: 'compressed',
importer: spriteImporter
}, function (error, result) {
if (error) {
@@ -51,17 +52,21 @@ function buildSass(file) {
});
}
function minifyJs(file) {
function minifyJs(file, dist)
{
console.log(color.green('minify ' + file));
let code = {};
code[file] = fs.readFileSync(srcDir + '/js/' + file).toString('utf8');
fs.writeFileSync(distDir + '/js/' + file,
UglifyJS.minify(code).code);
fs.writeFileSync(
dist + '/' + file,
UglifyJS.minify(code).code
);
}
function listFiles(dir, regExp) {
let files = fs.readdirSync(srcDir + dir), result = [];
function listFiles(dir, regExp)
{
let files = fs.readdirSync(dir), result = [];
files.map(function (file) {
if (file.match(regExp)) {
@@ -75,14 +80,20 @@ function listFiles(dir, regExp) {
if (action === 'css') {
console.log(color.blue('build css'));
listFiles('/scss', /^[a-z0-9-]+\.scss$/).forEach(function (file) {
buildSass(file);
listFiles(srcDir + '/scss', /^[a-z0-9-]+\.scss$/).forEach(function (file) {
buildSass(file, distDir + '/css', srcDir + '/scss');
});
} else if (action === 'js') {
console.log(color.blue('build js'));
listFiles('/js', /^[-\w]+\.js$/).forEach(function (file) {
minifyJs(file);
listFiles(srcDir + '/js', /^[-\w]+\.js$/).forEach(function (file) {
minifyJs(file, distDir + '/js');
});
} else if (action === 'theme_css') {
console.log(color.blue('build theme css'));
listFiles(themeDir + '/static/scss', /^[a-z0-9-]+\.scss$/).forEach(function (file) {
buildSass(file, themeDir + '/static/css', themeDir + '/static/scss');
});
} else {
console.log(color.red('Please choose correct action.'));

7286
tools/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -4,11 +4,12 @@
"description": "Typecho build tools",
"main": "build.js",
"engines": {
"node": "16.x"
"node": "16.x"
},
"scripts": {
"build_js": "node build.js js",
"build_css": "node build.js css"
"build_css": "node build.js css",
"build_css:theme": "node build.js theme_css"
},
"keywords": [
"typecho"
@@ -16,8 +17,9 @@
"author": "joyqi",
"license": "GPL-2.0-only",
"dependencies": {
"@picocss/pico": "^1.5.0",
"chalk": "^4.0.0",
"node-sass": "^6.0.1",
"node-sass": "^9.0.0",
"sprite-magic-importer": "^1.6.2",
"uglify-js": "^3.11.6"
}

View File

@@ -0,0 +1,19 @@
<?php if (!defined('__TYPECHO_ROOT_DIR__')) exit; ?>
<?php $this->need('header.php'); ?>
<main class="container">
<div class="container-thin">
<h1 class="text-center" style="font-size: 4rem; margin-bottom: 2rem">404</h1>
<ul style="margin-bottom: 2rem">
<li>当前页面无法访问,可能没权限或已删除。</li>
<li>The current page is not accessible, may not have permission or has been deleted.</li>
<li>La page actuelle n'est pas accessible, elle n'a peut-être pas de droits ou a été supprimée.</li>
<li>No se puede acceder a la página actual, puede que no tenga permiso o que haya sido eliminada.</li>
<li>Доступ к текущей странице невозможен, возможно, у нее нет разрешения или она была удалена.</li>
<li>現在のページにアクセスできない、権限がない、または削除された可能性があります。</li>
</ul>
<p class="text-center"><a href="<?php $this->options->siteUrl(); ?>" role="button" class="outline"><?php _e('回首页'); ?></a></p>
</div>
</main>
<?php $this->need('footer.php'); ?>

View File

@@ -0,0 +1,44 @@
<?php if (!defined('__TYPECHO_ROOT_DIR__')) exit; ?>
<div id="comments">
<?php $this->comments()->to($comments); ?>
<?php if ($comments->have()): ?>
<h2 class="text-center"><?php $this->commentsNum(_t('暂无评论'), _t('1 条评论'), _t('%d 条评论')); ?></h2>
<?php $comments->listComments(array(
'commentStatus' => _t('你的评论正等待审核'),
'avatarSize' => 64,
'defaultAvatar' => 'identicon'
)); ?>
<?php $comments->pageNav('&laquo; 前一页', '后一页 &raquo;'); ?>
<?php endif; ?>
<?php if ($this->allow('comment')): ?>
<div id="<?php $this->respondId(); ?>" class="respond">
<div class="cancel-comment-reply">
<?php $comments->cancelReply(); ?>
</div>
<h5 id="response"><?php _e('你的评论'); ?></h5>
<form method="post" action="<?php $this->commentUrl() ?>" id="comment-form" role="form">
<textarea placeholder="<?php _e('评论内容...'); ?>" rows="4" cols="50" name="text" id="textarea" required><?php $this->remember('text'); ?></textarea>
<?php if ($this->user->hasLogin()): ?>
<p>
<?php _e('登录身份:'); ?><a href="<?php $this->options->profileUrl(); ?>"><?php $this->user->screenName(); ?></a><span class="mx-2 text-muted">&middot;</span><a href="<?php $this->options->logoutUrl(); ?>"><?php _e('退出'); ?></a>
</p>
<?php else: ?>
<div class="grid">
<input type="text" placeholder="<?php _e('名字'); ?>" name="author" id="author" value="<?php $this->remember('author'); ?>" required/>
<input type="email" placeholder="<?php _e('Email'); ?>" name="mail" id="mail" value="<?php $this->remember('mail'); ?>"<?php if ($this->options->commentsRequireMail): ?> required<?php endif; ?> />
<input type="url" placeholder="<?php _e('网站 http://'); ?><?php if (!($this->options->commentsRequireUrl)): ?><?php _e('(选填)'); ?><?php endif; ?>" name="url" id="url" placeholder="<?php _e('https://'); ?>" value="<?php $this->remember('url'); ?>"<?php if ($this->options->commentsRequireUrl): ?> required<?php endif; ?> />
</div>
<?php endif; ?>
<button type="submit"><?php _e('提交评论'); ?></button>
</form>
</div>
<?php else: ?>
<div class="text-center text-muted"><?php _e('评论已关闭'); ?></div>
<?php endif; ?>
</div>

View File

@@ -0,0 +1,19 @@
<?php if (!defined('__TYPECHO_ROOT_DIR__')) exit; ?>
<footer class="site-footer container-fluid">
<div class="d-flex justify-content-between container-inner">
<ul class="list-inline text-muted">
<li>&copy; <?php echo date('Y'); ?> <a href="<?php $this->options->siteUrl(); ?>"><?php $this->options->title(); ?></a></li>
<li><a href="<?php $this->options->feedUrl(); ?>"><?php _e('RSS'); ?></a></li>
</ul>
<ul class="list-inline text-muted">
<li>
<?php _e('由 <a href="https://typecho.org">Typecho</a> 强力驱动'); ?>
</li>
</ul>
</div>
</footer>
<?php $this->footer(); ?>
</body>
</html>

View File

@@ -0,0 +1,49 @@
<?php
if (!defined('__TYPECHO_ROOT_DIR__')) exit;
function themeConfig($form)
{
$logoUrl = new \Typecho\Widget\Helper\Form\Element\Text(
'logoUrl',
null,
null,
_t('网站 Logo'),
_t('在这里填写图片 URL网站将显示 Logo')
);
$form->addInput($logoUrl->addRule('url', _t('请填写正确的 URL 地址')));
$themeStyle = new \Typecho\Widget\Helper\Form\Element\Radio(
'themeStyle',
array(
'auto' => _t('自动'),
'light' => _t('浅色'),
'dark' => _t('深色')
),
'auto',
_t('外观风格')
);
$form->addInput($themeStyle);
}
function postMeta(
\Widget\Archive $archive,
string $metaType = 'archive'
)
{
?>
<header class="entry-header text-center">
<h1 class="entry-title" itemprop="name headline">
<a href="<?php $archive->permalink() ?>" itemprop="url"><?php $archive->title() ?></a>
</h1>
<?php if ($metaType != 'page'): ?>
<ul class="entry-meta list-inline text-muted">
<li class="feather-calendar"><time datetime="<?php $archive->date('c'); ?>" itemprop="datePublished"><?php $archive->date(); ?></time></li>
<li class="feather-folder"><?php $archive->category(', '); ?></li>
<li class="feather-message"><a href="<?php $archive->permalink() ?>#comments" itemprop="discussionUrl"><?php $archive->commentsNum(_t('暂无评论'), _t('1 条评论'), _t('%d 条评论')); ?></a></li>
</ul>
<?php endif; ?>
</header>
<?php
}

View File

@@ -0,0 +1,60 @@
<?php if (!defined('__TYPECHO_ROOT_DIR__')) exit; ?>
<!DOCTYPE html>
<html lang="zh-Hans" data-theme="<?php $this->options->themeStyle(); ?>">
<head>
<meta charset="<?php $this->options->charset(); ?>">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?php $this->archiveTitle('', '', ' | '); ?><?php $this->options->title(); ?><?php if ($this->is('index')): ?> | <?php $this->options->description() ?><?php endif; ?></title>
<link rel="stylesheet" href="<?php $this->options->themeUrl('static/css/style.css'); ?>">
<?php $this->header(); ?>
</head>
<body>
<header class="site-navbar container-fluid">
<div class="container-inner">
<nav>
<ul class="site-name">
<?php if ($this->options->logoUrl): ?>
<li><a href="<?php $this->options->siteUrl(); ?>" class="brand"><img src="<?php $this->options->logoUrl() ?>" alt="<?php $this->options->title() ?>"></a></li>
<?php else: ?>
<li>
<a href="<?php $this->options->siteUrl(); ?>" class="brand"><?php $this->options->title() ?></a>
</li>
<li class="desc"><?php $this->options->description() ?></li>
<?php endif; ?>
</ul>
<ul>
<li>
<label for="nav-toggler" class="nav-toggler-btn"><img src="<?php $this->options->themeUrl('static/img/menu.svg'); ?>" alt="Menu"></label>
</li>
</ul>
</nav>
<nav class="site-nav">
<input type="checkbox" id="nav-toggler">
<ul class="nav-menu">
<li>
<a href="<?php $this->options->siteUrl(); ?>"<?php if ($this->is('index')): ?> class="active"<?php endif; ?>><?php _e('首页'); ?></a>
</li>
<?php \Widget\Contents\Page\Rows::alloc()->to($pages); ?>
<?php while ($pages->next()): ?>
<li>
<a href="<?php $pages->permalink(); ?>"<?php if ($this->is('page', $pages->slug)): ?> class="active"<?php endif; ?>><?php $pages->title(); ?></a>
</li>
<?php endwhile; ?>
<li>
<form method="post" action="<?php $this->options->siteUrl(); ?>">
<input type="search" id="s" name="s">
</form>
</li>
</ul>
</nav>
</div>
</header>

View File

@@ -0,0 +1,48 @@
<?php
/**
* Just another official theme
*
* @package Classic 22
* @author Typecho Team
* @version 1.0
* @link http://typecho.org
*/
if (!defined('__TYPECHO_ROOT_DIR__')) exit;
$this->need('header.php');
?>
<main class="container">
<div class="container-thin">
<?php if (!($this->is('index')) and !($this->is('post'))): ?>
<h4 class="text-center text-muted">
<?php $this->archiveTitle([
'category' => _t('分类 %s 下的文章'),
'search' => _t('包含关键字 %s 的文章'),
'tag' => _t('标签 %s 下的文章'),
'author' => _t('%s 发布的文章')
], '', ''); ?>
</h4>
<?php endif; ?>
<?php while ($this->next()): ?>
<article class="post" itemscope itemtype="http://schema.org/BlogPosting">
<?php postMeta($this); ?>
<div class="entry-content fmt" itemprop="articleBody">
<?php $this->content(_t('阅读全文')); ?>
</div>
</article>
<hr class="post-separator">
<?php endwhile; ?>
</div>
<!-- <div class="text-center">
<a href="#">&laquo; Older Posts</a>
<span class="mx-2 text-muted">&middot;</span>
<a href="#">Newer Posts &raquo;</a>
</div> -->
<?php $this->pageNav('← ' . _t('前一页'), _t('后一页') . ' →'); ?>
</main>
<?php $this->need('footer.php'); ?>

View File

@@ -0,0 +1,20 @@
<?php if (!defined('__TYPECHO_ROOT_DIR__')) exit; ?>
<?php $this->need('header.php'); ?>
<main class="container">
<div class="container-thin">
<article class="post" itemscope itemtype="http://schema.org/BlogPosting">
<?php postMeta($this, 'page'); ?>
<div class="entry-content fmt" itemprop="articleBody">
<?php $this->content(); ?>
</div>
</article>
<hr class="post-separator">
<?php $this->need('comments.php'); ?>
</div>
</main>
<?php $this->need('footer.php'); ?>

View File

@@ -0,0 +1,28 @@
<?php if (!defined('__TYPECHO_ROOT_DIR__')) exit; ?>
<?php $this->need('header.php'); ?>
<main class="container">
<div class="container-thin">
<article class="post" itemscope itemtype="http://schema.org/BlogPosting">
<?php postMeta($this, 'post'); ?>
<div class="entry-content fmt" itemprop="articleBody">
<?php $this->content(); ?>
<p itemprop="keywords"><?php _e('标签'); ?><?php $this->tags(', ', true, _t('无')); ?></p>
</div>
</article>
<div class="grid post-next">
<div>
← <?php $this->thePrev('%s', _t('没有了')); ?>
</div>
<div class="text-end">
<?php $this->theNext('%s', _t('没有了')); ?> →
</div>
</div>
<?php $this->need('comments.php'); ?>
</div>
</main>
<?php $this->need('footer.php'); ?>

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

View File

@@ -0,0 +1,42 @@
<?php if (!defined('__TYPECHO_ROOT_DIR__')) exit; ?>
<?php $this->need('header.php'); ?>
<main class="container">
<div class="container-thin">
<h1 class="text-center"><?php _e('搜索'); ?></h1>
<form method="post" action="<?php $this->options->siteUrl(); ?>">
<input type="search" id="s" name="s" placeholder="<?php _e('搜索关键字'); ?>" value="<?php $this->archiveTitle('','',''); ?>">
</form>
<div class="text-center">
<?php \Widget\Metas\Category\Rows::alloc()->listCategories('wrapClass=list-inline'); ?>
</div>
<hr class="post-separator">
<?php if ($this->have()): ?>
<?php while ($this->next()): ?>
<article class="post" itemscope itemtype="http://schema.org/BlogPosting">
<?php postMeta($this); ?>
<div class="entry-content fmt" itemprop="articleBody">
<?php $this->content('阅读全文'); ?>
</div>
</article>
<hr class="post-separator">
<?php endwhile; ?>
<?php else: ?>
<article class="post">
<div class="entry-content fmt text-center" itemprop="articleBody">
<p><?php _e('没有找到内容'); ?></p>
</div>
</article>
<?php endif; ?>
</div>
<?php $this->pageNav('&laquo; 前一页', '后一页 &raquo;'); ?>
</main>
<?php $this->need('footer.php'); ?>

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,16 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="#64748b"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<rect x="3" y="4" width="18" height="18" rx="2" ry="2" />
<line x1="16" y1="2" x2="16" y2="6" />
<line x1="8" y1="2" x2="8" y2="6" />
<line x1="3" y1="10" x2="21" y2="10" />
</svg>

After

Width:  |  Height:  |  Size: 385 B

View File

@@ -0,0 +1,13 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="#64748b"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z" />
</svg>

After

Width:  |  Height:  |  Size: 294 B

View File

@@ -0,0 +1,15 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="#fff"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<line x1="3" y1="12" x2="21" y2="12" />
<line x1="3" y1="6" x2="21" y2="6" />
<line x1="3" y1="18" x2="21" y2="18" />
</svg>

After

Width:  |  Height:  |  Size: 324 B

View File

@@ -0,0 +1,13 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="#64748b"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z" />
</svg>

After

Width:  |  Height:  |  Size: 403 B

View File

@@ -0,0 +1,14 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="#fff"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<circle cx="11" cy="11" r="8" />
<line x1="21" y1="21" x2="16.65" y2="16.65" />
</svg>

After

Width:  |  Height:  |  Size: 284 B

View File

@@ -0,0 +1,105 @@
/*!
* Pico.css (https://picocss.com)
* Licensed under MIT
*/
// Config
// $enable-responsive-typography: false;
// Grey
$grey-50: #f8fafc;
$grey-100: #f1f5f9;
$grey-200: #e2e8f0;
$grey-300: #cbd5e1;
$grey-400: #94a3b8;
$grey-500: #64748b;
$grey-600: #475569;
$grey-700: #334155;
$grey-800: #1e293b;
$grey-900: #0f172a;
// Blue
$primary-50: #E9F2FC;
$primary-100: #D1E5FB;
$primary-200: #9BCCFD;
$primary-300: #51B4FF;
$primary-400: #029AE8;
$primary-500: #017FC0;
$primary-600: #02659A;
$primary-700: #014C75;
$primary-800: #033452;
$primary-900: #061E2F;
// Amber
$amber-50: #fffbeb;
$amber-100: #fef3c7;
$amber-200: #fde68a;
$amber-300: #fcd34d;
$amber-400: #fbbf24;
$amber-500: #f59e0b;
$amber-600: #d97706;
$amber-700: #b45309;
$amber-800: #92400e;
$amber-900: #78350f;
// Green
$green-50: #f0fdf4;
$green-100: #dcfce7;
$green-200: #bbf7d0;
$green-300: #86efac;
$green-400: #4ade80;
$green-500: #22c55e;
$green-600: #16a34a;
$green-700: #15803d;
$green-800: #166534;
$green-900: #14532d;
// Red
$red-50: #fef2f2;
$red-100: #fee2e2;
$red-200: #fecaca;
$red-300: #fca5a5;
$red-400: #f87171;
$red-500: #ef4444;
$red-600: #dc2626;
$red-700: #b91c1c;
$red-800: #991b1b;
$red-900: #7f1d1d;
@import "../../../../../tools/node_modules/@picocss/pico/scss/variables";
// Theming
@import "../../../../../tools/node_modules/@picocss/pico/scss/themes/default";
// Layout
@import "../../../../../tools/node_modules/@picocss/pico/scss/layout/document"; // html
@import "../../../../../tools/node_modules/@picocss/pico/scss/layout/sectioning"; // body, header, main, footer
@import "../../../../../tools/node_modules/@picocss/pico/scss/layout/container"; // .container, .container-fluid
@import "../../../../../tools/node_modules/@picocss/pico/scss/layout/section"; // section
@import "../../../../../tools/node_modules/@picocss/pico/scss/layout/grid"; // .grid
// @import "../../../../../tools/node_modules/@picocss/pico/scss/layout/scroller"; // figure
// Content
@import "../../../../../tools/node_modules/@picocss/pico/scss/content/typography"; // a, headings, p, ul, blockquote, ...
@import "../../../../../tools/node_modules/@picocss/pico/scss/content/embedded"; // audio, canvas, iframe, img, svg, video
@import "../../../../../tools/node_modules/@picocss/pico/scss/content/button"; // button, a[role=button], type=button, type=submit ...
@import "../../../../../tools/node_modules/@picocss/pico/scss/content/form"; // input, select, textarea, label, fieldset, legend
// @import "../../../../../tools/node_modules/@picocss/pico/scss/content/form-checkbox-radio"; // type=checkbox, type=radio, role=switch
@import "../../../../../tools/node_modules/@picocss/pico/scss/content/form-alt-input-types"; // type=color, type=date, type=file, type=search, ...
@import "../../../../../tools/node_modules/@picocss/pico/scss/content/table"; // table, tr, td, ...
@import "../../../../../tools/node_modules/@picocss/pico/scss/content/code"; // pre, code, ...
@import "../../../../../tools/node_modules/@picocss/pico/scss/content/miscs"; // hr, template, [hidden], dialog, canvas
// Components
// @import "../../../../../tools/node_modules/@picocss/pico/scss/components/accordion"; // details, summary
// @import "../../../../../tools/node_modules/@picocss/pico/scss/components/card"; // article
// @import "../../../../../tools/node_modules/@picocss/pico/scss/components/modal"; // dialog
@import "../../../../../tools/node_modules/@picocss/pico/scss/components/nav"; // nav
// @import "../../../../../tools/node_modules/@picocss/pico/scss/components/progress"; // progress
// @import "../../../../../tools/node_modules/@picocss/pico/scss/components/dropdown"; // dropdown
// Utilities
// @import "../../../../../tools/node_modules/@picocss/pico/scss/utilities/loading"; // aria-busy=true
// @import "../../../../../tools/node_modules/@picocss/pico/scss/utilities/tooltip"; // data-tooltip
@import "../../../../../tools/node_modules/@picocss/pico/scss/utilities/accessibility"; // -ms-touch-action, aria-*
@import "../../../../../tools/node_modules/@picocss/pico/scss/utilities/reduce-motion"; // prefers-reduced-motion

View File

@@ -0,0 +1,425 @@
@import "pico";
// Global Set
:root {
--border-radius: .5rem;
}
body {
cursor: auto;
}
// Theme
[data-theme="light"],
:root:not([data-theme="dark"]) {
--primary: #{$primary-500};
--primary-hover: #{$primary-600};
--muted-border-color: #{$grey-200};
}
[data-theme="dark"] {
--primary: #{$primary-500};
--primary-hover: #{$primary-400};
--muted-border-color: #{$grey-800};
.site-navbar {
background-color: #{$primary-600};
}
.comment-level-odd {
background-color: #{$grey-900};
}
}
// Content
h1, h2, h3, h4, h5 { line-height: 1.25; }
// h1 { --font-size: 2.5rem; }
// h2 { --font-size: 2rem; }
// h3 { --font-size: 1.75rem; }
// h4 { --font-size: 1.5rem; }
// h5 { --font-size: 1.25rem; }
// Icon Size
.is-sm {
width: 1.25em;
height: 1.25em;
}
// Utilities
.text-muted,
.text-muted a {
color: var(--muted-color);
}
.text-muted a:hover {
color: var(--secondary-hover);
}
.text-center {
text-align: center;
}
.text-end {
text-align: right;
}
.ms-2 {
margin-left: calc(var(--spacing) / 2);
}
.me-2 {
margin-right: calc(var(--spacing) / 2);
}
.mx-2 {
margin-left: calc(var(--spacing) / 2);
margin-right: calc(var(--spacing) / 2);
}
.list-inline {
padding-left: 0;
list-style: none;
margin-bottom: 0;
li {
display: inline-block;
margin-bottom: 0;
&:not(:last-child) { margin-right: var(--spacing); }
}
svg { vertical-align: text-bottom; }
}
// Layout
.container-inner {
@if map-get($breakpoints, "lg") {
@media (min-width: map-get($breakpoints, "lg")) {
padding-left: calc(var(--spacing) / 2);
padding-right: calc(var(--spacing) / 2);
}
}
}
.container-thin {
margin-left: auto;
margin-right: auto;
max-width: 40rem;
}
.d-flex {
display: flex;
}
.align-items-center {
align-items: center;
}
.justify-content-between {
justify-content: space-between;
}
.justify-content-end {
justify-content: end;
}
.align-self-center {
align-self: center;
}
// Header & Navbar
.site-navbar {
padding-top: .25rem;
padding-bottom: .25rem;
background-color: var(--primary);
a {
color: var(--primary-inverse);
// color: rgba(255, 255, 255);
// &:hover { text-decoration: underline; }
}
.site-name {
flex-grow: 1;
}
.brand {
font-size: 1.25rem;
font-weight: 700;
}
.desc {
color: rgba(255, 255, 255, .5);
display: none;
@if map-get($breakpoints, "sm") {
@media (min-width: map-get($breakpoints, "sm")) {
display: inline-block;
}
}
}
}
.site-nav {
display: block;
}
#nav-toggler {
display: none;
&:checked ~ .nav-menu {
display: block;
}
}
// Dropdown Menu
.nav-menu {
display: none;
li {
display: block;
padding: calc(var(--spacing) * .5);
}
form {
margin-bottom: 0;
input[type=search] {
height: 50px;
background-image: url("../img/search.svg");
background-size: auto;
background-color: inherit;
color: var(--primary-inverse);
&:focus {
--form-element-focus-color: rgba(255, 255, 255, .5);
}
&:not(:focus) {
padding: 0;
border: none;
width: 30px;
padding-inline-start: 0;
background-position: center center;
cursor: pointer;
}
}
}
}
.nav-toggler-btn {
margin: calc(var(--spacing) * -1) calc(var(--spacing) * -0.5);
padding: var(--spacing) calc(var(--spacing) * 0.5);
color: rgba(255, 255, 255, 1.0);
cursor: pointer;
}
@if map-get($breakpoints, "lg") {
@media (min-width: map-get($breakpoints, "lg")) {
.site-navbar .container-inner,
.site-nav { display: flex; }
.site-navbar .container-inner nav:first-child { flex-grow: 1; }
.nav-toggler-btn { display: none; }
.nav-menu {
display: flex !important;
li:not(:last-child) { margin-right: calc(var(--spacing) / 2); }
}
}
}
// Posts
.post-separator {
margin: var(--block-spacing-vertical) 0;
}
.entry-header {
margin-bottom: calc(var(--spacing) * 2);
}
.entry-title {
margin-bottom: var(--spacing);
a { color: var(--h1-color); }
}
.entry-meta {
font-size: .875rem;
}
.feather-calendar::before,
.feather-folder::before,
.feather-message::before {
content: "";
display: inline-block;
margin-right: .25rem;
background: url("../img/calendar.svg") no-repeat center center / contain;
width: 1rem;
height: 1rem;
vertical-align: text-top;
fill: #396;
}
.feather-folder::before {
background-image: url("../img/folder.svg");
}
.feather-message::before {
background-image: url("../img/message-circle.svg");
}
.entry-content .more {
text-align: center;
a {
display: inline-block;
font-size: .875rem;
padding: 6px 16px;
border: 1px solid var(--muted-border-color);
color: var(--muted-color);
border-radius: 100px;
text-decoration: none;
}
}
.post-next {
border-top: 1px solid var(--muted-border-color);
padding-top: calc(var(--spacing) * 1.5);
margin: var(--block-spacing-vertical) 0;
a {
color: var(--h5-color);
}
}
// Format
.fmt {
line-height: 1.6;
pre, hr {
margin-bottom: var(--typography-spacing-vertical);
}
}
// Footer
.site-footer {
padding-bottom: calc(var(--block-spacing-vertical) / 2);
}
// Comments
.comment-list {
list-style: none;
padding: 0;
// padding-left: calc(var(--spacing) * 4);
}
.comment-level-odd {
background-color: #{$grey-50};
}
.comment-level-even {
background-color: var(--background-color);
}
.comment-body {
margin: calc(var(--spacing) * 1.5) 0;
padding: var(--spacing);
border: 1px solid var(--muted-border-color);
border-radius: var(--border-radius);
}
.comment-by-author > .comment-author::after {
content: "OP";
margin-left: .25rem;
color: var(--muted-color);
padding: 0 .375rem;
border: 1px solid var(--muted-color);
font-size: .75rem;
border-radius: var(--border-radius);
}
.comment-author {
display: inline-block;
.avatar {
margin-right: .25rem;
width: calc(var(--spacing) * 2);
border-radius: 48px;
}
cite {
font-style: normal;
font-weight: 700;
}
}
.comment-meta a,
.comment-reply a {
font-size: .875em;
color: var(--muted-color);
&:hover { color: var(--secondary-hover); }
}
.comment-meta {
display: inline-block;
color: var(--muted-color);
margin-left: calc(var(--spacing) / 4);
&::before {
content: "·";
margin-right: calc(var(--spacing) / 4);
}
}
.comment-content {
margin-top: var(--spacing);
}
.comment-reply:blank {
margin-top: 0;
}
.comment-awaiting-moderation {
margin-left: calc(var(--spacing) / 2);
font-size: .875em;
color: var(--del-color);
}
.comment-children {
margin-bottom: calc(var(--spacing) * -1);
}
.comment-by-author {
// background-color: var(--mark-background-color);
}
#response {
margin-bottom: var(--spacing);
}
#cancel-comment-reply-link {
font-size: .875em;
color: var(--del-color);
}
.comment-body .respond {
margin-top: var(--spacing);
}
#comment-form textarea {
resize: vertical;
}
// page nav
.page-navigator {
list-style: none;
padding: 0;
text-align: center;
li {
display: inline;
margin-left: calc(var(--spacing) / 2);
margin-right: calc(var(--spacing) / 2);
&.current a {
font-weight: 700;
color: var(--h5-color);
}
}
}

View File

@@ -1,45 +0,0 @@
<?php if (!defined('__TYPECHO_ROOT_DIR__')) exit; ?>
<?php $this->need('header.php'); ?>
<div class="col-mb-12 col-8" id="main" role="main">
<h3 class="archive-title"><?php $this->archiveTitle([
'category' => _t('分类 %s 下的文章'),
'search' => _t('包含关键字 %s 的文章'),
'tag' => _t('标签 %s 下的文章'),
'author' => _t('%s 发布的文章')
], '', ''); ?></h3>
<?php if ($this->have()): ?>
<?php while ($this->next()): ?>
<article class="post" itemscope itemtype="http://schema.org/BlogPosting">
<h2 class="post-title" itemprop="name headline"><a itemprop="url"
href="<?php $this->permalink() ?>"><?php $this->title() ?></a>
</h2>
<ul class="post-meta">
<li itemprop="author" itemscope itemtype="http://schema.org/Person"><?php _e('作者: '); ?><a
itemprop="name" href="<?php $this->author->permalink(); ?>"
rel="author"><?php $this->author(); ?></a></li>
<li><?php _e('时间: '); ?>
<time datetime="<?php $this->date('c'); ?>"
itemprop="datePublished"><?php $this->date(); ?></time>
</li>
<li><?php _e('分类: '); ?><?php $this->category(','); ?></li>
<li itemprop="interactionCount"><a
href="<?php $this->permalink() ?>#comments"><?php $this->commentsNum('评论', '1 条评论', '%d 条评论'); ?></a>
</li>
</ul>
<div class="post-content" itemprop="articleBody">
<?php $this->content('- 阅读剩余部分 -'); ?>
</div>
</article>
<?php endwhile; ?>
<?php else: ?>
<article class="post">
<h2 class="post-title"><?php _e('没有找到内容'); ?></h2>
</article>
<?php endif; ?>
<?php $this->pageNav('&laquo; 前一页', '后一页 &raquo;'); ?>
</div><!-- end #main -->
<?php $this->need('sidebar.php'); ?>
<?php $this->need('footer.php'); ?>

View File

@@ -6,7 +6,7 @@
<?php $comments->listComments(); ?>
<?php $comments->pageNav('&laquo; 前一页', '后一页 &raquo;'); ?>
<?php $comments->pageNav(); ?>
<?php endif; ?>
@@ -19,7 +19,7 @@
<h3 id="response"><?php _e('添加新评论'); ?></h3>
<form method="post" action="<?php $this->commentUrl() ?>" id="comment-form" role="form">
<?php if ($this->user->hasLogin()): ?>
<p><?php _e('登录身份: '); ?><a
<p><?php _e('登录身份'); ?>: <a
href="<?php $this->options->profileUrl(); ?>"><?php $this->user->screenName(); ?></a>. <a
href="<?php $this->options->logoutUrl(); ?>" title="Logout"><?php _e('退出'); ?> &raquo;</a>
</p>
@@ -37,9 +37,9 @@
</p>
<p>
<label
for="url"<?php if ($this->options->commentsRequireURL): ?> class="required"<?php endif; ?>><?php _e('网站'); ?></label>
for="url"<?php if ($this->options->commentsRequireUrl): ?> class="required"<?php endif; ?>><?php _e('网站'); ?></label>
<input type="url" name="url" id="url" class="text" placeholder="<?php _e('http://'); ?>"
value="<?php $this->remember('url'); ?>"<?php if ($this->options->commentsRequireURL): ?> required<?php endif; ?> />
value="<?php $this->remember('url'); ?>"<?php if ($this->options->commentsRequireUrl): ?> required<?php endif; ?> />
</p>
<?php endif; ?>
<p>

View File

@@ -6,7 +6,7 @@
<footer id="footer" role="contentinfo">
&copy; <?php echo date('Y'); ?> <a href="<?php $this->options->siteUrl(); ?>"><?php $this->options->title(); ?></a>.
<?php _e('由 <a href="http://www.typecho.org">Typecho</a> 强力驱动'); ?>.
<?php _e('由 <a href="https://typecho.org">Typecho</a> 强力驱动'); ?>.
</footer><!-- end #footer -->
<?php $this->footer(); ?>

View File

@@ -11,7 +11,7 @@ function themeConfig($form)
_t('在这里填入一个图片 URL 地址, 以在网站标题前加上一个 LOGO')
);
$form->addInput($logoUrl);
$form->addInput($logoUrl->addRule('url', _t('请填写一个合法的URL地址')));
$sidebarBlock = new \Typecho\Widget\Helper\Form\Element\Checkbox(
'sidebarBlock',
@@ -29,6 +29,39 @@ function themeConfig($form)
$form->addInput($sidebarBlock->multiMode());
}
function postMeta(
\Widget\Archive $archive,
string $metaType = 'archive'
)
{
$titleTag = $metaType == 'archive' ? 'h2' : 'h1';
?>
<<?php echo $titleTag ?> class="post-title" itemprop="name headline">
<a itemprop="url"
href="<?php $archive->permalink() ?>"><?php $archive->title() ?></a>
</<?php echo $titleTag ?>>
<?php if ($metaType != 'page'): ?>
<ul class="post-meta">
<li itemprop="author" itemscope itemtype="http://schema.org/Person">
<?php _e('作者'); ?>: <a itemprop="name"
href="<?php $archive->author->permalink(); ?>"
rel="author"><?php $archive->author(); ?></a>
</li>
<li><?php _e('时间'); ?>:
<time datetime="<?php $archive->date('c'); ?>" itemprop="datePublished"><?php $archive->date(); ?></time>
</li>
<li><?php _e('分类'); ?>: <?php $archive->category(','); ?></li>
<?php if ($metaType == 'archive'): ?>
<li itemprop="interactionCount">
<a itemprop="discussionUrl"
href="<?php $archive->permalink() ?>#comments"><?php $archive->commentsNum('评论', '1 条评论', '%d 条评论'); ?></a>
</li>
<?php endif; ?>
</ul>
<?php endif; ?>
<?php
}
/*
function themeFields($layout)
{

View File

@@ -13,32 +13,30 @@ $this->need('header.php');
?>
<div class="col-mb-12 col-8" id="main" role="main">
<?php if (!($this->is('index')) and !($this->is('post'))): ?>
<h3 class="archive-title"><?php $this->archiveTitle([
'category' => _t('分类 %s 下的文章'),
'search' => _t('包含关键字 %s 的文章'),
'tag' => _t('标签 %s 下的文章'),
'author' => _t('%s 发布的文章')
], '', ''); ?></h3>
<?php endif; ?>
<?php if ($this->have()): ?>
<?php while ($this->next()): ?>
<article class="post" itemscope itemtype="http://schema.org/BlogPosting">
<h2 class="post-title" itemprop="name headline">
<a itemprop="url"
href="<?php $this->permalink() ?>"><?php $this->title() ?></a>
</h2>
<ul class="post-meta">
<li itemprop="author" itemscope itemtype="http://schema.org/Person"><?php _e('作者: '); ?><a
itemprop="name" href="<?php $this->author->permalink(); ?>"
rel="author"><?php $this->author(); ?></a></li>
<li><?php _e('时间: '); ?>
<time datetime="<?php $this->date('c'); ?>" itemprop="datePublished"><?php $this->date(); ?></time>
</li>
<li><?php _e('分类: '); ?><?php $this->category(','); ?></li>
<li itemprop="interactionCount">
<a itemprop="discussionUrl"
href="<?php $this->permalink() ?>#comments"><?php $this->commentsNum('评论', '1 条评论', '%d 条评论'); ?></a>
</li>
</ul>
<?php postMeta($this); ?>
<div class="post-content" itemprop="articleBody">
<?php $this->content('- 阅读剩余部分 -'); ?>
<?php $this->content(_t('阅读剩余部分')); ?>
</div>
</article>
<?php endwhile; ?>
<?php else: ?>
<article class="post">
<h2 class="post-title"><?php _e('没有找到内容'); ?></h2>
</article>
<?php endif; ?>
<?php $this->pageNav('&laquo; 前一页', '后一页 &raquo;'); ?>
<?php $this->pageNav('&laquo; ' . _t('前一页'), _t('后一页') . ' &raquo;'); ?>
</div><!-- end #main-->
<?php $this->need('sidebar.php'); ?>

View File

@@ -3,10 +3,7 @@
<div class="col-mb-12 col-8" id="main" role="main">
<article class="post" itemscope itemtype="http://schema.org/BlogPosting">
<h1 class="post-title" itemprop="name headline">
<a itemprop="url"
href="<?php $this->permalink() ?>"><?php $this->title() ?></a>
</h1>
<?php postMeta($this, 'page'); ?>
<div class="post-content" itemprop="articleBody">
<?php $this->content(); ?>
</div>

View File

@@ -3,32 +3,18 @@
<div class="col-mb-12 col-8" id="main" role="main">
<article class="post" itemscope itemtype="http://schema.org/BlogPosting">
<h1 class="post-title" itemprop="name headline">
<a itemprop="url"
href="<?php $this->permalink() ?>"><?php $this->title() ?></a>
</h1>
<ul class="post-meta">
<li itemprop="author" itemscope itemtype="http://schema.org/Person">
<?php _e('作者: '); ?><a itemprop="name"
href="<?php $this->author->permalink(); ?>"
rel="author"><?php $this->author(); ?></a>
</li>
<li><?php _e('时间: '); ?>
<time datetime="<?php $this->date('c'); ?>" itemprop="datePublished"><?php $this->date(); ?></time>
</li>
<li><?php _e('分类: '); ?><?php $this->category(','); ?></li>
</ul>
<?php postMeta($this, 'post'); ?>
<div class="post-content" itemprop="articleBody">
<?php $this->content(); ?>
</div>
<p itemprop="keywords" class="tags"><?php _e('标签: '); ?><?php $this->tags(', ', true, 'none'); ?></p>
<p itemprop="keywords" class="tags"><?php _e('标签'); ?>: <?php $this->tags(', ', true, 'none'); ?></p>
</article>
<?php $this->need('comments.php'); ?>
<ul class="post-near">
<li>上一篇: <?php $this->thePrev('%s', '没有了'); ?></li>
<li>下一篇: <?php $this->theNext('%s', '没有了'); ?></li>
<li>上一篇: <?php $this->thePrev('%s', _t('没有了')); ?></li>
<li>下一篇: <?php $this->theNext('%s', _t('没有了')); ?></li>
</ul>
</div><!-- end #main-->

View File

@@ -55,7 +55,7 @@
<?php endif; ?>
<li><a href="<?php $this->options->feedUrl(); ?>"><?php _e('文章 RSS'); ?></a></li>
<li><a href="<?php $this->options->commentsFeedUrl(); ?>"><?php _e('评论 RSS'); ?></a></li>
<li><a href="http://www.typecho.org">Typecho</a></li>
<li><a href="https://typecho.org">Typecho</a></li>
</ul>
</section>
<?php endif; ?>

View File

@@ -14,7 +14,7 @@ class Base64
*
* @var string
*/
private $data;
private string $data;
/**
* 初始化数据

View File

@@ -20,33 +20,33 @@ class Client
*
* @var string
*/
private $url;
private string $url;
/**
* 消息体
*
* @var Message
*/
private $message;
private Message $message;
/**
* 调试开关
*
* @var boolean
*/
private $debug = false;
private bool $debug = false;
/**
* 请求前缀
*
* @var string|null
*/
private $prefix;
private ?string $prefix;
/**
* @var Error
*/
private $error;
private Error $error;
/**
* 客户端构造函数

View File

@@ -9,17 +9,17 @@ namespace IXR;
*/
class Date
{
private $year;
private int $year;
private $month;
private int $month;
private $day;
private int $day;
private $hour;
private int $hour;
private $minute;
private int $minute;
private $second;
private int $second;
/**
* @param int|string $time
@@ -39,12 +39,12 @@ class Date
*/
private function parseTimestamp(int $timestamp)
{
$this->year = date('Y', $timestamp);
$this->month = date('m', $timestamp);
$this->day = date('d', $timestamp);
$this->hour = date('H', $timestamp);
$this->minute = date('i', $timestamp);
$this->second = date('s', $timestamp);
$this->year = intval(date('Y', $timestamp));
$this->month = intval(date('m', $timestamp));
$this->day = intval(date('d', $timestamp));
$this->hour = intval(date('H', $timestamp));
$this->minute = intval(date('i', $timestamp));
$this->second = intval(date('s', $timestamp));
}
/**

View File

@@ -15,7 +15,7 @@ class Error
* @access public
* @var integer
*/
public $code;
public int $code;
/**
* 错误消息
@@ -23,7 +23,7 @@ class Error
* @access public
* @var string|null
*/
public $message;
public ?string $message;
/**
* 构造函数

View File

@@ -12,35 +12,35 @@ class Message
/**
* @var string
*/
public $message;
public string $message;
/**
* @var string
*/
public $messageType; // methodCall / methodResponse / fault
public string $messageType; // methodCall / methodResponse / fault
public $faultCode;
public int $faultCode;
public $faultString;
public string $faultString;
/**
* @var string
*/
public $methodName;
public string $methodName;
/**
* @var array
*/
public $params = [];
public array $params = [];
// Current variable stacks
private $arrayStructs = []; // The stack used to keep track of the current array/struct
private array $arrayStructs = []; // The stack used to keep track of the current array/struct
private $arrayStructsTypes = []; // Stack keeping track of if things are structs or array
private array $arrayStructsTypes = []; // Stack keeping track of if things are structs or array
private $currentStructName = []; // A stack as well
private array $currentStructName = []; // A stack as well
private $currentTagContents;
private string $currentTagContents;
/**
* @param string $message
@@ -76,7 +76,7 @@ class Message
xml_parser_free($parser);
// Grab the error messages, if any
if ($this->messageType == 'fault') {
$this->faultCode = $this->params[0]['faultCode'];
$this->faultCode = intval($this->params[0]['faultCode']);
$this->faultString = $this->params[0]['faultString'];
}
return true;
@@ -84,7 +84,7 @@ class Message
/**
* @param $parser
* @param $tag
* @param string $tag
* @param $attr
*/
private function tagOpen($parser, string $tag, $attr)
@@ -133,7 +133,7 @@ class Message
$this->currentTagContents = '';
break;
case 'string':
$value = (string)trim($this->currentTagContents);
$value = trim($this->currentTagContents);
$this->currentTagContents = '';
break;
case 'dateTime.iso8601':
@@ -144,7 +144,7 @@ class Message
case 'value':
// "If no type is indicated, the type is string."
if (trim($this->currentTagContents) != '') {
$value = (string) $this->currentTagContents;
$value = $this->currentTagContents;
$this->currentTagContents = '';
}
break;

View File

@@ -14,12 +14,12 @@ class Pingback
/**
* @var string
*/
private $html;
private string $html;
/**
* @var string
*/
private $target;
private string $target;
/**
* @param string $url
@@ -73,7 +73,7 @@ class Pingback
*/
public function getTitle(): string
{
if (preg_match("/\<title\>([^<]*?)\<\/title\\>/is", $this->html, $matchTitle)) {
if (preg_match("/<title>([^<]*?)<\/title>/is", $this->html, $matchTitle)) {
return Common::subStr(Common::removeXSS(trim(strip_tags($matchTitle[1]))), 0, 150, '...');
}

View File

@@ -12,7 +12,7 @@ class Request
/**
* @var string
*/
private $xml;
private string $xml;
/**
* @param string $method

View File

@@ -16,19 +16,19 @@ class Server
*
* @var array
*/
private $callbacks;
private array $callbacks;
/**
* 默认参数
*
* @var array
*/
private $capabilities;
private array $capabilities;
/**
* @var Hook
*/
private $hook;
private Hook $hook;
/**
* 构造函数
@@ -248,9 +248,9 @@ class Server
*
* @access private
* @param string $method 方法名
* @return mixed
* @return bool
*/
private function hasMethod(string $method)
private function hasMethod(string $method): bool
{
return in_array($method, array_keys($this->callbacks));
}

View File

@@ -11,13 +11,13 @@ class Value
{
private $data;
private $type;
private ?string $type;
/**
* @param mixed $data
* @param bool|string $type
* @param string|null $type
*/
public function __construct($data, $type = false)
public function __construct($data, ?string $type)
{
$this->data = $data;
if (!$type) {

Some files were not shown because too many files have changed in this diff Show More