Tampermonkey: GM_deleteValue Issue

Created on 16 May 2020  Â·  4Comments  Â·  Source: Tampermonkey/tampermonkey

Expected Behavior

Data deleted on another tab must also have been deleted on the current tab. More explanatory video is available here : https://streamable.com/dmr6yb

Actual Behavior

Data is still available without refreshing or changing the current tab.

Specifications

  • Google Chrome 81.0.4044.138
  • Tampermonkey 4.10

Script

Open the script below in two tabs. Save data in someone and delete it later. You will see that the other one has not been deleted.

// ==UserScript==
// @name         Test GM_deleteValue
// @include      http*://www.google.com/*
// @version      0.1
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_deleteValue
// @grant        GM_listValues
// ==/UserScript==

let key = "name";

(function() {
    document.documentElement.innerHTML = `
<p> Check: <label id="count">0</label> </p>
<p> Key lists: <label id="list_keys">[${GM_listValues().join(", ")}]</label></p>
<p> <label>GM_getValue("${key}")</label>: <label id="value">${GM_getValue(key)}</label> </p>
<p> <label>GM_setValue("${key}") : <input id="new_value" type="text"></input></label> <input type="button" id="set" value="GM_setValue('${key}',...)"> </p>
<p> <input type="button" value="GM_deleteValue('${key}')" id="delete"> </p>
`;
    setInterval(function(){
        document.getElementById('value').innerHTML = GM_getValue(key);
        document.getElementById('count').textContent = parseInt(document.getElementById('count').textContent)+1;
    },1000);

    document.getElementById('set').addEventListener("click",function(){
        GM_setValue(key,document.getElementById('new_value').value);
        document.getElementById('new_value').value = "";

        document.getElementById('list_keys').innerHTML = "["+GM_listValues().join(", ")+"]";
    });

    document.getElementById('delete').addEventListener("click",function(){
        GM_deleteValue(key);

        document.getElementById('list_keys').innerHTML = "["+GM_listValues().join(", ")+"]";
    });

})();
bug fixed at beta

Most helpful comment

Should be fixed at TM BETA 4.11.6113

Thanks for reporting.

All 4 comments

I've also met this bug.

I put an extra line of code as the following snippet to the OP's userscript,

// ... headers
// @grant GM_addValueChangeListener

(function() {
  // ... skipped

  GM_addValueChangeListener(key, console.log);
})();

and found that only the tab where the delete button was clicked logged the value change (with remote equal to false), while the other tab was not aware of the change.

I wrote the code below to solve this problem. I also added expiry time for data to be deleted. video

let GM_data = new class{
    constructor(){
        this.prefix = "GM_data_";
        this.keyList = "GM_dataKeys";
        for(let k of this.getKeys()){
            let e = this.get(k,{}).e;
            if(e!=undefined && this.checkExpiryTime(e)) this.delete(k); //data will be deleted automatically here
        }
    }

    getKeys(){
        let self=this;
        return GM_getValue(this.keyList,[]).filter(function(key){
            let o = GM_getValue(self.prefix+key);
            if(typeof o != 'object' || o.constructor != Object || !o.hasOwnProperty('v') //Format control
               || o.hasOwnProperty('d') //This data deleted on a other tab.
              ) return false;
            return true;
        });
    }

    exist(key){ return this.getKeys().includes(key); }

    set(key,value,seconds=null){
        let o = {v: value};
        if(seconds!=null){
            if(!Number.isInteger(seconds)) throw new Error("Parameter {seconds} is not a number!");
            else if(seconds<1) throw new RangeError("Parameter {seconds} must be positive!")
            o.e = new Date().getTime()+seconds*1000; //expiry time
        }
        GM_setValue(this.prefix+key,o);
        if(!this.exist(key)) GM_setValue(this.keyList,this.getKeys().concat(key));
    }

    get(key,defaultValue=null){
        if(!this.exist(key)) return defaultValue;
        let o = GM_getValue(this.prefix+key,defaultValue);
        if(o.e!=undefined && !this.checkExpiryTime(o.e)){
            this.delete(key);
            return defaultValue;
        }
        return o.v;
    }

    checkExpiryTime(e){ return new Date().getTime() < e;}

    delete(key){
        let keys = this.getKeys(),
            index = keys.indexOf(key);
        if(index!=-1){
            keys.splice(index,1);
            GM_setValue(this.keyList,keys);
        }
        GM_setValue(this.prefix+key,Object.assign(GM_getValue(this.prefix+key,{}),{d:1}));
        GM_deleteValue(this.prefix+key);
    }

    getExpires(key){
        if(!this.exist(key)) return -1;
        let o = GM_getValue(this.prefix+key);
        if(o.e == undefined) return Infinity;
        return o.e;
    }

    getRemainingTime(key){
        let t = this.getExpires(key);
        if(t==-1 || t==Infinity) return t;
        t -= new Date().getTime();
        if(t<0){
            this.delete(key);
            return -1;
        }
        return parseFloat(t/1000);
    }

    logAllData(){
        let keys = this.getKeys()
        console.log(this.keyList+"(len:"+keys.length+"): "+keys.map(k=>{return JSON.stringify(k);}).join(', '));
        if(keys.length==0){
            console.log("\t[GM_data] No data!");
            return;
        }
        for(let key of keys){
            let o = GM_getValue(this.prefix+key);
            if(o == undefined) continue;
            if(o.hasOwnProperty('e')) console.log("\t["+key+"] %o , remaining time: "+this.getRemainingTime(key) +" sec ["+new Date(this.getExpires(key)).toLocaleString()+"]",o);
            else console.log("\t["+key+"] %o , remaining time: ∞",o);
        }
    }
}();

I got your point. You mark a value as deleted instead of actually deleting it, and prune the storage on access.

However, it's actually a workaround since the problem is not solved yet, it is still there in the TamperMonkey.

Thank you for the snippet anyway, and let's look forward to v4.11.

Should be fixed at TM BETA 4.11.6113

Thanks for reporting.

Was this page helpful?
0 / 5 - 0 ratings