您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Determines ideal goal value based on Created on and Due dates
当前为
// ==UserScript== // @name Lattice Goals - Add Ideal // @namespace Violentmonkey Scripts // @match http://*.latticehq.com/goals/* // @match https://*.latticehq.com/goals/* // @grant none // @version 1.1 // @author pedro-mass // @description Determines ideal goal value based on Created on and Due dates // @run-at document-idle // @require http://code.jquery.com/jquery-3.5.0.min.js // ==/UserScript== waitUntilTrue(shouldRun, run) function isPercentageBasedGoal() { // todo: make this actually check if there is a percentage based check? return true } function run() { console.log('Starting Lattice Goal Percentage calculations...') if (!isPercentageBasedGoal()) return const Dates = getDates() const GoalStats = getGoalStats() const percentageByDate = getRelativePercentage( Dates.start, Dates.end, Dates.current ) const idealValue = Math.round( getRelativeValue(GoalStats.start, GoalStats.goal, percentageByDate) ) const goalDirection = GoalStats.start <= GoalStats.end ? 1 : -1 return insertIdeal( idealValue, GoalStats.unit, GoalStats.current, goalDirection ) } function getRelativeValue(start, end, percentage) { const offset = start return (end - offset) * percentage + offset } function getDates() { const start = getDate(/^created\n\n/i) const end = getDate(/^due\n\n/i) const current = Date.now() return { start, end, current, } } function getGoalStats() { const unit = getValue(/^start: /i, 'span').replace(/\d+/, '') const getNumber = (regex) => Number(getValue(regex, 'span').replace(unit, '')) const start = getNumber(/^start: /i) const current = getNumber(/^current: /i) const goal = getNumber(/^goal: /i) return { start, goal, current, unit, } } function getProgressIndicator(ideal, current) { if (!current) return if (ideal <= current) { return '🎉' } return '😢' } function insertIdeal(ideal, unit, current, isAscendingGoal) { if (contains('span', /^ideally: /i).length > 0) { return } const progressIndicator = isAscendingGoal ? getProgressIndicator(ideal, current) : getProgressIndicator(current, ideal) const idealElem = `<span class="css-1mddpa2">Ideally: <span>${ideal}${unit}</span> <span>${progressIndicator}</span></span>` const goalsContainer = contains('div', /^start:/i) return $(goalsContainer).find('span').first().after(idealElem) } function shouldRun() { const pageCheck = contains('span', /^start: /i) return pageCheck != null && pageCheck.length > 0 } function getRelativePercentage(startDate, endDate, currentDate) { const offset = startDate endDate = endDate - offset currentDate = currentDate - offset return currentDate / endDate } function getDate(regex, selector = 'div') { return new Date(getValue(regex, selector)).getTime() } function getValue(regex, selector) { return replaceString(getText(first(contains(selector, regex))), regex, '') } function replaceString(string, searchString, newString) { if (!string) { console.warn('Received bad params', { string, searchString, newString }) return string } return string.replace(searchString, newString) } function contains(selector, text) { var elements = document.querySelectorAll(selector) return Array.prototype.filter.call(elements, function (element) { return RegExp(text).test(getText(element)) }) } function getText(element) { return element.innerText } function first(arr) { return arr[0] } function waitUntilTrue(checkFn, cb = (x) => x, timeout = 250) { const intervalId = setInterval(checkInterval, timeout) function checkInterval() { if (checkFn()) { clearInterval(intervalId) cb() } } }