diff --git a/app/_locales/ja/messages.json b/app/_locales/ja/messages.json index fe2f2fc..b464a45 100644 --- a/app/_locales/ja/messages.json +++ b/app/_locales/ja/messages.json @@ -75,6 +75,9 @@ "wentWrong": { "message": "申し訳ございません。問題が発生しました。" }, + "confirmPublishOverwrite": { + "message": "小説の入力内容が変更されています。\n上書きしてもよろしいですか?" + }, "options": { "message": "設定" diff --git a/app/scripts/lib/sites/kakuyomu/publish.js b/app/scripts/lib/sites/kakuyomu/publish.js index cdbfadf..4abbf96 100644 --- a/app/scripts/lib/sites/kakuyomu/publish.js +++ b/app/scripts/lib/sites/kakuyomu/publish.js @@ -1,4 +1,5 @@ import _ from "lodash"; +import { translate } from "@io-monad/chrome-util"; import moment from "../../util/moment"; import openPage from "../../util/open-page"; import KakuyomuURL from "./url"; @@ -12,7 +13,7 @@ import KakuyomuURL from "./url"; export default function publish(publication) { const url = getURL(publication); const code = getCode(publication); - return openPage(url, code); + return openPage(url, code, { update: true }); } function getURL(pub) { @@ -24,31 +25,44 @@ function getURL(pub) { } function getCode(pub) { - const title = JSON.stringify(pub.title || ""); - const body = JSON.stringify(pub.body || ""); - let code = ` + const embedPub = { + title: pub.title || "", + body: pub.body || "", + }; + if (pub.time) { + const time = moment(pub.time).tz("Asia/Tokyo"); + embedPub.date = time.format("YYYY-MM-DD"); + embedPub.time = time.format("HH:mm"); + } + return ` + var pub = ${JSON.stringify(embedPub)}; var form = document.getElementById("episode-editForm"); + var lastPub = window.novelousLastPublication || { title: "", body: "" }; + if (form.title.value !== lastPub.title || form.body.value !== lastPub.body) { + if (!confirm(${JSON.stringify(translate("confirmPublishOverwrite"))})) { + return; + } + } + var change = document.createEvent("HTMLEvents"); change.initEvent("change", true, true); - form.title.value = ${title}; + form.title.value = pub.title; form.title.dispatchEvent(change); - form.body.value = ${body}; + form.body.value = pub.body; form.body.dispatchEvent(change); - `; - if (pub.time) { - const time = moment(pub.time).tz("Asia/Tokyo"); - const dateValue = JSON.stringify(time.format("YYYY-MM-DD")); - const timeValue = JSON.stringify(time.format("HH:mm")); - code += ` - document.querySelector(".js-reservation-panel-button").click(); + if (pub.date && pub.time) { + var button = document.querySelector(".js-reservation-panel-button"); + if (!/isPanelShown/.test(button.className)) { + button.click(); + } document.getElementById("reservationInput-reserved").click(); - form.reservation_date.value = ${dateValue}; - form.reservation_time.value = ${timeValue}; - `; - } + form.reservation_date.value = pub.date; + form.reservation_time.value = pub.time; + } - return code; + window.novelousLastPublication = pub; + `; } diff --git a/app/scripts/lib/sites/narou/publish.js b/app/scripts/lib/sites/narou/publish.js index 2a77e3a..380734a 100644 --- a/app/scripts/lib/sites/narou/publish.js +++ b/app/scripts/lib/sites/narou/publish.js @@ -1,4 +1,5 @@ import _ from "lodash"; +import { translate } from "@io-monad/chrome-util"; import moment from "../../util/moment"; import openPage from "../../util/open-page"; import NarouURL from "./url"; @@ -12,7 +13,7 @@ import NarouURL from "./url"; export default function publish(publication) { const url = getURL(publication); const code = getCode(publication); - return openPage(url, code); + return openPage(url, code, { update: true }); } function getURL(pub) { @@ -24,25 +25,36 @@ function getURL(pub) { } function getCode(pub) { - const title = JSON.stringify(pub.title || ""); - const body = JSON.stringify(pub.body || ""); - let code = ` - var form = document.getElementById("manage_form"); - form.subtitle.value = ${title}; - form.novel.value = ${body}; - `; - + const embedPub = { + title: pub.title || "", + body: pub.body || "", + }; if (pub.time) { const time = moment(pub.time).tz("Asia/Tokyo"); - const monthValue = JSON.stringify(time.format("YYYY-MM")); - const dayValue = JSON.stringify(time.format("D")); - const hourValue = JSON.stringify(time.format("H")); - code += ` - form.month.value = ${monthValue}; - form.day.value = ${dayValue}; - form.hour.value = ${hourValue}; - `; + embedPub.month = time.format("YYYY-MM"); + embedPub.day = time.format("D"); + embedPub.hour = time.format("H"); } + return ` + var pub = ${JSON.stringify(embedPub)}; + var form = document.getElementById("manage_form"); - return code; + var lastPub = window.novelousLastPublication || { title: "", body: "" }; + if (form.subtitle.value !== lastPub.title || form.novel.value !== lastPub.body) { + if (!confirm(${JSON.stringify(translate("confirmPublishOverwrite"))})) { + return; + } + } + + form.subtitle.value = pub.title; + form.novel.value = pub.body; + + if (pub.month && pub.day) { + form.month.value = pub.month; + form.day.value = pub.day; + form.hour.value = pub.hour; + } + + window.novelousLastPublication = pub; + `; } diff --git a/app/scripts/lib/util/open-page.js b/app/scripts/lib/util/open-page.js index a2cab03..930e800 100644 --- a/app/scripts/lib/util/open-page.js +++ b/app/scripts/lib/util/open-page.js @@ -3,20 +3,49 @@ * * @param {string} url - A URL of the opening page. * @param {string} code - A code to be executed on the page. + * @param {Object} [options] - Options. + * @param {boolean} [options.update=false] - Set this to `true` for updating existing tab. * @return {Promise} */ -export default function openPage(url, code) { - return new Promise((resolve, reject) => { - chrome.tabs.create({ url }, (tab) => { - const wrapped = wrapInjectCode(code); - chrome.tabs.executeScript(tab.id, { code: wrapped }, (results) => { - // results = [error] or [null] - if (results.length > 0 && results[0]) { - reject(results[0]); +export default function openPage(url, code, options) { + options = options || {}; + return new Promise(resolve => { + if (options.update) { + chrome.tabs.query({ url }, (tabs) => { + if (tabs.length > 0) { + chrome.tabs.update(tabs[0].id, { active: true }, tab => { + resolve(executeCode(tab, code)); + }); } else { - resolve(); + chrome.tabs.create({ url }, tab => { + resolve(executeCode(tab, code)); + }); } }); + } else { + chrome.tabs.create({ url }, tab => { + resolve(executeCode(tab, code)); + }); + } + }); +} + +/** + * @param {chrome~Tab} tab + * @param {string} code + * @return {Promise} + * @private + */ +function executeCode(tab, code) { + return new Promise((resolve, reject) => { + const wrapped = wrapInjectCode(code); + chrome.tabs.executeScript(tab.id, { code: wrapped }, (results) => { + // results = [error] or [null] + if (results.length > 0 && results[0]) { + reject(results[0]); + } else { + resolve(); + } }); }); } @@ -35,6 +64,6 @@ function wrapInjectCode(code) { return e.message || e; } return null; - })(); + }()); `; } diff --git a/test/lib/sites/kakuyomu/publish-test.js b/test/lib/sites/kakuyomu/publish-test.js index 784b5ae..9a18773 100644 --- a/test/lib/sites/kakuyomu/publish-test.js +++ b/test/lib/sites/kakuyomu/publish-test.js @@ -2,34 +2,69 @@ import { _, assert, factory } from "../../../common"; import publish from "../../../../app/scripts/lib/sites/kakuyomu/publish"; describe("KakuyomuPublish", () => { - it("publishes novel to sites", () => { - const pub = factory.buildSync("publication", { + let pub; + let publishUrl; + before(() => { + pub = factory.buildSync("publication", { sites: { kakuyomu: { novelId: "12341234" }, }, }); - chrome.tabs.create.callsArgWithAsync(1, { id: 123 }); - chrome.tabs.executeScript.callsArgWithAsync(2, [null]); + publishUrl = `https://kakuyomu.jp/my/works/${pub.sites.kakuyomu.novelId}/episodes/new`; + }); + + it("opens a new tab with publication contents", () => { + chrome.tabs.query.yieldsAsync([]); + chrome.tabs.create.yieldsAsync({ id: 123 }); + chrome.tabs.executeScript.yieldsAsync([null]); return publish(pub).then(() => { - assert(chrome.tabs.create.calledOnce); - assert.deepEqual(chrome.tabs.create.args[0][0], { - url: `https://kakuyomu.jp/my/works/${pub.sites.kakuyomu.novelId}/episodes/new`, + assert(chrome.tabs.query.calledOnce === true); + assert.deepEqual(chrome.tabs.query.args[0][0], { url: publishUrl }); + + assert(chrome.tabs.create.calledOnce === true); + assert.deepEqual(chrome.tabs.create.args[0][0], { url: publishUrl }); + + assert(chrome.tabs.executeScript.calledOnce === true); + assert(chrome.tabs.executeScript.args[0][0] === 123); + assert(_.isString(chrome.tabs.executeScript.args[0][1].code)); + + const code = chrome.tabs.executeScript.args[0][1].code; + const embedPub = JSON.parse(code.match(/var pub = (.+?);/)[1]); + assert.deepEqual(embedPub, { + title: pub.title, + body: pub.body, + date: "2016-03-01", + time: "11:34", }); - assert(chrome.tabs.executeScript.calledOnce); + }); + }); + + it("updates an existing tab with publication contents", () => { + chrome.tabs.query.yieldsAsync([{ id: 123 }]); + chrome.tabs.update.yieldsAsync({ id: 123 }); + chrome.tabs.executeScript.yieldsAsync([null]); + + return publish(pub).then(() => { + assert(chrome.tabs.query.calledOnce === true); + assert.deepEqual(chrome.tabs.query.args[0][0], { url: publishUrl }); + + assert(chrome.tabs.update.calledOnce === true); + assert(chrome.tabs.update.args[0][0] === 123); + assert.deepEqual(chrome.tabs.update.args[0][1], { active: true }); + + assert(chrome.tabs.executeScript.calledOnce === true); assert(chrome.tabs.executeScript.args[0][0] === 123); assert(_.isString(chrome.tabs.executeScript.args[0][1].code)); const code = chrome.tabs.executeScript.args[0][1].code; - const formValue = (name) => { - const re = new RegExp(`form\\.${name}\\.value = (.+?);`); - return JSON.parse(code.match(re)[1]); - }; - - assert(formValue("title") === pub.title); - assert(formValue("body") === pub.body); - assert(formValue("reservation_date") === "2016-03-01"); - assert(formValue("reservation_time") === "11:34"); + const embedPub = JSON.parse(code.match(/var pub = (.+?);/)[1]); + assert.deepEqual(embedPub, { + title: pub.title, + body: pub.body, + date: "2016-03-01", + time: "11:34", + }); }); }); }); diff --git a/test/lib/sites/narou/publish-test.js b/test/lib/sites/narou/publish-test.js index 6da9ece..5f6a3f3 100644 --- a/test/lib/sites/narou/publish-test.js +++ b/test/lib/sites/narou/publish-test.js @@ -2,31 +2,67 @@ import { _, assert, factory } from "../../../common"; import publish from "../../../../app/scripts/lib/sites/narou/publish"; describe("NarouPublish", () => { - it("publishes novel to sites", () => { - const pub = factory.buildSync("publication"); - chrome.tabs.create.callsArgWithAsync(1, { id: 123 }); - chrome.tabs.executeScript.callsArgWithAsync(2, [null]); + let pub; + let publishUrl; + before(() => { + pub = factory.buildSync("publication"); + publishUrl = `http://syosetu.com/usernovelmanage/ziwainput/ncode/${pub.sites.narou.novelId}/`; + }); + + it("opens a new tab with publication contents", () => { + chrome.tabs.query.yieldsAsync([]); + chrome.tabs.create.yieldsAsync({ id: 123 }); + chrome.tabs.executeScript.yieldsAsync([null]); return publish(pub).then(() => { - assert(chrome.tabs.create.calledOnce); - assert.deepEqual(chrome.tabs.create.args[0][0], { - url: `http://syosetu.com/usernovelmanage/ziwainput/ncode/${pub.sites.narou.novelId}/`, + assert(chrome.tabs.query.calledOnce === true); + assert.deepEqual(chrome.tabs.query.args[0][0], { url: publishUrl }); + + assert(chrome.tabs.create.calledOnce === true); + assert.deepEqual(chrome.tabs.create.args[0][0], { url: publishUrl }); + + assert(chrome.tabs.executeScript.calledOnce === true); + assert(chrome.tabs.executeScript.args[0][0] === 123); + assert(_.isString(chrome.tabs.executeScript.args[0][1].code)); + + const code = chrome.tabs.executeScript.args[0][1].code; + const embedPub = JSON.parse(code.match(/var pub = (.+?);/)[1]); + assert.deepEqual(embedPub, { + title: pub.title, + body: pub.body, + month: "2016-03", + day: "1", + hour: "11", }); - assert(chrome.tabs.executeScript.calledOnce); + }); + }); + + it("updates an existing tab with publication contents", () => { + chrome.tabs.query.yieldsAsync([{ id: 123 }]); + chrome.tabs.update.yieldsAsync({ id: 123 }); + chrome.tabs.executeScript.yieldsAsync([null]); + + return publish(pub).then(() => { + assert(chrome.tabs.query.calledOnce === true); + assert.deepEqual(chrome.tabs.query.args[0][0], { url: publishUrl }); + + assert(chrome.tabs.update.calledOnce === true); + assert(chrome.tabs.update.args[0][0] === 123); + assert.deepEqual(chrome.tabs.update.args[0][1], { active: true }); + + assert(chrome.tabs.executeScript.calledOnce === true); assert(chrome.tabs.executeScript.args[0][0] === 123); assert(_.isString(chrome.tabs.executeScript.args[0][1].code)); const code = chrome.tabs.executeScript.args[0][1].code; - const formValue = (name) => { - const re = new RegExp(`form\\.${name}\\.value = (.+?);`); - return JSON.parse(code.match(re)[1]); - }; - - assert(formValue("subtitle") === pub.title); - assert(formValue("novel") === pub.body); - assert(formValue("month") === "2016-03"); - assert(formValue("day") === "1"); - assert(formValue("hour") === "11"); + const embedPub = JSON.parse(code.match(/var pub = (.+?);/)[1]); + assert.deepEqual(embedPub, { + title: pub.title, + body: pub.body, + month: "2016-03", + day: "1", + hour: "11", + }); }); }); });