Skip to content

Instantly share code, notes, and snippets.

@djirdehh
Created October 25, 2021 18:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save djirdehh/c4b28c072a54957398bf4363c8739a75 to your computer and use it in GitHub Desktop.
Save djirdehh/c4b28c072a54957398bf4363c8739a75 to your computer and use it in GitHub Desktop.
// ==UserScript==
// @name Override Instacart Ads Manager flippers
// @namespace https://ads.instacart.com/
// @version 0.6
// @updateURL https://gist.githubusercontent.com/jiang925/94b31524a7f38d32000c20797f1d53db/raw/override-flippers.user.js
// @downloadURL https://gist.githubusercontent.com/jiang925/94b31524a7f38d32000c20797f1d53db/raw/override-flippers.user.js
// @description Override Instacart Ads Manager flippers from UI. Note that this only affects pure UI flippers. This does not affects the flippers on the backend.
// @author Tian Jiang
// @include *://*.instacart.com/*
// @include *://*-web-ads-stg.instacart.team/*
// @include *://localhost:4000/*
// @require http://code.jquery.com/jquery-3.5.0.min.js
// @run-at document-start
// @grant GM_setValue
// @grant GM_getValue
// ==/UserScript==
(function () {
"use strict";
const toggleStyle = `
<style>
/* Change header colour*/
._ko16_widget_top_cntr {
background-color: white;
padding: 25px 10px 14px 37px;
}
/* Align title left and update color. */
._ko16_widget_title {
color: #424242;
text-align: left;
font-size: 18px;
}
/* Update close button styles. */
._ko16_widget_close_cntr svg {
fill: #757575;
height: 18px;
width: 18px;
position: absolute;
right: 16px;
bottom: 2px;
}
/* Update back button styles. */
._ko16_widget_back svg {
fill: #757575;
top: 24px;
position: absolute;
left: 8px;
height: 20px;
width: 20px;
}
.override-flipper-drawer textarea.full {
width: 100%;
height: 300px;
}
.override-flipper-drawer textarea.half {
width: 100%;
height: 150px;
}
</style>`;
const $ko = $(`
<div id="_ko16-widget-wrapper" class="_ko16-widget-wrapper override-flipper-drawer" style="width: 480px;">
<input type="hidden" id="rgroups" name="groups" value="5d5d98b58e121c3022464519">
<div class="_ko16_widget_top_cntr">
<div class="_ko16_widget_back" style="display:none;">
<svg viewBox="0 0 34 60" preserveAspectRatio="xMinYMid">
<path d="M1.2,32.8l26,26c0.7,0.7,1.7,1.2,2.8,1.2c2.2,0,4-1.8,4-4c0-1.1-0.4-2.1-1.2-2.8L9.7,30 L32.8,6.8C33.6,6.1,34,5.1,34,4c0-2.2-1.8-4-4-4c-1.1,0-2.1,0.4-2.8,1.2l-26,26C0.4,27.9,0,28.9,0,30C0,31.1,0.4,32.1,1.2,32.8z"></path>
</svg>
</div>
<div class="_ko16_widget_title">Overrider Flippers</div>
<div id="_ko16_widget_close_cntr" class="_ko16_widget_close_cntr">
<svg viewBox="0 0 60 60" preserveAspectRatio="xMinYMid">
<path d="M35.7,30L58.8,6.8C59.6,6.1,60,5.1,60,4c0-2.2-1.8-4-4-4c-1.1,0-2.1,0.4-2.8,1.2L30,24.3
L6.8,1.2C6.1,0.4,5.1,0,4,0C1.8,0,0,1.8,0,4c0,1.1,0.4,2.1,1.2,2.8L24.3,30L1.2,53.2C0.4,53.9,0,54.9,0,56c0,2.2,1.8,4,4,4
c1.1,0,2.1-0.4,2.8-1.2L30,35.7l23.2,23.2c0.7,0.7,1.7,1.2,2.8,1.2c2.2,0,4-1.8,4-4c0-1.1-0.4-2.1-1.2-2.8L35.7,30z"></path>
</svg>
</div>
</div>
</div>
`);
const interestingData = {};
(function (open) {
XMLHttpRequest.prototype.open = function () {
this.addEventListener(
"readystatechange",
function () {
if (this.readyState != 4) {
return;
}
if (this.responseURL.endsWith("/api/auth")) {
const json = JSON.parse(this.response);
console.log(JSON.parse(this.response));
const overridenFlippers = JSON.parse(
GM_getValue("override-flippers") || '{ "on": [], "off": [] }'
);
const overridenFlippersOn = [].concat(overridenFlippers.on);
const overridenFlippersOff = [].concat(overridenFlippers.off);
if (
!json ||
!json.data ||
!json.data.attributes ||
!json.data.attributes.flippers
) {
console.log("no flippers");
return;
}
const flippers = []
.concat(json.data.attributes.flippers, overridenFlippersOn)
.filter(
(v, i, a) =>
a.indexOf(v) === i && !overridenFlippersOff.includes(v)
);
interestingData.user_id = json.data.attributes.user_id;
interestingData.user_type = json.data.attributes.user_type;
interestingData.user_uuid = json.data.attributes.user_uuid;
json.data.attributes.flippers = flippers;
Object.defineProperty(this, "response", { writable: true });
Object.defineProperty(this, "responseText", { writable: true });
this.response = JSON.stringify(json);
this.responseText = JSON.stringify(json);
}
},
false
);
open.apply(this, arguments);
};
})(XMLHttpRequest.prototype.open);
const toggleDrawer = function ($drawer) {
const closed = "_ko16-widget-closed";
const open = "_ko16-widget-open";
if ($drawer.hasClass(open)) {
$drawer.addClass(closed).removeClass(open);
} else {
$drawer.removeClass(closed).addClass(open);
}
};
const $toggle = $(
'<div class="override-flippers-toggle open"><div></div></div>'
);
const injectDrawer = function () {
if ($(".override-flipper-drawer").length)
return $(".override-flipper-drawer");
const $button = $('div[data-testid="change-account"] button');
// inject css
$(
'<link rel="stylesheet" href="https://instacart-ads.knowledgeowl.com/css/widget_responsive_min.css" />'
).appendTo("head");
$(toggleStyle).appendTo("head");
const $clone = $ko.clone();
const $title = $clone.find("._ko16_widget_title");
$title.text("Overrider Flippers");
const $close = $clone.find("._ko16_widget_close_cntr");
$clone.find("._ko16_widget_top_cntr").nextAll().remove();
$close.click(function () {
toggleDrawer($clone);
});
$clone.addClass("override-flipper-drawer");
$("body").append($clone);
const pageFlippers = JSON.parse(sessionStorage.getItem("flippers"));
const overridenFlippers = JSON.parse(
GM_getValue("override-flippers") || '{ "on": [], "off": [] }'
);
const overridenFlippersOn = [].concat(overridenFlippers.on);
const overridenFlippersOff = [].concat(overridenFlippers.off);
$("<div />").html("Flippers on the page").appendTo($clone);
$("<textarea readonly />")
.addClass("full")
.html(pageFlippers.join("\n"))
.appendTo($clone);
$("<div />").html("Flippers to enforce on").appendTo($clone);
const $on = $("<textarea />")
.addClass("half")
.html(overridenFlippersOn.join("\n"))
.appendTo($clone);
$($button.clone()[1])
.html("clear")
.appendTo($clone)
.click(function () {
$on.val("");
});
$("<div />").html("Flippers to enforce off").appendTo($clone);
const $off = $("<textarea />")
.addClass("half")
.html(overridenFlippersOff.join("\n"))
.appendTo($clone);
$($button.clone()[1])
.html("clear")
.appendTo($clone)
.click(function () {
$off.val("");
});
$($button.clone()[1])
.html("Save")
.appendTo($clone)
.click(function () {
const on = $on.val().split("\n");
const off = $off.val().split("\n");
const overrides = { on, off };
GM_setValue("override-flippers", JSON.stringify(overrides));
});
// Add the interesting data
$("<div />")
.html(
"user_id: " +
interestingData.user_id +
"<br />user_type: " +
interestingData.user_type +
"<br />user_uuid: " +
interestingData.user_uuid
)
.appendTo($clone);
return $clone;
};
const handleButtonClick = function () {
const $drawer = injectDrawer();
toggleDrawer($drawer);
console.log("my button clicked");
};
const injectButton = function ($box) {
const $button = $box.find("button:first").clone();
$button.addClass("override-flipper-button");
$button.click(handleButtonClick);
$button.css("margin-right", "24px");
$button.text("Override Flippers");
$box.prepend($button);
return $button;
};
const injectUI = setInterval(function () {
// const $boxes = $('div[data-testid="change-account"]');
const $boxes = $('div[data-testid="change-account__new-nav"]');
if ($boxes.length) {
$boxes.each(function (i, box) {
const $box = $(box);
if ($box.find("button.override-flipper-button").length) return;
const $button = injectButton($box);
});
}
}, 200);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment