您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Google日历键盘键盘操作,功能:Alt+hjkl 移动日程
当前为
// ==UserScript== // @name [SNOLAB] Google Calendar keyboard enhance // @name:zh [SNOLAB] Google 日历键盘操作 // @namespace https://userscript.snomiao.com/ // @version 0.1.0 // @description Google日历键盘键盘操作,功能:Alt+hjkl 移动日程 // @author [email protected] // @match *://calendar.google.com/* // @grant none // @contributionURL https://snomiao.com/donate // @supportURL https://github.com/snomiao/userscript/issues // ==/UserScript== // // 1. event move enhance // - date time input change // - event drag // 2. journal view text copy for the day-summary // /* eslint-disable */ // clipboardy/browser var clipboard = {}; clipboard.write = async (text) => { await navigator.clipboard.writeText(text); }; clipboard.read = async () => navigator.clipboard.readText(); clipboard.readSync = () => { throw new Error("`.readSync()` is not supported in browsers!"); }; clipboard.writeSync = () => { throw new Error("`.writeSync()` is not supported in browsers!"); }; var browser_default = clipboard; // hotkey-mapper var { keys } = Object; function mapObject(fn, obj) { if (arguments.length === 1) { return (_obj) => mapObject(fn, _obj); } let index = 0; const objKeys = keys(obj); const len = objKeys.length; const willReturn = {}; while (index < len) { const key = objKeys[index]; willReturn[key] = fn(obj[key], key, obj); index++; } return willReturn; } var mapObjIndexed = mapObject; function hotkeyMapper(mapping, options) { const handler = (event) => { const key = event.key.toLowerCase(); const code = event.code.toLowerCase(); const simp = code.replace(/^(?:Key|Digit|Numpad)/, ""); const map = new Proxy(event, { get: (target, p) => Boolean( { [`${key}Key`]: true, [`${code}Key`]: true, [`${simp}Key`]: true, }[p] ?? target[p] ), }); const mods = "meta+alt+shift+ctrl"; mapObjIndexed((fn, hotkey) => { const conds = `${mods}+${hotkey.toLowerCase()}` .replace(/win|command|search/, "meta") .replace(/control/, "ctrl") .split("+") .map((k, i) => [k, i >= 4 === map[`${k}Key`]]); if (!Object.entries(Object.fromEntries(conds)).every(([, ok]) => ok)) return; event.stopPropagation(), event.preventDefault(); return fn(event); }, mapping); }; window.addEventListener(options?.on ?? "keydown", handler, options); return function unload() { window.removeEventListener(options?.on ?? "keydown", handler, options); }; } // rambda var cloneList = (list) => Array.prototype.slice.call(list); function curry(fn, args = []) { return (..._args) => ((rest) => (rest.length >= fn.length ? fn(...rest) : curry(fn, rest)))([ ...args, ..._args, ]); } function adjustFn(index, replaceFn2, list) { const actualIndex = index < 0 ? list.length + index : index; if (index >= list.length || actualIndex < 0) return list; const clone = cloneList(list); clone[actualIndex] = replaceFn2(clone[actualIndex]); return clone; } var adjust = curry(adjustFn); function always(x) { return (_) => x; } var { isArray } = Array; function assocFn(prop2, newValue, obj) { return Object.assign({}, obj, { [prop2]: newValue, }); } var assoc = curry(assocFn); function _isInteger(n) { return n << 0 === n; } var isInteger = Number.isInteger || _isInteger; function assocPathFn(path2, newValue, input) { const pathArrValue = typeof path2 === "string" ? path2.split(".").map((x) => (isInteger(Number(x)) ? Number(x) : x)) : path2; if (pathArrValue.length === 0) { return newValue; } const index = pathArrValue[0]; if (pathArrValue.length > 1) { const condition = typeof input !== "object" || input === null || !input.hasOwnProperty(index); const nextInput = condition ? isInteger(pathArrValue[1]) ? [] : {} : input[index]; newValue = assocPathFn( Array.prototype.slice.call(pathArrValue, 1), newValue, nextInput ); } if (isInteger(index) && isArray(input)) { const arr = cloneList(input); arr[index] = newValue; return arr; } return assoc(index, newValue, input); } var assocPath = curry(assocPathFn); function clampFn(min, max, input) { if (min > max) { throw new Error( "min must not be greater than max in clamp(min, max, value)" ); } if (input >= min && input <= max) return input; if (input > max) return max; if (input < min) return min; } var clamp = curry(clampFn); var ReduceStopper = class { constructor(value) { this.value = value; } }; function reduceFn(reducer, acc, list) { if (!isArray(list)) { throw new TypeError("reduce: list must be array or iterable"); } let index = 0; const len = list.length; while (index < len) { acc = reducer(acc, list[index], index, list); if (acc instanceof ReduceStopper) { return acc.value; } index++; } return acc; } var reduce = curry(reduceFn); var { keys: keys$1 } = Object; function isFalsy(input) { return input === void 0 || input === null || Number.isNaN(input) === true; } function defaultTo(defaultArgument, input) { if (arguments.length === 1) { return (_input) => defaultTo(defaultArgument, _input); } return isFalsy(input) ? defaultArgument : input; } function type(input) { if (input === null) { return "Null"; } else if (input === void 0) { return "Undefined"; } else if (Number.isNaN(input)) { return "NaN"; } const typeResult = Object.prototype.toString.call(input).slice(8, -1); return typeResult === "AsyncFunction" ? "Promise" : typeResult; } function _indexOf(valueToFind, list) { if (!isArray(list)) { throw new Error(`Cannot read property 'indexOf' of ${list}`); } const typeOfValue = type(valueToFind); if (!["Object", "Array", "NaN", "RegExp"].includes(typeOfValue)) return list.indexOf(valueToFind); let index = -1; let foundIndex = -1; const { length } = list; while (++index < length && foundIndex === -1) { if (equals(list[index], valueToFind)) { foundIndex = index; } } return foundIndex; } function _arrayFromIterator(iter) { const list = []; let next; while (!(next = iter.next()).done) { list.push(next.value); } return list; } function _equalsSets(a, b) { if (a.size !== b.size) { return false; } const aList = _arrayFromIterator(a.values()); const bList = _arrayFromIterator(b.values()); const filtered = aList.filter( (aInstance) => _indexOf(aInstance, bList) === -1 ); return filtered.length === 0; } function parseError(maybeError) { const typeofError = maybeError.__proto__.toString(); if (!["Error", "TypeError"].includes(typeofError)) return []; return [typeofError, maybeError.message]; } function parseDate(maybeDate) { if (!maybeDate.toDateString) return [false]; return [true, maybeDate.getTime()]; } function parseRegex(maybeRegex) { if (maybeRegex.constructor !== RegExp) return [false]; return [true, maybeRegex.toString()]; } function equals(a, b) { if (arguments.length === 1) return (_b) => equals(a, _b); const aType = type(a); if (aType !== type(b)) return false; if (aType === "Function") { return a.name === void 0 ? false : a.name === b.name; } if (["NaN", "Undefined", "Null"].includes(aType)) return true; if (aType === "Number") { if (Object.is(-0, a) !== Object.is(-0, b)) return false; return a.toString() === b.toString(); } if (["String", "Boolean"].includes(aType)) { return a.toString() === b.toString(); } if (aType === "Array") { const aClone = Array.from(a); const bClone = Array.from(b); if (aClone.toString() !== bClone.toString()) { return false; } let loopArrayFlag = true; aClone.forEach((aCloneInstance, aCloneIndex) => { if (loopArrayFlag) { if ( aCloneInstance !== bClone[aCloneIndex] && !equals(aCloneInstance, bClone[aCloneIndex]) ) { loopArrayFlag = false; } } }); return loopArrayFlag; } const aRegex = parseRegex(a); const bRegex = parseRegex(b); if (aRegex[0]) { return bRegex[0] ? aRegex[1] === bRegex[1] : false; } else if (bRegex[0]) return false; const aDate = parseDate(a); const bDate = parseDate(b); if (aDate[0]) { return bDate[0] ? aDate[1] === bDate[1] : false; } else if (bDate[0]) return false; const aError = parseError(a); const bError = parseError(b); if (aError[0]) { return bError[0] ? aError[0] === bError[0] && aError[1] === bError[1] : false; } if (aType === "Set") { return _equalsSets(a, b); } if (aType === "Object") { const aKeys = Object.keys(a); if (aKeys.length !== Object.keys(b).length) { return false; } let loopObjectFlag = true; aKeys.forEach((aKeyInstance) => { if (loopObjectFlag) { const aValue = a[aKeyInstance]; const bValue = b[aKeyInstance]; if (aValue !== bValue && !equals(aValue, bValue)) { loopObjectFlag = false; } } }); return loopObjectFlag; } return false; } function prop(propToFind, obj) { if (arguments.length === 1) return (_obj) => prop(propToFind, _obj); if (!obj) return void 0; return obj[propToFind]; } function eqPropsFn(property, objA, objB) { return equals(prop(property, objA), prop(property, objB)); } var eqProps = curry(eqPropsFn); function createPath(path2, delimiter = ".") { return typeof path2 === "string" ? path2.split(delimiter) : path2; } function path(pathInput, obj) { if (arguments.length === 1) return (_obj) => path(pathInput, _obj); if (obj === null || obj === void 0) { return void 0; } let willReturn = obj; let counter = 0; const pathArrValue = createPath(pathInput); while (counter < pathArrValue.length) { if (willReturn === null || willReturn === void 0) { return void 0; } if (willReturn[pathArrValue[counter]] === null) return void 0; willReturn = willReturn[pathArrValue[counter]]; counter++; } return willReturn; } function ifElseFn(condition, onTrue, onFalse) { return (...input) => { const conditionResult = typeof condition === "boolean" ? condition : condition(...input); if (conditionResult === true) { return onTrue(...input); } return onFalse(...input); }; } var ifElse = curry(ifElseFn); function baseSlice(array, start, end) { let index = -1; let { length } = array; end = end > length ? length : end; if (end < 0) { end += length; } length = start > end ? 0 : (end - start) >>> 0; start >>>= 0; const result = Array(length); while (++index < length) { result[index] = array[index + start]; } return result; } function is(targetPrototype, x) { if (arguments.length === 1) return (_x) => is(targetPrototype, _x); return ( (x != null && x.constructor === targetPrototype) || x instanceof targetPrototype ); } function updateFn(index, newValue, list) { const clone = cloneList(list); if (index === -1) return clone.fill(newValue, index); return clone.fill(newValue, index, index + 1); } var update = curry(updateFn); function maxByFn(compareFn, x, y) { return compareFn(y) > compareFn(x) ? y : x; } var maxBy = curry(maxByFn); function mergeWithFn(mergeFn, a, b) { const willReturn = {}; Object.keys(a).forEach((key) => { if (b[key] === void 0) { willReturn[key] = a[key]; } else { willReturn[key] = mergeFn(a[key], b[key]); } }); Object.keys(b).forEach((key) => { if (willReturn[key] !== void 0) return; if (a[key] === void 0) { willReturn[key] = b[key]; } else { willReturn[key] = mergeFn(a[key], b[key]); } }); return willReturn; } var mergeWith = curry(mergeWithFn); function minByFn(compareFn, x, y) { return compareFn(y) < compareFn(x) ? y : x; } var minBy = curry(minByFn); function ownKeys(object, enumerableOnly) { var keys2 = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys2.push.apply(keys2, symbols); } return keys2; } function _objectSpread2(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties( target, Object.getOwnPropertyDescriptors(source) ) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty( target, key, Object.getOwnPropertyDescriptor(source, key) ); }); } return target; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value, enumerable: true, configurable: true, writable: true, }); } else { obj[key] = value; } return obj; } function isIterable(input) { return Array.isArray(input) || type(input) === "Object"; } function modifyFn(property, fn, iterable) { if (!isIterable(iterable)) return iterable; if (iterable[property] === void 0) return iterable; if (isArray(iterable)) { return updateFn(property, fn(iterable[property]), iterable); } return _objectSpread2( _objectSpread2({}, iterable), {}, { [property]: fn(iterable[property]), } ); } var modify = curry(modifyFn); function modifyPathFn(pathInput, fn, object) { const path$1 = createPath(pathInput); if (path$1.length === 1) { return _objectSpread2( _objectSpread2({}, object), {}, { [path$1[0]]: fn(object[path$1[0]]), } ); } if (path(path$1, object) === void 0) return object; const val = modifyPath( Array.prototype.slice.call(path$1, 1), fn, object[path$1[0]] ); if (val === object[path$1[0]]) { return object; } return assoc(path$1[0], val, object); } var modifyPath = curry(modifyPathFn); function moveFn(fromIndex, toIndex, list) { if (fromIndex < 0 || toIndex < 0) { throw new Error("Rambda.move does not support negative indexes"); } if (fromIndex > list.length - 1 || toIndex > list.length - 1) return list; const clone = cloneList(list); clone[fromIndex] = list[toIndex]; clone[toIndex] = list[fromIndex]; return clone; } var move = curry(moveFn); function multiply(x, y) { if (arguments.length === 1) return (_y) => multiply(x, _y); return x * y; } var Identity = (x) => ({ x, map: (fn) => Identity(fn(x)), }); function overFn(lens, fn, object) { return lens((x) => Identity(fn(x)))(object).x; } var over = curry(overFn); function pathEqFn(pathToSearch, target, input) { return equals(path(pathToSearch, input), target); } var pathEq = curry(pathEqFn); function pathOrFn(defaultValue, pathInput, obj) { return defaultTo(defaultValue, path(pathInput, obj)); } var pathOr = curry(pathOrFn); var product = reduce(multiply, 1); function propEqFn(propToFind, valueToMatch, obj) { if (!obj) return false; return equals(valueToMatch, prop(propToFind, obj)); } var propEq = curry(propEqFn); function propIsFn(targetPrototype, property, obj) { return is(targetPrototype, obj[property]); } var propIs = curry(propIsFn); function propOrFn(defaultValue, property, obj) { if (!obj) return defaultValue; return defaultTo(defaultValue, obj[property]); } var propOr = curry(propOrFn); function propSatisfiesFn(predicate, property, obj) { return predicate(prop(property, obj)); } var propSatisfies = curry(propSatisfiesFn); function replaceFn(pattern, replacer, str) { return str.replace(pattern, replacer); } var replace = curry(replaceFn); function setFn(lens, replacer, x) { return over(lens, always(replacer), x); } var set = curry(setFn); function sliceFn(from, to, list) { return list.slice(from, to); } var slice = curry(sliceFn); function take(howMany, listOrString) { if (arguments.length === 1) return (_listOrString) => take(howMany, _listOrString); if (howMany < 0) return listOrString.slice(); if (typeof listOrString === "string") return listOrString.slice(0, howMany); return baseSlice(listOrString, 0, howMany); } var isFunction = (x) => ["Promise", "Function"].includes(type(x)); function tryCatch(fn, fallback) { if (!isFunction(fn)) { throw new Error(`R.tryCatch | fn '${fn}'`); } const passFallback = isFunction(fallback); return (...inputs) => { try { return fn(...inputs); } catch (e) { return passFallback ? fallback(e, ...inputs) : fallback; } }; } function whenFn(predicate, whenTrueFn, input) { if (!predicate(input)) return input; return whenTrueFn(input); } var when = curry(whenFn); function zipWithFn(fn, x, y) { return take(x.length > y.length ? y.length : x.length, x).map( (xInstance, i) => fn(xInstance, y[i]) ); } var zipWith = curry(zipWithFn); // $$ function $$(sel2, el = document) { return [...el.querySelectorAll(sel2)]; } // po2dt var SPAN_PRECISION = 15 * 6e4; function po2dt([dday, dtime]) { return dday * 864e5 + dtime * SPAN_PRECISION; } // google-calendar-keys var gkcs_unload = globalThis.gkcs_unload; gkcs_unload?.(); globalThis.gkcs_unload = main(); globalThis.gkcs_verbose = true; var { draggingGet: dg, draggingSet: ds } = draggingUse(); var lastpos = null; function touchHandler(event) { const touches = event.changedTouches; if (touches.length > 1) return; const first = touches[0]; const type2 = { touchstart: "mousedown", touchmove: "mousemove", touchend: "mouseup", }[event.type]; if (!type2) return; var simulatedEvent = new MouseEvent(type2, { bubbles: true, cancelable: true, view: window, detail: 1, screenX: first.screenX, screenY: first.screenY, clientX: first.clientX, clientY: first.clientY, ctrlKey: false, altKey: false, shiftKey: false, metaKey: false, button: 0, relatedTarget: null, }); first.target.dispatchEvent(simulatedEvent); if (type2 === "mousedown") lastpos = [first.screenX, first.screenY]; if (type2 === "mousemove") event.preventDefault(); if ( type2 === "mouseup" && JSON.stringify(lastpos) === JSON.stringify([first.screenX, first.screenY]) ) event.preventDefault(); } function initTouchEventerConverter() { const e = document.body; e.appendChild( Object.assign(document.createElement("div"), { innerHTML: '<style>[role="presentation"]{touch-action:none}</style>', }).children[0] ); e.addEventListener("touchstart", touchHandler, true); e.addEventListener("touchmove", touchHandler, true); e.addEventListener("touchend", touchHandler, true); e.addEventListener("touchcancel", touchHandler, true); } function main() { initTouchEventerConverter(); console.clear(); const unloaders = []; unloaders.push( hotkeyMapper( { "ctrl+b": async () => { const menuBtn = $visiable(sel.Menu); menuBtn?.click(); }, "alt+v": async () => await cpr(), "alt+k": () => eventMove([0, -1]), "alt+j": () => eventMove([0, 1]), "alt+h": () => eventMove([-1, 0]), "alt+l": () => eventMove([1, 0]), "alt+shift+k": () => eventExpand([0, -1]), "alt+shift+j": () => eventExpand([0, 1]), "alt+shift+h": () => eventExpand([-1, 0]), "alt+shift+l": () => eventExpand([1, 0]), }, { capture: true } ) ); return () => [...unloaders].reverse().forEach((e) => e?.()); } async function cpr() { const r = $$("input,[role=button]") .map((element) => { const { ps, deep } = onlyPatternSelectorGenerate(element); const label = element.ariaLabel ?? ""; return { e: element, label, ps, deep, }; }) .filter((e) => Boolean(e.label)); const cpr2 = r.map(({ e, ...r2 }) => r2); console.table(r); globalThis.patternSelectorGenerate = patternSelectorGenerate; await browser_default.write(JSON.stringify(cpr2, null, 2)); } function useListener(target = window) { return (event, onEvent, options) => { target.addEventListener(event, onEvent, options); const unload = () => target.removeEventListener(event, onEvent, options); return unload; }; } async function eventExpand([dx, dy] = [0, 0]) { if (dy && (await timeAddTry())) return; return tryCatch( () => eventDrag([dx, dy], { expand: true }), () => inputDateTimeChange(0, po2dt([dx, dy])) )(null); } async function eventMove([dx, dy] = [0, 0]) { if (dy && (await timeAddTry())) return; return tryCatch( () => eventDrag([dx, dy]), () => inputDateTimeChange(po2dt([dx, dy]), 0) )(null); } async function inputValueSet(el, value) { console.log("inputValueSet", el, value); if (!el) throw new Error("no element"); if (void 0 === value) throw new Error("no value"); el.value = value; el.dispatchEvent(new InputEvent("input", { bubbles: true })); el.dispatchEvent(new Event("change", { bubbles: true })); el.dispatchEvent( new KeyboardEvent("keydown", { bubbles: true, keyCode: 13, }) ); el.focus(); await sleep(0); el.blur(); } async function dateInputParse(dateInput, timeInput) { const dataDate = dateInput.getAttribute("data-date"); const dataIcalElement = parentList(dateInput).find((e) => e.getAttribute("data-ical") ); if (!dataIcalElement) throw new Error("dataIcalElement not found"); const dataIcal = dataIcalElement.getAttribute("data-ical"); const datestringRaw = dataDate || dataIcal; if (!datestringRaw) throw new Error("no datestring"); const dateString = datestringRaw.replace( /(\d{4})(\d{2})(\d{2})/, (_, a, b, c) => [a, b, c].join("-") ); const timeString = timeInput?.value || "00:00"; return new Date(`${dateString} ${timeString} Z`); } function dateParse(dateObj) { const m = dateObj .toISOString() .match(/(\d\d\d\d-\d\d-\d\d)T(\d\d:\d\d):\d\d\.\d\d\dZ/); if (!m) throw m; const [date, time] = m.slice(1); return [date, time]; } var sel = { Menu: '[aria-label="\u30E1\u30A4\u30F3\u30C9\u30ED\u30EF\u30FC"]', Summary: [ '[aria-label="\u30BF\u30A4\u30C8\u30EB\u3068\u65E5\u6642\u3092\u8FFD\u52A0"]', '[aria-label="\u30BF\u30A4\u30C8\u30EB\u3092\u8FFD\u52A0"]', '[aria-label="\u30BF\u30A4\u30C8\u30EB"]', ].join(","), StartDate: '[aria-label="\u958B\u59CB\u65E5"]', StartTime: '[aria-label="\u958B\u59CB\u6642\u9593"]', EndTime: '[aria-label="\u7D42\u4E86\u6642\u9593"]', EndDate: '[aria-label="\u7D42\u4E86\u65E5"]', AllDay: '[aria-label="\u7D42\u65E5"]', TimeZone: '[aria-label="\u30BF\u30A4\u30E0\u30BE\u30FC\u30F3"]', Guests: '[aria-label="\u30B2\u30B9\u30C8"]', }; async function inputDateTimeChange(sdt = 0, edt = 0) { const startDateInputPeek = $visiable(sel.StartDate); if (!startDateInputPeek) { const tz = $visiable(sel.TimeZone); if (!tz) throw new Error("tz not found"); const editBtn = parentList(tz) ?.find((e) => e.querySelector('[role="button"]')) ?.querySelector('[role="button"]'); if (!editBtn) throw new Error("No editable input"); editBtn.click(); await sleep(64); } const startDateInput = $visiable(sel.StartDate); const startTimeInput = $visiable(sel.StartTime); const endTimeInput = $visiable(sel.EndTime); const endDateInput = $visiable(sel.EndDate); const endDateInput1 = endDateInput ?? startDateInput; if (!startDateInput) throw new Error("no startDateInput"); const startDate = await dateInputParse(startDateInput, startTimeInput); const endDate = await dateInputParse(endDateInput1, endTimeInput); const startDateObj1 = new Date(+startDate + sdt); const endDateObj1 = new Date(+endDate + edt); const [startDate0, startTime0] = dateParse(startDate); const [endDate0, endTime0] = dateParse(endDate); const [startDate1, startTime1] = dateParse(startDateObj1); const [endDate1, endTime1] = dateParse(endDateObj1); if (globalThis.gkcs_verbose) console.table({ startDate: startDate.toISOString(), endDate: endDate.toISOString(), startDateObj1: startDateObj1.toISOString(), endDateObj1: endDateObj1.toISOString(), }); if (globalThis.gkcs_verbose) console.table({ startDateInput: Boolean(startDateInput), startTimeInput: Boolean(startTimeInput), endDateInput: Boolean(endDateInput), endTimeInput: Boolean(endTimeInput), startDate0, startDate1, startTime0, startTime1, endDate0, endDate1, endTime0, endTime1, }); startDateInput && startDate1 !== startDate0 && (await inputValueSet(startDateInput, startDate1)); endDateInput && endDate1 !== endDate0 && (await inputValueSet(endDateInput, endDate1)); startTimeInput && startTime1 !== startTime0 && (await inputValueSet(startTimeInput, startTime1)); endTimeInput && endTime1 !== endTime0 && (await inputValueSet(endTimeInput, endTime1)); $visiable(sel.Summary)?.focus(); } async function timeAddTry() { const btn = $$("button").find((e) => ["Add time", "\u6642\u9593\u3092\u8FFD\u52A0"].includes(e.textContent ?? "") ); if (!btn) return 0; btn.click(); await sleep(64); return 1; } function eleVisiable(ele) { return (ele.getClientRects().length && ele) ?? false; } function $visiable(sel2, el = document) { return $$(sel2, el).filter(eleVisiable)[0] ?? null; } function parentList(el) { const parent = el?.parentElement; if (!parent) return []; return [parent, ...parentList(parent)]; } function sleep(ms = 0) { return new Promise((resolve) => setTimeout(resolve, ms)); } function mouseOpt([x, y]) { return { isTrusted: true, bubbles: true, button: 0, buttons: 1, cancelBubble: false, cancelable: true, clientX: x, clientY: y, movementX: 0, movementY: 0, x, y, }; } function centerGet(element) { const { x, y, width: w, height: h } = element.getBoundingClientRect(); return [x + w / 2, y + h / 2]; } function vec2add([x, y], [z, w]) { return [x + z, y + w]; } function $(sel2) { return document.querySelector(sel2); } function onlyPatternSelectorGenerate(element) { let deep = 0; let ps = ""; while (1) { ps = patternSelectorGenerate(element, { deep }); if ($$(ps).length <= 1) break; deep++; } return { ps, deep }; } function patternSelectorGenerate(element, { deep = 0 } = {}) { const psg = (e) => patternSelectorGenerate(e, { deep: deep - 1 }); const tag = element.tagName.toLowerCase(); const attrs = ["aria-label", "data-key", "role", "type"] .map((name) => attrSel(element, name)) .filter((e) => !e.match("\n")) .join(""); let base = `${tag}${attrs}`; if (!deep) return base; const next = element.nextElementSibling; if (next) base = `${base}:has(+${psg(next).replace(/:has\(.*?\)/g, "")})`; const prev = element.previousElementSibling; if (prev) return `${psg(prev)}+${base}`; const parent = element.parentElement; if (!parent) return base; const children = [...parent.children]; const nth = children.findIndex((v) => element === v) + 1; const nthl = children.length - nth + 1; if (!nth) return base; const parentSelector = psg(parent); return `${parentSelector}>${base}:nth-child(${nth}):nth-last-child(${nthl})`; } function attrSel(element, name) { const attr = element.getAttribute(name); const dataKey = attr !== null ? (attr ? `[${name}="${attr}"]` : `[${name}]`) : ""; return dataKey; } function eventDrag([dx, dy] = [0, 0], { expand = false } = {}) { const summaryInput = $visiable(sel.Summary); summaryInput?.focus(); if (!dg()) { const floatingBtns = [ .../* @__PURE__ */ new Set([ ...$$('div[role="button"]') .reverse() .filter((e) => getComputedStyle(e).zIndex === "5004"), ...$$('div:has([role="button"])') .reverse() .filter((e) => getComputedStyle(e).zIndex === "5004"), ]), ]; if (floatingBtns.length > 1) throw new Error("Multiple floating"); const floatingBtn = floatingBtns[0]; if (!floatingBtn) throw new Error("no event selected"); const target = expand ? floatingBtn.querySelector('*[data-dragsource-type="3"]') : floatingBtn; if (!target) throw new Error("no dragTarget exists"); console.log(target); const pos = centerGet(target); console.log("cpos", pos); ds({ pos, target }); posHint(pos); target.dispatchEvent(new MouseEvent("mousedown", mouseOpt(pos))); document.dispatchEvent(new MouseEvent("mousemove", mouseOpt(pos))); } if (dg()) { const container = $('[role="row"][data-dragsource-type="4"]'); const gridcells = [...container.querySelectorAll('[role="gridcell"]')]; const containerSize = container.getBoundingClientRect(); const w = containerSize.width / gridcells.length; const h = containerSize.height / 24 / 4; ds({ pos: vec2add(dg().pos, [dx * w, dy * h]), target: dg().target, }); const pos = dg().pos; posHint(pos); document.body.dispatchEvent(new MouseEvent("mousemove", mouseOpt(pos))); } const unload = useListener()("keyup", (e) => { if (!["AltLeft", "AltRight"].includes(e.code)) return; unload(); ds(null); document.dispatchEvent( new MouseEvent("mouseup", { bubbles: true, cancelable: true }) ); }); return unload; } function posHint(pos) { const div = document.createElement("div"); div.style.background = "red"; div.style.position = "absolute"; div.style.left = pos[0] + "px"; div.style.top = pos[1] + "px"; div.style.width = "1px"; div.style.height = "1px"; div.style.zIndex = "10000"; document.body.appendChild(div); setTimeout(() => div.remove(), 200); } function draggingUse() { const draggingGet = () => globalThis.gcks_dragging; const draggingSet = (s) => (globalThis.gcks_dragging = s); return { draggingGet, draggingSet }; }