NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript==
// @name OpenUserCSS Tweaks
// @namespace almaceleste
// @version 0.2.2
// @description some useful tweaks, that make working with the OpenUserCSS.org more convenient
// @description:ru некоторые полезные настройки, которые делают работу с OpenUserCSS.org более удобной
// @author (ɔ) almaceleste (https://almaceleste.github.io)
// @license AGPL-3.0-or-later; http://www.gnu.org/licenses/agpl
// @icon https://openusercss.org/img/openusercss.icon-x16.png
// @icon64 https://openusercss.org/img/openusercss.icon-x640.png
// @homepageURL https://greasyfork.org/en/users/174037-almaceleste
// @homepageURL https://openuserjs.org/users/almaceleste
// @homepageURL https://github.com/almaceleste/userscripts
// @supportURL https://github.com/almaceleste/userscripts/issues
// @updateURL https://github.com/almaceleste/userscripts/raw/master/src/OpenUserCSS_Tweaks.user.js
// @downloadURL https://github.com/almaceleste/userscripts/raw/master/dist/OpenUserCSS_Tweaks.user.js
// @downloadURL https://openuserjs.org/install/almaceleste/OpenUserCSS_Tweaks.user.js
// @require https://code.jquery.com/jquery-3.3.1.js
// @require https://raw.githubusercontent.com/uzairfarooq/arrive/master/minified/arrive.min.js
// @require https://openuserjs.org/src/libs/sizzle/GM_config.js
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_registerMenuCommand
// @grant GM_openInTab
// @grant GM_getResourceText
// @resource css https://github.com/almaceleste/userscripts/raw/master/css/default.css
// @match http*://openusercss.org/*
// ==/UserScript==
// ==OpenUserJS==
// @author almaceleste
// ==/OpenUserJS==
const state = {};
// create objects for the site pages
const profile = {};
const theme = {};
const site = {};
const search = {};
const edit = {};
// create regex patterns for the site pages
profile.path = /^\/profile/;
theme.path = /^\/theme\/(?!edit)/;
site.path = /^\/$/;
search.path = /^\/search/;
edit.path = /^\/theme\/edit/;
// create paths for the elements
site.layout = '#__layout > .ouc-ancestor';
site.navbar = `${site.layout} > .ouc-navbar-wrapper > .ouc-navbar`;
site.routeroot = `${site.layout} > .ouc-app-root > .ouc-route-root`;
site.section = `${site.routeroot} .container .section`;
site.level = `${site.section} > .level`;
site.levelright = `${site.level} > .level-right`;
site.main = `${site.section} > .columns`;
site.columnleft = `${site.main} > .column:nth-of-type(1)`;
site.columnright = `${site.main} > .column:nth-of-type(2)`;
profile.account = `${site.navbar} > .container > .navbar-menu > .navbar-end > a:first-of-type`;
profile.statsbutton = '#showStatsToggle';
profile.donatebutton = `${site.columnright} > .ouc-user-donation-wrapper a`;
profile.theme = `${site.columnright} > .columns > .column`;
profile.image = `${profile.theme} .card .card-image .ouc-responsive-image-wrapper > .ouc-responsive-image`;
site.image = profile.image;
search.image = profile.image;
search.theme = profile.theme;
search.author = `${site.columnleft} > .columns > .column`;
theme.card = `${site.columnleft} .box`;
theme.image = `${theme.card} .ouc-responsive-image-wrapper .ouc-responsive-image`;
theme.installbutton = `${site.levelright} > .tile:nth-of-type(1) > .tile:nth-of-type(3) a`;
edit.savebutton = `${site.levelright} > button[type='submit']`;
edit.form = `${site.section} > .ouc-new-theme-form`;
edit.theme = `${edit.form} > .card:nth-of-type(1)`;
edit.variables = `${edit.form} > .card:nth-of-type(2) > .card-content`;
edit.variable = `${edit.variables} > div.field.box`;
edit.editor = `${edit.form} > .card:nth-of-type(5) .ouc-editor-wrapper > .ouc-editor`;
edit.scrollbar = `${edit.editor} > .ace_scrollbar`;
edit.code = `${edit.editor} > .ace_scroller > .ace_content > .ace_text-layer`;
edit.codeline = `${edit.code} > .ace_line > span`;
edit.metadatastart = `${edit.codeline}:contains('/* ==UserStyle==')`;
edit.metadataend = `${edit.codeline}:contains('==/UserStyle== */')`;
edit.header = `${edit.theme} > .card-header`;
edit.content = `${edit.theme} > .card-content`;
edit.screenshots = `${edit.content} > .field:nth-of-type(4)`;
edit.image = `${edit.screenshots} > .columns > .column:nth-of-type(2) .ouc-responsive-image-wrapper > .ouc-responsive-image`;
const card = '.card';
const cardheader = '.card-header';
const box = '.box';
const boxheader = '.level';
const data = `[itemtype=SoftwareApplication]`;
// options for arrivejs
const options = {
existing: true
};
// config settings
const configId = 'ouctCfg';
const iconUrl = GM_info.script.icon64;
const pattern = {};
pattern[`#${configId}`] = /#configId/g;
pattern[`${iconUrl}`] = /iconUrl/g;
let css = GM_getResourceText('css');
Object.keys(pattern).forEach((key) => {
css = css.replace(pattern[key], key);
});
const windowcss = css;
const iframecss = `
height: 485px;
width: 435px;
border: 1px solid;
border-radius: 3px;
position: fixed;
z-index: 9999;
`;
GM_registerMenuCommand(`${GM_info.script.name} Settings`, () => {
GM_config.open();
GM_config.frame.style = iframecss;
});
GM_config.init({
id: `${configId}`,
title: `${GM_info.script.name} ${GM_info.script.version}`,
fields: {
version: {
section: ['', 'Any Profile Settings'],
label: 'display version',
labelPos: 'right',
title: 'display the version information for the themes',
type: 'checkbox',
default: true,
},
compact: {
label: 'compact view',
labelPos: 'right',
title: '',
type: 'checkbox',
default: true,
},
highlight: {
label: 'highlight theme on hover',
labelPos: 'right',
title: '',
type: 'checkbox',
default: true,
},
color: {
label: 'highlight color',
labelPos: 'left',
type: 'select',
options: [
'black',
'blue',
'green',
'aqua',
'red',
'purple',
'yellow',
'white',
'gray',
'lightskyblue',
'lightgreen',
'orangered',
'pink',
'gold',
'whitesmoke',
'lightgray',
'dimgray',
'deepskyblue',
'dodgerblue',
],
default: 'dodgerblue',
},
stats: {
section: ['', 'Own Profile Settings'],
label: 'display statistics',
labelPos: 'right',
title: 'display the statistics information for the themes',
type: 'checkbox',
default: true,
},
screenshot: {
label: 'display screenshot',
labelPos: 'right',
title: 'display the screenshots for the themes',
type: 'checkbox',
default: true,
},
editbutton: {
label: 'edit button',
labelPos: 'right',
title: 'add the edit buttons to edit theme directly from the profile page',
type: 'checkbox',
default: true,
},
deletevariables: {
section: ['', 'Edit Page Settings'],
label: 'do not create variables (experimental)',
labelPos: 'right',
title: '',
type: 'checkbox',
default: false,
},
// deletemetadata: {
// label: 'automatically delete metadata (experimental)',
// labelPos: 'right',
// title: '',
// type: 'checkbox',
// default: false,
// },
editsticky: {
label: 'sticky header',
labelPos: 'right',
title: '',
type: 'checkbox',
default: true,
},
// fixinstall: {
// section: ['', 'Theme Page Settings'],
// label: 'fix Install as usercss (experimental)',
// labelPos: 'right',
// title: '',
// type: 'checkbox',
// default: false,
// },
fiximages: {
section: ['', 'Miscellaneous Settings'],
label: 'fix image size',
labelPos: 'right',
title: 'some images do not fit in the image container, and the site crops them. this option restores these images and resizes the container for more accurate placement. \nanother advantage: these images support image zoom extensions',
type: 'checkbox',
default: true,
},
searchhome: {
label: 'start from the search page',
labelPos: 'right',
title: 'if you do not like the openusercss.org start page or if you have problems with a server error on it you can change it to a search page',
type: 'checkbox',
default: true,
},
support: {
section: ['', 'Support'],
label: 'almaceleste.github.io',
type: 'button',
click: () => {
GM_openInTab('https://almaceleste.github.io', {
active: true,
insert: true,
setParent: true
});
}
},
},
css: windowcss,
events: {
save: function() {
GM_config.close();
}
},
});
// script code
function getData(obj, data){
return $(obj).children(`[itemprop=${data}]`).attr('value');
}
function doHighlight(theme){
const color = GM_config.get('color');
$(theme).hover(
() => {
$(theme).css({
boxShadow: `0 0 5px 1px ${color}`,
});
},
() => {
$(theme).css({
boxShadow: 'none',
});
}
);
}
function isOwnProfile(pathname){
if ($(profile.account).attr('href') == pathname) {
return true;
}
else {
return false;
}
}
function doProfile(){
if (GM_config.get('compact')) {
$(profile.donatebutton).insertAfter($(site.level).children().first());
$(site.columnright).css({
paddingTop: '0',
});
}
$(document).arrive(profile.theme, options, (t) => {
const cl = t.classList;
const d = $(t).children(data);
const c = $(t).children(`${card}, ${box}`);
const h = $(c).children().first().children().first();
const height = $(t).height();
const width = $(t).width();
let w = $('<div/>', {
class: cl,
}).css({
margin: '5px',
padding: '0',
position: 'relative',
width: `${width}px`,
});
$(t).wrap(w);
$(t).removeAttr('class');
$(c).css({
margin: '0',
position: 'relative',
});
if (GM_config.get('version')) {
$(`<span>${getData(d, 'version')}</span>`).insertAfter(h);
}
if (GM_config.get('compact')) {
$(c).css({
padding: '.7rem',
}).children('.level:nth-child(2)').css({
display: 'inline-block',
marginBottom: '0',
});
}
if (GM_config.get('highlight')) {
doHighlight($(t).parent());
}
if (isOwnProfile(state.pathname)){
if (GM_config.get('screenshot')) {
const img = $('<img/>', {
src: `https://imageproxy.openusercss.org/${getData(d, 'screenshot')}`,
on: {
load: (e) => {
let height = $(e.target).height();
if (height > width){
height = width;
}
$(e.target).parent().css({
height: `${height}px`,
});
}
}
});
$('<div/>', {
class: 'image-wrapper',
}).append(img).appendTo(t)
.css({
display: 'inline-block',
height: `100%`,
right: `0px`,
position: 'absolute',
top: `0px`,
width: `${width/3}px`,
});
$(c).css({
display: 'inline-block',
width: `${width*2/3}px`,
})
}
if (GM_config.get('editbutton')) {
let width = $(c).width();
let u = getData(d, 'url');
u = u.replace(/^(\/theme)\/(.*)$/, '$1/edit/$2');
const padding = 10;
const size = 35;
const a = $('<a/>',{
href: u,
text: '🖉',
});
a.insertAfter(t).css({
bottom: `${padding}px`,
height: `${size}px`,
left: `${width - size}px`,
padding: `${padding}px`,
position: 'absolute',
width: `${size}px`,
});
if (GM_config.get('highlight')){
const color = GM_config.get('color');
a.hover(
() => {
a.css({
textShadow: `0 0 5px ${color}`,
filter: `drop-shadow(0 0 5px ${color})`,
});
},
() => {
a.css({
textShadow: 'none',
filter: 'none',
});
}
);
}
}
$(c).children('.level').first().children().first().css({
width: '57%',
});
$(c).children('.level').first().children().last().css({
width: '27%',
});
}
$(document).unbindArrive(profile.theme);
});
}
function doEdit(){
if (GM_config.get('deletevariables')){
$(document).arrive(edit.variable, options, (v) => {
$(v).remove();
});
}
// if (GM_config.get('deletemetadata')){
// $(edit.savebutton).on({
// click: (e) => {
// e.preventDefault();
// $(edit.scrollbar).scrollTop(0);
// $(edit.metadatastart).nextUntil(edit.metadataend).remove();
// },
// submit: (e) => {
// e.preventDefault();
// $(edit.scrollbar).scrollTop(0);
// $(edit.metadatastart).nextUntil(edit.metadataend).remove();
// }
// });
// $(edit.code).arrive(edit.variable, options, (v) => {
// });
// }
if (GM_config.get('editsticky')){
const top = $(site.navbar).height();
$(edit.header).css({
position: 'sticky',
top: `${top}px`,
zIndex: '100',
});
}
}
// function fixinstall(){
// // console.log('fixinstall:', theme.installbutton);
// $(theme.installbutton).on({
// click: (e) => {
// e.preventDefault();
// const url = $(e.target).attr('href');
// const name = url.split('/').pop().split('#').shift().split('?').shift();
// fetch(url).then((response) => {
// response.text().then((usercss) => {
// const pattern = /\/\* ==UserStyle==[\s\S]*==\/UserStyle== \*\/[\s\S]*(\/\* ==UserStyle==[\s\S]*)/;
// if (pattern.test(usercss)) {
// usercss = usercss.replace(pattern, '$1');
// }
// // const install = window.open(`chrome-extension://apmmpaebfobifelkijhaljbmpcgbjbdo/install-usercss.html?${encodeURIComponent(usercss)}`, '_self');
// // const install = window.open(`data:text/css;charset=utf-8,${encodeURIComponent(usercss)}`, '_blank');
// // install.document.write(usercss);
// // var install = window.open(url, '_self');
// // install.document.onload = function() {
// // install.document.write('¡hola, mundo!');
// // console.log('¡hola, mundo!');
// // $('body > pre').text(usercss);
// // }
// // test
// // var newWin = window.open(url, 'example', 'width=600,height=400');
// // newWin.onload = function() {
// // // создать div в документе нового окна
// // var div = newWin.document.createElement('div'),
// // body = newWin.document.body;
// // div.innerHTML = 'Добро пожаловать!'
// // div.style.fontSize = '30px'
// // // вставить первым элементом в body нового окна
// // body.insertBefore(div, body.firstChild);
// // }
// // install.onload = function() {
// // install.document.write(usercss);
// // install.focus();
// // }
// // console.log('fixinstall:', install);
// // var newWin = window.open("about:blank", "hello", "width=200,height=200");
// // newWin.document.write("Привет, мир!");
// // const a = $('<a/>', {
// // href: `data:text/css;charset=utf-8,${encodeURIComponent(usercss)}`,
// // download: name,
// // // style: 'display:none',
// // target: '_blank',
// // text: 'click me',
// // type: 'text/css;charset=utf-8',
// // });
// // a.appendTo(site.level).click();
// // GM_openInTab(`data:text/js;charset=utf-8,${encodeURIComponent(usercss)}`, {
// // active: true,
// // insert: true,
// // setParent: true
// // });
// });
// });
// // const install = window.open(`${url}`, '_self');
// // install.onload = function(){
// // console.log('fixinstall:', install);
// // $('body > pre').text(usercss);
// // }
// },
// load: () => {}
// });
// }
function fiximages(path){
if (GM_config.get('fiximages')) {
$(document).arrive(path, options, (image) => {
if ($(image).next('img').length == 0){
let url = $(image).css('background-image');
url = url.replace('url("', '').replace('")', '');
if (url.startsWith('https://imageproxy.openusercss.org/50x')){
url = url.replace('https://imageproxy.openusercss.org/50x', 'https://imageproxy.openusercss.org/540x');
}
if (url != ''){
const img = $('<img/>', {
src: url,
on: {
load: (e) => {
const width = $(e.target).width();
let height = $(e.target).height();
if (height == 0 || height > width) {
height = width;
}
$(image).css({
display: 'none',
backgroundImage: 'none',
}).parent().addClass('image-wrapper').css({
height: `${height}px`,
overflow: 'hidden',
}).parent().parent().css({
height: `${height}px`,
}).next('.card-content').css({
paddingBottom: '0',
paddingTop: '0',
});
},
}
});
img.insertAfter(image);
}
}
$(document).unbindArrive(path);
});
}
}
function doThings(){
if (!state.changed) {
const pathname = window.location.pathname;
switch (true) {
case profile.path.test(pathname):
console.log('doThings:', profile.path, pathname);
if (isOwnProfile(state.pathname)) {
if (GM_config.get('stats')) {
$(document).arrive(profile.statsbutton, options, () => {
$(profile.statsbutton).click();
$(document).unbindArrive(profile.statsbutton);
});
}
}
else {
fiximages(profile.image);
}
doProfile();
break;
case theme.path.test(pathname):
console.log('doThings:', theme.path, pathname);
fiximages(theme.image);
// fixinstall();
break;
case site.path.test(pathname):
console.log('doThings:', site.path, pathname);
fiximages(site.image);
break;
case search.path.test(pathname):
console.log('doThings:', search.path, pathname);
fiximages(search.image);
$(document).arrive(search.theme, options, (t) => {
doHighlight($(t));
$(document).unbindArrive(search.theme);
});
$(document).arrive(search.author, options, (a) => {
doHighlight($(a));
$(document).unbindArrive(search.author);
});
break;
case edit.path.test(pathname):
console.log('doThings:', edit.path, pathname);
doEdit();
fiximages(edit.image);
break;
default:
console.log('doThings:', 'default', pathname);
break;
}
state.changed = true;
}
}
(function() {
'use strict';
$(document).ready(() => {
state.pathname = window.location.pathname;
state.changed = false;
doThings();
if (state.pathname == '/') {
if (GM_config.get('searchhome')) {
window.location.replace(`${window.location.origin}/search`);
}
}
$(window).on({
transitionend: (e) => {
const pathname = window.location.pathname;
switch (true){
case e.target.classList.contains('ouc-route-root'):
if (state.pathname != pathname) {
state.pathname = pathname;
state.changed = false;
doThings();
}
break;
case e.target.classList.contains('ouc-responsive-image-wrapper'):
if (search.path.test(pathname)) {
state.pathname = pathname;
state.changed = false;
doThings();
}
break;
default:
break;
}
}
});
});
})();