Last active
February 12, 2019 15:29
-
-
Save seanemmel-ba/192d7ba425d8f6a51d00 to your computer and use it in GitHub Desktop.
A bookmarklet that enables you to retrieve information about Qubit experiments, including IDs, variations mapping, creative key groups, SmartServe script ID, and more, all in a GUI modal.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
javascript:(function() { | |
/** | |
* @package N/A | |
* @version 1.1 //=> 3/1/2016 | |
* @author Blue Acorn <[email protected]>, Sean Emmel <[email protected]> | |
* @copyright Copyright © 2016 Blue Acorn. | |
* | |
* LAST UPDATED: 3/1/2016 | |
@FIXES: | |
* Fixing issue where you were shown to be in the Control when actually it was a | |
variation and vice versa | |
* No longer able to pull the variation index as this was based on erroneous data | |
* Rewording results for full experiment info to reflect above changes | |
@TODO: | |
* Find out if there's a way to determine variation index | |
* Determine what a value of 0 means for exp.ckg property (multivariate usage) | |
* | |
* Errors? Email me: <[email protected]> | |
*/ | |
/* Quick check to ensure Qubit is loaded on the page */ | |
if (!window._qb_ss || !window.qb_etc_data) { | |
alert('Qubit is not on page OR Qubit global variable dependencies not loaded!'); | |
return; | |
} | |
var ALL_EXP = window._qb_ss[0].experiments; | |
var CURR_EXP = window.qb_etc_data; | |
var DOC = window.document; | |
var HEAD = DOC.getElementsByTagName('head')[0]; | |
var BODY = DOC.body; | |
function Modal() { | |
this.el = document.createElement('div'); | |
this.el.id = 'qubit-modal-overlay'; | |
this.styles = '#qubit-modal-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: 10000000000; background-color: rgba(180, 180, 180, 0.6); overflow-y: auto; } #qubit-modal-container { position: relative; margin: 8% auto; width: 500px; padding: 20px; z-index: 100000000000; background-color: #4c4f53; border-radius: 2px; box-shadow: 1px 1px 5px 2px #444; font-family: \'Arial\', sans-serif; text-align: left; font-size: 16px; } #qubit-modal-close-x { position: absolute; top: -30px; right: -25px; width: 30px; height: 30px; background-image: url(\'//cdn.optimizely.com/img/543470256/b2d11caa90f5463e9d8cbae950656144.png\'); background-repeat: no-repeat; background-size: 30px 30px; } #qubit-modal-close-x:hover { cursor: pointer; } #qubit-header { margin-bottom: 20px; padding: 10px 0; color: #fff; background-color: #f9b03d; font-weight: bold; font-size: 22px; text-align: center; } #qubit-options h3 { display: block; margin: 20px 0 12px 0; color: #fff; font-weight: bold; font-size: 20px; font-family: \'Arial\', sans-serif; letter-spacing: 0; } #qubit-options label { display: inline-block; width: 100%; margin-bottom: 10px; color: #fff; font-size: 18px; font-weight: bold; letter-spacing: 0; transition: all 0.1s ease-in-out; } #qubit-options label:hover { cursor: pointer; color: #5d9fd5; text-shadow: 1px 1px 2px #000; } #qubit-options input[type=\"checkbox\"] { display:none; } #qubit-options input[type=\"checkbox\"] + label span { display:inline-block; width:19px; height:19px; margin:-1px 4px 0 0; vertical-align:middle; background-image: url(\'http://cdn.optimizely.com/img/404692387/9fd5ca6857104cbebb2502b34a49bc66.png\'); background-position: left top; background-repeat: no-repeat; cursor:pointer; } #qubit-options input[type=\"checkbox\"]:checked + label { color: #5d9fd5; } #qubit-options input[type=\"checkbox\"]:checked + label span { background-image: url(\'http://cdn.optimizely.com/img/404692387/9fd5ca6857104cbebb2502b34a49bc66.png\'); background-position: -19px top; background-repeat: no-repeat; } #qubit-options .note { margin-top: 5px; font-style: italic; font-size: 14px; color: #fff; } #qubit-modal-container .center-me { text-align: center; } #qubit-go { width: 150px; height: 50px; margin: 10px auto 0 auto; border: 2px solid #48b28d; border-radius: 5px; background-color: #48b28d; color: #fff; letter-spacing: 3px; font-size: 20px; transition: all 0.2s ease-in-out; } #qubit-go:hover { cursor: pointer; background-color: #249780; border-color: #249780; transform: scale(1.1); } #qubit-help { margin-top: 5px; padding: 10px 5px 0 5px; letter-spacing: 0; } #qubit-help::after { content: \'\'; display: block; width: 100%; clear: both; } #qubit-help a { color: #e2e2e2; text-decoration: none; letter-spacing: 0; transition: all 0.2s ease-in-out; } #qubit-help a:hover { color: #fff; transform: translateY(1px) scale(1.1); } #qubit-help a:first-child { float: left; } #qubit-help a:last-child { float: right; } #qubit-close-modal { width: 150px; height: 50px; margin: 10px auto 0 auto; border: 1px solid #fff; border-radius: 2px; background-color: #4c4f53; color: #fff; letter-spacing: 3px; font-size: 20px; transition: all 0.2s ease-in-out; } #qubit-close-modal:hover { cursor: pointer; background-color: #fff; color: #4c4f53; transform: scale(1.1); } #qubit-results, #qubit-help, #qubit-close-modal-wrap { display: none; } #qubit-results { max-height: 350px; margin-top: 20px; padding: 10px; background-color: #B3AFAF; border: 1px solid #e2e2e2; border-radius: 2px; overflow-y: auto; } #qubit-results .row { padding: 8px 0; border-bottom: 1px solid #eee; color: #000; } #qubit-results .title { margin-bottom: 5px; font-weight: bold; letter-spacing: 0; color: #000; } #qubit-results .value { margin-bottom: 10px; padding-bottom: 10px; word-wrap: break-word; letter-spacing: 0; color: #000; } #qubit-results strong { font-weight: bold; color: #000; }'; | |
} | |
Modal.prototype = { | |
checkQubitVarsLoaded: function() { | |
if (ALL_EXP === null || ALL_EXP === undefined || CURR_EXP === null || CURR_EXP === undefined) { | |
alert('Qubit is not on page OR Qubit global variable dependencies not loaded!'); | |
return false; | |
} | |
return true; | |
}, | |
buildDivRow: function(html) { | |
var div = document.createElement('div'); | |
div.setAttribute('class', 'row'); | |
div.innerHTML = html; | |
return div; | |
}, | |
getSmartServeScriptId: function() { | |
var script = document.querySelector('script[src*="smartserve"]'); | |
var id = script.src.match(/\b\d+\b/g)[0]; /* currently works for both regular smartserve AND preview script versions */ | |
var html = '<strong>SmartServe Script ID: </strong>' + id; | |
return this.buildDivRow(html); | |
}, | |
getExperimentVariationMapByIndex: function(exp) { | |
var index = exp.cnt === 1 ? 'Control (0) ' : 'Variation X'; | |
var html = '<strong>Experiment ID: </strong>' + exp.e + ' :: <strong>Variation Index: </strong>' + index; | |
return this.buildDivRow(html); | |
}, | |
getExperimentVariationMapById: function(exp) { | |
var id = exp.cm; | |
var html = '<strong>Experiment ID: </strong>' + exp.e + ' :: <strong>Variation ID: </strong>' + id; | |
return this.buildDivRow(html); | |
}, | |
getMultivariateCreativeKeyGroup: function(exp) { | |
var ckg = exp.ckg; /* What does 0 mean here? Does that mean not a multivariate? */ | |
var html = '<strong>Experiment ID: </strong>' + exp.e + ' :: <strong>Variation Creative Key Group: </strong>' + ckg; | |
return this.buildDivRow(html); | |
}, | |
getExperimentFullInfo: function(exp) { | |
var index = exp.cnt === 1 ? 'Control (0) ' : 'X'; | |
var html = | |
'<strong>Experiment ID: </strong>' + exp.e + ' :: ' + | |
'<strong>Iteration ID: </strong>' + exp.i + ' :: ' + | |
'<strong>Active Variation ID: </strong>' + exp.cm + ' :: ' + | |
'<strong>Active Variation Index: </strong>' + index + ' :: ' + | |
'<strong>Active Variation Creative Key Group: </strong>' + exp.ckg + ' :: ' + | |
'<strong>Probability to Bucket: </strong>' + (exp.pc * 100) + '% :: ' + | |
'<strong>Actual Probability of User to Bucket: </strong>' + (exp.p * 100) + '% '; | |
return this.buildDivRow(html); | |
}, | |
getAllRunningExperiments: function() { | |
var all_exps = []; | |
var curr_exp; | |
var html = ''; | |
for (var i = 0; i < ALL_EXP.length; i++) { | |
curr_exp = ALL_EXP[i]; | |
all_exps.push(curr_exp.id); | |
} | |
html += '<strong>All Running Experiments (by ID): </strong>' + all_exps.join(', '); | |
return this.buildDivRow(html); | |
}, | |
getActiveExperiments: function() { | |
var active_exps = []; | |
var curr_exp; | |
var html = ''; | |
for (var i = 0; i < CURR_EXP.length; i++) { | |
curr_exp = CURR_EXP[i]; | |
active_exps.push(curr_exp.e); | |
} | |
html += '<strong>All ACTIVE Experiments (by ID): </strong>' + active_exps.join(', '); | |
return this.buildDivRow(html); | |
}, | |
getActiveExperimentsFullInfo: function() { | |
var curr_exp; | |
var wrap = document.createElement('div'); | |
for (var i = 0; i < CURR_EXP.length; i++) { | |
curr_exp = CURR_EXP[i]; | |
wrap.appendChild(this.getExperimentFullInfo(curr_exp)); | |
} | |
return wrap; | |
}, | |
loopAndBuild: function(exps, buildFn) { | |
var wrap = document.createElement('div'); | |
for (var i = 0; i < exps.length; i++) { | |
wrap.appendChild(buildFn.call(this, exps[i])); | |
} | |
return wrap; | |
}, | |
createAndAddStylesheet: function(styles) { | |
var css = document.createElement('style'); | |
css.type = 'text/css'; | |
css.id = "qubit-debugger-styles"; | |
if (css.styleSheet) { | |
css.styleSheet.cssText = styles; | |
} else { | |
css.appendChild(document.createTextNode(styles)); | |
} | |
HEAD.appendChild(css); | |
}, | |
buildModal: function() { | |
var html = ""; | |
html += "<div id=\"qubit-modal-overlay\"> "; | |
html += " <div id=\"qubit-modal-container\">"; | |
html += " <div id=\"qubit-modal-close-x\"><\/div>"; | |
html += " <div id=\"qubit-header\">Qubit Debugger \/ Experiment Info<\/div>"; | |
html += " <div id=\"qubit-options\">"; | |
html += " <h3>Experiments & Variations Mapping<\/h3>"; | |
html += " <input type=\"checkbox\" id=\"qubit-all-running-experiments\" \/>"; | |
html += " <label for=\"qubit-all-running-experiments\"><span><\/span>All Running Experiments*<\/label>"; | |
html += " <input type=\"checkbox\" id=\"qubit-active-experiments\" \/>"; | |
html += " <label for=\"qubit-active-experiments\"><span><\/span>Active Experiments<\/label>"; | |
html += " <br \/>"; | |
html += " <input type=\"checkbox\" id=\"qubit-variations-index-map\" \/>"; | |
html += " <label for=\"qubit-variations-index-map\"><span><\/span>Variations Mapping By Index (0 is Original)<\/label>"; | |
html += " <br \/>"; | |
html += " <input type=\"checkbox\" id=\"qubit-variations-id-map\" \/>"; | |
html += " <label for=\"qubit-variations-id-map\"><span><\/span>Variations Mapping By ID<\/label>"; | |
html += " <br \/>"; | |
html += " <input type=\"checkbox\" id=\"qubit-variations-name-ckg\" \/>"; | |
html += " <label for=\"qubit-variations-name-ckg\"><span><\/span>Variations Mapping By Creative Key Group<\/label>"; | |
html += " <br \/>"; | |
html += " <input type=\"checkbox\" id=\"qubit-smartserve-id\" \/>"; | |
html += " <label for=\"qubit-smartserve-id\"><span><\/span>SmartServe Script ID<\/label>"; | |
html += " <br \/>"; | |
html += " <input type=\"checkbox\" id=\"qubit-active-experiments-full-info\" \/>"; | |
html += " <label for=\"qubit-active-experiments-full-info\"><span><\/span>All Active Experiments Full Info<\/label>"; | |
html += " <br \/>"; | |
html += " <p class=\"note\">* All \"running experiments\" refers to all currently active layers (i.e. experiments) within a container, <strong>regardless of bucketing\/segmentation criteria<\/strong><\/p>"; | |
html += " <p class=\"note\">* \"Active\" experiments refers to all layers (i.e. experiments) within a container <strong>that you are currently bucketed into<\/strong><\/p>"; | |
html += " <\/div>"; | |
html += " <div class=\"center-me\"><button id=\"qubit-go\">Go!<\/button><\/div>"; | |
html += " <div id=\"qubit-results\"><\/div>"; | |
html += " <div id=\"qubit-help\">"; | |
html += " <a id=\"qubit-modal-destroy\" href=\"#\">Start Over<\/a>"; | |
html += " <a href=\"http:\/\/docs.qubitproducts.com\" target=\"_blank\">Qubit Docs<\/a>"; | |
html += " <\/div>"; | |
html += " <div id=\"qubit-close-modal-wrap\" class=\"center-me\"><button id=\"qubit-close-modal\">CLOSE<\/button><\/div>"; | |
html += " <\/div>"; | |
html += "<\/div>"; | |
this.el.innerHTML = html; | |
BODY.appendChild(this.el); | |
}, | |
destroy: function() { | |
this.el.remove(); | |
var stylesheet = document.getElementById('qubit-debugger-styles'); | |
if (stylesheet) stylesheet.remove(); | |
}, | |
showResults: function() { | |
document.getElementById('qubit-options').style.display = "none"; | |
document.getElementById('qubit-go').style.display = "none"; | |
document.getElementById('qubit-results').style.display = "block"; | |
document.getElementById('qubit-help').style.display = "block"; | |
document.getElementById('qubit-close-modal-wrap').style.display = "block"; | |
}, | |
handleSelectedOptions: function() { | |
var results = document.getElementById('qubit-results'); | |
var self = this; | |
if (document.getElementById('qubit-all-running-experiments').checked) { | |
results.appendChild(this.getAllRunningExperiments()); | |
} | |
if (document.getElementById('qubit-active-experiments').checked) { | |
results.appendChild(this.getActiveExperiments()); | |
} | |
if (document.getElementById('qubit-variations-index-map').checked) { | |
results.appendChild(this.loopAndBuild(CURR_EXP, this.getExperimentVariationMapByIndex)); | |
} | |
if (document.getElementById('qubit-variations-id-map').checked) { | |
results.appendChild(this.loopAndBuild(CURR_EXP, this.getExperimentVariationMapById)); | |
} | |
if (document.getElementById('qubit-variations-name-ckg').checked) { | |
results.appendChild(this.loopAndBuild(CURR_EXP, this.getMultivariateCreativeKeyGroup)); | |
} | |
if (document.getElementById('qubit-smartserve-id').checked) { | |
results.appendChild(this.getSmartServeScriptId()); | |
} | |
if (document.getElementById('qubit-active-experiments-full-info').checked) { | |
results.appendChild(this.getActiveExperimentsFullInfo()); | |
} | |
}, | |
setGoBtnHandler: function() { | |
var self = this; | |
var go_btn = document.getElementById('qubit-go'); | |
go_btn.addEventListener('click', function() { | |
self.handleSelectedOptions(); | |
self.showResults(); | |
}); | |
}, | |
setCloseBtnsHandler: function() { | |
var self = this; | |
var close_btn = document.getElementById('qubit-close-modal'); | |
var x_btn = document.getElementById('qubit-modal-close-x'); | |
close_btn.addEventListener('click', function() { | |
self.destroy(); | |
}); | |
x_btn.addEventListener('click', function() { | |
self.destroy(); | |
}); | |
}, | |
setStartOverBtnHandler: function() { | |
var self = this; | |
var start_over_btn = document.getElementById('qubit-modal-destroy'); | |
start_over_btn.addEventListener('click', function(e) { | |
e.preventDefault(); | |
self.destroy(); | |
self.init(); | |
}); | |
}, | |
setListeners: function() { | |
this.setGoBtnHandler(); | |
this.setCloseBtnsHandler(); | |
this.setStartOverBtnHandler(); | |
}, | |
init: function() { | |
if (this.checkQubitVarsLoaded()) { | |
this.createAndAddStylesheet(this.styles); | |
this.buildModal(); | |
this.setListeners(); | |
} | |
} | |
}; | |
var modal = new Modal(); | |
modal.init(); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment