mirror of
https://github.com/miggymofongo/asteroid.git
synced 2024-11-24 14:10:27 +00:00
193 lines
8.9 KiB
JavaScript
193 lines
8.9 KiB
JavaScript
|
(() => { 'use strict'; if(window['bibi:jo']) return;
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
const Jo = window['bibi:jo'] = { 'version': '____Bibi-Version____',
|
||
|
CSS: require('./jo.scss'),
|
||
|
Status: '',
|
||
|
Bibis: [],
|
||
|
TrustworthyOrigins: [location.origin],
|
||
|
Loaded: 0,
|
||
|
};
|
||
|
|
||
|
const BibiEventRE = /^bibi:[a-z][a-z:_\-]*$/;
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
Jo.Bibi = function() { return Jo.callBibi.apply(Jo, arguments); };
|
||
|
|
||
|
Jo.callBibi = (Love) => {
|
||
|
let Anchor = null, Frame = null, Receiver = null, ToReceive = [];
|
||
|
try {
|
||
|
if(!(Love instanceof HTMLElement)) {
|
||
|
if(Love && typeof Love == 'object') {
|
||
|
if(!Love['bibi-href']) return null;
|
||
|
Anchor = Jo.create('a', { href: Love['bibi-href'] });
|
||
|
Frame = Jo.create('iframe');
|
||
|
Receiver = Frame;
|
||
|
}
|
||
|
if(Love['bibi-receive'] instanceof Array) ToReceive = Love['bibi-receive'];
|
||
|
} else {
|
||
|
if(/^iframe$/i.test(Love.tagName)) {
|
||
|
const BibiHref = Love.getAttribute('data-bibi-href');
|
||
|
if(!BibiHref) return null;
|
||
|
Anchor = Love.parentNode.insertBefore(Jo.create('a', { href: BibiHref }), Love);
|
||
|
Frame = Love.parentNode.removeChild(Love);
|
||
|
} else if(/^a$/i.test(Love.tagName)) {
|
||
|
if(!Love.href) return null;
|
||
|
Anchor = Love;
|
||
|
Frame = Jo.create('iframe');
|
||
|
(BibiClass => BibiClass ? BibiClass.trim().replace(/\s+/, ' ').split(' ').forEach(CN => CN ? Frame.classList.add(CN) : false) : false)(Anchor.getAttribute('data-bibi-class'));
|
||
|
(BibiID => BibiID ? Frame.setAttribute('id', BibiID ) : false)(Anchor.getAttribute('data-bibi-id' ));
|
||
|
(BibiStyle => BibiStyle ? Frame.setAttribute('style', BibiStyle) : false)(Anchor.getAttribute('data-bibi-style'));
|
||
|
}
|
||
|
Receiver = Love;
|
||
|
let BibiReceive = Receiver.getAttribute('data-bibi-receive');
|
||
|
if(BibiReceive && (BibiReceive = BibiReceive.replace(/\s+/, ''))) ToReceive = BibiReceive.split(',');
|
||
|
|
||
|
}
|
||
|
} catch(Err) { return null; } if(!Anchor || !Frame || !Receiver) return null;
|
||
|
const Bibi = Anchor.Bibi = Frame.Bibi = { Jo: Jo, Anchor: Anchor, Frame: Frame, Receiver: Receiver, Index: Jo.Bibis.length, Status: '' };
|
||
|
Bibi.listen = (EN, fun) => !BibiEventRE.test(EN) ? false : Receiver.addEventListener(EN, Eve => fun.call(Receiver, Eve.detail), false);
|
||
|
Bibi.dispatch = (EN, Det = Bibi) => !BibiEventRE.test(EN) ? false : Receiver.dispatchEvent(new CustomEvent(EN, { detail: Det }));
|
||
|
Bibi.receive = (EN) => !BibiEventRE.test(EN) ? false : Frame.contentWindow.E.add(EN, Det => Bibi.dispatch(EN, Det));
|
||
|
Bibi.post = (EN, V) => !BibiEventRE.test(EN) ? false : Frame.contentWindow.postMessage(`{ "${ EN }" : "${ V }" }`, Anchor.origin);
|
||
|
Bibi.listen('bibi:initialized', (Status) => Bibi.Status = Bibi.Initialized = Status); if(ToReceive.length) Bibi.listen('bibi:initialized', () => ToReceive.forEach(EN => Bibi.receive('' + EN.trim())));
|
||
|
Bibi.listen('bibi:readied', (Status) => Bibi.Status = Bibi.Readied = Status);
|
||
|
Bibi.listen('bibi:prepared', (Status) => Bibi.Status = Bibi.Prepared = Status);
|
||
|
Bibi.listen('bibi:opened', (Status) => Bibi.Status = Bibi.Opened = Status);
|
||
|
Bibi.listen('bibi:opened', () => {
|
||
|
Bibi.move = (Distance) => Bibi.post('bibi:commands:move', Distance);
|
||
|
Bibi.focus = (Target) => Bibi.post('bibi:commands:focus', Target);
|
||
|
Bibi.changeView = (RVM) => Bibi.post('bibi:commands:change-view', RVM);
|
||
|
Bibi.togglePanel = () => Bibi.post('bibi:commands:toggle-panel', '');
|
||
|
});
|
||
|
Anchor.style.display = 'none';
|
||
|
if(!Jo.TrustworthyOrigins.includes(Anchor.origin)) Jo.TrustworthyOrigins.push(Anchor.origin); // It is NOT reflected to S['trustworthy-origins'].
|
||
|
Anchor.href += (/#/.test(Anchor.href) ? '&' : '#') + (() => {
|
||
|
const Fragments = new Jo.Fragments();
|
||
|
Fragments.add('parent-bibi-index', Bibi.Index);
|
||
|
[
|
||
|
'autostart-embedded', 'autostart',
|
||
|
'p',
|
||
|
'fix-reader-view-mode', 'fix-view', 'view-unchangeable',
|
||
|
'full-breadth-layout-in-scroll',
|
||
|
'iipp',
|
||
|
'nav',
|
||
|
'reader-view-mode', 'rvm', 'view',
|
||
|
'start-embedded-in-new-window', 'start-in-new-window'
|
||
|
].forEach(K => { let V = '' + (Love.ownerDocument ? Love.getAttribute('data-bibi-' + K) || '' : Love['bibi-' + K]);
|
||
|
if(V && (() => { switch(K) {
|
||
|
case 'p': return /^(\d*\.)?\d+$/;
|
||
|
case 'iipp': return /^(\d*\.)?\d+$/;
|
||
|
case 'nav': return /^[1-9][0-9]*$/;
|
||
|
case 'rvm': case 'view': K = 'reader-view-mode';
|
||
|
case 'reader-view-mode': return /^(paged|horizontal|vertical)$/;
|
||
|
case 'autostart': case 'start-in-new-window': K = K.replace('start', 'start-embedded'); break;
|
||
|
case 'view-unchangeable': K = 'fix-reader-view-mode'; break;
|
||
|
} return /^(true|false|1|0|yes|no|mobile|desktop)$/; })().test(V)) Fragments.add(K, V);
|
||
|
});
|
||
|
return Fragments.make();
|
||
|
})();
|
||
|
Frame.classList.add('bibi-frame');
|
||
|
Frame.setAttribute('frameborder', '0');
|
||
|
Frame.setAttribute('scrolling', 'auto');
|
||
|
Frame.setAttribute('allowfullscreen', 'true');
|
||
|
Frame.src = Anchor.href;
|
||
|
Jo.Bibis.push(Bibi);
|
||
|
return Bibi;
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
Jo.embed = () => {
|
||
|
const BibisToBeLoaded = [], BibisLoaded = [];
|
||
|
Array.prototype.forEach.call(document.body.querySelectorAll('*[data-bibi]'), Bed => {
|
||
|
if(Bed.getAttribute('data-bibi-processed')) return;
|
||
|
Bed.setAttribute('data-bibi-processed', 'true');
|
||
|
const Bibi = new Jo.Bibi(Bed);
|
||
|
if(Bibi) BibisToBeLoaded.push(Bibi);
|
||
|
});
|
||
|
if(!BibisToBeLoaded.length) return;
|
||
|
//Jo.listen('bibi:jo:embedded', Bibis => console.log(`[Bibi:Jo] Embedded. - ${ Bibis.length } of ${ Jo.Bibis.length }`));
|
||
|
BibisToBeLoaded.forEach(Bibi => {
|
||
|
const Anchor = Bibi.Anchor, Frame = Bibi.Frame;
|
||
|
Bibi.listen('bibi:initialized', () => (BibisLoaded.push(Bibi) < BibisToBeLoaded.length) ? false : Jo.dispatch('bibi:jo:embedded', BibisLoaded));
|
||
|
Anchor.parentNode.insertBefore(Frame, Anchor);
|
||
|
});
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
document.addEventListener('DOMContentLoaded', Jo.embed), window.addEventListener('load', Jo.embed);
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
window.addEventListener('message', Eve => {
|
||
|
if(!Eve || !Jo.judge(Eve.data, Eve.origin)) return false; try {
|
||
|
Data = JSON.parse(Data);
|
||
|
if(typeof Data != 'object' || !Data) return false;
|
||
|
for(let EN in Data) Jo.dispatch(EN, Data[EN]);
|
||
|
return true; } catch(Err) {} return false;
|
||
|
}, false);
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
// Utility
|
||
|
|
||
|
Jo.create = (TagName, Properties) => {
|
||
|
const Ele = document.createElement(TagName);
|
||
|
for(let Attribute in Properties) Ele[Attribute] = Properties[Attribute];
|
||
|
return Ele;
|
||
|
};
|
||
|
|
||
|
Jo.encode = (Str) => encodeURIComponent(Str).replace('(', '_BibiKakkoOpen_').replace(')', '_BibiKakkoClose_');
|
||
|
|
||
|
Jo.Fragments = function() { // constructor
|
||
|
this.FragmentKeys = [];
|
||
|
this.FragmentKeysAndValues = {};
|
||
|
this.add = function(Key, Value) {
|
||
|
if(!this.FragmentKeys.includes(Key)) this.FragmentKeys.push(Key);
|
||
|
this.FragmentKeysAndValues[Key] = Value;
|
||
|
};
|
||
|
this.make = function() {
|
||
|
if(!this.FragmentKeys.length) return '';
|
||
|
const Fragments = [];
|
||
|
for(let l = this.FragmentKeys.length, i = 0; i < l; i++) Fragments.push(`${ this.FragmentKeys[i] }=${ Jo.encode(this.FragmentKeysAndValues[this.FragmentKeys[i]]) }`);
|
||
|
return `jo(${ Fragments.join('&') })`;
|
||
|
};
|
||
|
return this;
|
||
|
};
|
||
|
|
||
|
Jo.judge = (Msg, Origin) => (Msg && typeof Msg == 'string' && Origin && typeof Origin == 'string' && Jo.TrustworthyOrigins.includes(Origin));
|
||
|
|
||
|
Jo.listen = (EN, fun) => !BibiEventRE.test(EN) ? false : document.addEventListener(EN, Eve => fun.call(document, Eve.detail));
|
||
|
Jo.dispatch = (EN, Det = Jo) => !BibiEventRE.test(EN) ? false : document.dispatchEvent(new CustomEvent(EN, { detail: Det }));
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
// Polyfill
|
||
|
|
||
|
if(!Array.prototype.includes) Array.prototype.includes = function(I) { for(let l = this.length, i = 0; i < l; i++) if(this[i] == I) return true; return false; };
|
||
|
|
||
|
if(!window.CustomEvent || (typeof window.CustomEvent !== 'function') && (window.CustomEvent.toString().indexOf('CustomEventConstructor') === -1)) {
|
||
|
window.CustomEvent = function(EventName, Arguments) { // constructor
|
||
|
Arguments = Arguments || { bubbles: false, cancelable: false, detail: undefined };
|
||
|
const Eve = document.createEvent('CustomEvent');
|
||
|
Eve.initCustomEvent(EventName, Arguments.bubbles, Arguments.cancelable, Arguments.detail);
|
||
|
return Eve;
|
||
|
};
|
||
|
window.CustomEvent.prototype = window.Event.prototype;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
})();
|