您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Make v2ex easyer to use
- // ==UserScript==
- // @name V2ex supper helper
- // @namespace http://tampermonkey.net/
- // @version 0.1
- // @description Make v2ex easyer to use
- // @author You
- // @match https://v2ex.com/*
- // @icon https://www.google.com/s2/favicons?sz=64&domain=v2ex.com
- // @grant GM_addStyle
- // @grant GM_getValue
- // @grant GM_setValue
- // @run-at document-start
- // @license MIT
- // ==/UserScript==
- class PageManager {
- constructor() {
- this.conditionalWorks = [];
- this.activeConditionWork = null;
- setInterval(() => {
- this.conditionalWorks.forEach(cw => {
- cw.conditionWork.report();
- });
- }, 1000);
- }
- stage(name) {
- var conditionalWork = new ConditionalWork(name);
- this.conditionalWorks.push({
- name: name,
- conditionWork: conditionalWork,
- });
- return conditionalWork;
- }
- off(name) {
- var check = this.conditionalWorks.find(cw => cw.name === name);
- if (check) {
- check.conditionWork.off();
- }
- }
- }
- class ConditionalWork {
- constructor(name) {
- this.__name = name;
- this.__conditionFn = null;
- this.__actionFn = null;
- this.__running = false;
- this.__timeDuration = 0;
- this.__intervalMethod = 'interval';
- this.__handlerId = null;
- this.__logLevel = 0;
- this.__log = console.log;
- }
- log = (message, level) => {
- if (isNaN(level)) level = 1;
- if (this.__logLevel > 0 && level >= this.__logLevel) {
- this.__log(message);
- }
- }
- __checkBeforeRun() {
- if (!this.__conditionFn) {
- throw new Error("Condition function must be defined");
- }
- if (!this.__timeDuration) {
- throw new Error(`${this.__intervalMethod} must be defined`);
- }
- }
- __complete() {
- this.__running = false;
- this.__handlerId = null;
- }
- logLevel(level) {
- this.__logLevel = level;
- return this;
- }
- asTimeout(timeout) {
- if (this.__intervalMethod === 'interval') {
- // initial set for timeout
- if (isNaN(timeout)) {
- throw new Error("Timeout must be a number");
- } else {
- if (timeout < 1) {
- throw new Error("timeout must be greater than 0");
- } else {
- timeout = Math.floor(timeout);
- }
- }
- } else {
- throw new Error("Interval already set");
- }
- this.__timeDuration = timeout;
- this.__intervalMethod = 'timeout';
- return this;
- }
- on(conditionFn) {
- if (typeof conditionFn !== "function") {
- throw new Error("Condition function must be a function");
- }
- if (typeof this.__conditionFn === "function") {
- throw new Error("Condition function already defined");
- }
- this.__conditionFn = conditionFn;
- return this;
- }
- act(actionFn) {
- // on must be called before act
- if (typeof this.__conditionFn !== "function") {
- throw new Error("Condition function must be defined first");
- }
- if (typeof actionFn !== "function") {
- throw new Error("Action function must be a function");
- }
- this.__actionFn = actionFn;
- return this;
- }
- every(interval) {
- if (!isNaN(this.__timeDuration) && this.__timeDuration !== 0) {
- throw new Error("Interval already set");
- }
- if (isNaN(interval)) {
- throw new Error("Interval must be a number");
- } else {
- if (interval < 1) {
- throw new Error("Interval must be greater than 0");
- } else {
- interval = Math.floor(interval);
- }
- }
- this.__timeDuration = interval;
- return this;
- }
- __hanlder = (cancelFn) => {
- let shouldContinue = false;
- if (this.__conditionFn()) {
- shouldContinue = this.__actionFn(this.log);
- } else {
- shouldContinue = true;
- }
- if (shouldContinue === false) {
- cancelFn(this.__handlerId);
- this.__complete();
- }
- }
- __timeoutHanlder = () => {
- this.__hanlder(clearTimeout);
- setTimeout(() => {
- this.__timeoutHanlder();
- }, this.__timeDuration);
- }
- __intervalHandler = () => {
- if (!this.__handlerId) {
- this.__handlerId = setInterval(this.__intervalHandler, this.__timeDuration);
- } else {
- this.__hanlder(clearInterval);
- }
- }
- run = () => {
- // check basic configurations: interval, conditionFn, isRunning
- this.__checkBeforeRun();
- if (this.__running) {
- this.log("Work is already running", 1);
- return;
- }
- switch (this.__intervalMethod) {
- case 'interval':
- this.__intervalHandler();
- this.__running = true;
- break;
- case 'timeout':
- this.__timeoutHanlder();
- this.__running = true;
- default:
- throw new Error("Interval method not defined");
- }
- }
- report() {
- if (this.__running) {
- this.log(`${this.__name} is running`, 1);
- } else {
- this.log(`${this.__name} is not running`, 2);
- }
- }
- }
- (function () {
- // 'use strict';
- GM_addStyle(`
- .cell.read {
- background-color: antiquewhite;
- }
- `);
- function getWebsite() {
- // Get website domain
- return window.location.hostname;
- }
- function getJsonDataObject() {
- return JSON.parse(GM_getValue(getWebsite(), '{}'));
- }
- function setUrlRead(url) {
- // Set url as read
- var data = getJsonDataObject();
- data[url] = true;
- GM_setValue(getWebsite(), JSON.stringify(data));
- }
- function isUrlRead(url) {
- // Check if url is read
- var data = getJsonDataObject();
- return data[url] === true;
- }
- function getMainPageCells() {
- // Get main page cells
- return document.querySelectorAll('#Main div.cell.item');
- }
- function getTopicsPageCells() {
- // Get topics page cells
- return document.querySelectorAll('#TopicsNode .cell');
- }
- function getCells() {
- const mainCells = getMainPageCells();
- const topicsCells = getTopicsPageCells();
- if (mainCells.length > 0) {
- return mainCells;
- }
- if (topicsCells.length > 0) {
- return topicsCells;
- }
- return [];
- }
- function findLinks() {
- return Array.from(getCells()).map((cell) => { return cell.querySelector('.item_title a').href; });
- }
- var pm = new PageManager();
- const condition = () => {
- return findLinks().length > 0;
- }
- // record current page as read
- setUrlRead(window.location.href);
- pm.stage('Add color to viewd topics')
- .on(condition)
- .logLevel(1)
- .act((logger) => {
- logger('Add color to viewd topics');
- // find all cells
- var cells = getCells();
- // add color to read topics
- Array.from(cells).forEach((cell) => {
- const link = cell.querySelector('.item_title a').href;
- logger(`${link} is ${isUrlRead(link) ? 'read' : 'unread'}`);
- if (isUrlRead(link)) {
- cell.classList.add('read');
- }
- });
- logger('Done', 2);
- return false;
- })
- .every(1000)
- .run();
- })();