diff --git a/lib/hexo/default_config.js b/lib/hexo/default_config.js index 8c529ac7bf..dae0beebc4 100644 --- a/lib/hexo/default_config.js +++ b/lib/hexo/default_config.js @@ -61,8 +61,10 @@ module.exports = { // Date / Time format date_format: 'YYYY-MM-DD', time_format: 'HH:mm:ss', - // Use post date for updated date instead of file modification date when front-matter provides no updated date - use_date_for_updated: false, + updated_option: 'mtime', + // * mtime: file modification date (default) + // * date: use_date_for_updated + // * empty: no more update // Pagination per_page: 10, pagination_dir: 'page', diff --git a/lib/models/page.js b/lib/models/page.js index 2f357765d6..fad83b28d6 100644 --- a/lib/models/page.js +++ b/lib/models/page.js @@ -17,7 +17,6 @@ module.exports = ctx => { }, updated: { type: Moment, - default: moment, language: ctx.config.languages, timezone: ctx.config.timezone }, diff --git a/lib/models/post.js b/lib/models/post.js index a6775f3cb6..3b2caba770 100644 --- a/lib/models/post.js +++ b/lib/models/post.js @@ -27,7 +27,6 @@ module.exports = ctx => { }, updated: { type: Moment, - default: moment, language: ctx.config.languages, timezone: ctx.config.timezone }, diff --git a/lib/plugins/processor/asset.js b/lib/plugins/processor/asset.js index 731a042b4f..1674903fa5 100644 --- a/lib/plugins/processor/asset.js +++ b/lib/plugins/processor/asset.js @@ -12,7 +12,7 @@ module.exports = ctx => { const { path } = file; const doc = Page.findOne({source: path}); const { config } = ctx; - const { timezone: timezoneCfg, use_date_for_updated } = config; + const { timezone: timezoneCfg, use_date_for_updated, updated_option } = config; if (file.type === 'skip' && doc) { return; @@ -48,8 +48,10 @@ module.exports = ctx => { if (data.updated) { if (timezoneCfg) data.updated = timezone(data.updated, timezoneCfg); - } else if (use_date_for_updated) { + } else if (use_date_for_updated || updated_option === 'date') { data.updated = data.date; + } else if (updated_option === 'empty') { + delete data.updated; } else { data.updated = stats.mtime; } diff --git a/lib/plugins/processor/post.js b/lib/plugins/processor/post.js index f3e50546ef..2b60adc12f 100644 --- a/lib/plugins/processor/post.js +++ b/lib/plugins/processor/post.js @@ -27,7 +27,7 @@ module.exports = ctx => { const { path } = file.params; const doc = Post.findOne({source: file.path}); const { config } = ctx; - const { timezone: timezoneCfg, use_date_for_updated } = config; + const { timezone: timezoneCfg, use_date_for_updated, updated_option } = config; let categories, tags; if (file.type === 'skip' && doc) { @@ -85,8 +85,10 @@ module.exports = ctx => { if (data.updated) { if (timezoneCfg) data.updated = timezone(data.updated, timezoneCfg); - } else if (use_date_for_updated) { + } else if (use_date_for_updated || updated_option === 'date') { data.updated = data.date; + } else if (updated_option === 'empty') { + delete data.updated; } else { data.updated = stats.mtime; } diff --git a/test/scripts/helpers/open_graph.js b/test/scripts/helpers/open_graph.js index 28ea49e894..da22b10ffa 100644 --- a/test/scripts/helpers/open_graph.js +++ b/test/scripts/helpers/open_graph.js @@ -49,7 +49,9 @@ describe('open_graph', () => { meta({property: 'og:site_name', content: hexo.config.title}), meta({property: 'og:locale', content: 'en_US'}), meta({property: 'article:published_time', content: post.date.toISOString()}), - meta({property: 'article:modified_time', content: post.updated.toISOString()}), + // page.updated will no longer exist by default + // See https://github.com/hexojs/hexo/pull/4278 + // meta({property: 'article:modified_time', content: post.updated.toISOString()}), meta({property: 'article:author', content: hexo.config.author}), meta({property: 'article:tag', content: 'optimize'}), meta({property: 'article:tag', content: 'web'}), diff --git a/test/scripts/models/page.js b/test/scripts/models/page.js index 7d2f60ecfe..da6a520009 100644 --- a/test/scripts/models/page.js +++ b/test/scripts/models/page.js @@ -21,11 +21,11 @@ describe('Page', () => { data.title.should.eql(''); data.date.valueOf().should.gte(now); - data.updated.valueOf().should.gte(now); data.comments.should.be.true; data.layout.should.eql('page'); data._content.should.eql(''); data.raw.should.eql(''); + should.not.exist(data.updated); should.not.exist(data.content); should.not.exist(data.excerpt); should.not.exist(data.more); diff --git a/test/scripts/models/post.js b/test/scripts/models/post.js index 25a2897f77..419e99a0bd 100644 --- a/test/scripts/models/post.js +++ b/test/scripts/models/post.js @@ -28,13 +28,13 @@ describe('Post', () => { }).then(data => { data.title.should.eql(''); data.date.valueOf().should.gte(now); - data.updated.valueOf().should.gte(now); data.comments.should.be.true; data.layout.should.eql('post'); data._content.should.eql(''); data.link.should.eql(''); data.raw.should.eql(''); data.published.should.be.true; + should.not.exist(data.updated); should.not.exist(data.content); should.not.exist(data.excerpt); should.not.exist(data.more); diff --git a/test/scripts/processors/asset.js b/test/scripts/processors/asset.js index 78256560b9..c77bf83f84 100644 --- a/test/scripts/processors/asset.js +++ b/test/scripts/processors/asset.js @@ -281,14 +281,65 @@ describe('asset', () => { ]); }); - it('page - use the date for updated if use_date_for_updated is set', async () => { + it('page - use the date for updated if updated_option = date', async () => { + const body = [ + 'date: 2011-4-5 14:19:19', + '---' + ].join('\n'); + const file = newFile({ path: 'hello.njk', type: 'create', renderable: true }); - hexo.config.use_date_for_updated = true; + hexo.config.updated_option = 'date'; + + await writeFile(file.source, body); + await process(file); + const stats = await stat(file.source); + const page = Page.findOne({source: file.path}); + + page.updated.toDate().should.eql(page.date.toDate()); + page.updated.toDate().should.not.eql(stats.mtime); + + await Promise.all([ + page.remove(), + unlink(file.source) + ]); + }); + + it('page - use the status if updated_option = mtime', async () => { + const file = newFile({ + path: 'hello.njk', + type: 'create', + renderable: true + }); + + hexo.config.updated_option = 'mtime'; + + await writeFile(file.source, ''); + await process(file); + const stats = await stat(file.source); + const page = Page.findOne({source: file.path}); + + page.date.toDate().should.eql(stats.ctime); + page.updated.toDate().should.eql(stats.mtime); + + await Promise.all([ + page.remove(), + unlink(file.source) + ]); + }); + + it('page - updated shouldn\'t exists if updated_option = empty', async () => { + const file = newFile({ + path: 'hello.njk', + type: 'create', + renderable: true + }); + + hexo.config.updated_option = 'empty'; await writeFile(file.source, ''); await process(file); @@ -296,7 +347,64 @@ describe('asset', () => { const page = Page.findOne({source: file.path}); page.date.toDate().should.eql(stats.ctime); + should.not.exist(page.updated); + + await Promise.all([ + page.remove(), + unlink(file.source) + ]); + }); + + it('page - use_date_for_updated as fallback', async () => { + const body = [ + 'date: 2011-4-5 14:19:19', + '---' + ].join('\n'); + + const file = newFile({ + path: 'hello.njk', + type: 'create', + renderable: true + }); + + hexo.config.use_date_for_updated = true; + + await writeFile(file.source, body); + await process(file); + const stats = await stat(file.source); + const page = Page.findOne({source: file.path}); + + page.updated.toDate().should.eql(page.date.toDate()); + page.updated.toDate().should.not.eql(stats.mtime); + + await Promise.all([ + page.remove(), + unlink(file.source) + ]); + }); + + it('page - ignore updated_option when use_date_for_updated is set', async () => { + const body = [ + 'date: 2011-4-5 14:19:19', + '---' + ].join('\n'); + + const file = newFile({ + path: 'hello.njk', + type: 'create', + renderable: true + }); + + hexo.config.use_date_for_updated = true; + hexo.config.updated_option = 'mtime'; + + await writeFile(file.source, body); + await process(file); + const stats = await stat(file.source); + const page = Page.findOne({source: file.path}); + page.updated.toDate().should.eql(page.date.toDate()); + page.updated.toDate().should.not.eql(stats.mtime); await Promise.all([ page.remove(), diff --git a/test/scripts/processors/post.js b/test/scripts/processors/post.js index d37a96c70e..11f26de2bc 100644 --- a/test/scripts/processors/post.js +++ b/test/scripts/processors/post.js @@ -507,7 +507,88 @@ describe('post', () => { unlink(file.source); }); - it('post - use date when no updated and use_date_for_updated', async () => { + it('post - use the date for updated if updated_option = date', async () => { + const body = [ + 'date: 2011-4-5 14:19:19', + 'title: "Hello world"', + '---' + ].join('\n'); + + const file = newFile({ + path: 'foo.html', + published: true, + type: 'create', + renderable: true + }); + + hexo.config.updated_option = 'date'; + + await writeFile(file.source, body); + const stats = await file.stat(); + await process(file); + const post = Post.findOne({source: file.path}); + + post.updated.toDate().setMilliseconds(0).should.eql(post.date.toDate().setMilliseconds(0)); + post.updated.toDate().setMilliseconds(0).should.not.eql(stats.mtime.setMilliseconds(0)); + + post.remove(); + unlink(file.source); + }); + + it('post - use the status of the source file if updated_option = mtime', async () => { + const body = [ + 'date: 2011-4-5 14:19:19', + 'title: "Hello world"', + '---' + ].join('\n'); + + const file = newFile({ + path: 'foo.html', + published: true, + type: 'create', + renderable: true + }); + + hexo.config.updated_option = 'mtime'; + + await writeFile(file.source, body); + const stats = await file.stat(); + await process(file); + const post = Post.findOne({source: file.path}); + + post.updated.toDate().setMilliseconds(0).should.eql(stats.mtime.setMilliseconds(0)); + post.updated.toDate().setMilliseconds(0).should.not.eql(post.date.toDate().setMilliseconds(0)); + + post.remove(); + unlink(file.source); + }); + + it('post - updated shouldn\'t exists if updated_option = empty', async () => { + const body = [ + 'title: "Hello world"', + '---' + ].join('\n'); + + const file = newFile({ + path: 'foo.html', + published: true, + type: 'create', + renderable: true + }); + + hexo.config.updated_option = 'empty'; + + await writeFile(file.source, body); + await process(file); + const post = Post.findOne({source: file.path}); + + should.not.exist(post.updated); + + post.remove(); + unlink(file.source); + }); + + it('post - use use_date_for_updated as a fallback', async () => { const body = [ 'title: "Hello world"', '---' @@ -534,6 +615,35 @@ describe('post', () => { unlink(file.source); }); + it('post - ignore updated_option when use_date_for_updated is set', async () => { + const body = [ + 'date: 2011-4-5 14:19:19', + 'title: "Hello world"', + '---' + ].join('\n'); + + const file = newFile({ + path: 'foo.html', + published: true, + type: 'create', + renderable: true + }); + + hexo.config.use_date_for_updated = true; + hexo.config.updated_option = 'mtime'; + + await writeFile(file.source, body); + const stats = await file.stat(); + await process(file); + const post = Post.findOne({source: file.path}); + + post.updated.toDate().setMilliseconds(0).should.eql(post.date.toDate().setMilliseconds(0)); + post.updated.toDate().setMilliseconds(0).should.not.eql(stats.mtime.setMilliseconds(0)); + + post.remove(); + unlink(file.source); + }); + it('post - photo is an alias for photos', async () => { const body = [ 'title: "Hello world"',