Created
January 7, 2018 14:34
-
-
Save anod700/dbfd90a2dff25d3eb6c078fcb8ddbf5d to your computer and use it in GitHub Desktop.
増田ヘルパー
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"manifest_version": 2, | |
"name": "masd", | |
"description": "増田ヘルパー", | |
"version": "1.0", | |
"browser_action": { | |
"default_popup": "popup.html" | |
}, | |
"permissions": [ "https://anond.hatelabo.jp/" ] | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
* { | |
box-sizing: border-box; | |
} | |
body { | |
font-size: 12px; | |
margin: 0; | |
} | |
.container { | |
width: 100vw; | |
height: 100vh; | |
min-width: 600px; | |
min-height: 400px; | |
display: flex; | |
flex-flow: row nowrap; | |
align-items: stretch; | |
} | |
aside { | |
width: 60px; | |
flex: none; | |
background: #484848; | |
color: #f0f0f0; | |
border-right: 1px solid #333; | |
padding: 5px; | |
position: relative; | |
} | |
aside div { | |
margin: 15px 0; | |
cursor: pointer; | |
} | |
aside div.active { | |
font-weight: bold; | |
font-size: 1.05em; | |
color: #fafafa; | |
text-shadow: 1px 1px 0px rgba(255,255,255,0.4); | |
} | |
#opentab { | |
position: absolute; | |
bottom: 0; | |
font-size: 22px; | |
border: 2px solid #aaa; | |
border-radius: 4px; | |
width: 30px; | |
height: 30px; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
} | |
main { | |
width: calc(100% - 60px); | |
flex: none; | |
padding: 10px; | |
} | |
main section { | |
width: 100%; | |
height: 100%; | |
overflow: auto; | |
} | |
main section:not(.active) { | |
display: none!important; | |
} | |
main ul { | |
margin: 0; | |
padding: 0; | |
list-style: none; | |
} | |
#panel-edit { | |
display: flex; | |
flex-flow: column nowrap; | |
} | |
#panel-edit div { | |
padding: 5px; | |
} | |
#panel-edit div:nth-child(2) { | |
flex: 1 0 0; | |
} | |
#panel-edit div:nth-child(3) { | |
text-align: right; | |
} | |
#panel-edit #text-title, #panel-edit #text-body { | |
display: block; | |
width: 100%; | |
height: 100%; | |
border: 1px solid #5279e7; | |
padding: 5px 10px; | |
resize: none; | |
font-size: 14px; | |
font-family: meiryo; | |
} | |
li { | |
margin: 5px 0; | |
padding: 5px; | |
border-bottom: 1px solid #5279e7; | |
} | |
li h1 { | |
font-size: 15px; | |
margin: 5px 0; | |
white-space: nowrap; | |
overflow: hidden; | |
text-overflow: ellipsis; | |
} | |
li p { | |
margin: 5px 0; | |
white-space: nowrap; | |
overflow: hidden; | |
text-overflow: ellipsis; | |
} | |
li a { | |
color: #5279e7; | |
} | |
li div { | |
text-align: right; | |
margin-right: 10px; | |
} | |
li input { | |
margin-left: calc(100% - 45px); | |
} | |
#panel-draft li { | |
cursor: pointer; | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<meta charset="utf-8"> | |
<link rel="stylesheet" href="popup.css"> | |
<script src="popup.js" defer></script> | |
<div class="container"> | |
<aside> | |
<div id="edit" class="active">書く</div> | |
<div id="draft">下書</div> | |
<div id="list">一覧</div> | |
<div id="opentab" title="タブで開く">➚</div> | |
</aside> | |
<main> | |
<section id="panel-edit" class="active"> | |
<div><input id="text-title"></div> | |
<div><textarea id="text-body"></textarea></div> | |
<div><input id="draft-btn" type="button" value="下書き"><input id="submit-btn" type="button" value="投稿"></div> | |
</section> | |
<section id="panel-draft"> | |
<ul></ul> | |
</section> | |
<section id="panel-list"> | |
<ul></ul> | |
</section> | |
</main> | |
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
async function parsePage(url){ | |
const res = await fetch(url, {credentials: "include"}) | |
const html = await res.text() | |
return new DOMParser().parseFromString(html, "text/html") | |
} | |
async function getURLs(top_url){ | |
const doc = await parsePage(top_url) | |
const menu_links = [...doc.querySelectorAll("#globalheader a")] | |
// ログアウトがみつからないのはログインしていない状態 | |
if(!menu_links.find(e => e.innerHTML.trim() === "ログアウト")){ | |
return {} | |
} | |
const my_page = menu_links.find(e => e.innerHTML.trim().endsWith("の日記")).getAttribute("href") | |
const edit_page = menu_links.find(e => e.innerHTML.trim() === "日記を書く").getAttribute("href") | |
return { | |
my_page: new URL(my_page, urls.top).href, | |
edit_page: new URL(edit_page, urls.top).href, | |
} | |
} | |
async function getEditForm(edit_url){ | |
const doc = await parsePage(edit_url) | |
return doc.querySelector("#body form") | |
} | |
async function post(title, body){ | |
if(!urls.edit_page){ | |
alert("ログインしていません") | |
return | |
} | |
const form = await getEditForm(urls.edit_page) | |
form.querySelector("#text-title").value = title | |
form.querySelector("#text-body").value = body | |
form.action = urls.edit_page | |
const frame = document.createElement("iframe") | |
frame.hidden = true | |
document.body.append(frame) | |
return new Promise(s => { | |
frame.contentDocument.body.append(form) | |
frame.onload = event => { | |
frame.remove() | |
s() | |
} | |
frame.contentDocument.querySelector(`input[value="この内容を登録する"]`).click() | |
}) | |
} | |
async function getMyEntries(){ | |
if(!urls.my_page){ | |
alert("ログインしていません") | |
return | |
} | |
const doc = await parsePage(urls.my_page) | |
return Array.from(doc.querySelectorAll(".sanchor"), e => { | |
const title = e.closest("h3").textContent | |
const href = new URL(e.closest("a").getAttribute("href"), urls.top).href | |
const tb = e.closest(".section").querySelector(".sectionfooter").textContent.match(/記事への反応\(([0-9]+)\)/)[1] | |
return {title, tb, href} | |
}) | |
} | |
const urls = { | |
top: "https://anond.hatelabo.jp/", | |
} | |
const text_title = document.querySelector("#text-title") | |
const text_body = document.querySelector("#text-body") | |
!async function(){ | |
Object.assign(urls, await getURLs(urls.top)) | |
if(Object.keys(urls).length === 1){ | |
alert("ログインしていません") | |
} | |
}() | |
async function loadList(){ | |
const entries = await getMyEntries() | |
const ul = document.querySelector("#panel-list ul") | |
ul.innerHTML = "" | |
for(const item of entries){ | |
const li = document.createElement("li") | |
li.innerHTML = ` | |
<h1><a href="${item.href}" target="_blank">${item.title}</a></h1> | |
<div>Trackback: ${item.tb}</div> | |
` | |
ul.append(li) | |
} | |
} | |
function loadDraftList(){ | |
const drafts = JSON.parse(localStorage.drafts || "[]") | |
const ul = document.querySelector("#panel-draft ul") | |
ul.innerHTML = "" | |
// 新しいのを上に表示する | |
for(const draft of drafts.sort((a, b) => b.lastUpdated - a.lastUpdated)){ | |
const li = document.createElement("li") | |
li.innerHTML = ` | |
<h1>${draft.title}</h1> | |
<p>${draft.body}</p> | |
<input type="button" value="削除"> | |
` | |
ul.append(li) | |
} | |
} | |
function saveDraft(title, body){ | |
const drafts = JSON.parse(localStorage.drafts || "[]") | |
drafts.push({ | |
title, | |
body, | |
lastUpdated: Date.now(), | |
}) | |
localStorage.drafts = JSON.stringify(drafts) | |
} | |
function deleteDraft(title, body){ | |
const drafts = JSON.parse(localStorage.drafts || "[]") | |
const idx = drafts.findIndex(e => e.title === title && e.body === body) | |
drafts.splice(idx, 1) | |
localStorage.drafts = JSON.stringify(drafts) | |
} | |
function switchPanel(name){ | |
for(const e of document.querySelectorAll(".active")){ | |
e.classList.remove("active") | |
} | |
for(const e of document.querySelectorAll(`#${name},#panel-${name}`)){ | |
e.classList.add("active") | |
} | |
} | |
function onswitch(name){ | |
if(name === "draft"){ | |
loadDraftList() | |
}else if(name === "list"){ | |
loadList() | |
} | |
} | |
function escapeHtml(text){ | |
return Object.assign(document.createElement("div"), { | |
textContent: text, | |
}).innerHTML | |
} | |
document.querySelector("aside").onclick = event => { | |
const btn = event.target.closest("aside>div") | |
if (!btn) return | |
const type = btn.id | |
switch(type){ | |
case "edit": | |
case "draft": | |
case "list": | |
switchPanel(type) | |
onswitch(type) | |
break | |
case "opentab": | |
window.open(location.href) | |
break | |
} | |
} | |
document.querySelector("#draft-btn").onclick = event => { | |
saveDraft(text_title.value, text_body.value) | |
} | |
document.querySelector("#submit-btn").onclick = async event => { | |
await post(text_title.value, text_body.value) | |
alert("投稿しました\n一覧 から確認してください") | |
} | |
document.querySelector("#panel-draft").onclick = event => { | |
const draft = event.target.closest("li") | |
if (!draft) return | |
const title = draft.querySelector("h1").textContent | |
const body = draft.querySelector("p").textContent | |
const del = event.target.closest("input") | |
if (del) { | |
deleteDraft(title, body) | |
loadDraftList() | |
return | |
} | |
text_title.value = title | |
text_body.value = body | |
switchPanel("edit") | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment