├── LICENSE ├── README.md ├── manifest.json ├── screenshot.png └── src └── inject ├── inject.css └── inject.js /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 mpyw 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Qiita Unstocker 2 | 3 | 個別ページに飛ばずに一覧からストック解除できる Chrome Extension 4 | 5 | ## インストール 6 | 7 | 1. [「Download ZIP」](https://github.com/mpyw/qiita-unstocker/archive/master.zip)で落としてきて展開 8 | 2. [chrome://extensions](chrome://extensions) を開く 9 | 3. 「デベロッパーモード」にチェックを入れる 10 | 4. 「パッケージ化されていない拡張機能を読み込む」で先ほど展開した **フォルダ** を選択
(`manifest.json`などのファイルが直下にくるフォルダ) 11 | 12 | ## スクリーンショット 13 | 14 | ![screenshot](screenshot.png) 15 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Qiita Unstocker", 3 | "version": "0.0.1", 4 | "manifest_version": 2, 5 | "description": "Unstock/Unstock取消を一覧に表示するエクステンション", 6 | "homepage_url": "https://github.com/mpyw/qiita-unstocker", 7 | "permissions": [ 8 | "http://qiita.com/*", 9 | "https://qiita.com/*" 10 | ], 11 | "content_scripts": [ 12 | { 13 | "matches": [ 14 | "http://qiita.com/*", 15 | "https://qiita.com/*" 16 | ], 17 | "css": [ 18 | "src/inject/inject.css" 19 | ] 20 | }, 21 | { 22 | "matches": [ 23 | "http://qiita.com/*", 24 | "https://qiita.com/*" 25 | ], 26 | "js": [ 27 | "src/inject/inject.js" 28 | ], 29 | "run_at": "document_end" 30 | } 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpyw-junks/qiita-unstocker/937e232152d96867f809ef784669e6c6af6cb8af/screenshot.png -------------------------------------------------------------------------------- /src/inject/inject.css: -------------------------------------------------------------------------------- 1 | button.unstock-button { 2 | /* Please decorate buttons !! */ 3 | } 4 | -------------------------------------------------------------------------------- /src/inject/inject.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | if (location.pathname === `/${document.body.querySelector('script').textContent.match(/"url_name":"([^"]+)"/)[1]}/stock`) { 4 | 5 | const token = document.head.querySelector('meta[name=csrf-token]').content; 6 | const articles = document.body.querySelectorAll('article.media.ItemLink'); 7 | 8 | for (const article of articles) { 9 | 10 | const ul = article.querySelector('ul.ItemLink__status'); 11 | const li = document.createElement('li'); 12 | const button = document.createElement('button'); 13 | 14 | let stocked = true; 15 | button.classList.add('unstocker-button'); 16 | button.textContent = 'アンストック'; 17 | button.onclick = () => { 18 | 19 | button.disabled = true; 20 | const href = article.querySelector('div.ItemLink__title a.u-link-no-underline').href; 21 | const action = stocked ? 'unstock' : 'stock'; 22 | const afterLabel = stocked ? 'ストック' : 'アンストック'; 23 | 24 | fetch(`${href}/${action}`, { 25 | method: 'POST', 26 | credentials: 'include', 27 | headers: new Headers({ 28 | 'X-CSRF-Token': token, 29 | }), 30 | }).then(() => { 31 | stocked = !stocked; 32 | button.textContent = afterLabel; 33 | }).catch(() => { 34 | alert('Request Failed !'); 35 | }).then(() => { 36 | button.disabled = false; 37 | }); 38 | 39 | }; 40 | 41 | li.appendChild(button); 42 | ul.appendChild(li); 43 | } 44 | 45 | } 46 | --------------------------------------------------------------------------------