diff --git a/404.php b/404.php index 75e9215..e786e83 100644 --- a/404.php +++ b/404.php @@ -9,7 +9,7 @@ get_header(); ?>
- Report Bug + Report Bug · - Request Feature + Request Feature
WordPress theme that focus on reading experience
@@ -44,4 +44,4 @@ We welcome all contributions. You can submit any ideas as pull requests or as is ## 📃 License -The project is released under the GNU General Public License v3.0, see the [LICENCE](https://github.com/seatonjiang/kratos/blob/main/LICENSE) file for details. +The project is released under the GNU General Public License v3.0, see the [LICENCE](https://github.com/devhaozi/kratos/blob/main/LICENSE) file for details. diff --git a/README.zh-CN.md b/README.zh-CN.md index 5bf231a..8e53184 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -7,21 +7,21 @@专注阅读体验的 WordPress 主题
@@ -44,4 +44,4 @@ ## 📃 开源许可 -项目基于 GNU 通用公共许可证 v3.0 发布,详细说明请参阅 [LICENCE](https://github.com/seatonjiang/kratos/blob/main/LICENSE) 文件。 +项目基于 GNU 通用公共许可证 v3.0 发布,详细说明请参阅 [LICENCE](https://github.com/devhaozi/kratos/blob/main/LICENSE) 文件。 diff --git a/assets/css/loader.css b/assets/css/loader.css new file mode 100644 index 0000000..acc1d3f --- /dev/null +++ b/assets/css/loader.css @@ -0,0 +1,236 @@ +@charset "utf-8"; +/* +Loader CSS +By:耗子 +*/ +body .loader { + position: fixed; + top: 0; + left: 0; + z-index: 99999; + display: none; + width: 100%; + height: 100%; + background-color: rgba(255, 255, 255, .2); + text-align: center; + font-size: 2em +} +body .loader_overlay { + width: 150px; + height: 150px; + background: transparent; + box-shadow: 0px 0px 0px 1000px rgba(255, 255, 255, 0.67), 0px 0px 19px 0px rgba(0, 0, 0, 0.16) inset; + border-radius: 100%; + z-index: -1; + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; + margin: auto; +} +body .loader_cogs { + z-index: -2; + width: 100px; + height: 100px; + top: -120px !important; + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; + margin: auto; +} +body .loader_cogs__top { + position: relative; + width: 100px; + height: 100px; + -webkit-transform-origin: 50px 50px; + transform-origin: 50px 50px; + -webkit-animation: rotate 10s infinite linear; + animation: rotate 10s infinite linear; +} +body .loader_cogs__top div:nth-of-type(1) { + -webkit-transform: rotate(30deg); + transform: rotate(30deg); +} +body .loader_cogs__top div:nth-of-type(2) { + -webkit-transform: rotate(60deg); + transform: rotate(60deg); +} +body .loader_cogs__top div:nth-of-type(3) { + -webkit-transform: rotate(90deg); + transform: rotate(90deg); +} +body .loader_cogs__top div.top_part { + width: 100px; + border-radius: 10px; + position: absolute; + height: 100px; + background: #f98db9; +} +body .loader_cogs__top div.top_hole { + width: 50px; + height: 50px; + border-radius: 100%; + background: white; + position: absolute; + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; + margin: auto; +} +body .loader_cogs__left { + position: relative; + width: 80px; + -webkit-transform: rotate(16deg); + transform: rotate(16deg); + top: 28px; + -webkit-transform-origin: 40px 40px; + transform-origin: 40px 40px; + -webkit-animation: rotate_left 10s .1s infinite reverse linear; + animation: rotate_left 10s .1s infinite reverse linear; + left: -24px; + height: 80px; +} +body .loader_cogs__left div:nth-of-type(1) { + -webkit-transform: rotate(30deg); + transform: rotate(30deg); +} +body .loader_cogs__left div:nth-of-type(2) { + -webkit-transform: rotate(60deg); + transform: rotate(60deg); +} +body .loader_cogs__left div:nth-of-type(3) { + -webkit-transform: rotate(90deg); + transform: rotate(90deg); +} +body .loader_cogs__left div.left_part { + width: 80px; + border-radius: 6px; + position: absolute; + height: 80px; + background: #97ddff; +} +body .loader_cogs__left div.left_hole { + width: 40px; + height: 40px; + border-radius: 100%; + background: white; + position: absolute; + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; + margin: auto; +} +body .loader_cogs__bottom { + position: relative; + width: 60px; + top: -65px; + -webkit-transform-origin: 30px 30px; + transform-origin: 30px 30px; + -webkit-animation: rotate_left 10.2s .4s infinite linear; + animation: rotate_left 10.2s .4s infinite linear; + -webkit-transform: rotate(4deg); + transform: rotate(4deg); + left: 79px; + height: 60px; +} +body .loader_cogs__bottom div:nth-of-type(1) { + -webkit-transform: rotate(30deg); + transform: rotate(30deg); +} +body .loader_cogs__bottom div:nth-of-type(2) { + -webkit-transform: rotate(60deg); + transform: rotate(60deg); +} +body .loader_cogs__bottom div:nth-of-type(3) { + -webkit-transform: rotate(90deg); + transform: rotate(90deg); +} +body .loader_cogs__bottom div.bottom_part { + width: 60px; + border-radius: 5px; + position: absolute; + height: 60px; + background: #ffcd66; +} +body .loader_cogs__bottom div.bottom_hole { + width: 30px; + height: 30px; + border-radius: 100%; + background: white; + position: absolute; + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; + margin: auto; +} + +/* Animations */ +@-webkit-keyframes rotate { + from { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + to { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@keyframes rotate { + from { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + to { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-webkit-keyframes rotate_left { + from { + -webkit-transform: rotate(16deg); + transform: rotate(16deg); + } + to { + -webkit-transform: rotate(376deg); + transform: rotate(376deg); + } +} +@keyframes rotate_left { + from { + -webkit-transform: rotate(16deg); + transform: rotate(16deg); + } + to { + -webkit-transform: rotate(376deg); + transform: rotate(376deg); + } +} +@-webkit-keyframes rotate_right { + from { + -webkit-transform: rotate(4deg); + transform: rotate(4deg); + } + to { + -webkit-transform: rotate(364deg); + transform: rotate(364deg); + } +} +@keyframes rotate_right { + from { + -webkit-transform: rotate(4deg); + transform: rotate(4deg); + } + to { + -webkit-transform: rotate(364deg); + transform: rotate(364deg); + } +} diff --git a/assets/js/kratos.js b/assets/js/kratos.js index c70de31..748cb54 100644 --- a/assets/js/kratos.js +++ b/assets/js/kratos.js @@ -150,9 +150,9 @@ var consoleConfig = function () { console.log( - "\n Kratos v" + + "\n Kratos Pjax Edition v" + KRATOS_VERSION + - "\n\n https://github.com/seatonjiang/kratos \n\n" + "\n\n https://github.com/devhaozi/kratos \n\n" ); }; diff --git a/assets/js/pjax.js b/assets/js/pjax.js new file mode 100644 index 0000000..1e6b6de --- /dev/null +++ b/assets/js/pjax.js @@ -0,0 +1,929 @@ +/*! + * Copyright 2012, Chris Wanstrath + * Released under the MIT License + * https://github.com/defunkt/jquery-pjax + */ + +(function($){ + + // When called on a container with a selector, fetches the href with + // ajax into the container or with the data-pjax attribute on the link + // itself. + // + // Tries to make sure the back button and ctrl+click work the way + // you'd expect. + // + // Exported as $.fn.pjax + // + // Accepts a jQuery ajax options object that may include these + // pjax specific options: + // + // + // container - Where to stick the response body. Usually a String selector. + // $(container).html(xhr.responseBody) + // (default: current jquery context) + // push - Whether to pushState the URL. Defaults to true (of course). + // replace - Want to use replaceState instead? That's cool. + // + // For convenience the second parameter can be either the container or + // the options object. + // + // Returns the jQuery object + function fnPjax(selector, container, options) { + var context = this + return this.on('click.pjax', selector, function(event) { + var opts = $.extend({}, optionsFor(container, options)) + if (!opts.container) + opts.container = $(this).attr('data-pjax') || context + handleClick(event, opts) + }) + } + + // Public: pjax on click handler + // + // Exported as $.pjax.click. + // + // event - "click" jQuery.Event + // options - pjax options + // + // Examples + // + // $(document).on('click', 'a', $.pjax.click) + // // is the same as + // $(document).pjax('a') + // + // $(document).on('click', 'a', function(event) { + // var container = $(this).closest('[data-pjax-container]') + // $.pjax.click(event, container) + // }) + // + // Returns nothing. + function handleClick(event, container, options) { + options = optionsFor(container, options) + + var link = event.currentTarget + + if (link.tagName.toUpperCase() !== 'A') + throw "$.fn.pjax or $.pjax.click requires an anchor element" + + // Middle click, cmd click, and ctrl click should open + // links in a new tab as normal. + if ( event.which > 1 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey ) + return + + // Ignore cross origin links + if ( location.protocol !== link.protocol || location.hostname !== link.hostname ) + return + + // Ignore case when a hash is being tacked on the current URL + if ( link.href.indexOf('#') > -1 && stripHash(link) == stripHash(location) ) + return + + // Ignore event with default prevented + if (event.isDefaultPrevented()) + return + + var defaults = { + url: link.href, + container: $(link).attr('data-pjax'), + target: link + } + + var opts = $.extend({}, defaults, options) + var clickEvent = $.Event('pjax:click') + $(link).trigger(clickEvent, [opts]) + + if (!clickEvent.isDefaultPrevented()) { + pjax(opts) + event.preventDefault() + $(link).trigger('pjax:clicked', [opts]) + } + } + + // Public: pjax on form submit handler + // + // Exported as $.pjax.submit + // + // event - "click" jQuery.Event + // options - pjax options + // + // Examples + // + // $(document).on('submit', 'form', function(event) { + // var container = $(this).closest('[data-pjax-container]') + // $.pjax.submit(event, container) + // }) + // + // Returns nothing. + function handleSubmit(event, container, options) { + options = optionsFor(container, options) + + var form = event.currentTarget + var $form = $(form) + + if (form.tagName.toUpperCase() !== 'FORM') + throw "$.pjax.submit requires a form element" + + var defaults = { + type: ($form.attr('method') || 'GET').toUpperCase(), + url: $form.attr('action'), + container: $form.attr('data-pjax'), + target: form + } + + if (defaults.type !== 'GET' && window.FormData !== undefined) { + defaults.data = new FormData(form); + defaults.processData = false; + defaults.contentType = false; + } else { + // Can't handle file uploads, exit + if ($(form).find(':file').length) { + return; + } + + // Fallback to manually serializing the fields + defaults.data = $(form).serializeArray(); + } + + pjax($.extend({}, defaults, options)) + + event.preventDefault() + } + + // Loads a URL with ajax, puts the response body inside a container, + // then pushState()'s the loaded URL. + // + // Works just like $.ajax in that it accepts a jQuery ajax + // settings object (with keys like url, type, data, etc). + // + // Accepts these extra keys: + // + // container - Where to stick the response body. + // $(container).html(xhr.responseBody) + // push - Whether to pushState the URL. Defaults to true (of course). + // replace - Want to use replaceState instead? That's cool. + // + // Use it just like $.ajax: + // + // var xhr = $.pjax({ url: this.href, container: '#main' }) + // console.log( xhr.readyState ) + // + // Returns whatever $.ajax returns. + function pjax(options) { + options = $.extend(true, {}, $.ajaxSettings, pjax.defaults, options) + + if ($.isFunction(options.url)) { + options.url = options.url() + } + + var target = options.target + + var hash = parseURL(options.url).hash + + var context = options.context = findContainerFor(options.container) + + // We want the browser to maintain two separate internal caches: one + // for pjax'd partial page loads and one for normal page loads. + // Without adding this secret parameter, some browsers will often + // confuse the two. + if (!options.data) options.data = {} + if ($.isArray(options.data)) { + options.data.push({ name: '_pjax', value: context.selector }) + } else { + options.data._pjax = context.selector + } + // + function fire(type, args, props) { + if (!props) props = {} + props.relatedTarget = target + var event = $.Event(type, props) + context.trigger(event, args) + return !event.isDefaultPrevented() + } + + var timeoutTimer + + options.beforeSend = function(xhr, settings) { + // No timeout for non-GET requests + // Its not safe to request the resource again with a fallback method. + if (settings.type !== 'GET') { + settings.timeout = 0 + } + + xhr.setRequestHeader('X-PJAX', 'true') + xhr.setRequestHeader('X-PJAX-Container', context.selector) + + if (!fire('pjax:beforeSend', [xhr, settings])) + return false + + if (settings.timeout > 0) { + timeoutTimer = setTimeout(function() { + if (fire('pjax:timeout', [xhr, options])) + xhr.abort('timeout') + }, settings.timeout) + + // Clear timeout setting so jquerys internal timeout isn't invoked + settings.timeout = 0 + } + + var url = parseURL(settings.url) + if (hash) url.hash = hash + options.requestUrl = stripInternalParams(url) + } + + options.complete = function(xhr, textStatus) { + if (timeoutTimer) + clearTimeout(timeoutTimer) + + fire('pjax:complete', [xhr, textStatus, options]) + + fire('pjax:end', [xhr, options]) + } + + options.error = function(xhr, textStatus, errorThrown) { + var container = extractContainer("", xhr, options) + + var allowed = fire('pjax:error', [xhr, textStatus, errorThrown, options]) + if (options.type == 'GET' && textStatus !== 'abort' && allowed) { + locationReplace(container.url) + } + } + + options.success = function(data, status, xhr) { + var previousState = pjax.state; + + // If $.pjax.defaults.version is a function, invoke it first. + // Otherwise it can be a static string. + var currentVersion = (typeof $.pjax.defaults.version === 'function') ? + $.pjax.defaults.version() : + $.pjax.defaults.version + + var latestVersion = xhr.getResponseHeader('X-PJAX-Version') + + var container = extractContainer(data, xhr, options) + + var url = parseURL(container.url) + if (hash) { + url.hash = hash + container.url = url.href + } + + // If there is a layout version mismatch, hard load the new url + if (currentVersion && latestVersion && currentVersion !== latestVersion) { + locationReplace(container.url) + return + } + + // If the new response is missing a body, hard load the page + if (!container.contents) { + locationReplace(container.url) + return + } + + pjax.state = { + id: options.id || uniqueId(), + url: container.url, + title: container.title, + container: context.selector, + fragment: options.fragment, + timeout: options.timeout + } + + if (options.push || options.replace) { + window.history.replaceState(pjax.state, container.title, container.url) + } + + // Only blur the focus if the focused element is within the container. + var blurFocus = $.contains(options.container, document.activeElement) + + // Clear out any focused controls before inserting new page contents. + if (blurFocus) { + try { + document.activeElement.blur() + } catch (e) { } + } + + if (container.title) document.title = container.title + + fire('pjax:beforeReplace', [container.contents, options], { + state: pjax.state, + previousState: previousState + }) + context.html(container.contents) + + // FF bug: Won't autofocus fields that are inserted via JS. + // This behavior is incorrect. So if theres no current focus, autofocus + // the last field. + // + // http://www.w3.org/html/wg/drafts/html/master/forms.html + var autofocusEl = context.find('input[autofocus], textarea[autofocus]').last()[0] + if (autofocusEl && document.activeElement !== autofocusEl) { + autofocusEl.focus(); + } + + executeScriptTags(container.scripts) + + var scrollTo = options.scrollTo + + // Ensure browser scrolls to the element referenced by the URL anchor + if (hash) { + var name = decodeURIComponent(hash.slice(1)) + var target = document.getElementById(name) || document.getElementsByName(name)[0] + if (target) scrollTo = $(target).offset().top + } + + if (typeof scrollTo == 'number') $(window).scrollTop(scrollTo) + + fire('pjax:success', [data, status, xhr, options]) + } + + + // Initialize pjax.state for the initial page load. Assume we're + // using the container and options of the link we're loading for the + // back button to the initial page. This ensures good back button + // behavior. + if (!pjax.state) { + pjax.state = { + id: uniqueId(), + url: window.location.href, + title: document.title, + container: context.selector, + fragment: options.fragment, + timeout: options.timeout + } + window.history.replaceState(pjax.state, document.title) + } + + // Cancel the current request if we're already pjaxing + abortXHR(pjax.xhr) + + pjax.options = options + var xhr = pjax.xhr = $.ajax(options) + + if (xhr.readyState > 0) { + if (options.push && !options.replace) { + // Cache current container element before replacing it + cachePush(pjax.state.id, cloneContents(context)) + + window.history.pushState(null, "", options.requestUrl) + } + + fire('pjax:start', [xhr, options]) + fire('pjax:send', [xhr, options]) + } + + return pjax.xhr + } + + // Public: Reload current page with pjax. + // + // Returns whatever $.pjax returns. + function pjaxReload(container, options) { + var defaults = { + url: window.location.href, + push: false, + replace: true, + scrollTo: false + } + + return pjax($.extend(defaults, optionsFor(container, options))) + } + + // Internal: Hard replace current state with url. + // + // Work for around WebKit + // https://bugs.webkit.org/show_bug.cgi?id=93506 + // + // Returns nothing. + function locationReplace(url) { + window.history.replaceState(null, "", pjax.state.url) + window.location.replace(url) + } + + + var initialPop = true + var initialURL = window.location.href + var initialState = window.history.state + + // Initialize $.pjax.state if possible + // Happens when reloading a page and coming forward from a different + // session history. + if (initialState && initialState.container) { + pjax.state = initialState + } + + // Non-webkit browsers don't fire an initial popstate event + if ('state' in window.history) { + initialPop = false + } + + // popstate handler takes care of the back and forward buttons + // + // You probably shouldn't use pjax on pages with other pushState + // stuff yet. + function onPjaxPopstate(event) { + // Hitting back or forward should override any pending PJAX request. + if (!initialPop) { + abortXHR(pjax.xhr) + } + + var previousState = pjax.state + var state = event.state + var direction + + if (state && state.container) { + // When coming forward from a separate history session, will get an + // initial pop with a state we are already at. Skip reloading the current + // page. + if (initialPop && initialURL == state.url) return + + if (previousState) { + // If popping back to the same state, just skip. + // Could be clicking back from hashchange rather than a pushState. + if (previousState.id === state.id) return + + // Since state IDs always increase, we can deduce the navigation direction + direction = previousState.id < state.id ? 'forward' : 'back' + } + //changed by jackchain cancel cache; + var cache = cacheMapping[state.id] || [] + //console.log(cache); + var container = $(cache[0] || state.container), contents = cache[1] + //console.log(container); + if (container.length) { + if (previousState) { + // Cache current container before replacement and inform the + // cache which direction the history shifted. + cachePop(direction, previousState.id, cloneContents(container)) + } + + var popstateEvent = $.Event('pjax:popstate', { + state: state, + direction: direction + }) + container.trigger(popstateEvent) + + var options = { + id: state.id, + url: state.url, + container: container, + push: false, + fragment: state.fragment, + timeout: state.timeout, + scrollTo: false + } + + if (contents) { + container.trigger('pjax:start', [null, options]) + + pjax.state = state + if (state.title) document.title = state.title + var beforeReplaceEvent = $.Event('pjax:beforeReplace', { + state: state, + previousState: previousState + }) + container.trigger(beforeReplaceEvent, [contents, options]) + container.html(contents) + + container.trigger('pjax:end', [null, options]) + } else { + pjax(options) + } + + // Force reflow/relayout before the browser tries to restore the + // scroll position. + container[0].offsetHeight + } else { + locationReplace(location.href) + } + } + initialPop = false + } + + // Fallback version of main pjax function for browsers that don't + // support pushState. + // + // Returns nothing since it retriggers a hard form submission. + function fallbackPjax(options) { + var url = $.isFunction(options.url) ? options.url() : options.url, + method = options.type ? options.type.toUpperCase() : 'GET' + + var form = $('Loading...
+