Add Rescroller chromium

This commit is contained in:
toto 2022-11-02 16:46:54 +01:00
parent c3086d65e0
commit 640b47342c
35 changed files with 31625 additions and 0 deletions

View File

@ -0,0 +1,5 @@
## About Rescroller
Rescroller allows you to customize the look and feel of scrollbars on webpages within Google Chrome. Using the included settings, set the color, shadows, borders, etc. of each scrollbar element, or write custom CSS to style the scrollbars manually.
[![Get Rescroller](https://developer.chrome.com/webstore/images/ChromeWebStore_Badge_v2_340x96.png "Get Rescroller")](https://chrome.google.com/webstore/detail/rescroller/ddehdnnhjimbggeeenghijehnpakijod)

View File

@ -0,0 +1 @@
[{"description":"treehash per file","signed_content":{"payload":"eyJjb250ZW50X2hhc2hlcyI6W3siYmxvY2tfc2l6ZSI6NDA5NiwiZGlnZXN0Ijoic2hhMjU2IiwiZmlsZXMiOlt7InBhdGgiOiJSRUFETUUubWQiLCJyb290X2hhc2giOiJ3VldaRHo5OUsza2F3SlhDZlY4ZXNFYTV6OEgwcVkzTFlFOTd2NFAwbXRzIn0seyJwYXRoIjoiUmlnaHRlb3VzLVJlZ3VsYXIudHRmIiwicm9vdF9oYXNoIjoiUGpPaTc1UFNlNFVzY21uM2R0bmFlcnhITjdsb2FfZHNYb2F2MktWdG1jZyJ9LHsicGF0aCI6ImFwcGljb25zL2ljb24xMjgucG5nIiwicm9vdF9oYXNoIjoiWFpnN3NFdk9SQkxrd2Zqd2JPUGdYUGNrZ1dwbk9TOWZvb3BIS19TRDVxUSJ9LHsicGF0aCI6ImFwcGljb25zL2ljb24xNi5wbmciLCJyb290X2hhc2giOiJFdzRsdVNzZkp4UEJUbjZ6N205U2xKNkJBa2E2Q2UxMUFOS0lxb21pTVVRIn0seyJwYXRoIjoiYXBwaWNvbnMvaWNvbjE5LnBuZyIsInJvb3RfaGFzaCI6ImhzZV9kbGJVZTdTanZORGd1SklBdG1QOUNPY19RSC13bzNfVFYxLWlVd1kifSx7InBhdGgiOiJhcHBpY29ucy9pY29uMzgucG5nIiwicm9vdF9oYXNoIjoiTzAzRUlfQUpuREgyUHozMUNjMmFlYVhMbXhWemZ6dXlTcEZCUXE4WkVzOCJ9LHsicGF0aCI6ImFwcGljb25zL2ljb240OC5wbmciLCJyb290X2hhc2giOiJFb3IxcFZ5Y3FwSzdlVzc1TjgwQkZtVVcxc1R1RUlYNnItblRJekw1QktVIn0seyJwYXRoIjoiaW1hZ2VzL2JnLnBuZyIsInJvb3RfaGFzaCI6IlZ6YU5pMjBxNmFHb2hmcEJ3RHpzMjR3NnozX1ltVzd6UjQwRzhIa1NiXzQifSx7InBhdGgiOiJpbWFnZXMvY2xvc2UtYnV0dG9uLnBuZyIsInJvb3RfaGFzaCI6Im02VkNCSUFCRm90Q0I5Z1VNN2RobVdja2xUZkJjTGN0TklYSzNLQnVycUkifSx7InBhdGgiOiJpbWFnZXMvZGVmYXVsdHMvZG93bi5wbmciLCJyb290X2hhc2giOiJpQmY2MVBoeTY1dm4wbzI2ZXlJVXFDUHoxaGttUnVmU2ZNYmFNaTB5RTJRIn0seyJwYXRoIjoiaW1hZ2VzL2RlZmF1bHRzL2xlZnQucG5nIiwicm9vdF9oYXNoIjoibUJscW5PQV84RldocXB6LUVINXpQVEpCbHdFcl9YOTFibEZ5RzF4V3RIZyJ9LHsicGF0aCI6ImltYWdlcy9kZWZhdWx0cy9yaWdodC5wbmciLCJyb290X2hhc2giOiJ5ZExHQTZSQ1plbkFaYmVzT0VRSmJjS3ZVbU5xSVBkMm1pTEtFWGcyb2NzIn0seyJwYXRoIjoiaW1hZ2VzL2RlZmF1bHRzL3VwLnBuZyIsInJvb3RfaGFzaCI6IkN1cm1yaUY4SG5ubEZyazdyRWlJYkFxSU4zVlJLUFVxS29iTUZDbTZkU3cifSx7InBhdGgiOiJpbWFnZXMvbG9nby1ob3Zlci5wbmciLCJyb290X2hhc2giOiJOUGsweU5zZEVNbXVSY2xvdV9fcFo2c1F2cWo2U2tld3FKN1M3YVljdnBzIn0seyJwYXRoIjoiaW1hZ2VzL2xvZ28ucG5nIiwicm9vdF9oYXNoIjoiV05Pbk5zdFN6QmpKbmZUWG5FZ2VnT1JUSjdwdFZQR0ZQSWRMNUppWXZRQSJ9LHsicGF0aCI6ImpzL2JhY2tncm91bmQuanMiLCJyb290X2hhc2giOiJoTDY1aGFOMjJxWTFsMC1nal9URzJvRjk5VXMxU1ZyeE9MMU9NOGd1SjhzIn0seyJwYXRoIjoianMvY3NzanNvbi5qcyIsInJvb3RfaGFzaCI6ImNVLWllQUExMER5MTJpcEhrajdpV2FZVTFJRXBUc3Q2X2JISW5WN0RMWUUifSx7InBhdGgiOiJqcy9qcXVlcnktbWluaWNvbG9ycy9pbWFnZXMvY29sb3JzLnBuZyIsInJvb3RfaGFzaCI6InZwbU1Ha29qbnVhYkQ3UG1LTC1aeW5lOFJTVDQtSXIwbHlrZ25QSVA0THMifSx7InBhdGgiOiJqcy9qcXVlcnktbWluaWNvbG9ycy9qcXVlcnkubWluaUNvbG9ycy5jc3MiLCJyb290X2hhc2giOiJ4Q3U4ZDYyakFtODJxdmJPOWZoMUVqblV1ZTVlM1hxTF83WWZCZHdDZFNjIn0seyJwYXRoIjoianMvanF1ZXJ5LW1pbmljb2xvcnMvanF1ZXJ5Lm1pbmlDb2xvcnMuanMiLCJyb290X2hhc2giOiJmRVpSbTF6aDVPVkxZWlhOc0JsZGxRX0pqQ0pwU3lzcjJzWmNoNHJRRzFjIn0seyJwYXRoIjoianMvanF1ZXJ5LXVpLmpzIiwicm9vdF9oYXNoIjoibWtuQ0cwSFFDS08tUTdKanczWXotckpiS2dldUlXZ3BlcVVaZXJZVDltcyJ9LHsicGF0aCI6ImpzL2pxdWVyeS5qcyIsInJvb3RfaGFzaCI6Im96UGZtWmtkYjRiS2d4WXdtaGptRXcxZE1nSXlfaC1jODhvTHZuM1dUV2sifSx7InBhdGgiOiJqcy9vcHRpb25zLmpzIiwicm9vdF9oYXNoIjoiRXhHS3luRmFvR1hvYXhXT0hpdnA4WFR3SEJHdlNTR2YwSzNhVEJJUHU3WSJ9LHsicGF0aCI6ImpzL3Jlc2Nyb2xsZXIuanMiLCJyb290X2hhc2giOiJudVdneDZZY25Yd01LZzh6anpDZFB0UEN5Q2RHZVJaT1dudVpCM1FKclpRIn0seyJwYXRoIjoibWFuaWZlc3QuanNvbiIsInJvb3RfaGFzaCI6IjVSUmJoUWhvSjRLVGtCTURiZTJYV25faXFSWmZPMS12ekRqQ1NsdjFpYmcifSx7InBhdGgiOiJub2h1cC5vdXQiLCJyb290X2hhc2giOiJNT0F1dXNrVkIyX29ra01LVDF1MjZqVGR4TUVFLU5OX2ZoYjhNMlVHS0xJIn0seyJwYXRoIjoib3B0aW9ucy5odG1sIiwicm9vdF9oYXNoIjoiRTlNRTZXaXZsOUVfaEdZM2Y0YWZ3Y25SRGRMLTNQcU82UkV5c0c1QWZ3OCJ9LHsicGF0aCI6InN0eWxlLmNzcyIsInJvb3RfaGFzaCI6InZySFNEOTh2M21HZkhScFZjdG9aYUk2RFlkeFZCbmN4MXRpMVVYd0RIdXcifV0sImZvcm1hdCI6InRyZWVoYXNoIiwiaGFzaF9ibG9ja19zaXplIjo0MDk2fV0sIml0ZW1faWQiOiJkZGVoZG5uaGppbWJnZ2VlZW5naGlqZWhucGFraWpvZCIsIml0ZW1fdmVyc2lvbiI6IjEuMyIsInByb3RvY29sX3ZlcnNpb24iOjF9","signatures":[{"header":{"kid":"publisher"},"protected":"eyJhbGciOiJSUzI1NiJ9","signature":"ghkBssOwtjM_sZKKAbrl3ezjK-TKYwfrMfWa1uFHs5kQ9K_Gyrv4f23ydLBS1DYU3Vb2jfLXVU9ng-byD0SNEzQshupx1lAg9YTjKxw3ngktdzHWSewEANmpljVinNwqqEp_oviMcc29rr_HVr5PFoucYWvuJ1Oec21YDIKuM9E"},{"header":{"kid":"webstore"},"protected":"eyJhbGciOiJSUzI1NiJ9","signature":"TzaONt0eUFC1D9jt2Rs-mWeZa0zAG8Ahig0kBBELA-fkT4vXLR3H4kAEy__RNqw6QgkwgoeZdJSdZP2VDYrDcDKE41axv1WyWFFNeyFuAkR8Gbn9Plu7Y6lsPMkQCG80M4H0tQWTT8ABd_vjBAlsZ0aL_5xRSJvZb23dZy2bBfQDsZp-PkHzuRJoK_vu9h1xnu0SOPjVI9E7Tz6MosaNP330RtnD3qmMU8zqeO48O0AzTJUeMcP-J_4t1VeBURo2bmc1F63Z2UjPpE36-XZI9ixyE0JXoApX1p9r3AvCIAYptz3JLGcOjb03rn0o4S7E5jZriMjGHzec9Xh6Q8dqpQ"}]}}]

View File

@ -0,0 +1,79 @@
/**
* Background Event page: this handles events for the extension between pages and performs the following:
*
* - Handles browser action button click (opening of options.html)
* - Handles first-time install by setting install_time in local storage and opening options.html
* - Hanldes changes to chrome.sync and syncs down CSS updated remotely
* - Hands generated CSS over to tabs when requested
*
* Note: because this is a non-persistent ('event') background page, this script will only load to run
* event callbacks. Do not put any code outside of listeners!
*
* Note: Unfortunately, we need to load jquery.js and cssjson.js here, since they are needed when the CSS
* hasn't been precomputed or needs to be regenerated.
*/
chrome.runtime.onInstalled.addListener(function(details) { // when extension installed/updated and chrome updated
/**
* If this is the first time running the extension, open options page
* and Download latest Chrome Storage to Local Storage.
*/
if (details.reason != 'install') { // no need to sync down if updating.
Rescroller.performMigrations();
return;
}
Rescroller.syncDown(function() {
if (localStorage['install_time']) { return; } // only open options.html if this is the first install on any of the users' Chromes
localStorage['install_time'] = new Date().getTime();
chrome.tabs.create({ url: 'options.html' });
});
});
/**
* Listen for page states to change and set our custom CSS when tabs are loading
*/
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
if (changeInfo.status != 'loading') { return; }
// Check to make sure this url isn't blacklisted. Exit early if so
var restrictedSites = Rescroller.getListOfDisabledSites();
for (var restricted in restrictedSites) {
var restricted = restrictedSites[restricted];
if (!restricted) { continue; }
if (tab.url.indexOf(restricted) >= 0) { return; } // @todo this could probably be more accurate
}
// Aaaand, inject our customized CSS into the webpage!
chrome.tabs.insertCSS(tabId, { // unfortunately, this requires the <all_urls> permission :/
code: localStorage['generated-css'],
allFrames: true,
runAt: 'document_start'
});
});
/**
* Handle action button in Chrome toolbar
*/
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.tabs.create({ url: "options.html" });
})
/**
* Detect changes to Chrome Storage, and import them into Local Storage
*/
chrome.storage.onChanged.addListener(function(changes, namespace) {
// Convert these 'changes' into a key-val object, parallel to how localStorage is formatted (no need for change[].oldValue)
var changesCleaned = {};
for (var key in changes) {
changesCleaned[key] = changes[key].newValue
}
Rescroller.mergeSyncWithLocalStorage(changesCleaned);
});

View File

@ -0,0 +1,297 @@
/**
* CSS-JSON Converter for JavaScript
* Converts CSS to JSON and back.
* Version 2.1
*
* Released under the MIT license.
*
* Copyright (c) 2013 Aram Kocharyan, http://aramk.com/
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
var CSSJSON = new function () {
var base = this;
base.init = function () {
// String functions
String.prototype.trim = function () {
return this.replace(/^\s+|\s+$/g, '');
};
String.prototype.repeat = function (n) {
return new Array(1 + n).join(this);
};
};
base.init();
var selX = /([^\s\;\{\}][^\;\{\}]*)\{/g;
var endX = /\}/g;
var lineX = /([^\;\{\}]*)\;/g;
var commentX = /\/\*[\s\S]*?\*\//g;
var lineAttrX = /([^\:]+):([^\;]*);/;
// This is used, a concatenation of all above. We use alternation to
// capture.
var altX = /(\/\*[\s\S]*?\*\/)|([^\s\;\{\}][^\;\{\}]*(?=\{))|(\})|([^\;\{\}]+\;(?!\s*\*\/))/gmi;
// Capture groups
var capComment = 1;
var capSelector = 2;
var capEnd = 3;
var capAttr = 4;
var isEmpty = function (x) {
return typeof x == 'undefined' || x.length == 0 || x == null;
};
var isCssJson = function (node) {
return !isEmpty(node) ? (node.attributes && node.children) : false;
}
/**
* Input is css string and current pos, returns JSON object
*
* @param cssString
* The CSS string.
* @param args
* An optional argument object. ordered: Whether order of
* comments and other nodes should be kept in the output. This
* will return an object where all the keys are numbers and the
* values are objects containing "name" and "value" keys for each
* node. comments: Whether to capture comments. split: Whether to
* split each comma separated list of selectors.
*/
base.toJSON = function (cssString, args) {
var node = {
children: {},
attributes: {}
};
var match = null;
var count = 0;
if (typeof args == 'undefined') {
var args = {
ordered: false,
comments: false,
stripComments: false,
split: false
};
}
if (args.stripComments) {
args.comments = false;
cssString = cssString.replace(commentX, '');
}
while ((match = altX.exec(cssString)) != null) {
if (!isEmpty(match[capComment]) && args.comments) {
// Comment
var add = match[capComment].trim();
node[count++] = add;
} else if (!isEmpty(match[capSelector])) {
// New node, we recurse
var name = match[capSelector].trim();
// This will return when we encounter a closing brace
var newNode = base.toJSON(cssString, args);
if (args.ordered) {
var obj = {};
obj['name'] = name;
obj['value'] = newNode;
// Since we must use key as index to keep order and not
// name, this will differentiate between a Rule Node and an
// Attribute, since both contain a name and value pair.
obj['type'] = 'rule';
node[count++] = obj;
} else {
if (args.split) {
var bits = name.split(',');
} else {
var bits = [name];
}
for (i in bits) {
var sel = bits[i].trim();
if (sel in node.children) {
for (var att in newNode.attributes) {
node.children[sel].attributes[att] = newNode.attributes[att];
}
} else {
node.children[sel] = newNode;
}
}
}
} else if (!isEmpty(match[capEnd])) {
// Node has finished
return node;
} else if (!isEmpty(match[capAttr])) {
var line = match[capAttr].trim();
var attr = lineAttrX.exec(line);
if (attr) {
// Attribute
var name = attr[1].trim();
var value = attr[2].trim();
if (args.ordered) {
var obj = {};
obj['name'] = name;
obj['value'] = value;
obj['type'] = 'attr';
node[count++] = obj;
} else {
if (name in node.attributes) {
var currVal = node.attributes[name];
if (!(currVal instanceof Array)) {
node.attributes[name] = [currVal];
}
node.attributes[name].push(value);
} else {
node.attributes[name] = value;
}
}
} else {
// Semicolon terminated line
node[count++] = line;
}
}
}
return node;
};
/**
* @param node
* A JSON node.
* @param depth
* The depth of the current node; used for indentation and
* optional.
* @param breaks
* Whether to add line breaks in the output.
*/
base.toCSS = function (node, depth, breaks) {
var cssString = '';
if (typeof depth == 'undefined') {
depth = 0;
}
if (typeof breaks == 'undefined') {
breaks = false;
}
if (node.attributes) {
for (i in node.attributes) {
var att = node.attributes[i];
if (att instanceof Array) {
for (var j = 0; j < att.length; j++) {
cssString += strAttr(i, att[j], depth);
}
} else {
cssString += strAttr(i, att, depth);
}
}
}
if (node.children) {
var first = true;
for (i in node.children) {
if (breaks && !first) {
cssString += '\n';
} else {
first = false;
}
cssString += strNode(i, node.children[i], depth);
}
}
return cssString;
};
/**
* @param data
* You can pass css string or the CSSJS.toJSON return value.
* @param id (Optional)
* To identify and easy removable of the style element
* @param replace (Optional. defaults to TRUE)
* Whether to remove or simply do nothing
* @return HTMLLinkElement
*/
base.toHEAD = function (data, id, replace) {
var head = document.getElementsByTagName('head')[0];
var xnode = document.getElementById(id);
var _xnodeTest = (xnode !== null && xnode instanceof HTMLStyleElement);
if (isEmpty(data) || !(head instanceof HTMLHeadElement)) return;
if (_xnodeTest) {
if (replace === true || isEmpty(replace)) {
xnode.removeAttribute('id');
} else return;
}
if (isCssJson(data)) {
data = base.toCSS(data);
}
var node = document.createElement('style');
node.type = 'text/css';
if (!isEmpty(id)) {
node.id = id;
} else {
node.id = 'cssjson_' + timestamp();
}
if (node.styleSheet) {
node.styleSheet.cssText = data;
} else {
node.appendChild(document.createTextNode(data));
}
head.appendChild(node);
if (isValidStyleNode(node)) {
if (_xnodeTest) {
xnode.parentNode.removeChild(xnode);
}
} else {
node.parentNode.removeChild(node);
if (_xnodeTest) {
xnode.setAttribute('id', id);
node = xnode;
} else return;
}
return node;
};
// Alias
if (typeof window != 'undefined') {
window.createCSS = base.toHEAD;
}
// Helpers
var isValidStyleNode = function (node) {
return (node instanceof HTMLStyleElement) && node.sheet.cssRules.length > 0;
}
var timestamp = function () {
return Date.now() || +new Date();
};
var strAttr = function (name, value, depth) {
return '\t'.repeat(depth) + name + ': ' + value + ';\n';
};
var strNode = function (name, value, depth) {
var cssString = '\t'.repeat(depth) + name + ' {\n';
cssString += base.toCSS(value, depth + 1);
cssString += '\t'.repeat(depth) + '}\n';
return cssString;
};
};

View File

@ -0,0 +1,81 @@
.miniColors-trigger {
height: 22px;
width: 22px;
background: url(images/trigger.png) center no-repeat;
vertical-align: middle;
margin: 0 .25em;
display: inline-block;
outline: none;
}
.miniColors-selector {
position: absolute;
width: 175px;
height: 150px;
background: #FFF;
border: solid 1px #BBB;
-moz-box-shadow: 0 0 6px rgba(0, 0, 0, .25);
-webkit-box-shadow: 0 0 6px rgba(0, 0, 0, .25);
box-shadow: 0 0 6px rgba(0, 0, 0, .25);
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border-radius: 5px;
padding: 5px;
z-index: 999999;
}
.miniColors-selector.black {
background: #000;
border-color: #000;
}
.miniColors-colors {
position: absolute;
top: 5px;
left: 5px;
width: 150px;
height: 150px;
background: url(images/colors.png) right no-repeat;
cursor: crosshair;
}
.miniColors-hues {
position: absolute;
top: 5px;
left: 160px;
width: 20px;
height: 150px;
background: url(images/colors.png) left no-repeat;
cursor: crosshair;
}
.miniColors-colorPicker {
position: absolute;
width: 9px;
height: 9px;
border: 1px solid #fff;
-moz-border-radius: 11px;
-webkit-border-radius: 11px;
border-radius: 11px;
}
.miniColors-colorPicker-inner {
position: absolute;
top: 0;
left: 0;
width: 7px;
height: 7px;
border: 1px solid #000;
-moz-border-radius: 9px;
-webkit-border-radius: 9px;
border-radius: 9px;
}
.miniColors-huePicker {
position: absolute;
left: -3px;
width: 24px;
height: 1px;
border: 1px solid #fff;
border-radius: 2px;
background: #000;
}

View File

@ -0,0 +1,592 @@
/*
* jQuery miniColors: A small color selector
*
* Copyright 2011 Cory LaViska for A Beautiful Site, LLC. (http://abeautifulsite.net/)
*
* Dual licensed under the MIT or GPL Version 2 licenses
*
*/
if(jQuery) (function($) {
$.extend($.fn, {
miniColors: function(o, data) {
var create = function(input, o, data) {
//
// Creates a new instance of the miniColors selector
//
// Determine initial color (defaults to white)
var color = expandHex(input.val());
if( !color ) color = 'ffffff';
var hsb = hex2hsb(color);
// Create trigger
var trigger = $('<a class="miniColors-trigger" style="background-color: #' + color + '" href="#"></a>');
trigger.insertAfter(input);
// Set input data and update attributes
input
.addClass('miniColors')
.data('original-maxlength', input.attr('maxlength') || null)
.data('original-autocomplete', input.attr('autocomplete') || null)
.data('letterCase', 'uppercase')
.data('trigger', trigger)
.data('hsb', hsb)
.data('change', o.change ? o.change : null)
.data('close', o.close ? o.close : null)
.data('open', o.open ? o.open : null)
.attr('maxlength', 7)
.attr('autocomplete', 'off')
.val('#' + convertCase(color, o.letterCase));
// Handle options
if( o.readonly ) input.prop('readonly', true);
if( o.disabled ) disable(input);
// Show selector when trigger is clicked
trigger.bind('click.miniColors', function(event) {
event.preventDefault();
if( input.val() === '' ) input.val('#');
show(input);
});
// Show selector when input receives focus
input.bind('focus.miniColors', function(event) {
if( input.val() === '' ) input.val('#');
show(input);
});
// Hide on blur
input.bind('blur.miniColors', function(event) {
var hex = expandHex( hsb2hex(input.data('hsb')) );
input.val( hex ? '#' + convertCase(hex, input.data('letterCase')) : '' );
});
// Hide when tabbing out of the input
input.bind('keydown.miniColors', function(event) {
if( event.keyCode === 9 ) hide(input);
});
// Update when color is typed in
input.bind('keyup.miniColors', function(event) {
setColorFromInput(input);
});
// Handle pasting
input.bind('paste.miniColors', function(event) {
// Short pause to wait for paste to complete
setTimeout( function() {
setColorFromInput(input);
}, 5);
});
};
var destroy = function(input) {
//
// Destroys an active instance of the miniColors selector
//
hide();
input = $(input);
// Restore to original state
input.data('trigger').remove();
input
.attr('autocomplete', input.data('original-autocomplete'))
.attr('maxlength', input.data('original-maxlength'))
.removeData()
.removeClass('miniColors')
.unbind('.miniColors');
$(document).unbind('.miniColors');
};
var enable = function(input) {
//
// Enables the input control and the selector
//
input
.prop('disabled', false)
.data('trigger')
.css('opacity', 1);
};
var disable = function(input) {
//
// Disables the input control and the selector
//
hide(input);
input
.prop('disabled', true)
.data('trigger')
.css('opacity', 0.5);
};
var show = function(input) {
//
// Shows the miniColors selector
//
if( input.prop('disabled') ) return false;
// Hide all other instances
hide();
//Lines 145 and 146 and 147 were modified below by dwat to display color picker to the right of the "trigger" and the "apply" button
// Generate the selector
var selector = $('<div class="miniColors-selector"></div>');
selector
.append('<div class="miniColors-colors" style="background-color: #FFF;"><div class="miniColors-colorPicker"><div class="miniColors-colorPicker-inner"></div></div>')
.append('<div class="miniColors-hues"><div class="miniColors-huePicker"></div></div>')
.append('<div class="miniColors-apply"><a href="#">Apply</a></div>') //Added by dwat
.css({
top: input.is(':visible') ? input.offset().top + input.outerHeight() : input.data('trigger').offset().top + input.data('trigger').outerHeight() - ($(".miniColors-trigger").outerHeight() * 2.5),
left: input.is(':visible') ? input.offset().left : input.data('trigger').offset().left + $(".miniColors-trigger").outerWidth() + 3,
display: 'none'
})
.addClass( input.attr('class') );
// Set background for colors
var hsb = input.data('hsb');
selector
.find('.miniColors-colors')
.css('backgroundColor', '#' + hsb2hex({ h: hsb.h, s: 100, b: 100 }));
// Set colorPicker position
var colorPosition = input.data('colorPosition');
if( !colorPosition ) colorPosition = getColorPositionFromHSB(hsb);
selector.find('.miniColors-colorPicker')
.css('top', colorPosition.y + 'px')
.css('left', colorPosition.x + 'px');
// Set huePicker position
var huePosition = input.data('huePosition');
if( !huePosition ) huePosition = getHuePositionFromHSB(hsb);
selector.find('.miniColors-huePicker').css('top', huePosition.y + 'px');
// Set input data
input
.data('selector', selector)
.data('huePicker', selector.find('.miniColors-huePicker'))
.data('colorPicker', selector.find('.miniColors-colorPicker'))
.data('mousebutton', 0);
$('BODY').append(selector);
selector.fadeIn(100);
// Prevent text selection in IE
selector.bind('selectstart', function() { return false; });
$(document).bind('mousedown.miniColors touchstart.miniColors', function(event) {
input.data('mousebutton', 1);
var testSubject = $(event.target).parents().andSelf();
if( testSubject.hasClass('miniColors-colors') ) {
event.preventDefault();
input.data('moving', 'colors');
moveColor(input, event);
}
if( testSubject.hasClass('miniColors-hues') ) {
event.preventDefault();
input.data('moving', 'hues');
moveHue(input, event);
}
if( testSubject.hasClass('miniColors-selector') ) {
event.preventDefault();
return;
}
if( testSubject.hasClass('miniColors') ) return;
hide(input);
});
$(document)
.bind('mouseup.miniColors touchend.miniColors', function(event) {
event.preventDefault();
input.data('mousebutton', 0).removeData('moving');
})
.bind('mousemove.miniColors touchmove.miniColors', function(event) {
event.preventDefault();
if( input.data('mousebutton') === 1 ) {
if( input.data('moving') === 'colors' ) moveColor(input, event);
if( input.data('moving') === 'hues' ) moveHue(input, event);
}
});
// Fire open callback
if( input.data('open') ) {
input.data('open').call(input.get(0), '#' + hsb2hex(hsb), hsb2rgb(hsb));
}
};
var hide = function(input) {
//
// Hides one or more miniColors selectors
//
// Hide all other instances if input isn't specified
if( !input ) input = '.miniColors';
$(input).each( function() {
var selector = $(this).data('selector');
$(this).removeData('selector');
$(selector).fadeOut(100, function() {
// Fire close callback
if( input.data('close') ) {
var hsb = input.data('hsb'), hex = hsb2hex(hsb);
input.data('close').call(input.get(0), '#' + hex, hsb2rgb(hsb));
}
$(this).remove();
});
});
$(document).unbind('.miniColors');
};
var moveColor = function(input, event) {
var colorPicker = input.data('colorPicker');
colorPicker.hide();
var position = {
x: event.pageX,
y: event.pageY
};
// Touch support
if( event.originalEvent.changedTouches ) {
position.x = event.originalEvent.changedTouches[0].pageX;
position.y = event.originalEvent.changedTouches[0].pageY;
}
position.x = position.x - input.data('selector').find('.miniColors-colors').offset().left - 5;
position.y = position.y - input.data('selector').find('.miniColors-colors').offset().top - 5;
if( position.x <= -5 ) position.x = -5;
if( position.x >= 144 ) position.x = 144;
if( position.y <= -5 ) position.y = -5;
if( position.y >= 144 ) position.y = 144;
input.data('colorPosition', position);
colorPicker.css('left', position.x).css('top', position.y).show();
// Calculate saturation
var s = Math.round((position.x + 5) * 0.67);
if( s < 0 ) s = 0;
if( s > 100 ) s = 100;
// Calculate brightness
var b = 100 - Math.round((position.y + 5) * 0.67);
if( b < 0 ) b = 0;
if( b > 100 ) b = 100;
// Update HSB values
var hsb = input.data('hsb');
hsb.s = s;
hsb.b = b;
// Set color
setColor(input, hsb, true);
};
var moveHue = function(input, event) {
var huePicker = input.data('huePicker');
huePicker.hide();
var position = {
y: event.pageY
};
// Touch support
if( event.originalEvent.changedTouches ) {
position.y = event.originalEvent.changedTouches[0].pageY;
}
position.y = position.y - input.data('selector').find('.miniColors-colors').offset().top - 1;
if( position.y <= -1 ) position.y = -1;
if( position.y >= 149 ) position.y = 149;
input.data('huePosition', position);
huePicker.css('top', position.y).show();
// Calculate hue
var h = Math.round((150 - position.y - 1) * 2.4);
if( h < 0 ) h = 0;
if( h > 360 ) h = 360;
// Update HSB values
var hsb = input.data('hsb');
hsb.h = h;
// Set color
setColor(input, hsb, true);
};
var setColor = function(input, hsb, updateInput) {
input.data('hsb', hsb);
var hex = hsb2hex(hsb);
if( updateInput ) input.val( '#' + convertCase(hex, input.data('letterCase')) );
input.data('trigger').css('backgroundColor', '#' + hex);
if( input.data('selector') ) input.data('selector').find('.miniColors-colors').css('backgroundColor', '#' + hsb2hex({ h: hsb.h, s: 100, b: 100 }));
// Fire change callback
if( input.data('change') ) {
if( hex === input.data('lastChange') ) return;
input.data('change').call(input.get(0), '#' + hex, hsb2rgb(hsb));
input.data('lastChange', hex);
}
};
var setColorFromInput = function(input) {
input.val('#' + cleanHex(input.val()));
var hex = expandHex(input.val());
if( !hex ) return false;
// Get HSB equivalent
var hsb = hex2hsb(hex);
// If color is the same, no change required
var currentHSB = input.data('hsb');
if( hsb.h === currentHSB.h && hsb.s === currentHSB.s && hsb.b === currentHSB.b ) return true;
// Set colorPicker position
var colorPosition = getColorPositionFromHSB(hsb);
var colorPicker = $(input.data('colorPicker'));
colorPicker.css('top', colorPosition.y + 'px').css('left', colorPosition.x + 'px');
input.data('colorPosition', colorPosition);
// Set huePosition position
var huePosition = getHuePositionFromHSB(hsb);
var huePicker = $(input.data('huePicker'));
huePicker.css('top', huePosition.y + 'px');
input.data('huePosition', huePosition);
setColor(input, hsb);
return true;
};
var convertCase = function(string, letterCase) {
if( letterCase === 'lowercase' ) return string.toLowerCase();
if( letterCase === 'uppercase' ) return string.toUpperCase();
return string;
};
var getColorPositionFromHSB = function(hsb) {
var x = Math.ceil(hsb.s / 0.67);
if( x < 0 ) x = 0;
if( x > 150 ) x = 150;
var y = 150 - Math.ceil(hsb.b / 0.67);
if( y < 0 ) y = 0;
if( y > 150 ) y = 150;
return { x: x - 5, y: y - 5 };
};
var getHuePositionFromHSB = function(hsb) {
var y = 150 - (hsb.h / 2.4);
if( y < 0 ) h = 0;
if( y > 150 ) h = 150;
return { y: y - 1 };
};
var cleanHex = function(hex) {
return hex.replace(/[^A-F0-9]/ig, '');
};
var expandHex = function(hex) {
hex = cleanHex(hex);
if( !hex ) return null;
if( hex.length === 3 ) hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
return hex.length === 6 ? hex : null;
};
var hsb2rgb = function(hsb) {
var rgb = {};
var h = Math.round(hsb.h);
var s = Math.round(hsb.s*255/100);
var v = Math.round(hsb.b*255/100);
if(s === 0) {
rgb.r = rgb.g = rgb.b = v;
} else {
var t1 = v;
var t2 = (255 - s) * v / 255;
var t3 = (t1 - t2) * (h % 60) / 60;
if( h === 360 ) h = 0;
if( h < 60 ) { rgb.r = t1; rgb.b = t2; rgb.g = t2 + t3; }
else if( h < 120 ) {rgb.g = t1; rgb.b = t2; rgb.r = t1 - t3; }
else if( h < 180 ) {rgb.g = t1; rgb.r = t2; rgb.b = t2 + t3; }
else if( h < 240 ) {rgb.b = t1; rgb.r = t2; rgb.g = t1 - t3; }
else if( h < 300 ) {rgb.b = t1; rgb.g = t2; rgb.r = t2 + t3; }
else if( h < 360 ) {rgb.r = t1; rgb.g = t2; rgb.b = t1 - t3; }
else { rgb.r = 0; rgb.g = 0; rgb.b = 0; }
}
return {
r: Math.round(rgb.r),
g: Math.round(rgb.g),
b: Math.round(rgb.b)
};
};
var rgb2hex = function(rgb) {
var hex = [
rgb.r.toString(16),
rgb.g.toString(16),
rgb.b.toString(16)
];
$.each(hex, function(nr, val) {
if (val.length === 1) hex[nr] = '0' + val;
});
return hex.join('');
};
var hex2rgb = function(hex) {
hex = parseInt(((hex.indexOf('#') > -1) ? hex.substring(1) : hex), 16);
return {
r: hex >> 16,
g: (hex & 0x00FF00) >> 8,
b: (hex & 0x0000FF)
};
};
var rgb2hsb = function(rgb) {
var hsb = { h: 0, s: 0, b: 0 };
var min = Math.min(rgb.r, rgb.g, rgb.b);
var max = Math.max(rgb.r, rgb.g, rgb.b);
var delta = max - min;
hsb.b = max;
hsb.s = max !== 0 ? 255 * delta / max : 0;
if( hsb.s !== 0 ) {
if( rgb.r === max ) {
hsb.h = (rgb.g - rgb.b) / delta;
} else if( rgb.g === max ) {
hsb.h = 2 + (rgb.b - rgb.r) / delta;
} else {
hsb.h = 4 + (rgb.r - rgb.g) / delta;
}
} else {
hsb.h = -1;
}
hsb.h *= 60;
if( hsb.h < 0 ) {
hsb.h += 360;
}
hsb.s *= 100/255;
hsb.b *= 100/255;
return hsb;
};
var hex2hsb = function(hex) {
var hsb = rgb2hsb(hex2rgb(hex));
// Zero out hue marker for black, white, and grays (saturation === 0)
if( hsb.s === 0 ) hsb.h = 360;
return hsb;
};
var hsb2hex = function(hsb) {
return rgb2hex(hsb2rgb(hsb));
};
// Handle calls to $([selector]).miniColors()
switch(o) {
//Added by dwat (this case: hide...):
case 'hide':
$(this).each(function() {
if( !$(this).hasClass('miniColors') ) return;
hide($(this));
});
return $(this);
case 'readonly':
$(this).each( function() {
if( !$(this).hasClass('miniColors') ) return;
$(this).prop('readonly', data);
});
return $(this);
case 'disabled':
$(this).each( function() {
if( !$(this).hasClass('miniColors') ) return;
if( data ) {
disable($(this));
} else {
enable($(this));
}
});
return $(this);
case 'value':
// Getter
if( data === undefined ) {
if( !$(this).hasClass('miniColors') ) return;
var input = $(this),
hex = expandHex(input.val());
return hex ? '#' + convertCase(hex, input.data('letterCase')) : null;
}
// Setter
$(this).each( function() {
if( !$(this).hasClass('miniColors') ) return;
$(this).val(data);
setColorFromInput($(this));
});
return $(this);
case 'destroy':
$(this).each( function() {
if( !$(this).hasClass('miniColors') ) return;
destroy($(this));
});
return $(this);
default:
if( !o ) o = {};
$(this).each( function() {
// Must be called on an input element
if( $(this)[0].tagName.toLowerCase() !== 'input' ) return;
// If a trigger is present, the control was already created
if( $(this).data('trigger') ) return;
// Create the control
create($(this), o, data);
});
return $(this);
}
}
});
})(jQuery);

View File

@ -0,0 +1,565 @@
/**
* Javascript used to control the settings page, options.html
*/
var LOAD_START = new Date().getTime(); // keep track of when the page loads so we know to show the save settings dialog
var showSaveConfirmation;
var showSaveConfirmTime = 4000;
var saveconfirmationTimeout;
var lastClickedColorPickerPropertyID;
Rescroller.onSettingsUpdated = function() {
if (!Rescroller.settings.get('showSaveConfirmation') || (new Date().getTime() - 500) <= LOAD_START) { return; }
// Show "saved" confirmation box
clearTimeout(saveconfirmationTimeout);
$("#save-confirm").fadeIn("slow");
saveconfirmationTimeout = setTimeout(function() {
$("#save-confirm").fadeOut("slow");
}, showSaveConfirmTime)
};
//Enable functionality of Confirm Box "Never Show Again" button
$(document).ready(function() {
$("#save-confirm #hide-saved-confirm").click(function() {
Rescroller.settings.set('showSaveConfirmation', false);
$("#save-confirm").fadeOut("slow");
return false;
});
});
function refreshScrollbars() {
$("#rescroller").html(Rescroller.getCSSString());
var originalOverflow = $("body").css("overflow");
$("body").css("overflow", "hidden");
setTimeout(function() { $("body").css("overflow", originalOverflow) }, 0);
}
//Following "plugin" function found here: http://stackoverflow.com/a/10310815/477632
$.fn.draghover = function(options) {
return this.each(function() {
var collection = $(),
self = $(this);
//Note: "dragenter", "dragleave", and "dragover" need to be e.preventDefault()-ed
//in order for the webpage not to redirect to the dragged-in image:
//See explanation here: http://stackoverflow.com/a/8938581/477632
self.on('dragenter', function(e) {
e.stopPropagation();
e.preventDefault();
if (collection.size() === 0) {
self.trigger('draghoverstart');
}
collection = collection.add(e.target);
});
self.on('dragleave', function(e) {
e.stopPropagation();
e.preventDefault();
// timeout is needed because Firefox 3.6 fires the dragleave event on
// the previous element before firing dragenter on the next one
setTimeout( function() {
collection = collection.not(e.target);
if (collection.size() === 0) {
self.trigger('draghoverend');
}
}, 1);
self.on('dragover', function(e) {
e.stopPropagation();
e.preventDefault();
});
});
});
};
function showErrorMessage(msg) {
var errorBox = $("#errorbox");
errorBox.html(msg);
errorBox.slideDown("fast", function() {
setTimeout(function() {
//Hide the error message in 5 seconds
hideErrorMessage();
}, 5000);
});
}
function hideErrorMessage() {
$("#errorbox").slideUp("fast");
}
//Convert the styling stored in local storage into CSS:
var newCSS = Rescroller.getCSSString();
//Write the newly formatted CSS (from local storage) to the (beginning of the) page:
document.write('<style id="rescroller">' + newCSS + "</style>");
//When the page has loaded:
$(document).ready(function() {
refreshScrollbars();
//show generated css in css div:
$("#generatedcss").html(newCSS);
//Fill the excludedsites textarea with the list of excluded sites:
$("#excludedsites").val(Rescroller.settings.get('excludedsites'));
$("#excludedsites").change(function() {
Rescroller.settings.set('excludedsites', $(this).val());
});
//Fill the custom CSS form with the custom CSS
$("#customcss").val(Rescroller.properties.get("customcss"));
$("#customcss").change(function() {
Rescroller.properties.set("customcss", $(this).val());
refreshScrollbars();
});
//Fill the form elements with data from local storage:
$("input").each(function(index, element) {
if ($(this).attr("type") != "submit") { //Make sure we're not talking about the submit button here
if ($(this).attr("type") == "checkbox") { //If it's a check box...
//If local storage says this option should be checked, check it
if (Rescroller.properties.get($(this).attr("id")) == "checked") {
$(this).attr("checked", Rescroller.properties.get($(this).attr("id")));
}
}
//If it's an ordinary input, just fill the input with the corresponding value from local storage
else {
$(this).val(Rescroller.properties.get($(this).attr("id")));
}
}
});
});
function resetDragHoveringEventTriggering() {
var originalBackground;
var originalText;
//Following is a pain using "dragenter" and "dragleave" events. draghover() plugin (above) makes it easy!
$(window).draghover().on({
"draghoverstart" : function() {
originalBackground = $(".selector-button").css("background");
originalText = $(".selector-button").html();
$(".selector-button").animate({ "background-color" : "#C91313" }, "slow");
$(".selector-button").html("Drop Here");
},
"draghoverend" : function() {
$(".selector-button").html(originalText);
$(".selector-button").animate({ "background-color" : originalBackground }, "slow");
return false;
}
});
}
$(document).ready(function() {
$("#expandcss").click(function() {
$("#generatedcss").slideToggle("fast");
return false;
});
//Reset formatting button
$("#resetformatting").click(function() {
if (!confirm("Are you sure you would like to reset your scrollbars to default? This cannot be undone.")) { return false; }
Rescroller.restoreDefaults();
// full refresh instead of refreshScrollbars() so all our settings bars are reset as well.
// An actual JS view framework will fix this later on.
location.reload(true);
});
//Expand/collapse all non-custom css areas when that checkbox is checked
if (Rescroller.properties.get("usecustomcss") == "checked") {
$(".section").not("#misc").not($("#general")).hide();
$(".customcss-collapsible").hide();
}
$("#usecustomcss").change(function() {
if ($(this).is(":checked")) {
$(".section").not("#misc").not($("#general")).slideUp("slow");
$(".customcss-collapsible").slideUp("slow");
}
else {
$(".section").slideDown("slow");
$(".customcss-collapsible").slideDown("slow");
}
});
//Clear picture buttons
$(".clearimage").click(function() {
var key = $(this).parent().parent().attr("id");
Rescroller.properties.remove(key);
$(this).siblings(".thumbframe .thumbcontainer").html("No Image Loaded");
$(this).parents(".imagepicker-container").children("input[type=file].selector").val("");
//Hide the thumbframe and restore it with the "Select Image" button
$("#" + key).children(".thumbframe").hide();
$("#" + key).children(".selector-button").css("display", "block");
refreshScrollbars();
return false;
});
//Set correct value for <select>s
$("select").each(function() {
var thisProperty = $(this).attr('id');
var thisPropertyValue = Rescroller.properties.get(thisProperty);
$(this).children().each(function() {
if($(this).val() == thisPropertyValue) {
$(this).attr("selected", "selected");
}
});
});
//When <select> is changed, save it to local storage
$("select").change(function() {
var thisProperty = $(this).attr('id');
var currentValue = $(this).val();
Rescroller.properties.set(thisProperty, currentValue);
refreshScrollbars();
});
/***********Set up Sliders************/
//Main slider (scrollbar size)
$("#size .slider").slider({
animate: true,
min: 0,
max: 30
});
//All sliders
$(".slider").not("#size .slider").slider({
animate: true,
min: 0,
max: 100
});
//Loop through all "property" classes and set up their inner sliders, etc.
$(".slider-property").each(function() {
var propertyName = $(this).attr('id');
var theOrientation;
if ($(this).children(".slider").hasClass("slider-v")) { theOrientation = "vertical"; }
else { theOrientation = "horizontal"; }
//If this is one of the few scrollbars that uses px instead of %, set the "units" to px
var units;
if (propertyName == "size" || propertyName == "buttons-size") { units = "px"; }
else { units = "%"; }
//Fill slider value with value from local storage
$("#" + propertyName + " .slider-value").html(Rescroller.properties.get(propertyName) + units);
//Set up slider for this property
$("#" + propertyName + " .slider").slider({
value: Rescroller.properties.get(propertyName),
orientation: theOrientation,
slide: function(event, ui) {
$(this).siblings(".slider-value").html(ui.value + units);
},
change: function(event, ui) {
//Update value in local storage
Rescroller.properties.set(propertyName, ui.value);
refreshScrollbars();
}
});
});
/***********Set up Color Pickers************/
$(".colorselection").each(function() {
var localStorageKey = $(this).parent().attr("id");
var self = $(this);
$(this).miniColors({
change: function(hex, rgb) {
self.siblings(".colorvalue").val(hex);
},
close: function(hex, rgb) {
Rescroller.properties.set(localStorageKey, hex);
refreshScrollbars();
}
});
// Set default color to whatever it's been saved to
$(this).miniColors("value", Rescroller.properties.get($(this).parent().attr("id")));
// Add "apply" button
$(".miniColors-selector").append('<p><a href="#">Apply</a></p>');
});
// save the last-clicked color picker
$("a.miniColors-trigger").click(function() {
lastClickedColorPickerPropertyID = $(this).parent().attr("id");
});
// Set functionality of "apply" button
$("body").on("click", ".miniColors-apply a", function() { //applies listener to the <a> that hasn't been created yet
var colorSelectorInput = $("#" + lastClickedColorPickerPropertyID).children("input.colorselection");
colorSelectorInput.miniColors("hide");
return false;
});
// Loop through all image frames and fill them:
var keys = [
"slider-background-image-vertical",
"slider-background-image-horizontal",
"slider-background-image-vertical-hover",
"slider-background-image-horizontal-hover",
"slider-background-image-vertical-active",
"slider-background-image-horizontal-active",
"background-background-image-vertical",
"background-background-image-horizontal",
"background-background-image-vertical-hover",
"background-background-image-horizontal-hover",
"background-background-image-vertical-active",
"background-background-image-horizontal-active",
"buttons-background-image-up",
"buttons-background-image-down",
"buttons-background-image-left",
"buttons-background-image-right",
"buttons-background-image-up-hover",
"buttons-background-image-down-hover",
"buttons-background-image-left-hover",
"buttons-background-image-right-hover",
"buttons-background-image-up-active",
"buttons-background-image-down-active",
"buttons-background-image-left-active",
"buttons-background-image-right-active"
]
for (var i = 0; i < keys.length; i++) {
if (Rescroller.properties.get(keys[i]) && Rescroller.properties.get(keys[i]) != 0) {
$("#" + keys[i] + " .thumbframe div.thumbcontainer").html('<img src="' + Rescroller.properties.get(keys[i]) + '" />');
$("#" + keys[i] + " .thumbframe").css("display", "inline-block"); //show the image frame for this image
}
else {
//otherwise, show the "upload image" button (instead of the thumbframe)
$("#" + keys[i] + " .selector-button").css("display", "inline-block");
}
}
//draghover() "plugin" stops working after being utilized once, so needed to be in function that can be recalled
resetDragHoveringEventTriggering();
//Fill "colorvalue" inputs with color values
$(".colorvalue").each(function() {
$(this).val(Rescroller.properties.get($(this).parent().attr("id")));
});
//Automatically select text when clicking a color value
$(".colorvalue").focus(function() {
var self = $(this);
$(this).select(); //Select the value of the input form
$(this).mouseup(function(e) { //Prevent the text from being unselected when you stop the click
e.preventDefault();
self.off("mouseup"); //Remove the mouseup function to restore normal functionality
});
});
$(".colorvalue").change(function() {
var val = $(this).val();
//If the value is a hex value, save it
if (val.indexOf("#") == 0 && (val.length == 4 || val.length == 7)) {
$(this).siblings(".colorselection").miniColors("value", val);
Rescroller.properties.set($(this).parent().attr("id"), val);
refreshScrollbars();
}
//If the user just forgot the #, add it automatically and save
else if (val.indexOf("#") != 0 && (val.length == 3 || val.length == 6)) {
$(this).siblings(".colorselection").miniColors("value", "#" + val);
$(this).val("#" + val);
Rescroller.properties.set($(this).parent().attr("id"), val);
refreshScrollbars();
}
//If it's just a bad value, restore original
else {
$(this).val(Rescroller.properties.get($(this).parent().attr("id")));
}
});
/********** Collapsable Checkboxes *********************/
//Scroll buttons
var showButtons = $("#showbuttons");
//Make sure wrapper is correctly expanded on load
if (showButtons.is(":checked")) { $("#buttons-toggleable").show(); }
else { $("#buttons-toggleable").hide(); }
//When checkbox is changed:
showButtons.change(function() {
// Expand/collapse wrapper & save value to local storage
if ($(this).is(":checked")) {
Rescroller.properties.set($(this).attr("id"), "checked");
$("#buttons-toggleable").slideDown("fast", function() { refreshScrollbars(); });
}
else {
Rescroller.properties.set($(this).attr("id"), "unchecked");
$("#buttons-toggleable").slideUp("fast", function() { refreshScrollbars(); });
}
});
/************* Slider Hover/Active Checkboxes **************/
//Make sure wrappers are correctly expanded/collapsed on load
$(".toggle-hover-active").each(function() {
var targetWrapper = $("#" + $(this).attr("data-wrapperid"));
if ($(this).is(":checked")) { targetWrapper.show(); }
else { targetWrapper.hide(); }
});
//Expand/collapse and write to local Storage
$(".toggle-hover-active").change(function() {
if ($(this).is(":checked")) {
//alert("Checked!");
Rescroller.properties.set($(this).attr("id"), "checked");
$("#" + $(this).attr("data-wrapperid")).slideDown("slow", function() { refreshScrollbars(); });
}
else {
//alert("Unchecked!");
Rescroller.properties.set($(this).attr("id"), "unchecked");
$("#" + $(this).attr("data-wrapperid")).slideUp("slow", function() { refreshScrollbars(); });
}
refreshScrollbars();
});
/** Set functionality of "restore default buttons" link (for scrollbar buttons) **/
setRestoreArrowsDefaultImages("restore-arrow-defaults", "buttons-background-image-", "");
setRestoreArrowsDefaultImages("restore-arrow-defaults-hover", "buttons-background-image-", "-hover");
setRestoreArrowsDefaultImages("restore-arrow-defaults-active", "buttons-background-image-", "-active");
function setRestoreArrowsDefaultImages(triggerID, propertyPrefix, propertySuffix) {
$("#" + triggerID).click(function() {
var up = propertyPrefix + "up" + propertySuffix;
var down = propertyPrefix + "down" + propertySuffix;
var left = propertyPrefix + "left" + propertySuffix;
var right = propertyPrefix + "right" + propertySuffix;
Rescroller.properties.set(down, chrome.extension.getURL("images/defaults/down.png"));
Rescroller.properties.set(up, chrome.extension.getURL("images/defaults/up.png"));
Rescroller.properties.set(left, chrome.extension.getURL("images/defaults/left.png"));
Rescroller.properties.set(right, chrome.extension.getURL("images/defaults/right.png"));
$("#" + down + ", #" + up + ", #" + left + ", #" + right).each(function() {
$(this).children(".thumbframe").children(".thumbcontainer").html('<img src="' + Rescroller.properties.get($(this).attr("id")) + '" />');
$(this).children(".selector-button").hide();
$(this).children(".thumbframe").show();
});
refreshScrollbars();
return false;
});
}
});
/***********Image selector functionality*****************/
function handleFiles(files, frame, key) {
var file = files[0];
var imageType = /image.*/;
if (!file.type.match(imageType)) {
showErrorMessage("Sorry, you must select an image file. Please try again.")
return;
}
// For now, restrict the user from using large images that won't sync. In the future, we could allow it,
// but we'll have to warn the user that it will not be synced and make sure our raw value (the reference to
// the actual data image localStorage item) doesn't overwrite any remote ones.
if (file.size >= chrome.storage.sync.QUOTA_BYTES_PER_ITEM) {
showErrorMessage('Sorry, only very small images are allowed. Please choose one under 8 KB.')
return;
}
//hide any error messages
hideErrorMessage();
var img = document.createElement("img");
img.classList.add("obj");
img.file = file;
frame.innerHTML = ""; //clear frame before putting new image in
frame.appendChild(img);
var reader = new FileReader();
reader.onload = (function(aImg) {
return function(e) {
aImg.src = e.target.result;
//Save to local storage
Rescroller.properties.set(key, aImg.src);
//Change the "Select Image" button to an image frame
var container = $(frame).parents(".imagepicker-container");
container.children(".selector-button").hide();
container.children(".thumbframe").show();
//Redraw scrollbars
refreshScrollbars();
};
})(img);
reader.readAsDataURL(file);
}
$(document).ready(function() {
//Whenever selectors (hidden <input type="file">s) are changed, save their valuese to local storage
$(".selector").change(function() {
handleFiles(this.files, $(this).siblings(".thumbframe").children("div.thumbcontainer").get()[0], $(this).parent().attr("id"))
});
//Whenever selector buttons are clicked, invoke their related selector's click function (i.e., save their contents to local storage)
$(".selector-button").click(function() {
$(this).siblings(".selector").get()[0].click();
return false;
});
//Whenever a file is dropped on a dropbox, save the file to local storage with the associated value
$(".selector-button").bind("drop", function(eventObj) {
e = eventObj.originalEvent;
e.stopPropagation();
e.preventDefault();
var dt = e.dataTransfer;
var files = dt.files;
handleFiles(files, $(this).siblings(".thumbframe").children("div.thumbcontainer").get()[0], $(this).parent().attr("id"));
//Hide the dropbox
$(".selector-button").html("Select Image");
$(".selector-button").animate({ "background-color" : "#333" }, "slow");
resetDragHoveringEventTriggering();
return false;
});
});

View File

@ -0,0 +1,850 @@
/**
* The Rescroller API and other utility methods.
*/
if (!String.prototype.fmt) {
String.prototype.fmt = function() {
var args = arguments;
var i = 0;
return this.replace(/%((%)|s)/g, function(match) {
return_val = typeof args[i] != 'undefined' ? args[i] : match;
i++;
return return_val;
});
};
}
/**
* Superficial class creator. It may be better to use something like Backbone in the future.
*/
var createClass = function(proto) {
proto || (proto = {});
proto.constructor || (proto.constructor = function() {});
var obj = function() {
proto.constructor.apply(this, arguments)
};
obj.prototype = proto;
return obj;
};
window.Rescroller = {
version: chrome.app.getDetails().version,
/**
* An object that understands our image {} format and can handle image data values to and from localStorage
*/
Image: createClass({
data: {
localStorageKey: null
},
constructor: function(data) {
if (!data) { return; }
this.data = data;
},
getDataValue: function() {
var dataValue = localStorage[this.data.localStorageKey];
if (!dataValue) { return ''; }
return dataValue;
},
setImageData: function(imageData) {
var imageKey = 'image-' + new Date().getTime() + Math.random().toString().split('.')[1];
this.data.localStorageKey = imageKey;
localStorage[imageKey] = imageData;
return this;
},
removeImage: function() {
localStorage.removeItem(this.data.localStorageKey);
},
/**
* When we are converted to string, let's show our value string instead of [object Object]. This way,
* we don't need to handle this class vs other string values in getCSSString()
*/
toString: function() {
return this.getDataValue();
},
/**
* This is needed for JSON.stringify() and localStorage's stringify
*/
toJSON: function() {
return this.data;
}
}),
settings: {
_settings: null, // a cached JSON version of our settings from localStorage.
/**
* Perform setup of our settins struture for a new installation.
*/
_initializeFirstTimeSettings: function() {
localStorage['rescroller-settings'] = JSON.stringify({
showSaveConfirmation: true,
excludedsites: '',
scrollbarStyle: {
metadata: {}, // unused now, but will use it in the future if/when we allow saving/sharing/exporting of styles
data: {}
}
});
Rescroller.restoreDefaults(true);
},
/**
* Sometimes after localStorage has changed, we need to wipe our JS cache
* so the next time get()/getAll() is called, we return accurate results.
*/
resetJSCache: function() {
this._settings = null;
},
/**
* Get our settings object.
* @param {boolean} force If true, will get the setting from localStorage instead of our in-memory object
*/
getAll: function(force) {
var that = this;
if (!localStorage['rescroller-settings']) { // no matter what, we need a default for this
this._initializeFirstTimeSettings();
}
if (force === true || !this._settings) {
this._settings = JSON.parse(localStorage.getItem('rescroller-settings'));
// Convert all image {}'s into proper Image classes
Object.keys(this._settings.scrollbarStyle.data).forEach(function(key) {
var val = that._settings.scrollbarStyle.data[key];
if (!(val instanceof Object) && !val.localStorageKey) { return true; }
that._settings.scrollbarStyle.data[key] = new Rescroller.Image(val);
});
}
return this._settings;
},
/**
* Get a single setting value.
* @param {string} key The setting to get
* @param {boolean} force If true, will get the setting from localStorage instead of our in-memory object
*/
get: function(key, force) {
try { return this.getAll(force)[key]; }
catch(e) { return null; }
},
set: function(key, value, noSync) {
var settings = this.getAll();
settings[key] = value;
localStorage['rescroller-settings'] = JSON.stringify(settings);
localStorage['date-settings-last-updated'] = new Date().getTime();
Rescroller.onSettingsUpdated();
if (noSync) { return; }
Rescroller.syncUp();
}
},
properties: {
getAll: function(force) {
var props = null;
try { props = Rescroller.settings.get('scrollbarStyle', force); }
catch(e) { }
if (!props || !props.data) {
return {};
}
return props.data;
},
get: function(key, force) {
try {
var val = this.getAll(force)[key];
return val ? val : ''; // return empty string so we don't have 'null's in our CSS
} catch(e) {
return '';
}
},
set: function(key, value, noSync) {
var props = this.getAll();
// if previous value was image, we need to remove the old image before overwriting it
if (this.get(key) instanceof Rescroller.Image) {
this.get(key).removeImage();
}
if (typeof value == 'string' && value.indexOf('data') == 0) { // save images in separate localStorage key to avoid chrome.sync item size limits
props[key] = new Rescroller.Image().setImageData(value);
} else {
props[key] = value;
}
this.setMultiple(props, noSync);
Rescroller.generateScrollbarCSS(); // update our generated CSS for browser tabs
},
setMultiple: function(newProps, noSync) {
var props = this.getAll();
for (key in newProps) {
var newVal = newProps[key];
if (typeof newVal == 'string' && newVal.indexOf('data') == 0) {
newVal = new Rescroller.Image().setImageData(newVal);
}
props[key] = newVal;
}
Rescroller.settings.set('scrollbarStyle', {
metadata: Rescroller.settings.get('scrollbarStyle').metadata,
data: props
}, noSync);
Rescroller.generateScrollbarCSS(); // update our generated CSS for browser tabs
},
remove: function(key) {
if (this.get(key) instanceof Rescroller.Image) {
this.get(key).removeImage();
}
this.set(key, '');
}
},
performMigrations: function() {
if (!this._migrateDataToSingleKey() && !this._migrateImageNullValues()) {
return; // none of the migrations needed to run; we're done!
}
// Since localStorage has change, we need to invalide our JS cache so we get accurate results
this.settings.resetJSCache();
// we need to regenerate our CSS so it's in localStorage['generated-css'] for our background page to find it
this.generateScrollbarCSS();
// After switching to the new version, the new settings should be synced up.
localStorage['date-settings-last-updated'] = new Date().getTime(); // copied from set()
this.syncUp(); // sync migrated structures up
},
/**
* Migration from 1.2 --> 1.3. Migrate all our "sb-*" keys in localStorage to a single key.
*
* @returns {boolean} true if migration ran, false if it didn't (need to)
*/
_migrateDataToSingleKey: function() {
if (!localStorage['sb-size']) { return false; } // already migrated
var json = {
scrollbarStyle: {
metadata: {},
data: {}
}
};
Object.keys(localStorage).forEach(function(key) {
if (key == 'install_time') { return true; } // continue
if (key == 'sb-excludedsites') {
json['excludedsites'] = localStorage['sb-excludedsites']
} else if (key == 'showSaveConfirmation') { // change showSaveConfirmation form a '1'/'0' to true/false
json[key] = localStorage[key] !== '0';
} else if (key.indexOf('sb-') == 0) { // put scrollbar CSS settings in our scrollbar settings, without the 'sb-' prefix
json.scrollbarStyle.data[key.substr(3, key.length -1)] = (isNaN(parseInt(localStorage[key]))) ? localStorage[key] : parseInt(localStorage[key]) ;
}
// Remove the old key/val
localStorage.removeItem(key);
});
this._settings = json;
localStorage['rescroller-settings'] = JSON.stringify(json)
return true;
},
/**
* For whatever reason, we were setting default values for images as 0. They should be empty strings.
* Also, this migrates datea values (data-url strings) to their own key in local storage so that
* chrome.sync will handle them separately.
*
* @return {boolean} true if migration ran, false if it didn't (need to)
*/
_migrateImageNullValues: function() {
var i = 0;
var props = this.properties.getAll();
for (key in props) {
if (key.indexOf('background-image') <= -1) { continue; }
// Convert any data strings to Image classes
if (typeof key == 'string' && key.indexOf('data') === 0) {
props[key] = new Rescroller.Image().setImageData(props[key]);
continue;
}
if (parseInt(props[key]) !== 0) { continue; }
props[key] = '';
i++;
}
// don't set anything if no changes were made; this prevents a recursive loop with
// chrome.sync since this is run every every sync down
if (i == 0) { return false; }
this.properties.setMultiple(props, true)
return true;
},
/**
* Simple callback method that callers can set to act when the settings have been updated.
*/
onSettingsUpdated: function() {},
getListOfDisabledSites: function() {
var rawString = this.settings.get('excludedsites');
if (!rawString) { return []; }
//Remove all spaces from the string, etc.
rawString = this._replaceAll(rawString, " ", "");
rawString = this._replaceAll(rawString, "https://", "");
rawString = this._replaceAll(rawString, "http://", "");
rawString = this._replaceAll(rawString, "www.", "");
rawString = this._replaceAll(rawString, "*/", "");
rawString = this._replaceAll(rawString, "*.", "");
rawString = this._replaceAll(rawString, "*", "");
if (!rawString) { return []; }
return rawString.split(",");
},
_replaceAll: function(theString, toReplace, replaceWith) {
while (theString.indexOf(toReplace) >= 0) {
theString = theString.replace(toReplace, replaceWith);
}
return theString;
},
/**
* Get number of pixels from percentage
*/
_precentageToPixels: function(percentage, doNotReduceByHalf) {
if (!doNotReduceByHalf) {
return ((percentage / 100) * this.properties.get("size")) / 2;
}
return (percentage / 100) * this.properties.get("size");
},
/**
* Used for first-time install refresh from Chrome Storage -> Local Storage (or old localStorage -> Chrome Storage)
*/
syncDown: function(callback, force) {
callback || (callback = function() {});
var that = this;
chrome.storage.sync.get(function(items) {
that.mergeSyncWithLocalStorage(items, force);
callback();
});
},
/**
* Merge items from Chrome Sync into LocalStorage.
* Note: if a 'date-settings-last-updated' item exists in the synced items and localStorage,
* the update will only occur if a remote timestamp is newer than local.
*
* @param {object} items An object of key-value items to set in local storage.
* @param {boolean} force If true, we will force the merge - otherwise we will only sync if 'date-settings-last-updated' comparisons match
* @return {[type]} [description]
*/
mergeSyncWithLocalStorage: function(items, force) {
var lastUpdatedRemote = items['date-settings-last-updated'];
var lastUpdatedLocal = localStorage['date-settings-last-updated'];
// Do not proceed if remote data is older than local data
if (!force && lastUpdatedRemote && lastUpdatedLocal && parseInt(lastUpdatedLocal) >= parseInt(lastUpdatedRemote)) {
console.warn('[Rescroller] Warning: ignoring sync down; remote data is out of date.');
return;
}
for (var key in items) {
var val = items[key];
if (!val) { continue; }
localStorage[key] = val;
}
// force refresh of this.settings._settings
this.settings.resetJSCache();
// migrate incoming data
this.performMigrations();
this.generateScrollbarCSS();
},
/**
* Sync our settings up to Chrome Storage.
*
* @note we used to throttle this ourselves with a queueSyncUp() method, but it seemed like overkill since the limit was upped from 10/min to 120/min:
* https://bugs.chromium.org/p/chromium/issues/detail?id=270665#c19 (@see MAX_WRITE_OPERATIONS_PER_MINUTE)
*/
syncUp: function() {
var ls = {};
for (var key in localStorage) {
if (key == 'generated-css') { continue; } // waste of time to sync this
if (!localStorage[key]) { continue; }
// For legacy, ignore any images that are too big to sync
if ((encodeURI(localStorage[key]).split(/%..|./).length - 1) > chrome.storage.sync.QUOTA_BYTES_PER_ITEM) {
console.warn('[Rescroller] Ignoring sync up of image > 8 KB.')
continue;
}
ls[key] = localStorage[key];
}
chrome.storage.sync.set(ls);
},
/**
* Restore the default settings for the scrollbars.
*
* Slider/background theme are shades of Material's Blue Grey colors:
* https://material.google.com/style/color.html#color-color-palette
*/
restoreDefaults: function(noSync) {
this.properties.setMultiple({
// General
"size" : 8,
"subbackground-color" : "#000000",
"corner-background" : "#B0BEC5",
// "resizer-background" : "#FFC31F",
// Background
"background-color" : "#B0BEC5",
"background-shadow-color" : "#000000",
"background-shadow-size" : 0,
"background-border-size" : 0,
"background-border-color" : "#000000",
"background-border-style" : "solid",
"background-radius" : 0,
// hovering
"background-color-hover" : "#D9D9D9",
"background-shadow-color-hover" : "#000000",
"background-shadow-size-hover" : 0,
// active
"background-color-active" : "#D9D9D9",
"background-shadow-color-active" : "#000000",
"background-shadow-size-active" : 0,
// Scrollbar piece/slider
"slider-color" : "#455A64",
"slider-shadow-color" : "#000000",
"slider-shadow-size" : 0,
"slider-radius" : 0,
"slider-border-size" : 0,
"slider-border-color" : "#000000",
"slider-border-style" : "solid",
// hovering
"slider-color-hover" : "#666",
"slider-shadow-color-hover" : "#000000",
"slider-shadow-size-hover" : 0,
// active
"slider-color-active" : "#666",
"slider-shadow-color-active" : "#000000",
"slider-shadow-size-active" : 0,
// Buttons
"showbuttons" : "off",
"buttons-size" : 20,
"buttons-color" : "#666666",
"buttons-shadow-color" : "#000000",
"buttons-shadow-size" : 0,
"buttons-radius" : 0,
"buttons-border-size" : 0,
"buttons-border-color" : "#666",
"buttons-border-style" : "solid",
"buttons-background-image-up" : chrome.extension.getURL("images/defaults/up.png"),
"buttons-background-image-down" : chrome.extension.getURL("images/defaults/down.png"),
"buttons-background-image-left" : chrome.extension.getURL("images/defaults/left.png"),
"buttons-background-image-right" : chrome.extension.getURL("images/defaults/right.png"),
// hovering
"buttons-color-hover" : "#666666",
"buttons-shadow-color-hover" : "#000000",
"buttons-shadow-size-hover" : 0,
"buttons-background-image-up-hover" : chrome.extension.getURL("images/defaults/up.png"),
"buttons-background-image-down-hover" : chrome.extension.getURL("images/defaults/down.png"),
"buttons-background-image-left-hover" : chrome.extension.getURL("images/defaults/left.png"),
"buttons-background-image-right-hover" : chrome.extension.getURL("images/defaults/right.png"),
// active
"buttons-color-active" : "#666666",
"buttons-shadow-color-active" : "#000000",
"buttons-shadow-size-active" : 0,
"buttons-background-image-up-active" : chrome.extension.getURL("images/defaults/up.png"),
"buttons-background-image-down-active" : chrome.extension.getURL("images/defaults/down.png"),
"buttons-background-image-left-active" : chrome.extension.getURL("images/defaults/left.png"),
"buttons-background-image-right-active" : chrome.extension.getURL("images/defaults/right.png"),
// Reset all non-button images
"slider-background-image-vertical" : '',
"slider-background-image-horizontal" : '',
"slider-background-image-vertical-hover" : '',
"slider-background-image-horizontal-hover" : '',
"slider-background-image-vertical-active" : '',
"slider-background-image-horizontal-active" : '',
"background-background-image-vertical" : '',
"background-background-image-horizontal" : '',
"background-background-image-vertical-hover" : '',
"background-background-image-horizontal-hover" : '',
"background-background-image-vertical-active" : '',
"background-background-image-horizontal-active" : '',
// Custom CSS
// @note potential improvement: maybe, if the the user enters this, it should be used in addition to the generated CSS?
// This way people can override just some parts of the styling, or everything.
"customcss" : "::-webkit-scrollbar {\
\n\n\
}\n\
::-webkit-scrollbar-button {\
\n\n\
}\n\
::-webkit-scrollbar-track {\
\n\n\
}\n\
::-webkit-scrollbar-track-piece {\
\n\n\
}\n\
::-webkit-scrollbar-thumb {\
\n\n\
}\n\
::-webkit-scrollbar-corner {\
\n\n\
}\n\
::-webkit-resizer {\
\n\n\
}"
}, noSync);
},
/**
* Gnerate a CSS string from our scrollbar settings and save it to local storage for browser tabs to use.
*/
generateScrollbarCSS: function() {
localStorage['generated-css'] = this.getCSSString();
},
/**
* Grab data from local storage and convert it into a CSS string
*/
getCSSString: function() {
// If user has chosen to specify his own CSS, just return that
if (this.properties.get("usecustomcss") == "checked") { return this.properties.get("customcss"); }
// Build our CSS structure as JSON for readability and maintainability. Then, we'll convert it to CSS!
var json = {
children: {
// Base
"::-webkit-scrollbar, ::-webkit-scrollbar:horizontal, ::-webkit-scrollbar:vertical": {
"attributes": {
"width": "%spx".fmt(this.properties.get('size')),
"height": "%spx".fmt(this.properties.get('size')),
"background-color": "%s".fmt(this.properties.get('subbackground-color'))
}
},
"::-webkit-scrollbar-track-piece": {
"attributes": {
"background-color": this.properties.get('background-color'),
"box-shadow": "inset 0 0 %spx %s".fmt(this._precentageToPixels(this.properties.get('background-shadow-size'), true), this.properties.get('background-shadow-color')),
"border": "%spx %s %s".fmt(this._precentageToPixels(this.properties.get('background-border-size')), this.properties.get('background-border-style'), this.properties.get('background-border-color')),
"border-radius": "%spx".fmt(this._precentageToPixels(this.properties.get('background-radius')))
}
},
"::-webkit-scrollbar-track-piece:vertical": {
"attributes": {
"background-image": "url('%s')".fmt(this.properties.get('background-background-image-vertical'))
}
},
"::-webkit-scrollbar-track-piece:horizontal": {
"attributes": {
"background-image": "url('%s')".fmt(this.properties.get('background-background-image-horizontal'))
}
},
"::-webkit-scrollbar-thumb": {
"attributes": {
"background-color": this.properties.get('slider-color'),
"box-shadow": "inset 0 0 %spx %s".fmt(this._precentageToPixels(this.properties.get('slider-shadow-size'), true), this.properties.get('slider-shadow-color')),
"border-radius": "%spx".fmt(this._precentageToPixels(this.properties.get('slider-radius'))),
"border": "%spx %s %s".fmt(this._precentageToPixels(this.properties.get('slider-border-size')), this.properties.get('slider-border-style'), this.properties.get('slider-border-color'))
}
},
"::-webkit-scrollbar-thumb:vertical": {
"attributes": {
"background-image": "url('%s')".fmt(this.properties.get('slider-background-image-vertical'))
}
},
"::-webkit-scrollbar-thumb:horizontal": {
"attributes": {
"background-image": "url('%s')".fmt(this.properties.get('slider-background-image-horizontal'))
}
},
"::-webkit-scrollbar-corner": {
"attributes": {
"background-color": this.properties.get('corner-background')
}
}
// "::-webkit-resizer": {
// "attributes": {
// "background-color": this.properties.get('resizer-background')
// }
// }
}
};
// Conditionals:
if (this.properties.get('showbuttons') == 'checked') {
$.extend(json.children, {
"::-webkit-scrollbar-button": {
"attributes": {
"background-color": this.properties.get('buttons-color'),
"border-radius": "%spx".fmt(this._precentageToPixels(this.properties.get('buttons-radius'))),
"box-shadow": "inset 0 0 %spx %s".fmt(this._precentageToPixels(this.properties.get('buttons-shadow-size'), true), this.properties.get('buttons-shadow-color')),
"border": "%spx %s %s".fmt(this._precentageToPixels(this.properties.get('buttons-border-size')), this.properties.get('buttons-border-style'), this.properties.get('buttons-border-color')),
"display": "block"
}
},
"::-webkit-scrollbar-button:vertical": {
"attributes": {
"height": "%spx".fmt(this.properties.get('buttons-size'))
}
},
"::-webkit-scrollbar-button:horizontal": {
"attributes": {
"width": "%spx".fmt(this.properties.get('buttons-size'))
}
},
"::-webkit-scrollbar-button:vertical:decrement": {
"attributes": {
"background-image": "url('%s')".fmt(this.properties.get('buttons-background-image-up'))
}
},
"::-webkit-scrollbar-button:vertical:increment": {
"attributes": {
"background-image": "url('%s')".fmt(this.properties.get('buttons-background-image-down'))
}
},
"::-webkit-scrollbar-button:horizontal:increment": {
"attributes": {
"background-image": "url('%s')".fmt(this.properties.get('buttons-background-image-right'))
}
},
"::-webkit-scrollbar-button:horizontal:decrement": {
"attributes": {
"background-image": "url('%s')".fmt(this.properties.get('buttons-background-image-left'))
}
},
});
if (this.properties.get('buttons-use-hover') == 'checked') {
$.extend(json.children, {
"::-webkit-scrollbar-button:vertical:decrement:hover": {
"attributes": {
"background-image": "url('%s')".fmt(this.properties.get('buttons-background-image-up-hover'))
}
},
"::-webkit-scrollbar-button:vertical:increment:hover": {
"attributes": {
"background-image": "url('%s')".fmt(this.properties.get('buttons-background-image-down-hover'))
}
},
"::-webkit-scrollbar-button:horizontal:increment:hover": {
"attributes": {
"background-image": "url('%s')".fmt(this.properties.get('buttons-background-image-right-hover'))
}
},
"::-webkit-scrollbar-button:horizontal:decrement:hover": {
"attributes": {
"background-image": "url('%s')".fmt(this.properties.get('buttons-background-image-left-hover'))
}
},
"::-webkit-scrollbar-button:hover": {
"attributes": {
"background-color": this.properties.get('buttons-color-hover'),
"box-shadow": "inset 0 0 %spx %s".fmt(this._precentageToPixels(this.properties.get('buttons-shadow-size-hover'), true), this.properties.get('buttons-shadow-color-hover'))
}
}
});
}
if (this.properties.get('buttons-use-active') == 'checked') {
$.extend(json.children, {
"::-webkit-scrollbar-button:vertical:decrement:active": {
"attributes": {
"background-image": "url('%s')".fmt(this.properties.get('buttons-background-image-up-active'))
}
},
"::-webkit-scrollbar-button:vertical:increment:active": {
"attributes": {
"background-image": "url('%s')".fmt(this.properties.get('buttons-background-image-down-active'))
}
},
"::-webkit-scrollbar-button:horizontal:increment:active": {
"attributes": {
"background-image": "url('%s')".fmt(this.properties.get('buttons-background-image-right-active'))
}
},
"::-webkit-scrollbar-button:horizontal:decrement:active": {
"attributes": {
"background-image": "url('%s')".fmt(this.properties.get('buttons-background-image-left-active'))
}
},
"::-webkit-scrollbar-button:active": {
"attributes": {
"background-color": this.properties.get('buttons-color-active'),
"box-shadow": "inset 0 0 %spx %s')".fmt(this._precentageToPixels(this.properties.get('buttons-shadow-size-active'), true), this.properties.get('buttons-shadow-color-active'))
}
}
});
}
// Use single buttons (hide the doubles):
$.extend(json.children, {
"::-webkit-scrollbar-button:vertical:start:increment, ::-webkit-scrollbar-button:vertical:end:decrement, ::-webkit-scrollbar-button:horizontal:start:increment, ::-webkit-scrollbar-button:horizontal:end:decrement": {
"attributes": {
"display": "none"
}
}
});
}
if (this.properties.get("background-use-hover") == "checked") {
$.extend(json.children, {
"::-webkit-scrollbar-track-piece:vertical:hover": {
"attributes": {
"background-image": "url('%s')".fmt(this.properties.get('background-background-image-vertical-hover'))
}
},
"::-webkit-scrollbar-track-piece:horizontal:hover": {
"attributes": {
"background-image": "url('%s')".fmt(this.properties.get('background-background-image-horizontal-hover'))
}
},
"::-webkit-scrollbar-track-piece:hover ": {
"attributes": {
"background-color": this.properties.get('background-color-hover'),
"box-shadow": "inset 0 0 %spx %s".fmt(this._precentageToPixels(this.properties.get('background-shadow-size-hover'), true), this.properties.get('background-shadow-color-hover'))
}
}
});
}
if (this.properties.get("background-use-active") == "checked") {
$.extend(json.children, {
"::-webkit-scrollbar-track-piece:vertical:active": {
"attributes": {
"background-image": "url('%s')".fmt(this.properties.get('background-background-image-vertical-active'))
}
},
"::-webkit-scrollbar-track-piece:horizontal:active": {
"attributes": {
"background-image": "url('%s')".fmt(this.properties.get('background-background-image-horizontal-active'))
}
},
"::-webkit-scrollbar-track-piece:active": {
"attributes": {
"background-color": this.properties.get('background-color-active'),
"box-shadow": "inset 0 0 %spx %s".fmt(this._precentageToPixels(this.properties.get('background-shadow-size-active'), true), this.properties.get('background-shadow-color-active'))
}
}
});
}
if (this.properties.get("slider-use-hover") == "checked") {
$.extend(json.children, {
"::-webkit-scrollbar-thumb:hover": {
"attributes": {
"background-color": this.properties.get('slider-color-hover'),
"box-shadow": "inset 0 0 %spx %s".fmt(this._precentageToPixels(this.properties.get('slider-shadow-size-hover'), true), this.properties.get('slider-shadow-color-hover'))
}
},
"::-webkit-scrollbar-thumb:vertical:hover": {
"attributes": {
"background-image": "url('%s')".fmt(this.properties.get('slider-background-image-vertical-hover'))
}
},
"::-webkit-scrollbar-thumb:horizontal:hover": {
"attributes": {
"background-image": "url('%s')".fmt(this.properties.get('slider-background-image-horizontal-hover'))
}
}
});
}
if (this.properties.get("slider-use-active") == "checked") {
$.extend(json.children, {
"::-webkit-scrollbar-thumb:active": {
"attributes": {
"background-color": this.properties.get('slider-color-active'),
"box-shadow": "inset 0 0 %spx %s".fmt(this._precentageToPixels(this.properties.get('slider-shadow-size-active'), true), this.properties.get('slider-shadow-color-active'))
}
},
"::-webkit-scrollbar-thumb:vertical:active": {
"attributes": {
"background-image": "url('%s')".fmt(this.properties.get('slider-background-image-vertical-active'))
}
},
"::-webkit-scrollbar-thumb:horizontal:active": {
"attributes": {
"background-image": "url('%s')".fmt(this.properties.get('slider-background-image-horizontal-active'))
}
}
});
}
// Some cleanup before we send it off!
$.each(json.children, function(selector, children) {
var attrs = children.attributes
$.each(attrs, function(attr_name, attr_val) { // assume we never go deeper than one level
if (!attr_val) { return true; } // continue
// Clear out any empty image values to avoid erronius server calls
if (attr_val == "url('')") {
attrs[attr_name] = '""';
return true; // continue
}
// Make sure every attribute is marked '!important'
attrs[attr_name] = attr_val + ' !important';
});
});
return CSSJSON.toCSS(json);
}
}

View File

@ -0,0 +1,26 @@
{
"background": {
"persistant": false,
"scripts": [ "js/jquery.js", "js/cssjson.js", "js/rescroller.js", "js/background.js" ]
},
"browser_action": {
"default_icon": "appicons/icon19.png",
"default_title": "Rescroller Settings"
},
"description": "Decorate your scrollbars.",
"icons": {
"128": "appicons/icon128.png",
"16": "appicons/icon16.png",
"19": "appicons/icon19.png",
"48": "appicons/icon48.png"
},
"key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDf7Pb6m0Y9FUeE/I1KlD8Tv7E7K1AZY8MIdLm9Cknitwldt+SpwROOnI30pPyCh66kZVtvtAcAqp1lP+BGorm5wEdf5pAaXFccXFSxQtN861hnwYY+/s+FseGmGZWVCpaRZd4mowojAesS1cI1siTULWoz0u9c8pQ2t0L3vA3VxwIDAQAB",
"manifest_version": 2,
"name": "Rescroller",
"options_page": "options.html",
"permissions": [ "\u003Call_urls>", "storage", "tabs" ],
"update_url": "https://clients2.google.com/service/update2/crx",
"version": "1.3",
"version_name": "1.3",
"web_accessible_resources": [ "images/defaults/up.png", "images/defaults/down.png", "images/defaults/left.png", "images/defaults/right.png" ]
}

View File

@ -0,0 +1,9 @@
[06:45:51] Using gulpfile /vagrant/gulpfile.js
[06:45:51] Starting 'watch'...
[06:45:51] Finished 'watch' after 82 ms
[06:46:05] Using gulpfile /vagrant/gulpfile.js
[06:46:05] Starting 'watch'...
[06:46:05] Finished 'watch' after 80 ms
[06:47:30] Using gulpfile /vagrant/gulpfile.js
[06:47:30] Starting 'watch'...
[06:47:30] Finished 'watch' after 82 ms

View File

@ -0,0 +1,696 @@
<!DOCTYPE html>
<html>
<head>
<title>Rescroller</title>
<link type="text/css" rel="stylesheet" href="style.css"></link>
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/jquery-ui.js"></script>
<script type="text/javascript" src="js/rescroller.js"></script>
<script type="text/javascript" src="js/cssjson.js"></script>
<script type="text/javascript" src="js/options.js"></script>
<script type="text/javascript" src="js/jquery-minicolors/jquery.miniColors.js"></script>
<link type="text/css" rel="stylesheet" href="js/jquery-minicolors/jquery.miniColors.css" />
<!-- @todo:david put "fork on github" note in -->
</head>
<body>
<div id="errorbox">Error!</div>
<div id="save-confirm">
<p><b>Settings Saved</b></p>
<p>Your scrollbar settings are saved automatically. If you are signed into Chrome with sync, your scrollbars will follow you across computers.</p>
<p><a href="#" id="hide-saved-confirm">Don't show again</a></p>
</div>
<div id="settings">
<div id="logo-wrapper">
<img src="images/logo-hover.png" id="logo-hover" />
<img src="images/logo.png" id="logo" />
</div>
<form id="theform">
<div id="welcomemsg">
<p>Welcome to Rescroller! Using the tools below, you can customize the look and feel of scrollbars across your Chrome browser. Please take a moment to style each scrollbar element and their properties, including the sizes and colors of shadows and borders. This extension will override scrollbars on all websites, including those that have their own customized scrollbars, unless you specify them in the blacklist below.</p>
<p><small>(Please note that, due to general restrictions for Chrome extensions, your scrollbars will not appear on the Chrome Webstore, or URLS that begin with "<code>chrome://</code>". However, you can enable Rescroller for local webpages and incognito browsing in Chrome's extension manager.)</small></p>
</div>
<div class="section" id="general">
<h1 class="sectionheader">General</h1>
<div id="size" class="slider-property customcss-collapsible" style="display: block;">
<div class="property-title">Scrollbar Size</div>
<div class="slider slider-h"></div>
<div class="slider-value"></div>
<div style="clear: both;"></div>
</div>
<div id="resetformatting" class="button">Restore Default Formatting</div>
<p style="margin: 20px auto 10px"><b>Blacklist:</b></p>
<p class="small-description">Enter any sites for which you would not like to override scrollbar styling, below (separated by commas):</p>
<textarea id="excludedsites" placeholder="Example: mail.google.com, facebook.com"></textarea>
</div>
<div class="section" id="scrollbar-slider">
<h1 class="sectionheader">Slider Handle</h1>
<div id="slider-color" class="colorpicker-container" style="display: block">
<b>Color:</b>
<input type="hidden" id="colortext" class="colorselection" />
<input type="text" class="colorvalue" />
</div>
<table>
<tr>
<td><p class="imagepicker-label">Vertical Image:</p></td>
<td><p class="imagepicker-label">Horizontal Image:</p></td>
</tr>
<tr>
<td>
<div id="slider-background-image-vertical" class="imagepicker-container">
<input type="file" class="selector" />
<a href="#" class="selector-button">Select Image</a>
<div class="thumbframe">
<div class="thumbcontainer">No Image Loaded</div>
<img src="images/close-button.png" class="clearimage"></img>
</div>
</div>
</td>
<td>
<div id="slider-background-image-horizontal" class="imagepicker-container">
<input type="file" class="selector" />
<a href="#" class="selector-button">Select Image</a>
<div class="thumbframe">
<div class="thumbcontainer">No Image Loaded</div>
<img src="images/close-button.png" class="clearimage"></img>
</div>
</div>
</td>
</tr>
</table>
<div class="subsection">
<p class="sectionsubheader">Shadows</p>
<div id="slider-shadow-size" class="slider-property">
<div class="slider-value"></div>
<div class="slider slider-v"></div>
<div style="clear: both;"></div>
</div>
<div id="slider-shadow-color" class="colorpicker-container">
<input type="hidden" id="colortext" class="colorselection" />
<input type="text" class="colorvalue" />
</div>
<div style="clear: both;"></div>
</div>
<div class="subsection">
<p class="sectionsubheader">Borders</p>
<div id="slider-border-size" class="slider-property">
<div class="slider-value"></div>
<div class="slider slider-v"></div>
<div style="clear: both;"></div>
</div>
<div id="slider-border-color" class="colorpicker-container">
<input type="hidden" id="colortext" class="colorselection" />
<input type="text" class="colorvalue" />
</div>
<p>
Style:
<!--<input type="text" id="slider-border-style" />-->
<select id="slider-border-style">
<option value="solid">Solid</option>
<option value="dashed">Dashed</option>
<option value="dotted">Dotted</option>
<option value="double">Double</option>
<option value="groove">Groove</option>
<option value="inset">Inset</option>
<option value="outset">Outset</option>
<option value="ridge">Ridge</option>
</select>
</p>
</div>
<p class="sectionsubheader">Rounded Corners</p>
<div id="slider-radius" class="slider-property">
<div class="slider slider-h"></div>
<div class="slider-value"></div>
<div style="clear: both;"></div>
</div>
<p class="custom-hover-active-label">Customize Style When Hovering: <input type="checkbox" id="slider-use-hover" class="toggle-hover-active" data-wrapperid="slider-hover-wrapper" /></p>
<div id="slider-hover-wrapper">
<p class="sectionsubheader">Hovering State</p>
<div class="subsection">
<div id="slider-color-hover" class="colorpicker-container">
<b>Color:</b>
<input type="hidden" id="colortext" class="colorselection" />
<input type="text" class="colorvalue" />
</div>
<p class="imagepicker-label">Vertical Image:</p>
<div id="slider-background-image-vertical-hover" class="imagepicker-container">
<input type="file" class="selector" />
<a href="#" class="selector-button">Select Image</a>
<div class="thumbframe">
<div class="thumbcontainer">No Image Loaded</div>
<img src="images/close-button.png" class="clearimage"></img>
</div>
</div>
<p class="imagepicker-label">Horizontal Image:</p>
<div id="slider-background-image-horizontal-hover" class="imagepicker-container">
<input type="file" class="selector" />
<a href="#" class="selector-button">Select Image</a>
<div class="thumbframe">
<div class="thumbcontainer">No Image Loaded</div>
<img src="images/close-button.png" class="clearimage"></img>
</div>
</div>
</div>
<div class="subsection">
<p class="property-title">Shadows</p>
<div id="slider-shadow-size-hover" class="slider-property">
<div class="slider-value"></div>
<div class="slider slider-v"></div>
<div style="clear: both;"></div>
</div>
<div id="slider-shadow-color-hover" class="colorpicker-container">
<input type="hidden" id="colortext" class="colorselection" />
<input type="text" class="colorvalue" />
</div>
</div>
</div>
<p class="custom-hover-active-label">Customize Style When Clicking: <input type="checkbox" id="slider-use-active" class="toggle-hover-active" data-wrapperid="slider-active-wrapper" /></p>
<div id="slider-active-wrapper">
<p class="sectionsubheader">Active State</p>
<div class="subsection">
<div id="slider-color-active" class="colorpicker-container">
<b>Color:</b>
<input type="hidden" id="colortext" class="colorselection" />
<input type="text" class="colorvalue" />
</div>
<p class="imagepicker-label">Vertical Image:</p>
<div id="slider-background-image-vertical-active" class="imagepicker-container">
<input type="file" class="selector" />
<a href="#" class="selector-button">Select Image</a>
<div class="thumbframe">
<div class="thumbcontainer">No Image Loaded</div>
<img src="images/close-button.png" class="clearimage"></img>
</div>
</div>
<p class="imagepicker-label">Horizontal Image:</p>
<div id="slider-background-image-horizontal-active" class="imagepicker-container">
<input type="file" class="selector" />
<a href="#" class="selector-button">Select Image</a>
<div class="thumbframe">
<div class="thumbcontainer">No Image Loaded</div>
<img src="images/close-button.png" class="clearimage"></img>
</div>
</div>
</div>
<div class="subsection">
<p class="property-title">Shadows</p>
<div id="slider-shadow-size-active" class="slider-property">
<div class="slider-value"></div>
<div class="slider slider-v"></div>
<div style="clear: both;"></div>
</div>
<div id="slider-shadow-color-active" class="colorpicker-container">
<input type="hidden" id="colortext" class="colorselection" />
<input type="text" class="colorvalue" />
</div>
</div>
</div>
</div>
<!-- **************** Scrollbar Background ********************** -->
<div class="section" id="scrollbar-bg">
<h1 class="sectionheader">Background</h1>
<div id="background-color" class="colorpicker-container" style="display: block;">
<b>Color:</b>
<input type="hidden" id="colortext" class="colorselection" />
<input type="text" class="colorvalue" />
</div>
<table>
<tr>
<td><p class="imagepicker-label">Vertical Image:</p></td>
<td><p class="imagepicker-label">Horizontal Image:</p></td>
</tr>
<tr>
<td>
<div id="background-background-image-vertical" class="imagepicker-container">
<input type="file" class="selector" />
<a href="#" class="selector-button">Select Image</a>
<div class="thumbframe">
<div class="thumbcontainer">No Image Loaded</div>
<img src="images/close-button.png" class="clearimage"></img>
</div>
</div>
</td>
<td>
<div id="background-background-image-horizontal" class="imagepicker-container">
<input type="file" class="selector" />
<a href="#" class="selector-button">Select Image</a>
<div class="thumbframe">
<div class="thumbcontainer">No Image Loaded</div>
<img src="images/close-button.png" class="clearimage"></img>
</div>
</div>
</td>
</tr>
</table>
<div class="subsection">
<p class="sectionsubheader">Shadows</p>
<div id="background-shadow-size" class="slider-property">
<div class="slider-value"></div>
<div class="slider slider-v"></div>
<div style="clear: both;"></div>
</div>
<div id="background-shadow-color" class="colorpicker-container">
<input type="hidden" id="colortext" class="colorselection" />
<input type="text" class="colorvalue" />
</div>
</div>
<div class="subsection">
<p class="sectionsubheader">Borders</p>
<div id="background-border-size" class="slider-property">
<div class="slider-value"></div>
<div class="slider slider-v"></div>
<div style="clear: both;"></div>
</div>
<div id="background-border-color" class="colorpicker-container">
<input type="hidden" id="colortext" class="colorselection" />
<input type="text" class="colorvalue" />
</div>
<p>
Style:
<select id="background-border-style">
<option value="solid">Solid</option>
<option value="dashed">Dashed</option>
<option value="dotted">Dotted</option>
<option value="double">Double</option>
<option value="groove">Groove</option>
<option value="inset">Inset</option>
<option value="outset">Outset</option>
<option value="ridge">Ridge</option>
</select>
</p>
</div>
<p class="sectionsubheader">Rounded Corners</p>
<div id="background-radius" class="slider-property">
<div class="slider slider-h"></div>
<div class="slider-value"></div>
<div style="clear: both;"></div>
</div>
<p class="custom-hover-active-label">Customize Style When Hovering: <input type="checkbox" id="background-use-hover" class="toggle-hover-active" data-wrapperid="background-hover-wrapper" /></p>
<div id="background-hover-wrapper">
<p class="sectionsubheader">Hovering State</p>
<div class="subsection">
<div id="background-color-hover" class="colorpicker-container" style="display: block;">
<b>Color:</b>
<input type="hidden" id="colortext" class="colorselection" />
<input type="text" class="colorvalue" />
</div>
<p class="imagepicker-label">Vertical Image:</p>
<div id="background-background-image-vertical-hover" class="imagepicker-container">
<input type="file" class="selector" />
<a href="#" class="selector-button">Select Image</a>
<div class="thumbframe">
<div class="thumbcontainer">No Image Loaded</div>
<img src="images/close-button.png" class="clearimage"></img>
</div>
</div>
<p class="imagepicker-label">Horizontal Image:</p>
<div id="background-background-image-horizontal-hover" class="imagepicker-container">
<input type="file" class="selector" />
<a href="#" class="selector-button">Select Image</a>
<div class="thumbframe">
<div class="thumbcontainer">No Image Loaded</div>
<img src="images/close-button.png" class="clearimage"></img>
</div>
</div>
</div>
<div class="subsection">
<p class="property-title">Shadows:</p>
<div id="background-shadow-size-hover" class="slider-property">
<div class="slider-value"></div>
<div class="slider slider-v"></div>
<div style="clear: both;"></div>
</div>
<div id="background-shadow-color-hover" class="colorpicker-container">
<input type="hidden" id="colortext" class="colorselection" />
<input type="text" class="colorvalue" />
</div>
</div>
</div>
<p class="custom-hover-active-label">Customize Style When Clicking: <input type="checkbox" id="background-use-active" class="toggle-hover-active" data-wrapperid="background-active-wrapper" /></p>
<div id="background-active-wrapper">
<p class="sectionsubheader">Active State</p>
<div class="subsection">
<div id="background-color-active" class="colorpicker-container" style="display: block;">
<b>Color:</b>
<input type="hidden" id="colortext" class="colorselection" />
<input type="text" class="colorvalue" />
</div>
<p class="imagepicker-label">Vertical Image:</p>
<div id="background-background-image-vertical-active" class="imagepicker-container">
<input type="file" class="selector" />
<a href="#" class="selector-button">Select Image</a>
<div class="thumbframe">
<div class="thumbcontainer">No Image Loaded</div>
<img src="images/close-button.png" class="clearimage"></img>
</div>
</div>
<p class="imagepicker-label">Horizontal Image:</p>
<div id="background-background-image-horizontal-active" class="imagepicker-container">
<input type="file" class="selector" />
<a href="#" class="selector-button">Select Image</a>
<div class="thumbframe">
<div class="thumbcontainer">No Image Loaded</div>
<img src="images/close-button.png" class="clearimage"></img>
</div>
</div>
</div>
<div class="subsection">
<p class="property-title">Shadows:</p>
<div id="background-shadow-size-active" class="slider-property">
<div class="slider-value"></div>
<div class="slider slider-v"></div>
<div style="clear: both;"></div>
</div>
<div id="background-shadow-color-active" class="colorpicker-container">
<input type="hidden" id="colortext" class="colorselection" />
<input type="text" class="colorvalue" />
</div>
</div>
</div>
</div>
<!-- ********************** Scrollbar Buttons ************************ -->
<div class="section" id="scrollbar-buttons">
<h1 class="sectionheader">Buttons</h1>
<table>
<tr>
<td>Show scroll buttons:</td>
<td><input type="checkbox" id="showbuttons" /></td>
</tr>
</table>
<div id="buttons-toggleable">
<div id="buttons-color" class="colorpicker-container" style="display: block;">
<b>Color:</b>
<input type="hidden" id="colortext" class="colorselection" />
<input type="text" class="colorvalue" />
</div>
<div id="buttons-size" class="slider-property" style="display: block;">
<div class="slider slider-h"></div>
<div class="slider-value"></div>
<div style="clear: both;"></div>
</div>
<table>
<tr>
<td><p class="imagepicker-label">Up</p></td>
<td><p class="imagepicker-label">Down</p></td>
</tr>
<tr>
<td>
<div id="buttons-background-image-up" class="imagepicker-container">
<input type="file" class="selector" />
<a href="#" class="selector-button">Select Image</a>
<div class="thumbframe">
<div class="thumbcontainer">No Image Loaded</div>
<img src="images/close-button.png" class="clearimage"></img>
</div>
</div>
</td>
<td>
<div id="buttons-background-image-down" class="imagepicker-container">
<input type="file" class="selector" />
<a href="#" class="selector-button">Select Image</a>
<div class="thumbframe">
<div class="thumbcontainer">No Image Loaded</div>
<img src="images/close-button.png" class="clearimage"></img>
</div>
</div>
</td>
</tr>
<tr>
<td><p class="imagepicker-label">Left</p></td>
<td><p class="imagepicker-label">Right</p></td>
</tr>
<tr>
<td>
<div id="buttons-background-image-left" class="imagepicker-container">
<input type="file" class="selector" />
<a href="#" class="selector-button">Select Image</a>
<div class="thumbframe">
<div class="thumbcontainer">No Image Loaded</div>
<img src="images/close-button.png" class="clearimage"></img>
</div>
</div>
</td>
<td>
<div id="buttons-background-image-right" class="imagepicker-container">
<input type="file" class="selector" />
<a href="#" class="selector-button">Select Image</a>
<div class="thumbframe">
<div class="thumbcontainer">No Image Loaded</div>
<img src="images/close-button.png" class="clearimage"></img>
</div>
</div>
</td>
</tr>
</table>
<p><a href="#" id="restore-arrow-defaults">Restore Default Arrows</a></p>
<div style="clear: both;"></div>
<div class="subsection">
<p class="sectionsubheader">Shadows</p>
<div id="buttons-shadow-size" class="slider-property">
<div class="slider-value"></div>
<div class="slider slider-v"></div>
<div style="clear: both;"></div>
</div>
<div id="buttons-shadow-color" class="colorpicker-container">
<input type="hidden" id="colortext" class="colorselection" />
<input type="text" class="colorvalue" />
</div>
</div>
<div class="subsection">
<p class="sectionsubheader">Borders</p>
<div id="buttons-border-size" class="slider-property">
<div class="slider-value"></div>
<div class="slider slider-v"></div>
<div style="clear: both;"></div>
</div>
<div id="buttons-border-color" class="colorpicker-container">
<input type="hidden" id="colortext" class="colorselection" />
<input type="text" class="colorvalue" />
</div>
<p>
Style:
<select id="buttons-border-style">
<option value="solid">Solid</option>
<option value="dashed">Dashed</option>
<option value="dotted">Dotted</option>
<option value="double">Double</option>
<option value="groove">Groove</option>
<option value="inset">Inset</option>
<option value="outset">Outset</option>
<option value="ridge">Ridge</option>
</select>
</p>
</div>
<p class="sectionsubheader">Rounded Corners</p>
<div id="buttons-radius" class="slider-property">
<div class="slider slider-h"></div>
<div class="slider-value"></div>
<div style="clear: both;"></div>
</div>
<p class="custom-hover-active-label">Customize Style When Hovering: <input type="checkbox" id="buttons-use-hover" class="toggle-hover-active" data-wrapperid="buttons-hover-wrapper" /></p>
<div id="buttons-hover-wrapper">
<p class="sectionsubheader">Hovering State</p>
<div class="subsection">
<div id="buttons-color-hover" class="colorpicker-container" style="display: block;">
<b>Color:</b>
<input type="hidden" id="colortext" class="colorselection" />
<input type="text" class="colorvalue" />
</div>
<p class="imagepicker-label">Up Image:</p>
<div id="buttons-background-image-up-hover" class="imagepicker-container">
<input type="file" class="selector" />
<a href="#" class="selector-button">Select Image</a>
<div class="thumbframe">
<div class="thumbcontainer">No Image Loaded</div>
<img src="images/close-button.png" class="clearimage"></img>
</div>
</div>
<p class="imagepicker-label">Down Image:</p>
<div id="buttons-background-image-down-hover" class="imagepicker-container">
<input type="file" class="selector" />
<a href="#" class="selector-button">Select Image</a>
<div class="thumbframe">
<div class="thumbcontainer">No Image Loaded</div>
<img src="images/close-button.png" class="clearimage"></img>
</div>
</div>
<p class="imagepicker-label">Left Image:</p>
<div id="buttons-background-image-left-hover" class="imagepicker-container">
<input type="file" class="selector" />
<a href="#" class="selector-button">Select Image</a>
<div class="thumbframe">
<div class="thumbcontainer">No Image Loaded</div>
<img src="images/close-button.png" class="clearimage"></img>
</div>
</div>
<p class="imagepicker-label">Right Image:</p>
<div id="buttons-background-image-right-hover" class="imagepicker-container">
<input type="file" class="selector" />
<a href="#" class="selector-button">Select Image</a>
<div class="thumbframe">
<div class="thumbcontainer">No Image Loaded</div>
<img src="images/close-button.png" class="clearimage"></img>
</div>
</div>
<p><a href="#" id="restore-arrow-defaults-hover">Restore Default Arrows</a></p>
</div>
<div class="subsection">
<p class="property-title">Shadows:</p>
<div id="buttons-shadow-size-hover" class="slider-property">
<div class="slider-value"></div>
<div class="slider slider-v"></div>
<div style="clear: both;"></div>
</div>
<div id="buttons-shadow-color-hover" class="colorpicker-container">
<input type="hidden" id="colortext" class="colorselection" />
<input type="text" class="colorvalue" />
</div>
</div>
</div>
<p class="custom-hover-active-label">Customize Style When Clicking: <input type="checkbox" id="buttons-use-active" class="toggle-hover-active" data-wrapperid="buttons-active-wrapper" /></p>
<div id="buttons-active-wrapper">
<p class="sectionsubheader">Active State</p>
<div class="subsection">
<div id="buttons-color-active" class="colorpicker-container" style="display: block;">
<b>Color:</b>
<input type="hidden" id="colortext" class="colorselection" />
<input type="text" class="colorvalue" />
</div>
<p class="imagepicker-label">Up Image:</p>
<div id="buttons-background-image-up-active" class="imagepicker-container">
<input type="file" class="selector" />
<a href="#" class="selector-button">Select Image</a>
<div class="thumbframe">
<div class="thumbcontainer">No Image Loaded</div>
<img src="images/close-button.png" class="clearimage"></img>
</div>
</div>
<p class="imagepicker-label">Down Image:</p>
<div id="buttons-background-image-down-active" class="imagepicker-container">
<input type="file" class="selector" />
<a href="#" class="selector-button">Select Image</a>
<div class="thumbframe">
<div class="thumbcontainer">No Image Loaded</div>
<img src="images/close-button.png" class="clearimage"></img>
</div>
</div>
<p class="imagepicker-label">Left Image:</p>
<div id="buttons-background-image-left-active" class="imagepicker-container">
<input type="file" class="selector" />
<a href="#" class="selector-button">Select Image</a>
<div class="thumbframe">
<div class="thumbcontainer">No Image Loaded</div>
<img src="images/close-button.png" class="clearimage"></img>
</div>
</div>
<p class="imagepicker-label">Right Image:</p>
<div id="buttons-background-image-right-active" class="imagepicker-container">
<input type="file" class="selector" />
<a href="#" class="selector-button">Select Image</a>
<div class="thumbframe">
<div class="thumbcontainer">No Image Loaded</div>
<img src="images/close-button.png" class="clearimage"></img>
</div>
</div>
<p><a href="#" id="restore-arrow-defaults-active">Restore Default Arrows</a></p>
</div>
<div class="subsection">
<p class="property-title">Shadows:</p>
<div id="buttons-shadow-size-active" class="slider-property">
<div class="slider-value"></div>
<div class="slider slider-v"></div>
<div style="clear: both;"></div>
</div>
<div id="buttons-shadow-color-active" class="colorpicker-container">
<input type="hidden" id="colortext" class="colorselection" />
<input type="text" class="colorvalue" />
</div>
</div>
</div>
</div>
</div>
<div class="section" id="misc">
<h1 class="sectionheader">Miscellaneous</h1>
<div id="subbackground-color" class="colorpicker-container customcss-collapsible" style="display: block;">
<b>Sub-Background Color:</b>
<input type="hidden" id="colortext" class="colorselection" />
<input type="text" class="colorvalue" />
</div>
<div id="corner-background" class="colorpicker-container customcss-collapsible" style="display: block;">
<b>Corner Color:</b>
<input type="hidden" id="colortext" class="colorselection" />
<input type="text" class="colorvalue" />
</div>
<p>Use Custom CSS (Advanced Users Only): <input type="checkbox" id="usecustomcss" class="toggle-hover-active" data-wrapperid="customcss-wrapper" /></p>
<div id="customcss-wrapper">
<p class="small-description">While the tools above are useful in designing a unique scrollbar, they do not allow for complete customization of scrollbars within Google Chrome. If you are a web developer or are familiar with CSS styling, <a href="http://css-tricks.com/custom-scrollbars-in-webkit/" target="_blank">you may enter custom CSS</a> to override the above tools, below:</p>
<textarea id="customcss" placeholder="Enter CSS here"></textarea>
</div>
</div>
<br />
<!--<input type="submit" value="Update" />-->
</form>
<p style="display: none;"><a href="#" id="expandcss" >Click here to expand/collapse generated CSS</a></p>
<div id="generatedcss">Error</div>
</div>
</body>
</html>

View File

@ -0,0 +1,442 @@
body {
text-align: center;
font-family: Arial, Helvetica, sans-serif;
font-size: 13px;
background: url("images/bg.png"); /* http://subtlepatterns.com/patterns/dark_wall.png */
color: white;
overflow: scroll;
}
h1 {
font-size: 40px;
margin-bottom: 10px;
}
a {
color: #007ED3;
}
a:hover {
color: #09F;
}
.button {
display: inline-block;
background: #666;
color: white;
padding: 5px 10px;
border-radius: 3px;
font-weight: bold;
-webkit-transition: background-color 0.5s;
}
.button:hover {
cursor: pointer;
background-color: #333;
-webkit-transition: background-color 0.5s;
}
.colorvalue {
background: transparent;
border: 0;
font-size: 11px;
width: 50px;
}
#welcomemsg {
width: 515px;
margin: 0 auto 20px auto;
font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;
font-size: 15px;
text-align: justify;
}
div#logo-wrapper {
width: 500px;
height: 173px;
margin: 0;
position: relative;
}
img#logo, img#logo-hover {
position: absolute;
margin: 0;
top: 0;
left: 0;
}
img#logo {
-webkit-transition: opacity 3s;
}
img#logo:hover {
opacity: 0;
-webkit-transition: opacity 0.5s;
}
@font-face {
font-family: "Righteous-Regular";
src: url("Righteous-Regular.ttf");
}
.section h1 {
font-size: 25px;
font-family: "Righteous-Regular";
}
div#errorbox {
background: pink;
position: fixed;
top: 0;
left: 0;
color: #900;
width: 88%;
margin: 0 5%;
padding: 10px;
border-bottom-left-radius: 5px;
border-bottom-right-radius: 5px;
border: 1px solid #900;
border-top: 0px;
font-size: 16px;
font-weight: bold;
z-index: 500;
display: none;
box-shadow: 0 0 20px #333;
}
.small-description {
font-size: 11px;
margin: 20px auto 5px;
width: 80%;
}
textarea {
width: 90%;
padding: 10px;
font-family: Arial, Helvetica, sans-serif;
font-size: 13px;
border: 2px solid gray;
}
textarea#customcss {
font-family: "Consolas", "Courier New", Courier, monospacel;
height: 400px;
}
textarea:focus {
border: 2px solid #009600;
box-shadow: inset 0 0 5px gray;
outline: none;
}
div#settings {
width: 500px;
margin: 0 auto;
padding: 10px;
}
div.section {
background: rgba(204, 204, 204, 0.8);
padding: 0px 10px 20px;
border-radius: 3px;
width: 500px;
margin: 20px auto;
color: black;
box-shadow: 0 0 25px black;
}
.section:first-child {
margin-top: 0;
}
.section .subsection {
display: inline-block;
margin: 20px 20px 0px;
width: 185px; /*135*/
vertical-align: top;
}
.section .custom-hover-active-label {
font-weight: bold;
font-size: 12px;
}
div.section h1.sectionheader {
margin: 10px;
background: #333;
color: white;
padding: 10px;
margin: 0 5px 20px;
border-bottom-left-radius: 3px;
border-bottom-right-radius: 3px;
font-weight: normal;
}
div.section .sectionsubheader {
font-weight: bold;
font-size: 15px;
background: #6D6D6D;
color: white;
padding: 2px;
border-bottom: 2px solid #009600;
border-top-left-radius: 3px;
border-top-right-radius: 3px;
}
div.section table {
margin: 10px auto;
}
div.section table p {
margin: 0;
}
div.section table tr, div.section table td {
padding: 0;
}
.clearimage {
position: absolute;
top: 0;
right: 0;
margin-right: -6px;
margin-top: -4px;
cursor: pointer;
}
div#generatedcss {
width: 500px;
background: lightgray;
font-family: consolas, 'Courier New', Courier, monospace;
margin: 20px auto;
padding: 20px;
text-align: left;
color: black;
box-shadow: inset 0 0 10px black;
word-wrap: break-word;
display: none;
}
/* Checkboxes */
input[type=checkbox] {
vertical-align: top;
}
.selector { display: none; }
.selector-button {
display: none;
background: #333;
border: 3px dashed #333;
color: white;
padding: 10px;
border-radius: 3px;
text-decoration: none;
font-weight: bold;
vertical-align: middle;
width: 100px;
}
.selector-button:hover {
background: #2D2D2D;
box-shadow: 0 0 5px black;
}
.thumbframe {
width: 100px;
background: #666;
padding: 10px;
border-radius: 3px;
vertical-align: middle;
position: relative;
display: none;
}
.thumbframe img {
max-width: 100px;
}
.imagepicker-container {
display: inline-block;
margin: 5px;
}
.imagepicker-label {
font-size: 11px;
font-weight: bold;
margin: 5px 0 0;
}
.property-title {
font-weight: bold;
}
.slider {
background: gray;
position: relative;
border-radius: 5px;
display: inline-block;
vertical-align: middle;
}
.slider-h {
width: 150px;
height: 7px;
padding: 0 10px;
margin: 7px auto 10px;
}
.slider-v {
height: 100px;
width: 7px;
padding: 10px 0;
margin: 15px auto 10px;
}
/* All sliders */
.slider .ui-slider-handle {
width: 12px;
height: 12px;
position: absolute;
x-index: 200;
background: #06C;
border-radius: 10px;
outline: none;
}
.slider-h .ui-slider-handle {
top: -2.5px;
margin-left: -6px;
}
.slider-v .ui-slider-handle {
left: -2.5px !important;
margin-bottom: -6px;
}
.ui-slider-handle:active {
background: #353535;
}
.slider-value {
font-size: 11px;
display: inline-block;
margin: 7px 5px 10px;
vertical-align: middle;
width: 30px;
}
/* Color pickers */
.colorpicker-container {
margin: 10px auto;
position: relative;
}
.colorpicker-container, .slider-property {
display: inline-block;
margin: 5px;
}
/* Modify color picker default styling */
.miniColors-trigger {
width: 45px !important;
height: 30px !important;
background-image: none !important;
border: 1px solid #455A64;
}
.miniColors-selector {
-webkit-border-radius: 0px !important;
border-radius: 0px !important;
border: none !important;
padding: 3px 4px !important;
height: 167px !important;
}
.miniColors-selector:before {
content: "";
position: absolute;
width: 0;
height: 0;
left: -14px;
top: 35%;
border: 7px solid;
border-color: transparent white transparent transparent;
z-index: 10;
}
.miniColors-colors {
top: 3px !important;
left: 3px !important;
}
.miniColors-hues {
top: 3px !important;
}
.miniColors-apply {
left: 7px;
font-size: 11px;
position: absolute;
bottom: 3px;
}
#save-confirm {
position: fixed;
top: 50px;
right: 20px;
width: 225px;
background: rgb(245, 245, 164);
color: black;
box-shadow: 0 0 20px black;
padding: 10px;
border-radius: 5px;
display: none;
z-index: 999;
}
#save-confirm:after {
content: "";
position: absolute;
width: 0;
height: 0;
right: -20px;
top: 15px;
border: 10px solid;
border-color: transparent transparent transparent rgb(245, 245, 164);
}
#save-confirm a#hide-saved-confirm {
color: #003A91;
}
#save-confirm a#hide-saved-confirm:hover {
color: #005CE7;
}
/*********************
* WEBKIT SCROLLBARS *
********************/
/* The scrollbars themselves (height/width, mostly)
::-webkit-scrollbar {
width: 10px;
height: 10px;
}
/* The up/down/left/right buttons that move the "thumb"
::-webkit-scrollbar-button {
background-color: blue;
width: 20px;
height: 20px;
}
/* The entire scrollable area (including the track-piece and the scrollbar thumb)
::-webkit-scrollbar-track {
}
/* The scollbar area that is not being covered by the scrollbar
::-webkit-scrollbar-track-piece {
background-color: gray;
}
/* The scrollbar piece
::-webkit-scrollbar-thumb {
background-color: black;
}
/* The corner space between horizontal and verticle scrollbars
::-webkit-scrollbar-corner {
background: purple;
}
/* The resizer piece that covers the scrollbar-corner (sometimes)
::-webkit-resizer {
background: orange;
}

View File

@ -0,0 +1,2 @@
2022/11/02-16:37:20.208 3 Creating DB /home/toto/.config/chromium/Default/Local Storage/leveldb since it was missing.
2022/11/02-16:37:20.209 3 Reusing MANIFEST /home/toto/.config/chromium/Default/Local Storage/leveldb/MANIFEST-000001

View File

@ -311,6 +311,89 @@
"was_installed_by_default": false, "was_installed_by_default": false,
"was_installed_by_oem": false, "was_installed_by_oem": false,
"withholding_permissions": false "withholding_permissions": false
},
"ddehdnnhjimbggeeenghijehnpakijod": {
"active_bit": false,
"active_permissions": {
"api": [
"storage",
"tabs"
],
"explicit_host": [
"<all_urls>",
"chrome://favicon/*"
],
"manifest_permissions": []
},
"allowlist": 1,
"commands": {},
"content_settings": [],
"creation_flags": 9,
"events": [],
"from_webstore": true,
"granted_permissions": {
"api": [
"storage",
"tabs"
],
"explicit_host": [
"<all_urls>",
"chrome://favicon/*"
],
"manifest_permissions": []
},
"incognito_content_settings": [],
"incognito_preferences": {},
"install_time": "13311875435035454",
"location": 1,
"manifest": {
"background": {
"persistant": false,
"scripts": [
"js/jquery.js",
"js/cssjson.js",
"js/rescroller.js",
"js/background.js"
]
},
"browser_action": {
"default_icon": "appicons/icon19.png",
"default_title": "Rescroller Settings"
},
"description": "Decorate your scrollbars.",
"icons": {
"128": "appicons/icon128.png",
"16": "appicons/icon16.png",
"19": "appicons/icon19.png",
"48": "appicons/icon48.png"
},
"key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDf7Pb6m0Y9FUeE/I1KlD8Tv7E7K1AZY8MIdLm9Cknitwldt+SpwROOnI30pPyCh66kZVtvtAcAqp1lP+BGorm5wEdf5pAaXFccXFSxQtN861hnwYY+/s+FseGmGZWVCpaRZd4mowojAesS1cI1siTULWoz0u9c8pQ2t0L3vA3VxwIDAQAB",
"manifest_version": 2,
"name": "Rescroller",
"options_page": "options.html",
"permissions": [
"<all_urls>",
"storage",
"tabs"
],
"update_url": "https://clients2.google.com/service/update2/crx",
"version": "1.3",
"version_name": "1.3",
"web_accessible_resources": [
"images/defaults/up.png",
"images/defaults/down.png",
"images/defaults/left.png",
"images/defaults/right.png"
]
},
"needs_sync": true,
"path": "ddehdnnhjimbggeeenghijehnpakijod/1.3_0",
"preferences": {},
"regular_only_preferences": {},
"state": 1,
"was_installed_by_default": false,
"was_installed_by_oem": false,
"withholding_permissions": false
} }
} }
}, },