antville/static/formica.html

452 lines
12 KiB
HTML
Raw Normal View History

<!DOCTYPE html>
<title>Antvilles Formica Bookmarklet</title>
<meta charset='utf-8'>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<link rel='icon' type='image/x-icon' href='img/favicon.png'>
<link rel='shortcut icon' type='image/x-icon' href='img/favicon.png'>
<link rel='apple-touch-icon' href='img/favicon.png'>
<script>
const global = window;
const settings = {};
let proxyUri;
(search => {
search = String(search).substr(1);
if (search.length > 0) {
let parts = search.split('&');
parts.forEach((item, index) => {
parts = item.split('=');
settings[parts[0]] = decodeURIComponent(parts[1] || '').trim();
});
}
proxyUri = settings.b + 'claustra/proxy';
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = settings.b + 'main.css';
link.onload = () => document.querySelector('main').hidden = false;
document.head.appendChild(link);
})(location.search);
</script>
<style>
body {
margin: 1em;
padding: 1em;
}
.image {
height: 192px;
}
.image::after {
content: '';
background: center/10px url('img/favicon.png') !important;
opacity: 0.2;
top: 1px;
left: 1px;
bottom: 1px;
right: 1px;
position: absolute;
z-index: -1;
}
figure.uk-panel-box {
padding: 16px;
}
</style>
<main hidden class='uk-grid' data-uk-grid-margin>
<div class='uk-width-medium-2-5 uk-hidden left'>
<figure class='uk-panel uk-panel-box uk-panel-box-secondary' onclick='onToggleImage(event)'>
<div class='image uk-panel-teaser'>
<div id='dimensions' class='uk-panel-badge uk-badge'>0×0</div>
<img id='preview' class='loading uk-responsive-width uk-responsive-height'>
</div>
<figcaption>
<div id='info' class='info uk-float-left'></div>
<div class='controls uk-button-group uk-float-right'>
<a href='javascript:' class='uk-button' onclick='onChangeImage(event, -1)'>
<i class='uk-icon-arrow-left'></i>
</a>
<a href='javascript:' class='uk-button' onclick='onChangeImage(event, +1)'>
<i class='uk-icon-arrow-right'></i>
</a>
</div>
</figcaption>
</figure>
</div>
<form class='uk-width-medium-1-1 uk-form uk-form-stacked right'>
<div class='uk-form-row'>
<div class='uk-form-controls uk-text-bold'>
<input id='title' class='uk-form uk-width-medium-1-1' type='text' placeholder='Title'>
</div>
</div>
<div class='uk-form-row'>
<div class='uk-form-controls'>
<textarea id='text' class='uk-form uk-width-medium-1-1' rows=10 placeholder='Description'></textarea>
</div>
</div>
<div class='uk-form-row uk-text-right'>
<div id='feedback' class='uk-float-left'>
<i class='uk-icon-refresh uk-icon-spin'></i> Loading…
</div>
<button id='submit' name='button' type='button' class='uk-button uk-button-primary' onclick='onPublish(event)'>
<i class='uk-icon-image uk-hidden' id='image'></i>
Publish
</button>
</div>
</form>
</main>
<script>
(() => {
const script = document.createElement('script');
script.src = settings.b + 'main.js';
document.body.appendChild(script);
let _currentIndex;
let _images;
let _siteUri;
let _sourceUri;
global.onChangeImage = (event, direction = 1) => {
event.preventDefault();
event.stopPropagation();
let index = (_currentIndex || 0) + direction;
if (index >= _images.length) {
index = 0;
} else if (index < 0) {
index = _images.length - 1;
}
_currentIndex = index;
displayImage(_images[index]);
};
global.onToggleImage = event => {
const classList = (event ? event.currentTarget : document.querySelector('figure')).classList;
classList.toggle('uk-panel-box-primary');
classList.toggle('uk-panel-box-secondary');
global.image.classList.toggle('uk-hidden');
global.image.hidden = !global.image.hidden;
};
global.onPublish = event => {
event.preventDefault();
feedback(false);
event.currentTarget.disabled = true;
const imageUri = global.image.hidden ? _images[_currentIndex].src : null;
post(_sourceUri, imageUri);
};
const main = () => {
if (!settings.s || !settings.l) return;
_siteUri = settings.s;
_sourceUri = settings.l;
if (!_siteUri || !_sourceUri) return;
_images = [];
_currentIndex = 0;
if (_sourceUri.match(new RegExp('(?:bmp|gif|jpg|jpeg|png)$', 'i'))) {
feedback();
return addImage(_sourceUri);
}
const customCookie = settings.k;
const data = {
url: _sourceUri,
cookie: document.cookie + '; ' + customCookie,
ua: 'Mozilla/5.0 (Formica Bookmarklet by Antville)',
ref: location.href
}
jsonp(proxyUri, data, (result, error) => {
const content = result.content;
let text = '';
if (settings.c) text = settings.c.trim();
if (error) {
text = `[${text}](${_sourceUri})`;
if (settings.r) text += ` _(via ${settings.r})_.`;
global.text.value = text;
return feedback(null, 'Could not fetch URL; are you logged in?');
}
if (!content) {
return feedback('URL error; no data.');
}
const parser = new DOMParser();
const sourceDocument = parser.parseFromString(content, 'text/html');
const openGraphTitle = (meta => meta ? meta.getAttribute('content') : null)(
sourceDocument.querySelector('meta[property="og:title"]')
);
const openGraphDescription = (meta => meta ? meta.getAttribute('content') : null)(
sourceDocument.querySelector('meta[property="og:description"]')
);
const openGraphImage = (meta => meta ? meta.getAttribute('content') : null)(
sourceDocument.querySelector('meta[property="og:image"]')
);
if (!text || text === openGraphTitle) text = openGraphDescription || '';
text = `[${text}](${_sourceUri})`;
if (settings.r) text += ` _(via ${settings.r})_.`;
global.title.value = openGraphTitle || sourceDocument.title;
global.text.value = text;
const baseHref = getBaseHref(sourceDocument);
sourceDocument.querySelectorAll('img').forEach(img => {
addImage(img.src, baseHref);
});
if (openGraphImage) addImage(openGraphImage, baseHref);
const regexes = [
/(?:\(|=|"|')([^\s\(\)'">]+\.(?:gif|jpg|jpeg|png|webp))/gi
];
regexes.forEach(regex => {
let match;
while (match = regex.exec(content)) {
if (match[1]) addImage(match[1], baseHref);
}
});
feedback();
});
};
const getBaseHref = doc => {
const base = doc.querySelector('base');
if (base) {
const href = base.getAttribute('href');
if (href) return href;
2012-05-24 12:11:15 +00:00
}
const index = _sourceUri.lastIndexOf('/');
if (index !== _sourceUri.length - 1) {
return _sourceUri.substring(0, index + 1);
}
return _sourceUri;
};
const addImage = (url, baseUri) => {
if (!url || _images[url]) return;
if (!addImage.counter) addImage.counter = 0;
_images[url] = true;
if (url.charAt(0) === '/') {
if (url.charAt(1) !== '/') {
// url starts with one single slash: prepend root of _sourceUri.
const index = _sourceUri.indexOf('/', _sourceUri.indexOf('://') + 3);
baseUri = index > -1 ? _sourceUri.substring(0, index) : _sourceUri;
url = baseUri + url;
}
} else if (url.indexOf('://') < 0) {
// url does neither start with a slash, nor contain
// a protocol: prepend _sourceUri up to the final slash.
baseUri || (baseUri = _sourceUri.substring(0, _sourceUri.lastIndexOf('/') + 1));
url = baseUri + url;
}
const image = new Image();
image.onload = function () {
if (this.width < 100 || this.height < 100) return;
_images.push(this);
displayImage(_images[0]);
addImage.counter += 1;
if (_images.length && addImage.counter) {
showImagePane();
}
};
image.src = url;
};
const displayImage = image => {
const MAX_WIDTH = 200;
const MAX_HEIGHT = 600;
let width = image.width;
let height = image.height;
let factorH = 1;
let factorV = 1;
if (width > MAX_WIDTH) factorH = MAX_WIDTH / width;
if (height > MAX_HEIGHT) factorV = MAX_HEIGHT / height;
if (factorH !== 1 || factorV !== 1) {
width = Math.ceil(width * (factorH < factorV ? factorH : factorV));
height = Math.ceil(height * (factorH < factorV ? factorH : factorV));
}
global.preview.width = width;
global.preview.height = height;
global.preview.src = image.src;
global.dimensions.innerHTML = image.width + '×' + image.height;
info.innerHTML = (_currentIndex + 1) + ' of ' + _images.length;
return;
};
const post = (url, imageUrl) => {
const postStory = imageName => {
feedback("<i class='uk-icon-refresh uk-icon-spin'></i> Posting story…");
let imageMacro = '';
2020-04-12 19:07:14 +02:00
if (imageName) imageMacro = `\n\n<\x25 image '${imageName}' box link='${url}' \x25>`;
const data = {
save: 1,
title: global.title.value,
text: global.text.value + imageMacro,
'og:image': imageUrl
}
return jsonp(_siteUri + '/stories/create', data, (res, error) => {
restore();
if (error) return feedback(null, 'Access error; are you logged in?');
if (!res) {
feedback(null, 'Story error; maybe try again…');
} else if (global.opener) {
feedback("<i class='uk-icon-check-circle'></i> Success!");
setTimeout(() => global.close(), 1000);
} else {
location.href = _siteUri + '/stories/' + res;
}
});
}
if (imageUrl) {
feedback("<i class='uk-icon-refresh uk-icon-spin'></i> Uploading image…");
const name = 'image-' + Date.now();
const data = {
save: 1,
file_origin: imageUrl,
name: name,
maxWidth: settings.w || '',
maxHeight: settings.h || ''
};
jsonp(_siteUri + '/images/create', data, (res, error) => {
restore();
if (error) return feedback(null, 'Access error; are you logged in?');
if (!data) {
feedback(null, 'Image error; maybe try again…');
} else {
postStory(name);
}
});
} else {
postStory();
}
return;
}
const showImagePane = () => {
const rightPaneClasses = document.querySelector('.right').classList;
if (rightPaneClasses.contains('uk-width-medium-1-1')) {
rightPaneClasses.toggle('uk-width-medium-3-5');
rightPaneClasses.toggle('uk-width-medium-1-1');
document.querySelector('.left').classList.toggle('uk-hidden');
onToggleImage();
}
};
const feedback = (message, error) => {
if (error) {
global.feedback.innerHTML = "<i class='uk-icon-warning'></i> " + error;
} else if (message) {
global.feedback.innerHTML = message;
} else {
global.feedback.innerHTML = '';
}
};
const restore = () => {
setTimeout(() => global.submit.disabled = false, 3000);
};
const jsonp = (uri, data = {}, callback = () => {}) => {
const handlerId = 'jsonpHandler' + Date.now() +
parseInt(Math.random() * Math.pow(2, 16), 10);
window[handlerId] = (data, error) => {
window[handlerId] = null;
window['script-' + handlerId].remove();
return callback(data, error);
};
const script = document.createElement('script');
let queryString = '';
if (data) {
queryString = Object.keys(data).map(key => {
const value = data[key];
return `${key}=${encodeURIComponent(value)}`;
}).join('&');
}
script.src = `${uri}?${queryString}&callback=${handlerId}`;
script.id = 'script-' + handlerId;
script.onload = () => {
setTimeout(() => {
const handler = window[handlerId];
if (handler) handler(null, 'timeout');
}, 1000);
};
document.body.append(script);
}
main();
})();
</script>