您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
可以在Trello上设定任务难度的级别,并且在完成任务后,发放对应级别的奖励值。
- // ==UserScript==
- // @name Use Trello AS Playing Game
- // @name:zh-CN 将Trello改造为玩游戏做任务
- //
- // @description You can set the level of the difficulty for every job, and when you complete it, you can get the proper reward.
- // @description:zh-CN 可以在Trello上设定任务难度的级别,并且在完成任务后,发放对应级别的奖励值。
- //
- // @namespace http://tampermonkey.net/
- // @version 0.2
- // @match https://trello.com/b/*
- // @match https://trello.com/c/*
- // @author oraant
- // @grant none
- // ==/UserScript==
- // 更新:
- // 修复了Trello更新后,无法正常使用的问题。
- // 增加了自动触发功能,无需在看板页面等待,现在可以在卡片页面等待了。
- window.onload = function(){ // 必须这么搞,否则选择器获取不到东西。decument.ready也不行!
- // ------------------------------------------------------------------------------------------------------------------
- // 前置模块,存放通用的变量
- // ------------------------------------------------------------------------------------------------------------------
- var CustomFields = document.getElementsByClassName("custom-field-detail-item");
- var RandomButtons = document.getElementsByClassName("random-button");
- var WindowWrapper = document.getElementsByClassName("window-wrapper")[0];
- var CheckLists = document.getElementsByClassName("editable non-empty checklist-title");
- var CheckItems = document.getElementsByClassName("checklist-item");
- var CardTitle = document.getElementsByClassName('window-title');
- var LandTitle = document.getElementsByClassName('js-board-editing-target');
- // ------------------------------------------------------------------------------------------------------------------
- // common模块,存放通用的方法函数
- // ------------------------------------------------------------------------------------------------------------------
- // ----------------- 从自定义字段中存取配置 -----------------
- function GetDataDom(field){ // 获取指定的自定义字段的dom
- var dom; var i;
- switch (field){
- case 'Total': i = 0; break;
- case 'Copy': i = 1; break;
- case 'Object': i = 2; break;
- case 'Domain': i = 3; break;
- case 'Monster': i = 4; break;
- case 'Fstwin': i = 5; break;
- }
- dom = CustomFields[i].childNodes[1]
- return dom
- }
- function SetDataDom(field, value){ // 设置指定的自定义字段的内容
- var dataDom = GetDataDom(field);
- if (dataDom.value != value){
- dataDom.value = value;
- dataDom.focus({preventScroll: true});
- dataDom.blur();
- }
- }
- function GetDirectlyData(field){ // 获取指定的自定义字段的内容,若为空则解析为空字符串
- var dataDom = GetDataDom(field)
- var value = dataDom.value?dataDom.value:''
- return value
- }
- function SetDirectlyData(field, data){ // 覆写指定的自定义字段的内容
- var dataDom = GetDataDom(field)
- var value = JSON.stringify(data);
- SetDataDom(field, value);
- }
- function GetInternalData(field){ // 获取指定的自定义字段的内容,若为空则解析为空json
- var dataDom = GetDataDom(field)
- var value = dataDom.value?dataDom.value:'{}'
- return JSON.parse(value);
- }
- function SetInternalData(field, data){ // 覆写指定的自定义字段的内容
- var dataDom = GetDataDom(field)
- var value = JSON.stringify(data);
- SetDataDom(field, value);
- }
- // ----------------- 获取某一DOM的内容中,是否存在符合格式的标记,格式为:ID#LV,比如3#S -----------------
- function GetSigns(dom){
- // 判断标题格式是否正确
- var titles = dom.innerText.split(' ');
- if (titles.length < 2){return []}
- // 若标题格式正确,则判断标记格式是否正确
- var signs = titles[0].split('#');
- if (signs.length != 2){return []}
- // 若标记格式正确,则返回标志列表
- return signs;
- }
- // 获取徽章、最小值、最大值
- function GetConfigure(cls, level){
- // bedge, min, max configuration
- var LandConfiguration = [["🧱", 1, 10], ["💰", 10, 100], ["💿", 100, 1000], ["📀", 1000, 10000], ["💎", 10000, 100000], ["💣", 0, 0]];
- var AreaConfiguration = [["🧱", 1, 10], ["💰", 10, 100], ["💿", 100, 1000], ["📀", 1000, 10000], ["💎", 10000, 100000], ["💣", 0, 0]];
- var CopyConfiguration = [["🧱", 1, 10], ["💰", 10, 100], ["💿", 100, 1000], ["📀", 1000, 10000], ["💎", 10000, 100000], ["💣", 0, 0]];
- var DomainConfiguration = [["⭐", 1, 10], ["🌟", 10, 100], ["🌙", 100, 1000], ["🌝", 1000, 10000], ["🌞", 10000, 100000], ["🌠", 0, 0]];
- var MonsterConfiguration = [["🧱", 1, 10], ["💰", 10, 100], ["💿", 100, 1000], ["📀", 1000, 10000], ["💎", 10000, 100000], ["💣", 0, 0]];
- var ObjectConfiguration = [["🧱", 1, 10], ["💰", 10, 100], ["💿", 100, 1000], ["📀", 1000, 10000], ["💎", 10000, 100000], ["💣", 0, 0]];
- var FstwinConfiguration = [["🌀", 3, 30], ["🌌", 30, 300], ["💧", 300, 3000], ["🔥", 3000, 30000], ["⚡", 30000, 300000], ["💀", 0, 0]];
- var config; var suffix;
- switch(cls){
- case 'Land': config = LandConfiguration; break;
- case 'Area': config = AreaConfiguration; break;
- case 'Copy': config = CopyConfiguration; break;
- case 'Domain': config = DomainConfiguration; break;
- case 'Monster': config = MonsterConfiguration; break;
- case 'Object': config = ObjectConfiguration; break;
- case 'Fstwin': config = FstwinConfiguration; break;
- }
- switch(level){
- case 'S': suffix = 4; break;
- case 'A': suffix = 3; break;
- case 'B': suffix = 2; break;
- case 'C': suffix = 1; break;
- case 'D': suffix = 0; break;
- default: suffix = 5;
- }
- return config[suffix];
- }
- // 获取一个随机数
- function GetRandomNum(min, max){
- return parseInt(Math.random()*(max-min+1)+min,10);
- }
- // 判断按钮的内容是否正确,若正确时还一直插入,会引起栈溢出
- function SetInnerHTML(dom, inner){
- // console.log("正确内容为:" + inner + " 现在内容为:" + dom.innerHTML);
- if (dom.innerHTML != inner){
- dom.innerHTML = inner;
- }
- }
- // 向某一dom中插入新的dom,index为插在第几个后面,0代表最前面。数太大则插在最后面
- function InsertCustomDOM(fdom, ndom, index){ // 旧的文本处理方式
- if (index == 0){
- fdom.innerHTML = ndom + fdom.innerHTML;
- }else if (index>fdom.children.length){
- fdom.innerHTML += ndom
- }else{
- fdom.children[index-1].innerHTML += ndom;
- }
- }
- // 将字符串转为dom
- function parseDom(arg) {
- var objE = document.createElement("div");
- objE.innerHTML = arg;
- return objE.children[0];
- };
- // 像Dom中的最后添加一个新的Dom,并且为新Dom指定一个点击监听器
- function CustomTopButton(head, button, listener){
- if(head.children.length == 1){
- var ButtonDom = parseDom(button);
- ButtonDom.addEventListener("click", listener);
- head.appendChild(ButtonDom);
- };
- }
- // ------------------------------------------------------------------------------------------------------------------
- // 自定义计算总分
- // ------------------------------------------------------------------------------------------------------------------
- var TotalButton = '<a class="random-button card-label button" style="display:inline;margin-left:5px;">🏆🏆🏆</a>'
- function TotalButtonListener(event){
- // 获取所有的内部数据
- var copy_data = GetDirectlyData('Copy');
- var object_data = GetDirectlyData('Object');
- var domain_data = GetInternalData('Domain');
- var monster_data = GetInternalData('Monster');
- var fstwin_data = GetInternalData('Fstwin');
- // 把所有存储的数据加起来
- var number = 0;
- if (copy_data != ''){number += parseInt(copy_data)};
- if (object_data != ''){number += parseInt(object_data)};
- if (domain_data != {}){
- for (var key1 in domain_data){
- number += domain_data[key1]
- }
- }
- if (monster_data != {}){
- for (var key2 in monster_data){
- number += monster_data[key2]
- }
- }
- if (fstwin_data != {}){
- for (var key3 in fstwin_data){
- number += fstwin_data[key3][1]
- }
- }
- // 把数据在内部数据中显示出来
- SetDirectlyData('Total', number);
- }
- function CustomTotalButton(){
- CustomTopButton(CustomFields[0].children[0], TotalButton, TotalButtonListener);
- }
- // ------------------------------------------------------------------------------------------------------------------
- // 自定义副本积分
- // ------------------------------------------------------------------------------------------------------------------
- var CopyButton = '<a class="random-button card-label button" style="display:inline;margin-left:5px;">🎲🎲🎲</a>'
- function CopyButtonListener(event){
- // 获取标志
- var signs = GetSigns(CardTitle[0].children[0]);
- if (!signs.length){return}
- var id = signs[0]; var level = signs[1];
- // 获取数据和配置
- var copy_data = GetDirectlyData('Copy');
- var copy_config = GetConfigure('Copy', level) // 获取配置信息 // todo: 获取级别、ID之类的
- var copy_bedge = copy_config[0]; var copy_min = copy_config[1]; var copy_max = copy_config[2];
- var copy_number = GetRandomNum(copy_min, copy_max);
- SetDirectlyData('Copy', copy_number);
- }
- function CustomCopyButton(){
- CustomTopButton(CustomFields[1].children[0], CopyButton, CopyButtonListener);
- }
- // ------------------------------------------------------------------------------------------------------------------
- // 自定义副本奖励
- // ------------------------------------------------------------------------------------------------------------------
- var ObjectButton = '<a class="random-button card-label button" style="display:inline;margin-left:5px;">🎁🎁🎁</a>'
- function ObjectButtonListener(event){
- // 获取标志
- var signs = GetSigns(CardTitle[0].children[0]);
- if (!signs.length){return}
- var id = signs[0]; var level = signs[1];
- // 获取数据和配置
- var object_data = GetDirectlyData('Object'); // todo:换成object
- var object_config = GetConfigure('Object', level) // 获取配置信息
- var object_bedge = object_config[0]; var object_min = object_config[1]; var object_max = object_config[2];
- var object_number = GetRandomNum(object_min, object_max);
- SetDirectlyData('Object', object_number);
- }
- function CustomObjectButton(){
- CustomTopButton(CustomFields[2].children[0], ObjectButton, ObjectButtonListener);
- }
- // ------------------------------------------------------------------------------------------------------------------
- // 自定义清单
- // ------------------------------------------------------------------------------------------------------------------
- var CheckListButton = '<a class="random-button button subtle hide-on-edit" style="margin:0 0 0 6px;color:#fff;background-color:#f17143;font-weight:bold;">???</a>'
- function CustomCheckListsListener(event){
- var target = event.currentTarget;
- var title = target.parentNode.previousSibling; // 获取标题、ID、级别
- var signs = GetSigns(title);
- if (!signs.length){return}
- var id = signs[0]; var level = signs[1];
- var domain_data = GetInternalData('Domain'); // 获取内部数据
- var domain_config = GetConfigure('Domain', level) // 获取配置信息
- if (typeof(domain_data[id]) != "undefined"){return} // 若已有内部数据则禁止再次生成
- var domain_bedge = domain_config[0]; var domain_min = domain_config[1]; var domain_max = domain_config[2];
- var domain_number = GetRandomNum(domain_min, domain_max);
- domain_data[id] = domain_number; // 更新内部数据
- SetInternalData('Domain', domain_data)
- SetInnerHTML(target, domain_number);
- }
- function CustomCheckLists(){
- if(CheckLists.length == 0){return};
- for (var i=0; i<CheckLists.length; i++){
- // 获取关键DOM、获取检查项的名称DOM、自定义DOM
- var title = CheckLists[i].children[0];
- var option = CheckLists[i].children[1];
- // 获取标记中的信息
- var signs = GetSigns(title);
- if (!signs.length){continue}
- var id = signs[0]; var level = signs[1];
- // 添加自定义按钮
- if(option.children.length == 3){
- var CheckListButtonDom = parseDom(CheckListButton);
- CheckListButtonDom.addEventListener("click", CustomCheckListsListener);
- option.appendChild(CheckListButtonDom)
- }
- // 实时调整其按钮显示的内容
- else if(option.children.length == 4){
- var buttons = option.children; // 获取添加的自定义按钮
- var domain_data = GetInternalData('Domain'); // 获取内部数据
- var bedge = GetConfigure('Domain', level)[0] // 获取配置信息中的图标
- // 计算应正确显示的内容
- var inner = ""; // 按钮要显示的内容
- if (typeof(domain_data[id]) == "undefined"){ // 打开卡片时,若数据中没有相关的数据,则显示礼包按钮
- inner = bedge;
- }else{ // 若已经有相关数据了,则显示相关数据
- inner = domain_data[id];
- }
- // 判断按钮的内容是否正确,若正确时还一直插入,会引起栈溢出
- SetInnerHTML(buttons[0], '显');
- SetInnerHTML(buttons[1], '隐');
- SetInnerHTML(buttons[2], '删');
- SetInnerHTML(buttons[3], inner);
- }
- }
- }
- // ------------------------------------------------------------------------------------------------------------------
- // 自定义检查项
- // ------------------------------------------------------------------------------------------------------------------
- var CheckItemTag = '<span class="oraant-custom card-label" style="float:left; max-height:20px;padding:0px 2px;margin:8px 5px;background-color:#e3e7e9;overflow:initial;color:#17394d;">?</span>'
- var CheckItemCoin = '<span class="oraant-custom card-label card-label-green" style="float:right;max-height:20px;padding:0px 5px;margin:8px 2px;text-overflow:initial; overflow:initial;font-weight:bold;">?</span>'
- var CheckItemFstwin = '<span class="oraant-custom card-label card-label-sky" style="float:right;max-height:20px;padding:0px 5px;margin:8px 2px;text-overflow:initial; overflow:initial;">?</span>'
- // 自定义检查项后的信息
- function CustomCheckItems(){
- if(CheckItems.length == 0){return};
- for (var i=0; i<CheckItems.length; i++){
- // 获取详情DOM、获取检查项的名称DOM、自定义DOM
- var detail = CheckItems[i].children[1].children[0];
- var cbtag, cbtext, cbcoin, cbfstw;
- var signs, id, level;
- // 计算应正确显示的内容
- // 添加自定义按钮
- if(detail.children.length == 2){
- // 单独验证格式是否合适,因为插入的原因,两次cbtext的位置是不一样的
- cbtext = detail.children[0];
- signs = GetSigns(cbtext);
- if (!signs.length){continue}
- InsertCustomDOM(detail, CheckItemTag, 0)
- InsertCustomDOM(detail, CheckItemCoin, 10)
- InsertCustomDOM(detail, CheckItemFstwin, 20)
- }
- // 实时调整其按钮显示的内容(之前那些DOM里Onclick的功能,也要做到这里面来。因为这个不是个按钮,不需要去按。)
- else if(detail.children.length == 5){
- // 获取各组件的dom
- cbtag = detail.children[0];
- cbtext = detail.children[1];
- cbcoin = detail.children[3];
- cbfstw = detail.children[4];
- // 单独验证格式是否合适,因为插入的原因,两次cbtext的位置是不一样的
- signs = GetSigns(cbtext);
- if (!signs.length){continue}
- id = signs[0]; level = signs[1];
- // console.log("->内容全面,判断是否要进行修正");
- var state = CheckItems[i].getAttribute("class"); // 获取类属性
- var monster_data = GetInternalData('Monster'); // 获取内部数据
- var fstwin_data = GetInternalData('Fstwin'); // 获取内部数据
- var cbcoin_config = GetConfigure('Monster', level) // 获取配置信息
- var cbfstw_config = GetConfigure('Fstwin', level) // 获取配置信息
- var cbcoin_bedge = cbcoin_config[0]; var cbcoin_min = cbcoin_config[1]; var cbcoin_max = cbcoin_config[2];
- var cbfstw_bedge = cbfstw_config[0]; var cbfstw_min = cbfstw_config[1]; var cbfstw_max = cbfstw_config[2];
- var cbcoin_inner = ""; // 金币标签要显示的内容
- var cbfstw_inner = ""; // 首胜标签要显示的内容
- SetInnerHTML(cbtag, cbfstw_bedge); // 不管是否勾选,都在前面显示图标
- if (state == "checklist-item"){ // 若未勾选,则根据难度,显示图标
- cbcoin_inner = cbcoin_bedge;
- cbfstw_inner = '';
- }else if(state.search("checklist-item-state-complete") != -1){ // 若已勾选 // todo:这里应该能去掉,和下面的一起if
- // 计算首胜标签应正确显示的内容
- // ----------------------------------------
- // 判断今天的有没有记录过(必须得在coin前边,需要根据coin的状态,判断是否是已经有数据的)
- // 若已勾选但没有今日数据,且这个检查项也没有存过数据(否则昨天加了11号的后,今天还会加11号的首胜),则在数据栏中添加数据
- var options = {year: 'numeric', month: 'numeric', day: 'numeric' };
- var date = new Date().toLocaleDateString('ch-zh', options);
- if (typeof(fstwin_data[date]) == "undefined" && typeof(monster_data[id]) == "undefined"){
- var cbfstw_number = GetRandomNum(cbfstw_min, cbfstw_max); // 每日首胜奖励+3倍
- fstwin_data[date] = [id, cbfstw_number];
- SetInternalData('Fstwin', fstwin_data)
- }
- // 根据以前的数据,将首胜信息展示出来
- for (var k in fstwin_data){
- if(fstwin_data[k][0] == id){ // 若已经有今日数据了,且是这个ID,则显示相关数据
- cbfstw_inner = fstwin_data[k][1];
- }
- }
- // 计算金币标签应正确显示的内容
- // ----------------------------------------
- if (typeof(monster_data[id]) == "undefined"){ // 已勾选但未曾保存数据,则插入数据
- var cbcoin_number = GetRandomNum(cbcoin_min, cbcoin_max);
- monster_data[id] = cbcoin_number;
- SetInternalData('Monster', monster_data)
- cbcoin_inner = cbcoin_number
- }else{ // 若已经有相关数据了,则显示相关数据
- cbcoin_inner = monster_data[id];
- }
- }else{console.log('很奇怪,检查项的类属性和预期的不同:'+state)}
- SetInnerHTML(cbfstw, cbfstw_inner);
- SetInnerHTML(cbcoin, cbcoin_inner);
- if(cbfstw_inner == ""){
- cbfstw.style.display = "none";
- }else{
- cbfstw.style.display = "initial";
- }
- }
- }
- }
- // ------------------------------------------------------------------------------------------------------------------
- // 程序入口
- // ------------------------------------------------------------------------------------------------------------------
- var callback = function (records){
- // 检查看板的标题是否符合格式
- if(LandTitle.length == 0){return};
- var title_signs = GetSigns(LandTitle[0]);
- if (!title_signs.length){return}
- // 校验是否有自定义域
- if(CustomFields.length == 0){return};
- // 获取判断卡片标题是否符合要求
- var card_signs = GetSigns(CardTitle[0].children[0]);
- if (!card_signs.length){return}
- CustomTotalButton()
- CustomCopyButton()
- CustomObjectButton()
- CustomCheckLists()
- CustomCheckItems()
- console.log('看看能不能输出日志')
- };
- var mo = new MutationObserver(callback);
- mo.observe(WindowWrapper, {'childList': true, 'subtree': true}); // 设置一个监听器,页面由变化就触发。
- callback(); // 如果直接打开一个页面的话,默认监听器不会被触发。这时手动触发一次就很有必要了。
- };