<commit_before>'use strict';

class ApplicationController extends ModelController {

    static create(model, view) {
        // console.log('ApplicationController.create');
        // console.log('debug:', ApplicationController.isInDebugMode());
        if (model.data.js) {
            const CustomClass = eval(model.data.js);
            if (!CustomClass) throw new Error(`custom class of "${model.getFullName()}" form does not return type`);
            return new CustomClass(model, view);
        }
        return eval(`new ${model.getClassName()}Controller(model, view)`);
    }

    constructor(model, view) {
        // console.log('ApplicationController.constructor', model, view);
        super(model);
        this.view = view;
        this.view2 = null;
        this.lastPageId = 0;
        this.menu       = null;
        this.tabWidget  = null;
        this.statusbar  = null;
        this.pages = null;
        this.activePage = null;
        this.tab    = null;
    }

    static getSearchObj() {
        // console.log('ApplicationController.getSearchObj:', window.location);
        if (!window.location.search.split('?')[1]) return {};
        return window.location.search.split('?')[1].split('&').reduce((acc, item) => {
            const kv = item.split('=');
            acc[kv[0]] = kv[1];
            return acc;
        }, {});
    }

    static isInDebugMode() {
        return ApplicationController.getSearchObj()['debug'] === '1';
    }

    init() {
        // console.log('ApplicationController.init');

        // app
        this.model.on('logout' , this.listeners.logout  = this.onLogout.bind(this));
        this.model.on('request', this.listeners.request = this.onRequest.bind(this));

        this.initMenu();
        this.initStatusbar();
        this.initTab();
        this.createPages();
        if (!this.view) {
            this.pages = this.createPages2();
            this.activePage = this.pages.length ? this.pages[0] : null;
        }
    }

    getActivePageIndex = () => {
        const i = this.activePage ? this.pages.indexOf(this.activePage) : null;
        if (i === -1) throw new Error('active page not in list');
        return i;
    }

    createView(root) {
        console.log('ApplicationController.createView');
        this.view2 = ApplicationController.createReactComponent(root, ApplicationView, {ctrl: this});
    }

    getMenuItemsProp() {
        return Object.keys(this.model.data.menu).map(key => ({
            name: key,
            title: key,
            items: this.model.data.menu[key].map(item => ({
                name: item.page,
                title: item.caption
            }))
        }));
    }

    initMenu() {
        if (!this.view) return;
        this.menu = ApplicationController.createReactComponent(this.view.querySelector('.menu'), Menu, {
            items: this.getMenuItemsProp(),
            onClick: this.onMenuItemClick,
            cb: menu => this.menu = menu
        });
        // setTimeout(() => this.menu.toggleMenu('Pages'), 1000);
    }

    initStatusbar() {
        if (!this.view) return;
        this.statusbar = ApplicationController.createReactComponent(this.view.querySelector('.statusbar'), Statusbar);
    }

    initTab() {
        if (!this.view) return;
        this.tabWidget = new TabWidget(this.view.querySelector('.ApplicationView > .TabWidget'));
        this.tabWidget.init();
        this.tabWidget.on('tabClosingByUser', this.listeners.tabClosingByUser = this.onTabClosingByUser.bind(this));
        this.tabWidget.on('tabShow'         , this.listeners.tabShow          = this.onTabShow.bind(this));
        this.tabWidget.on('tabHide'         , this.listeners.tabHide          = this.onTabHide.bind(this));
    }

    createPages() {
        if (!this.view) return;
        for (const name in this.model.data.pages) {
            const page = new Page(this.model.data.pages[name], this.model, {
                // app : this.model,
                // data: this.model.data.pages[name],
                id  : `p${this.getNextPageId()}`
            });
            page.init();
            this.createPageController(page);
        }
    }
    createPages2() {
        return Object.keys(this.model.data.pages).map(name => {
            // model
            const page = new Page(this.model.data.pages[name], this.model, {
                // app : this.model,
                // data: this.model.data.pages[name],
                id  : `p${this.getNextPageId()}`
            });
            page.init();

            // controller
            const pageController = PageController.create(page, null, this);
            pageController.init();
            return pageController;
        });
    }

    deinit() {
        // app
        this.model.off('logout', this.listeners.logout);
        this.model.off('request', this.listeners.request);

        // TabWidget
        this.tabWidget.off('tabClosingByUser', this.listeners.tabClosingByUser);
        this.tabWidget.off('tabShow', this.listeners.tabShow);
        this.tabWidget.off('tabHide', this.listeners.tabHide);
        super.deinit();
    }

    createPageController(model, select = false, track = false) {
        console.log('ApplicationController.createPageController', model.getFullName());
        // const html = QForms.render(model.data.view, {model});
        // const view = $(html).get(0);

        // tab
        const [tab, root] = this.tabWidget.createTab2(null, null, null, model.id);
        if (select) this.tabWidget.selectTab(tab, track);

        // pageController
        const pageController = PageController.create(model, null, this);
        pageController.tab = tab;
        tab.pageController = pageController;
        pageController.init();
        // pageController.fill();
        pageController.createView(root);
    }
    createModalPageController(model) {
        console.log('ApplicationController.createModalPageController', model.getFullName());
        // const html = QForms.render(model.data.view, {model});
        // const view = $(html).get(0);

        const [el, root] = ModalWidget.createElementAndRoot();
        this.view.appendChild(el);
        const modal = new ModalWidget(el);

        // pageController
        const pageController = PageController.create(model, null, this);
        pageController.modal = modal;
        pageController.init();
        // pageController.fill();
        pageController.createView(root);
    }

    onPageSelected(pc) {
        console.log('ApplicationController.onPageSelected', pc.model.getName());
        const i = this.pages.indexOf(pc);
        if (i === -1) throw new Error(`no page controller ${pc.model.getName()} in pages`);
        this.activePage = pc;
        this.tab.rerender();
        // const tab = this.findTabByPageController(pageController);
        // this.tabWidget.selectTab(tab);
    }

    onTabClosingByUser(e) {
        e.tab.pageController.close();
    }

    onTabShow(e) {
        // console.log('ApplicationController.onTabShow', e.tab.pageController);
        if (e.tab.pageController) {
            e.tab.pageController.emit('show', {source: this});
        }
    }

    onTabHide(e) {
        if (e.tab.pageController) {
            e.tab.pageController.emit('hide', {source: this});
        }
    }

    onLogout(ea) {
        location.reload();
    }

    onRequest(e) {
        // console.log('onRequest', e);
        if (this.statusbar) {
            this.statusbar.setLastQueryTime(e.time);
        }
    }

    closePage(pageController) {
        console.log('ApplicationController.closePage', pageController.model.getFullName());
        /*
        if (pageController.tab) {
            this.tabWidget.closeTab(pageController.tab);
        } else if (pageController.modal) {
            pageController.modal.close();
        }
        pageController.deinit();
        pageController.model.deinit();*/
        const i = this.pages.indexOf(pageController);
        this.pages.splice(i, 1);
        if (this.tab.state.active === i) {
            this.tab.state.active = this.pages.length - 1;
            console.log('this.tab.state.active:', this.tab.state.active);
        }
        this.view2.rerender();
        pageController.deinit();
        pageController.model.deinit();
    }

    onPageClose = i => {
        console.log('ApplicationController.onPageClose', this.pages[i].model.getFullName());
        this.closePage(this.pages[i])
    }

    findPageControllerByPageNameAndKey(pageName, key) {
        /*// console.log('ApplicationController.findPageControllerByPageNameAndKey', pageName, key);
        for (let i = 0; i < this.tabWidget.tabList.childNodes.length; i++) {
            const tab = this.tabWidget.tabList.childNodes[i];
            if (tab.pageController.model.getName() === pageName && tab.pageController.model.getKey() === key) {
                return tab.pageController;
            }
        }*/
        return this.pages.find(({model}) => model.getName() === pageName && model.getKey() === key);
    }

    findTabByPageController(pageController) {
        // console.log('ApplicationController.findTabByPageController');
        for (let i = 0; i < this.tabWidget.tabList.childNodes.length; i++) {
            const tab = this.tabWidget.tabList.childNodes[i];
            if (tab.pageController === pageController) {
                return tab;
            }
        }
        return null;
    }

    async openPage(options) {
        console.log('ApplicationController.openPage', options);
        const name       = options.name;
        const key        = options.key || null;
        const parentPage = options.parentPage;
        const newMode    = !!options.newMode;
        const modal      = !!options.modal;

        // if this page with this key is already opened, then show it
        const pageController = this.findPageControllerByPageNameAndKey(name, key);
        // console.log('pageController:', pageController);
        if (pageController) {
            this.onPageSelected(pageController);
            return;
        }

        const parentPageName = parentPage ? parentPage.getName() : null;
        let keyParams = {};
        const params = {};
        //console.log('open ' + name + ' with key: ' + key);
        if (key) {
            keyParams = QForms.keyToParams(key);
            for (const keyName in keyParams) {
                params[keyName] = keyParams[keyName];
            }
        }

        // if page doesn't exist, create it
        const response = await this.model.request({
            action        : 'page',
            page          : name,
            newMode       : newMode,
            parentPageName: parentPageName,
            params        : params
        });

        // copy params from parent page to make possible refer to parent page params
        if (parentPage !== undefined) {
            for (const name in parentPage.params) {
                if (keyParams[name] === undefined) {
                    params[name] = parentPage.params[name];
                }
            }
        }
        const page = new Page(response.page, this.model, {
            // app           : this.model,
            // data          : response.page,
            id            : `p${this.getNextPageId()}`,
            params        : params,
            parentPageName: parentPageName,
        });
        page.init();
        const pc = new PageController(page, null, this);
        pc.init();
        this.pages.push(pc);
        this.activePage = pc;
        this.view2.rerender();
        /*
        if (modal) {
            this.createModalPageController(page);
        } else {
            this.createPageController(page, true, parentPage !== undefined);
        }*/
    }

    getNextPageId() {
        this.lastPageId++;
        return this.lastPageId;
    }

    onMenuItemClick = async (menu, item) => {
        // console.log('ApplicationController.onMenuItemClick', menu, item);
        try {
            await this.openPage({name: item});
        } catch (err) {
            console.error(err);
            alert(err.message);
        }
    }

    // static createReactRoot(name, props, children) {
    //     console.log('ApplicationController.createReactRoot', name, props);
    //     const div = document.createElement('div');
    //     div.className = name;
    //     ReactDOM.render(React.createElement(eval(name), props, children), div);
    //     return div;
    // }

    static createReactComponent(root, type, props = {}, children) {
        // console.log('ApplicationController.createReactComponent', root, type);
        let component;
        props.cb = c => component = c;
        const reactElement = React.createElement(type, props, children);
        ReactDOM.render(reactElement, root);
        return component;
    }
    onTabCreated = tab => {
        // console.log('ApplicationController.onTabCreated', tab);
        this.tab = tab;
    }
}
<commit_msg>close active page<commit_after>'use strict';

class ApplicationController extends ModelController {

    static create(model, view) {
        // console.log('ApplicationController.create');
        // console.log('debug:', ApplicationController.isInDebugMode());
        if (model.data.js) {
            const CustomClass = eval(model.data.js);
            if (!CustomClass) throw new Error(`custom class of "${model.getFullName()}" form does not return type`);
            return new CustomClass(model, view);
        }
        return eval(`new ${model.getClassName()}Controller(model, view)`);
    }

    constructor(model, view) {
        // console.log('ApplicationController.constructor', model, view);
        super(model);
        this.view = view;
        this.view2 = null;
        this.lastPageId = 0;
        this.menu       = null;
        this.tabWidget  = null;
        this.statusbar  = null;
        this.pages = null;
        this.activePage = null;
        this.tab    = null;
    }

    static getSearchObj() {
        // console.log('ApplicationController.getSearchObj:', window.location);
        if (!window.location.search.split('?')[1]) return {};
        return window.location.search.split('?')[1].split('&').reduce((acc, item) => {
            const kv = item.split('=');
            acc[kv[0]] = kv[1];
            return acc;
        }, {});
    }

    static isInDebugMode() {
        return ApplicationController.getSearchObj()['debug'] === '1';
    }

    init() {
        // console.log('ApplicationController.init');

        // app
        this.model.on('logout' , this.listeners.logout  = this.onLogout.bind(this));
        this.model.on('request', this.listeners.request = this.onRequest.bind(this));

        this.initMenu();
        this.initStatusbar();
        this.initTab();
        this.createPages();
        if (!this.view) {
            this.pages = this.createPages2();
            this.activePage = this.pages.length ? this.pages[0] : null;
        }
    }

    getActivePageIndex = () => {
        const i = this.activePage ? this.pages.indexOf(this.activePage) : null;
        if (i === -1) throw new Error('active page not in list');
        return i;
    }

    createView(root) {
        console.log('ApplicationController.createView');
        this.view2 = ApplicationController.createReactComponent(root, ApplicationView, {ctrl: this});
    }

    getMenuItemsProp() {
        return Object.keys(this.model.data.menu).map(key => ({
            name: key,
            title: key,
            items: this.model.data.menu[key].map(item => ({
                name: item.page,
                title: item.caption
            }))
        }));
    }

    initMenu() {
        if (!this.view) return;
        this.menu = ApplicationController.createReactComponent(this.view.querySelector('.menu'), Menu, {
            items: this.getMenuItemsProp(),
            onClick: this.onMenuItemClick,
            cb: menu => this.menu = menu
        });
        // setTimeout(() => this.menu.toggleMenu('Pages'), 1000);
    }

    initStatusbar() {
        if (!this.view) return;
        this.statusbar = ApplicationController.createReactComponent(this.view.querySelector('.statusbar'), Statusbar);
    }

    initTab() {
        if (!this.view) return;
        this.tabWidget = new TabWidget(this.view.querySelector('.ApplicationView > .TabWidget'));
        this.tabWidget.init();
        this.tabWidget.on('tabClosingByUser', this.listeners.tabClosingByUser = this.onTabClosingByUser.bind(this));
        this.tabWidget.on('tabShow'         , this.listeners.tabShow          = this.onTabShow.bind(this));
        this.tabWidget.on('tabHide'         , this.listeners.tabHide          = this.onTabHide.bind(this));
    }

    createPages() {
        if (!this.view) return;
        for (const name in this.model.data.pages) {
            const page = new Page(this.model.data.pages[name], this.model, {
                // app : this.model,
                // data: this.model.data.pages[name],
                id  : `p${this.getNextPageId()}`
            });
            page.init();
            this.createPageController(page);
        }
    }
    createPages2() {
        return Object.keys(this.model.data.pages).map(name => {
            // model
            const page = new Page(this.model.data.pages[name], this.model, {
                // app : this.model,
                // data: this.model.data.pages[name],
                id  : `p${this.getNextPageId()}`
            });
            page.init();

            // controller
            const pageController = PageController.create(page, null, this);
            pageController.init();
            return pageController;
        });
    }

    deinit() {
        // app
        this.model.off('logout', this.listeners.logout);
        this.model.off('request', this.listeners.request);

        // TabWidget
        this.tabWidget.off('tabClosingByUser', this.listeners.tabClosingByUser);
        this.tabWidget.off('tabShow', this.listeners.tabShow);
        this.tabWidget.off('tabHide', this.listeners.tabHide);
        super.deinit();
    }

    createPageController(model, select = false, track = false) {
        console.log('ApplicationController.createPageController', model.getFullName());
        // const html = QForms.render(model.data.view, {model});
        // const view = $(html).get(0);

        // tab
        const [tab, root] = this.tabWidget.createTab2(null, null, null, model.id);
        if (select) this.tabWidget.selectTab(tab, track);

        // pageController
        const pageController = PageController.create(model, null, this);
        pageController.tab = tab;
        tab.pageController = pageController;
        pageController.init();
        // pageController.fill();
        pageController.createView(root);
    }
    createModalPageController(model) {
        console.log('ApplicationController.createModalPageController', model.getFullName());
        // const html = QForms.render(model.data.view, {model});
        // const view = $(html).get(0);

        const [el, root] = ModalWidget.createElementAndRoot();
        this.view.appendChild(el);
        const modal = new ModalWidget(el);

        // pageController
        const pageController = PageController.create(model, null, this);
        pageController.modal = modal;
        pageController.init();
        // pageController.fill();
        pageController.createView(root);
    }

    onPageSelected(pc) {
        console.log('ApplicationController.onPageSelected', pc.model.getName());
        const i = this.pages.indexOf(pc);
        if (i === -1) throw new Error(`no page controller ${pc.model.getName()} in pages`);
        this.activePage = pc;
        this.tab.rerender();
        // const tab = this.findTabByPageController(pageController);
        // this.tabWidget.selectTab(tab);
    }

    onTabClosingByUser(e) {
        e.tab.pageController.close();
    }

    onTabShow(e) {
        // console.log('ApplicationController.onTabShow', e.tab.pageController);
        if (e.tab.pageController) {
            e.tab.pageController.emit('show', {source: this});
        }
    }

    onTabHide(e) {
        if (e.tab.pageController) {
            e.tab.pageController.emit('hide', {source: this});
        }
    }

    onLogout(ea) {
        location.reload();
    }

    onRequest(e) {
        // console.log('onRequest', e);
        if (this.statusbar) {
            this.statusbar.setLastQueryTime(e.time);
        }
    }

    closePage(pageController) {
        console.log('ApplicationController.closePage', pageController.model.getFullName());
        /*
        if (pageController.tab) {
            this.tabWidget.closeTab(pageController.tab);
        } else if (pageController.modal) {
            pageController.modal.close();
        }
        pageController.deinit();
        pageController.model.deinit();*/
        this.pages.splice(this.pages.indexOf(pageController), 1);
        if (this.activePage === pageController) {
            this.activePage = this.pages[this.pages.length - 1];
        }
        this.view2.rerender();
        pageController.deinit();
        pageController.model.deinit();
    }

    onPageClose = i => {
        console.log('ApplicationController.onPageClose', this.pages[i].model.getFullName());
        this.closePage(this.pages[i]);
    }

    findPageControllerByPageNameAndKey(pageName, key) {
        /*// console.log('ApplicationController.findPageControllerByPageNameAndKey', pageName, key);
        for (let i = 0; i < this.tabWidget.tabList.childNodes.length; i++) {
            const tab = this.tabWidget.tabList.childNodes[i];
            if (tab.pageController.model.getName() === pageName && tab.pageController.model.getKey() === key) {
                return tab.pageController;
            }
        }*/
        return this.pages.find(({model}) => model.getName() === pageName && model.getKey() === key);
    }

    findTabByPageController(pageController) {
        // console.log('ApplicationController.findTabByPageController');
        for (let i = 0; i < this.tabWidget.tabList.childNodes.length; i++) {
            const tab = this.tabWidget.tabList.childNodes[i];
            if (tab.pageController === pageController) {
                return tab;
            }
        }
        return null;
    }

    async openPage(options) {
        console.log('ApplicationController.openPage', options);
        const name       = options.name;
        const key        = options.key || null;
        const parentPage = options.parentPage;
        const newMode    = !!options.newMode;
        const modal      = !!options.modal;

        // if this page with this key is already opened, then show it
        const pageController = this.findPageControllerByPageNameAndKey(name, key);
        // console.log('pageController:', pageController);
        if (pageController) {
            this.onPageSelected(pageController);
            return;
        }

        const parentPageName = parentPage ? parentPage.getName() : null;
        let keyParams = {};
        const params = {};
        //console.log('open ' + name + ' with key: ' + key);
        if (key) {
            keyParams = QForms.keyToParams(key);
            for (const keyName in keyParams) {
                params[keyName] = keyParams[keyName];
            }
        }

        // if page doesn't exist, create it
        const response = await this.model.request({
            action        : 'page',
            page          : name,
            newMode       : newMode,
            parentPageName: parentPageName,
            params        : params
        });

        // copy params from parent page to make possible refer to parent page params
        if (parentPage !== undefined) {
            for (const name in parentPage.params) {
                if (keyParams[name] === undefined) {
                    params[name] = parentPage.params[name];
                }
            }
        }
        const page = new Page(response.page, this.model, {
            // app           : this.model,
            // data          : response.page,
            id            : `p${this.getNextPageId()}`,
            params        : params,
            parentPageName: parentPageName,
        });
        page.init();
        const pc = new PageController(page, null, this);
        pc.init();
        this.pages.push(pc);
        this.activePage = pc;
        this.view2.rerender();
        /*
        if (modal) {
            this.createModalPageController(page);
        } else {
            this.createPageController(page, true, parentPage !== undefined);
        }*/
    }

    getNextPageId() {
        this.lastPageId++;
        return this.lastPageId;
    }

    onMenuItemClick = async (menu, item) => {
        // console.log('ApplicationController.onMenuItemClick', menu, item);
        try {
            await this.openPage({name: item});
        } catch (err) {
            console.error(err);
            alert(err.message);
        }
    }

    // static createReactRoot(name, props, children) {
    //     console.log('ApplicationController.createReactRoot', name, props);
    //     const div = document.createElement('div');
    //     div.className = name;
    //     ReactDOM.render(React.createElement(eval(name), props, children), div);
    //     return div;
    // }

    static createReactComponent(root, type, props = {}, children) {
        // console.log('ApplicationController.createReactComponent', root, type);
        let component;
        props.cb = c => component = c;
        const reactElement = React.createElement(type, props, children);
        ReactDOM.render(reactElement, root);
        return component;
    }
    onTabCreated = tab => {
        // console.log('ApplicationController.onTabCreated', tab);
        this.tab = tab;
    }
}
<|endoftext|>


<commit_before>'use strict'

const LRU = require('lru-cache');
const cayley = require('cayley');
const array_stream = require('../array_stream');
const cache_options = {max: 500};

module.exports = (entrypoint) => {

    entrypoint.module_root = entrypoint.base + '/node_modules/';

    const client = cayley(process.flow_env.db);
    const g = client.graph;

    return {
        cache: LRU(cache_options),
        read: (event_iri, args) => {

            let role = '*'
            if (args.session) {
                role = args.session.role || role;
            }

            let count = 0;
            const stream = array_stream();
            const array = [];

            // TODO stream API for node cayley
            const handler = (err, result) => {

                if (err) {
                    return stream.emit('error', err);
                }

                if (result && result.length) {
                    result.forEach(item => array.push([item.subject, item.predicate, item.id]));
                }

                if (++count === 3) {

                    if (!array.length) {
                        return stream.emit('error', new Error('Flow-nodejs.adapter.cayley.read: Empty result for "' + event_iri + '".'));
                    }

                    stream.set(array);
                }
            };

            // event
            g.V(event_iri).Tag('subject').Out([
              'http://schema.jillix.net/vocab/onError',
              'http://schema.jillix.net/vocab/onEnd',
              'http://schema.jillix.net/vocab/sequence',
            ], 'predicate').All(handler);

            // sequences
            g.V().Has(
              'http://schema.jillix.net/vocab/event',
              event_iri
            ).Has(
              'http://www.w3.org/1999/02/22-rdf-syntax-ns#type',
              'http://schema.jillix.net/vocab/Sequence'
            ).Tag('subject').Out([
              'http://schema.jillix.net/vocab/instance',
              'http://schema.jillix.net/vocab/args',
              'http://schema.jillix.net/vocab/dataHandler',
              'http://schema.jillix.net/vocab/onceHandler',
              'http://schema.jillix.net/vocab/streamHandler',
              'http://schema.jillix.net/vocab/emit',
              'http://schema.jillix.net/vocab/sequence'
            ], 'predicate').All(handler);

            // instances
            g.V().Has(
              'http://schema.jillix.net/vocab/event',
              event_iri
            ).Has(
              'http://www.w3.org/1999/02/22-rdf-syntax-ns#type',
              'http://schema.jillix.net/vocab/Sequence'
            ).Out('http://schema.jillix.net/vocab/instance').
            Has('http://schema.jillix.net/vocab/roles', '"' + role + '"').
            Tag('subject').Out([
                'http://schema.jillix.net/vocab/args',
                'http://schema.jillix.net/vocab/roles',
                'http://schema.jillix.net/vocab/module'
            ], 'predicate').All(handler);

            return stream;
        },

        mod: (module_iri, args, cb) => {
            g.V(module_iri).Out('http://schema.org/name').GetLimit(1, (err, module) => {

                if (err) {
                    return cb(err);
                }

                if (!module || !module[0] || !module[0].id) {
                    return cb(new Error('Flow-nodejs.adapter.cayley.mod: Empty respone for ' + module_iri));
                }

                module = module[0].id;
                module = module[0] === '"' ? module.slice(1, -1) : module;

                try {
                    cb(null, require(entrypoint.module_root + module));
                } catch (e) {
                    cb(e);
                }
            });
        }
    };
};
<commit_msg>put repeating strings in vars<commit_after>'use strict'

const LRU = require('lru-cache');
const cayley = require('cayley');
const exec = require('child_process').exec;
const array_stream = require('../array_stream');
const cache_options = {max: 500};
const vocab = 'http://schema.jillix.net/vocab/';
const type_predicate = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type';

module.exports = (entrypoint) => {

    entrypoint.module_root = entrypoint.base + '/node_modules/';

    const client = cayley(process.flow_env.db);
    const g = client.graph;

    return {
        cache: LRU(cache_options),
        read: (event_iri, args) => {

            let role = '*'
            if (args.session) {
                role = args.session.role || role;
            }

            let count = 0;
            const stream = array_stream();
            const array = [];

            // TODO stream API for node cayley
            const handler = (err, result) => {

                if (err) {
                    return stream.emit('error', err);
                }

                if (result && result.length) {
                    result.forEach(item => array.push([item.subject, item.predicate, item.id]));
                }

                if (++count === 3) {

                    if (!array.length) {
                        return stream.emit('error', new Error('Flow-nodejs.adapter.cayley.read: Empty result for "' + event_iri + '".'));
                    }

                    stream.set(array);
                }
            };

            // event
            g.V(event_iri).Tag('subject').Out([
              vocab + 'onError',
              vocab + 'onEnd',
              vocab + 'sequence',
            ], 'predicate').All(handler);

            // sequences
            g.V().Has(
              vocab + 'event',
              event_iri
            ).Has(
              type_predicate,
              vocab + 'Sequence'
            ).Tag('subject').Out([
              vocab + 'instance',
              vocab + 'args',
              vocab + 'dataHandler',
              vocab + 'onceHandler',
              vocab + 'streamHandler',
              vocab + 'emit',
              vocab + 'sequence'
            ], 'predicate').All(handler);

            // instances
            g.V().Has(
              vocab + 'event',
              event_iri
            ).Has(
              type_predicate,
              vocab + 'Sequence'
            ).Out(vocab + 'instance').
            Has(vocab + 'roles', '"' + role + '"').
            Tag('subject').Out([
                vocab + 'args',
                vocab + 'roles',
                vocab + 'module'
            ], 'predicate').All(handler);

            return stream;
        },

        mod: (module_iri, args, cb) => {
            g.V(module_iri).Out('http://schema.org/name').GetLimit(1, (err, module) => {

                if (err) {
                    return cb(err);
                }

                if (!module || !module[0] || !module[0].id) {
                    return cb(new Error('Flow-nodejs.adapter.cayley.mod: Empty respone for ' + module_iri));
                }

                module = module[0].id;
                module = module[0] === '"' ? module.slice(1, -1) : module;

                try {
                    cb(null, require(entrypoint.module_root + module));
                } catch (e) {
                    cb(e);
                }
            });
        }
    };
};
<|endoftext|>


<commit_before>var $ = require('jquery');
var _ = require('underscore');
var helpers = require('../helpers');
var underscored = require('underscore.string').underscored;

// Preload all templates from lib/apps/templates (using require-globify)
var templates = require('../templates/*.html.ejs', {mode: 'hash', resolve: ['reduce']});

/**
 * Find a template
 * @param {String} templateName Name of template load
 * @return {Function} template Template render function
 */
function getTemplate(templateName) {
  var name = underscored(templateName);
  if (!templates[name]) {
    templates[name] = _.template($('#' + templateName).html());
  }

  return templates[name];
}

/**
 * Find a template and render it with provided data
 * @param {String} templateName Name of template to render
 * @param {Object} [templateData] Data to make availabe to the template
 * @return {String} html tasty html
 */
function render(templateName, templateData) {
  templateData = templateData || {}; // templateData is optional
  // Get the template function, pass the provided data and extra helper functions
  return getTemplate(templateName)(_.defaults(templateData, helpers, {
    _: _, $: $, // make underscore and jquery available in the templates
    render: render // make this render function available in the template
  }));
}

module.exports.getTemplate = getTemplate;
module.exports.render = render;
<commit_msg>add comments<commit_after>var $ = require('jquery');
var _ = require('underscore');
var helpers = require('../helpers');
var underscored = require('underscore.string').underscored;

// Preload all templates from lib/apps/templates (using require-globify)
var templates = require('../templates/*.html.ejs', {mode: 'hash', resolve: ['reduce']});

/**
 * Find a template
 * @param {String} templateName Name of template load
 * @return {Function} template Template render function
 */
function getTemplate(templateName) {
  var name = underscored(templateName); // convert myTemplateName to my_template_name
  if (!templates[name]) {
    // Load templates from index.html if not preloaded
    templates[name] = _.template($('#' + templateName).html());
  }

  return templates[name];
}

/**
 * Find a template and render it with provided data
 * @param {String} templateName Name of template to render
 * @param {Object} [templateData] Data to make availabe to the template
 * @return {String} html tasty html
 */
function render(templateName, templateData) {
  templateData = templateData || {}; // templateData is optional
  // Get the template function, pass the provided data and extra helper functions
  return getTemplate(templateName)(_.defaults(templateData, helpers, {
    _: _, $: $, // make underscore and jquery available in the templates
    render: render // make this render function available in the template
  }));
}

module.exports.getTemplate = getTemplate;
module.exports.render = render;
<|endoftext|>


<commit_before>/** @module Provides bitwise arithmetic operations. */

/**
 * Converts given decimal to binary form.
 * @param{number} dec - Decimal number.
 * @returns{string}   - Binary representation.
 */
export function decTobin(dec) {
  return (dec >>> 0).toString(2);
};

/**
 * Converts given decimal to binary form.
 * @param{number} dec - Decimal number.
 * @returns{string}   - Binary representation.
 */
export function binToDec(bin) {
  parseInt(bin, 2);
};

/**
 * Measures the complexity of given binary or CSD expansion.
 * @param {string} number - Binary / CSD expansion of a number.
 * @returns {number}      - Complexity defined as the total number of non-zero bits in the given binary / csd expansion.
 */
export function complexity(number) {
  let counter = 0
  for(let i of number) {
    if(i !== '0')
      counter++;
  }
  // return number of non-zero bits
  return counter;
};

export default {
  decTobin,
  binToDec,
  complexity
};
<commit_msg>float support added to bitwise conversion methods<commit_after>/** @module Provides bitwise arithmetic operations. */

/**
 * Converts given decimal to binary form.
 * @param{number} dec  - Decimal number.
 * @param{number} bits - Number of result bits.
 * @returns{string}    - Binary representation.
 */
export function decTobin(dec, bits = 8) {
  // convert whole number part
  let number = parseInt(dec);
  let numberBin = (number >>> 0).toString(2);

  // convert fraction part
  let fraction = dec - number;
  let fractionBin = '';

  if(fraction > 0.0) {
    let i = 1;
    while(i < bits) {
      let outcome = fraction * 2;

      if(outcome == 1.0) {
        fractionBin += '1';
        break;
      }

      if(outcome > 1.0) {
        fractionBin += '1';
        // extract fraction part of the outcome
        fraction = outcome - parseInt(outcome);
      }
      else {
        fractionBin += '0';
        fraction = outcome;
      }
      i++;
    }
  }

  return numberBin + '.' + fractionBin;
};

/**
 * Converts given decimal to binary form.
 * @param{number} dec - Decimal number.
 * @returns{string}   - Binary representation.
 */
export function binToDec(bin) {
  let numberDec = parseInt(bin, 2);
  let fraction = (bin+'').split('.')[1];

  console.log(numberDec, fraction);

  let fractionDec = 0;
  if(fraction && fraction.length) {
    let i = -1;
    let f;
    for(f of fraction) {
      console.log
      fractionDec += f * Math.pow(2, i);
      i--;
    }
  }
  return numberDec + fractionDec;
};

/**
 * Measures the complexity of given binary or CSD expansion.
 * @param {string} number - Binary / CSD expansion of a number.
 * @returns {number}      - Complexity defined as the total number of non-zero bits in the given binary / csd expansion.
 */
export function complexity(number) {
  let counter = 0
  for(let i of number) {
    if(i !== '0')
      counter++;
  }
  // return number of non-zero bits
  return counter;
};

export default {
  decTobin,
  binToDec,
  complexity
};
<|endoftext|>


<commit_before>var _ = require('underscore'),
    templates = require('./templates'),
    toSrc = require('toSrc'),
    AbstractInstanceError = templates.AbstractInstanceError,
    ClassConstructor = templates.ClassConstructor,
    Code = templates.Code,
    FunctionRightHand = templates.FunctionRightHand,
    GetterFunction = templates.GetterFunction,
    ImplAbstractsLeftHand = templates.ImplAbstractsLeftHand,
    InitCall = templates.InitCall,
    InitConstructor = templates.InitConstructor,
    PropertiesLeftHand = templates.PropertiesLeftHand,
    SetterFunction = templates.SetterFunction,
    StaticsLeftHand = templates.StaticsLeftHand,
    StaticsRightHand = templates.StaticsRightHand,
    SuperConstructor = templates.SuperConstructor,
    SuperConstructorCall = templates.SuperConstructorCall,
    WrapperLeftHand = templates.WrapperLeftHand,
    WrapperSuperRightHand = templates.WrapperSuperRightHand;

/**
 *
Capitalizes the first letter. Used for camelCase-names for all setters and getters.

 *
 * @private
 * @param {String} string
 * @returns {String} string
 */
function capitalize(string) {
    return string.charAt(0).toUpperCase() + string.slice(1);
}

/**
 *
Modifies the key-string, so it looks like an ordinary setter.

 *
_someProperty becomes setSomeProperty

 *
 * @private
 * @param {String} key
 * @returns {String} key
 */
function setterKeyModificator(key) {
    return 'set' + capitalize(trimPrefix(key));
}

/**
 *
Modifies the key-string, so it looks like an ordinary getter.

 *
_someProperty becomes getSomeProperty

 *
 * @private
 * @param {String} key
 * @returns {String} key
 */
function getterKeyModificator(key) {
    return 'get' + capitalize(trimPrefix(key));
}

/**
 *
Trims all prefixes like _ __ ? $

 *
 * @private
 * @param {String} key
 * @returns {String} key
 */
function trimPrefix(key) {
    return key.replace(/^[_\?\$]_?/, '');
}

/**
 *
Returns a string that contains some JavaScript-assignments.

 *
 *
All properties of the given collection will be transformed to an assignment
 * using the given templates. Additionally you can pass a function that modifies
 * the key that are used in the assignment.

 *
 *
All keys contained in the blacklist-object are ignored.

 *
 *
Example:

 *

 * collection = {"name": "John Doe", "age": 27 }

 * blacklist = {"age": null}

 * leftHandTemplate = "this.<%= varName %>"

 * rightHandTemplate = "<%= varValue %>;"

 * leftHandKeyModificator = function(key) {return key.charAt(0);}

 * rightHandKeyModificator = function(key) {return key.charAt(0);}

 *

 * will result in:

 * "this.n=J;"
 *

 *
 * @private
 * @param {String} collection collection of key-value-pairs
 * @param {Function} leftHandTemplate a function from the template module
 * @param {Function} [rightHandTemplate] optional a function from the template module. If it's null, the value will be turned into source code
 * @param {Object} [blacklist={}] optional object with all keys that will be ignored
 * @param {Function} [leftHandKeyModificator] optional function to modify the key on the left side
 * @param {Function} [rightHandKeyModificator] optional function to modify the key on the right side
 * @returns {String} source code
 */
function getAssignment(
        collection,
        leftHandTemplate,
        rightHandTemplate,
        blacklist,
        leftHandKeyModificator,
        rightHandKeyModificator
    ) {

    var src = '',
        leftHandKey,
        rightHandKey;

    if(!blacklist) {
        blacklist = {};
    }
    if(!leftHandKeyModificator) {
        leftHandKeyModificator = _.identity;
    }
    if(!rightHandKeyModificator) {
        rightHandKeyModificator = _.identity;
    }
    _(collection).each(function eachProperty(value, key) {
        if(blacklist[key]) {
            return;
        }
        leftHandKey = leftHandKeyModificator(key);
        rightHandKey = rightHandKeyModificator(key);
        src += leftHandTemplate(leftHandKey) + '=';
        if(rightHandTemplate) {
            src += rightHandTemplate(rightHandKey);
        } else {
            src += toSrc(value);
        }
        src += ';';
    });

    return src;
}

/**
 *
Returns the source code for a class module

 *
 * @private
 * @param {String} This the result object after you've called collectProperties().
 *      If you pass a Super-object, the This-object should have the properties
 *      This.Overridden (by calling collect.collectOverriddenProperties) and
 *      This.ImplementedAbstracts (by calling collect.collectImplAbstracts)
 * @param {String} classFile the class file. necessary for error messages.
 * @param {String} [Super] optional an object containing all super properties, created via collectSuperProperties()
 * @returns {String} key
 */
function assembleStrings(This, Super) {
    var properties = '',
        implAbstracts = '',
        wrapper = '',
        exposeWrapper = '',
        statics = '',
        classConstructor = '',
        initCall = '',
        abstractInstanceError = '',
        superConstructor = '',
        superConstructorCall = '',
        initConstructor = '';

    // Creating the source code of the Properties-object.
    // The Properties-object contains copies from all properties of the original
    // Class-object. Additionally all functions are binded to this object.
    // Thus it is an independent instance and all changes occur only on this
    // object.
    properties += getAssignment(
            This.Private.Function,
            PropertiesLeftHand,
            FunctionRightHand
        )
        + getAssignment(
            This.Private.Other,
            PropertiesLeftHand
        )
        + getAssignment(
            This.Protected.Function,
            PropertiesLeftHand,
            FunctionRightHand
        )
        + getAssignment(
            This.Protected.Other,
            PropertiesLeftHand
        )
        + getAssignment(
            This.Public.Function,
            PropertiesLeftHand,
            FunctionRightHand
        )
        + getAssignment(
            This.Public.Other,
            PropertiesLeftHand
        );

    if(_(This.Abstract).size() > 0) { // Is this class abstract? In case of, we're adding an Error that is thrown when the class is instantiated.'
        abstractInstanceError = AbstractInstanceError(
            '\\"' + _(This.Abstract).keys().join('\\", \\"') + '\\"'
        );
    }

    if(This.Init) {
        initCall = InitCall(This.Init);
    }

    // The wrapper provides access only to public. Additionally all properties,
    // that are not functions are wrapped with getters and setters.
    wrapper += getAssignment(
            This.Public.Function,
            WrapperLeftHand,
            FunctionRightHand
        )
        + getAssignment(
            This.Public.Other,
            WrapperLeftHand,
            SetterFunction,
            null,
            setterKeyModificator
        )
        + getAssignment(
            This.Public.Other,
            WrapperLeftHand,
            GetterFunction,
            null,
            getterKeyModificator
        );

    // The expose wrapper is only applied if the exposeProtected flag is set.
    // It provides access to protected properties so a child class can use them.
    exposeWrapper += getAssignment(
            This.Protected.Function,
            WrapperLeftHand,
            FunctionRightHand,
            null,
            trimPrefix
        )
        + getAssignment(
            This.Protected.Other,
            WrapperLeftHand,
            SetterFunction,
            null,
            setterKeyModificator
        )
        + getAssignment(
            This.Protected.Other,
            WrapperLeftHand,
            GetterFunction,
            null,
            getterKeyModificator
        );

    // If we have a super class, than all super properties must be added to the
    // wrapper, too.
    if(Super) {
        wrapper += getAssignment(
                Super.Public.Function,
                WrapperLeftHand,
                WrapperSuperRightHand,
                This.Overridden
            )
            + getAssignment(
                Super.Public.Other,
                WrapperLeftHand,
                WrapperSuperRightHand,
                This.Overridden,
                setterKeyModificator,
                setterKeyModificator
            )
            + getAssignment(
                Super.Public.Other,
                WrapperLeftHand,
                WrapperSuperRightHand,
                This.Overridden,
                getterKeyModificator,
                getterKeyModificator
            );

        exposeWrapper += getAssignment(
                Super.Protected.Function,
                WrapperLeftHand,
                WrapperSuperRightHand,
                This.Overridden,
                trimPrefix,
                trimPrefix
            )
            + getAssignment(
                Super.Protected.Other,
                WrapperLeftHand,
                WrapperSuperRightHand,
                This.Overridden,
                setterKeyModificator,
                setterKeyModificator
            )
            + getAssignment(
                Super.Protected.Other,
                WrapperLeftHand,
                WrapperSuperRightHand,
                This.Overridden,
                getterKeyModificator,
                getterKeyModificator
            );

        initConstructor = InitConstructor();
        superConstructor = SuperConstructor();
        superConstructorCall = SuperConstructorCall();

        // All abstract functions that are implemented by a child class are
        // now added to the Properties-object so we can access them in this class
        implAbstracts = getAssignment(
            This.ImplementedAbstracts,
            ImplAbstractsLeftHand,
            FunctionRightHand
        );
    }

    // At last we're adding all static properties to the Class-object
    statics += getAssignment(
            This.Static.Function,
            StaticsLeftHand,
            StaticsRightHand,
            null,
            trimPrefix
        )
        + getAssignment(
            This.Static.Other,
            StaticsLeftHand,
            StaticsRightHand,
            null,
            trimPrefix
        );

    classConstructor = ClassConstructor(
        properties,
        wrapper,
        exposeWrapper,
        initCall,
        implAbstracts,
        abstractInstanceError,
        superConstructor,
        superConstructorCall
    );

    return Code(classConstructor, initConstructor, statics);
}

module.exports = assembleStrings;<commit_msg>fixed bug where you couldn't override automatic setters and getters<commit_after>var _ = require('underscore'),
    templates = require('./templates'),
    toSrc = require('toSrc'),
    AbstractInstanceError = templates.AbstractInstanceError,
    ClassConstructor = templates.ClassConstructor,
    Code = templates.Code,
    FunctionRightHand = templates.FunctionRightHand,
    GetterFunction = templates.GetterFunction,
    ImplAbstractsLeftHand = templates.ImplAbstractsLeftHand,
    InitCall = templates.InitCall,
    InitConstructor = templates.InitConstructor,
    PropertiesLeftHand = templates.PropertiesLeftHand,
    SetterFunction = templates.SetterFunction,
    StaticsLeftHand = templates.StaticsLeftHand,
    StaticsRightHand = templates.StaticsRightHand,
    SuperConstructor = templates.SuperConstructor,
    SuperConstructorCall = templates.SuperConstructorCall,
    WrapperLeftHand = templates.WrapperLeftHand,
    WrapperSuperRightHand = templates.WrapperSuperRightHand;

/**
 *
Capitalizes the first letter. Used for camelCase-names for all setters and getters.

 *
 * @private
 * @param {String} string
 * @returns {String} string
 */
function capitalize(string) {
    return string.charAt(0).toUpperCase() + string.slice(1);
}

/**
 *
Modifies the key-string, so it looks like an ordinary setter.

 *
_someProperty becomes setSomeProperty

 *
 * @private
 * @param {String} key
 * @returns {String} key
 */
function setterKeyModificator(key) {
    return 'set' + capitalize(trimPrefix(key));
}

/**
 *
Modifies the key-string, so it looks like an ordinary getter.

 *
_someProperty becomes getSomeProperty

 *
 * @private
 * @param {String} key
 * @returns {String} key
 */
function getterKeyModificator(key) {
    return 'get' + capitalize(trimPrefix(key));
}

/**
 *
Trims all prefixes like _ __ ? $

 *
 * @private
 * @param {String} key
 * @returns {String} key
 */
function trimPrefix(key) {
    return key.replace(/^[_\?\$]_?/, '');
}

/**
 *
Returns a string that contains some JavaScript-assignments.

 *
 *
All properties of the given collection will be transformed to an assignment
 * using the given templates. Additionally you can pass a function that modifies
 * the key that are used in the assignment.

 *
 *
All keys contained in the blacklist-object are ignored.

 *
 *
Example:

 *

 * collection = {"name": "John Doe", "age": 27 }

 * blacklist = {"age": null}

 * leftHandTemplate = "this.<%= varName %>"

 * rightHandTemplate = "<%= varValue %>;"

 * leftHandKeyModificator = function(key) {return key.charAt(0);}

 * rightHandKeyModificator = function(key) {return key.charAt(0);}

 *

 * will result in:

 * "this.n=J;"
 *

 *
 * @private
 * @param {String} collection collection of key-value-pairs
 * @param {Function} leftHandTemplate a function from the template module
 * @param {Function} [rightHandTemplate] optional a function from the template module. If it's null, the value will be turned into source code
 * @param {Object} [blacklist={}] optional object with all keys that will be ignored
 * @param {Function} [leftHandKeyModificator] optional function to modify the key on the left side
 * @param {Function} [rightHandKeyModificator] optional function to modify the key on the right side
 * @returns {String} source code
 */
function getAssignment(
        collection,
        leftHandTemplate,
        rightHandTemplate,
        blacklist,
        leftHandKeyModificator,
        rightHandKeyModificator
    ) {

    var src = '',
        leftHandKey,
        rightHandKey;

    if(!blacklist) {
        blacklist = {};
    }
    if(!leftHandKeyModificator) {
        leftHandKeyModificator = _.identity;
    }
    if(!rightHandKeyModificator) {
        rightHandKeyModificator = _.identity;
    }
    _(collection).each(function eachProperty(value, key) {
        if(blacklist[key]) {
            return;
        }
        leftHandKey = leftHandKeyModificator(key);
        rightHandKey = rightHandKeyModificator(key);
        src += leftHandTemplate(leftHandKey) + '=';
        if(rightHandTemplate) {
            src += rightHandTemplate(rightHandKey);
        } else {
            src += toSrc(value);
        }
        src += ';';
    });

    return src;
}

/**
 *
Returns the source code for a class module

 *
 * @private
 * @param {String} This the result object after you've called collectProperties().
 *      If you pass a Super-object, the This-object should have the properties
 *      This.Overridden (by calling collect.collectOverriddenProperties) and
 *      This.ImplementedAbstracts (by calling collect.collectImplAbstracts)
 * @param {String} classFile the class file. necessary for error messages.
 * @param {String} [Super] optional an object containing all super properties, created via collectSuperProperties()
 * @returns {String} key
 */
function assembleStrings(This, Super) {
    var properties = '',
        implAbstracts = '',
        wrapper = '',
        exposeWrapper = '',
        statics = '',
        classConstructor = '',
        initCall = '',
        abstractInstanceError = '',
        superConstructor = '',
        superConstructorCall = '',
        initConstructor = '';

    // Creating the source code of the Properties-object.
    // The Properties-object contains copies from all properties of the original
    // Class-object. Additionally all functions are binded to this object.
    // Thus it is an independent instance and all changes occur only on this
    // object.
    properties += getAssignment(
            This.Private.Function,
            PropertiesLeftHand,
            FunctionRightHand
        )
        + getAssignment(
            This.Private.Other,
            PropertiesLeftHand
        )
        + getAssignment(
            This.Protected.Function,
            PropertiesLeftHand,
            FunctionRightHand
        )
        + getAssignment(
            This.Protected.Other,
            PropertiesLeftHand
        )
        + getAssignment(
            This.Public.Function,
            PropertiesLeftHand,
            FunctionRightHand
        )
        + getAssignment(
            This.Public.Other,
            PropertiesLeftHand
        );

    if(_(This.Abstract).size() > 0) { // Is this class abstract? In case of, we're adding an Error that is thrown when the class is instantiated.'
        abstractInstanceError = AbstractInstanceError(
            '\\"' + _(This.Abstract).keys().join('\\", \\"') + '\\"'
        );
    }

    if(This.Init) {
        initCall = InitCall(This.Init);
    }

    // The wrapper provides access only to public. Additionally all properties,
    // that are not functions are wrapped with getters and setters.
    wrapper += getAssignment(
            This.Public.Other,
            WrapperLeftHand,
            SetterFunction,
            null,
            setterKeyModificator
        )
        + getAssignment(
            This.Public.Other,
            WrapperLeftHand,
            GetterFunction,
            null,
            getterKeyModificator
        )
        + getAssignment(
                This.Public.Function,
                WrapperLeftHand,
                FunctionRightHand
        );

    // The expose wrapper is only applied if the exposeProtected flag is set.
    // It provides access to protected properties so a child class can use them.
    exposeWrapper += getAssignment(
            This.Protected.Function,
            WrapperLeftHand,
            FunctionRightHand,
            null,
            trimPrefix
        )
        + getAssignment(
            This.Protected.Other,
            WrapperLeftHand,
            SetterFunction,
            null,
            setterKeyModificator
        )
        + getAssignment(
            This.Protected.Other,
            WrapperLeftHand,
            GetterFunction,
            null,
            getterKeyModificator
        );

    // If we have a super class, than all super properties must be added to the
    // wrapper, too.
    if(Super) {
        wrapper += getAssignment(
                Super.Public.Function,
                WrapperLeftHand,
                WrapperSuperRightHand,
                This.Overridden
            )
            + getAssignment(
                Super.Public.Other,
                WrapperLeftHand,
                WrapperSuperRightHand,
                This.Overridden,
                setterKeyModificator,
                setterKeyModificator
            )
            + getAssignment(
                Super.Public.Other,
                WrapperLeftHand,
                WrapperSuperRightHand,
                This.Overridden,
                getterKeyModificator,
                getterKeyModificator
            );

        exposeWrapper += getAssignment(
                Super.Protected.Function,
                WrapperLeftHand,
                WrapperSuperRightHand,
                This.Overridden,
                trimPrefix,
                trimPrefix
            )
            + getAssignment(
                Super.Protected.Other,
                WrapperLeftHand,
                WrapperSuperRightHand,
                This.Overridden,
                setterKeyModificator,
                setterKeyModificator
            )
            + getAssignment(
                Super.Protected.Other,
                WrapperLeftHand,
                WrapperSuperRightHand,
                This.Overridden,
                getterKeyModificator,
                getterKeyModificator
            );

        initConstructor = InitConstructor();
        superConstructor = SuperConstructor();
        superConstructorCall = SuperConstructorCall();

        // All abstract functions that are implemented by a child class are
        // now added to the Properties-object so we can access them in this class
        implAbstracts = getAssignment(
            This.ImplementedAbstracts,
            ImplAbstractsLeftHand,
            FunctionRightHand
        );
    }

    // At last we're adding all static properties to the Class-object
    statics += getAssignment(
            This.Static.Function,
            StaticsLeftHand,
            StaticsRightHand,
            null,
            trimPrefix
        )
        + getAssignment(
            This.Static.Other,
            StaticsLeftHand,
            StaticsRightHand,
            null,
            trimPrefix
        );

    classConstructor = ClassConstructor(
        properties,
        wrapper,
        exposeWrapper,
        initCall,
        implAbstracts,
        abstractInstanceError,
        superConstructor,
        superConstructorCall
    );

    return Code(classConstructor, initConstructor, statics);
}

module.exports = assembleStrings;<|endoftext|>


<commit_before>import { get, has, isEmpty } from 'lodash';

const getDraftRelations = (data, ctSchema, components) => {
  const getDraftRelationsCount = (data, schema) =>
    Object.keys(data).reduce((acc, current) => {
      const type = get(schema, ['schema', 'attributes', current, 'type'], 'string');
      const relationType = get(schema, ['schema', 'attributes', current, 'relationType'], '');
      const isMorph = relationType.toLowerCase().includes('morph');
      const oneWayTypes = ['oneWay', 'oneToOne', 'manyToOne'];
      const currentData = data[current];

      if (type === 'dynamiczone') {
        currentData.forEach(curr => {
          const compoSchema = get(components, curr.__component, {});

          acc += getDraftRelationsCount(curr, compoSchema);
        });
      }

      if (type === 'component') {
        const isRepeatable = get(schema, ['schema', 'attributes', current, 'repeatable'], false);
        const compoUID = get(schema, ['schema', 'attributes', current, 'component'], '');
        const compoSchema = get(components, compoUID, {});

        if (isRepeatable) {
          currentData.forEach(curr => {
            acc += getDraftRelationsCount(curr, compoSchema);
          });
        } else if (currentData !== null) {
          acc += getDraftRelationsCount(currentData, compoSchema);
        }
      }

      if (type === 'relation' && !isMorph) {
        if (oneWayTypes.includes(relationType)) {
          const hasDraftAndPublish = has(currentData, 'published_at');

          if (hasDraftAndPublish && isEmpty(currentData.published_at)) {
            acc += 1;
          }
        } else {
          currentData.forEach(value => {
            if (has(value, 'published_at') && isEmpty(value.published_at)) {
              acc += 1;
            }
          });
        }
      }

      return acc;
    }, 0);

  const count = getDraftRelationsCount(data, ctSchema, components);

  return count;
};

export default getDraftRelations;
<commit_msg>Fix util when no data (#8224)<commit_after>import { get, has, isEmpty, isNil } from 'lodash';

const getDraftRelations = (data, ctSchema, components) => {
  const getDraftRelationsCount = (data, schema) =>
    Object.keys(data).reduce((acc, current) => {
      const type = get(schema, ['schema', 'attributes', current, 'type'], 'string');
      const relationType = get(schema, ['schema', 'attributes', current, 'relationType'], '');
      const isMorph = relationType.toLowerCase().includes('morph');
      const oneWayTypes = ['oneWay', 'oneToOne', 'manyToOne'];
      const currentData = data[current];

      if (isNil(currentData)) {
        return acc;
      }

      if (type === 'dynamiczone') {
        currentData.forEach(curr => {
          const compoSchema = get(components, curr.__component, {});

          acc += getDraftRelationsCount(curr, compoSchema);
        });
      }

      if (type === 'component') {
        const isRepeatable = get(schema, ['schema', 'attributes', current, 'repeatable'], false);
        const compoUID = get(schema, ['schema', 'attributes', current, 'component'], '');
        const compoSchema = get(components, compoUID, {});

        if (isRepeatable) {
          currentData.forEach(curr => {
            acc += getDraftRelationsCount(curr, compoSchema);
          });
        } else {
          acc += getDraftRelationsCount(currentData, compoSchema);
        }
      }

      if (type === 'relation' && !isMorph) {
        if (oneWayTypes.includes(relationType)) {
          const hasDraftAndPublish = has(currentData, 'published_at');

          if (hasDraftAndPublish && isEmpty(currentData.published_at)) {
            acc += 1;
          }
        } else {
          currentData.forEach(value => {
            if (has(value, 'published_at') && isEmpty(value.published_at)) {
              acc += 1;
            }
          });
        }
      }

      return acc;
    }, 0);

  const count = getDraftRelationsCount(data, ctSchema, components);

  return count;
};

export default getDraftRelations;
<|endoftext|>


<commit_before>//array of supported players on domains
var isYoutube = ['youtube','youtu'];

//image URLs
var whiteSVG_Icon = safari.extension.baseURI + 'PiP_Toolbar_Icon_white.svg'
var blackSVG_Icon = safari.extension.baseURI + 'PiP_Toolbar_Icon.svg'

safari.self.addEventListener("message", messageHandler); // Message recieved from Swift code
window.onfocus = checkForVideo // Tab selected
new MutationObserver(checkForVideo).observe(document, {subtree: true, childList: true}); // DOM changed

function dispatchMessage(messageName) {
	safari.extension.dispatchMessage(messageName);
}

function messageHandler(event) {
    if (event.name === "enablePiP" && getVideo() != null) {
        getVideo().webkitSetPresentationMode('picture-in-picture');
    }
    else if (event.name === "addCustomPiPButtons"){
        checkForCustomPiPButtonSupport();
    }
}

function checkForVideo() {
	if (getVideo() != null) {
		console.log("Found a video");
		shouldCustomPiPButtonsBeAdded();
		dispatchMessage("videoFound");
	} else if (window == window.top) {
		console.log("Found no video on top");
		dispatchMessage("noVideoFound");
	}
}

function getVideo() {
	return document.getElementsByTagName('video')[0];
}

//----------------- Custom Button Methods -----------------

function shouldCustomPiPButtonsBeAdded(){
    dispatchMessage("shouldCustomPiPButtonsBeAdded");
}

function checkForCustomPiPButtonSupport(){
    //add custom eventListener for youtube
    if (isYoutube.map(function(obj){return location.hostname.match(obj) != null;}).indexOf(true) >= 0){
        addYouTubeVideoButton();
    }
    //check for other players
    //TODO: add other players here
}

//----------------- Player Implementations -------------------------
function addYouTubeVideoButton() {
    var video = document.getElementsByTagName('video')[0];

    if (video != null && document.getElementsByClassName('PiPifierButton').length == 0) {
        var button = document.createElement("button");
        button.className = "ytp-button PiPifierButton";
        button.title = "PiP (by PiPifier)";
        button.onclick = function(){document.getElementsByTagName('video')[0].webkitSetPresentationMode('picture-in-picture');};
        //TODO add style
        //button.style.backgroundImage = 'url('+ whiteSVG_Icon + ')';

        var buttonImage = document.createElement("img");
        buttonImage.src = whiteSVG_Icon;
        buttonImage.width = 22;
        buttonImage.height = 36;
        button.appendChild(buttonImage);

        document.getElementsByClassName("ytp-right-controls")[0].appendChild(button);
    }
}
<commit_msg>Disabled PiP for iframes<commit_after>//array of supported players on domains
var isYoutube = ['youtube','youtu'];

//image URLs
var whiteSVG_Icon = safari.extension.baseURI + 'PiP_Toolbar_Icon_white.svg'
var blackSVG_Icon = safari.extension.baseURI + 'PiP_Toolbar_Icon.svg'

safari.self.addEventListener("message", messageHandler); // Message recieved from Swift code
window.onfocus = checkForVideo // Tab selected
new MutationObserver(checkForVideo).observe(document, {subtree: true, childList: true}); // DOM changed

function dispatchMessage(messageName) {
	safari.extension.dispatchMessage(messageName);
}

function messageHandler(event) {
    if (event.name === "enablePiP" && getVideo() != null) {
        getVideo().webkitSetPresentationMode('picture-in-picture');
    }
    else if (event.name === "addCustomPiPButtons"){
        checkForCustomPiPButtonSupport();
    }
}

function checkForVideo() {
	if (window != window.top) return;
	if (getVideo() != null) {
		console.log("Found a video");
		shouldCustomPiPButtonsBeAdded();
		dispatchMessage("videoFound");
	} else {
		console.log("Found no video on top");
		dispatchMessage("noVideoFound");
	}
}

function getVideo() {
	return document.getElementsByTagName('video')[0];
}

//----------------- Custom Button Methods -----------------

function shouldCustomPiPButtonsBeAdded(){
    dispatchMessage("shouldCustomPiPButtonsBeAdded");
}

function checkForCustomPiPButtonSupport(){
    //add custom eventListener for youtube
    if (isYoutube.map(function(obj){return location.hostname.match(obj) != null;}).indexOf(true) >= 0){
        addYouTubeVideoButton();
    }
    //check for other players
    //TODO: add other players here
}

//----------------- Player Implementations -------------------------
function addYouTubeVideoButton() {
    var video = document.getElementsByTagName('video')[0];

    if (video != null && document.getElementsByClassName('PiPifierButton').length == 0) {
        var button = document.createElement("button");
        button.className = "ytp-button PiPifierButton";
        button.title = "PiP (by PiPifier)";
        button.onclick = function(){document.getElementsByTagName('video')[0].webkitSetPresentationMode('picture-in-picture');};
        //TODO add style
        //button.style.backgroundImage = 'url('+ whiteSVG_Icon + ')';

        var buttonImage = document.createElement("img");
        buttonImage.src = whiteSVG_Icon;
        buttonImage.width = 22;
        buttonImage.height = 36;
        button.appendChild(buttonImage);

        document.getElementsByClassName("ytp-right-controls")[0].appendChild(button);
    }
}
<|endoftext|>


<commit_before>// ==UserScript==
// @name         Pogdesign-Widgets
// @namespace    https://github.com/fabiencrassat
// @version      1.3.4
// @description  Add links relative to the episode
// @author       Fabien Crassat <fabien@crassat.com>
// @match        https://www.pogdesign.co.uk/cat/
// @match        http://www.pogdesign.co.uk/cat/
// @include      /^https:\/\/www\.pogdesign\.co\.uk\/cat\/\d{1,}-\d{4}/
// @include      /^https:\/\/www\.pogdesign\.co\.uk\/cat\/day\/\d{1,}-\d{1,}-\d{4}/
// @include      /^https:\/\/www\.pogdesign\.co\.uk\/cat\/\w+(-*\w+)*\/Season-\d+\/Episode-\d+/
// @include      /^https:\/\/www\.pogdesign\.co\.uk\/cat\/\w+(-*\w+)*-summary/
// @require      https://greasyfork.org/scripts/35624-pogdesign-widgets-js/code/Pogdesign-Widgetsjs.js?version=271629
// @grant        none
// @run-at       document-start
// ==/UserScript==

/*global $, fabiencrassat */
"use strict";

var page = function() {
    var externalLinks = fabiencrassat.view.externalLinks;
    var controller = fabiencrassat.main.controller;
    var shared = fabiencrassat.main.shared;

    var page = {
        calendar: {
            stylesheets() {
                return `
                span.fcr-episodeContainer > :last-child {
                    float: right;
                }
                span.fcr-episodeContainer > :first-child {
                    float: left;
                }
                .ep.infochecked .fcr-externalLink-image {
                    filter: contrast(0);
                }
                .fcr-externalLink-image {
                    height: 12px;
                    width: 12px;
                    background-image: url('` + shared.linkImage + `');
                }`;
            },
            extractTitle(element) {
                return element.parent().prev().text();
            },
            extractSeasonAndEpisode(element) {
                return element.prev().text();
            },
            displayExternalLinksPopup(element) {
                var popup = externalLinks.create(element, "fcr-calendar-page", "block");
                element.parent().parent().parent().after(popup);
            },
            isInLocationPage() {
                /* The regex is the same than the @include in the header */
                return controller.isInLocationPage(/^https:\/\/www\.pogdesign\.co\.uk\/cat\/($|\d{1,}-\d{4})/g);
            },
            insertExternalLink(element) {
                $(element).wrap("");
                $("span.fcr-episodeContainer > :last-child").after(shared.externalImageLink());
            }
        },
        day: {
            stylesheets() {
                return `
                .overbox h4 a {
                    width: 35%;
                    padding-right: 0;
                    margin-right: 25%;
                }
                span.fcr-episodeContainer {
                    padding-top: 24px !important;
                    padding-left: 30px !important;
                    float: left !important;
                    width: 36px !important;
                }
                .fcr-externalLink-image {
                    height: 12px;
                    width: 12px !important;
                    padding: 0 !important;
                    background-image: url('` + shared.linkImage + `');
                }
                .fcr-external-links-popup #poptext > span > a {
                    color: #66bbff;
                }`;
            },
            extractTitle(element) {
                return element.parent().prev().text();
            },
            extractSeasonAndEpisode(element) {
                var seasonAndEpisode = element.parent().next().text();
                var regex = /^Season (\d{1,}), Episode (\d{1,})/g;
                return {
                    season: seasonAndEpisode.replace(regex, "$1"),
                    episode: seasonAndEpisode.replace(regex, "$2")
                };
            },
            displayExternalLinksPopup(element) {
                page.summary.displayExternalLinksPopup(element);
            },
            isInLocationPage() {
                /* The regex is the same than the @include in the header */
                return controller.isInLocationPage(/^https:\/\/www\.pogdesign\.co\.uk\/cat\/day\/\d{1,}-\d{1,}-\d{4}/g);
            },
            insertExternalLink(element) {
                $("").insertAfter(element);
                $(shared.externalImageLink()).appendTo("span.fcr-episodeContainer");
            }
        },
        summary: {
            stylesheets() {
                return `
                span.fcr-episodeContainer {
                    display: flex;
                }
                .fcr-externalLink-image {
                    height: 12px !important;
                    width: 12px !important;
                    filter: contrast(0);
                    margin: 9px -12px 9px 54px;
                    background-image: url('` + shared.linkImage + `');
                }
                .ep.infochecked .fcr-externalLink-image {
                    filter: contrast(0.4);
                }
                .fcr-external-links-popup #pop {
                    padding: 1px;
                    font-size: initial;
                    letter-spacing: initial;
                    line-height: 1.5;
                    border: 1px solid #000;
                    border-radius: 10px;
                    box-shadow: 0px 0px 21px rgba(0, 0, 0, 0.5);
                    text-shadow: 1px 1px 0 #000;
                    background-color: rgba(38, 38, 38, 0.9);
                    opacity: .95;
                }
                .fcr-external-links-popup #popheader {
                    background-color: rgba(0, 0, 0, 0.3);
                    color: #fff;
                    border-radius: 9px 9px 0 0;
                }
                .fcr-external-links-popup #poptext > span > a {
                    color: #66bbff;
                }
                .fcr-external-links-popup #popfooter {
                    background-color: rgba(0, 0, 0, 0.3);
                    color: #FF9326;
                    border-radius: 0 0 9px 9px;
                }`;
            },
            extractTitle() {
                return $("h2.sumhead > a").text();
            },
            extractSeasonAndEpisode(element) {
                var seasonAndEpisodeElement = element.parent().parent().parent();
                return {
                    season: seasonAndEpisodeElement.find("[itemprop=seasonNumber]").text(),
                    episode: seasonAndEpisodeElement.find("[itemprop=episodeNumber]").text()
                };
            },
            displayExternalLinksPopup(element) {
                var top = element.offset().top + 20;
                var left = element.offset().left - 200;
                var popup = externalLinks.create(element, "fcr-external-links-popup", "block", top, left);
                $("body > div:last").after(popup);
            },
            isInLocationPage() {
                /* The regex is the same than the @include in the header */
                return controller.isInLocationPage(/^https:\/\/www\.pogdesign\.co\.uk\/cat\/\w+(-*\w+)*-summary/g);
            },
            insertExternalLink(element) {
                $(element).wrap("");
                $(shared.externalImageLink()).appendTo("span.fcr-episodeContainer");
            }
        },
        episode: {
            stylesheets() {
                return page.summary.stylesheets();
            },
            extractTitle() {
                return $(".furtherinfo a:first").text();
            },
            extractSeasonAndEpisode() {
                return $("h3.sdfsdf").children().first().text();
            },
            displayExternalLinksPopup(element) {
                var popup = externalLinks.create(element, "fcr-external-links-popup", "inline-flex");
                element.after(popup);
            },
            isInLocationPage() {
                /* The regex is the same than the @include in the header */
                return controller.isInLocationPage(/^https:\/\/www\.pogdesign\.co\.uk\/cat\/\w+(-*\w+)*\/Season-\d+\/Episode-\d+/g);
            },
            insertExternalLink(element) {
                $(" " + shared.externalTextLink() + "").appendTo(element);
            }
        }
    };

    return {
        calendar: page.calendar,
        day: page.day,
        summary: page.summary,
        episode: page.episode
    };
};

var script = document.createElement("script");
script.appendChild(document.createTextNode("var fabiencrassat = fabiencrassat || {}; fabiencrassat.page = ("+ page +")();"));
(document.body || document.head || document.documentElement).appendChild(script);

window.addEventListener("load", function() {
    // Add search episode links for calendar pages
    fabiencrassat.main.controller.addExternalLink(fabiencrassat.page.calendar, "#month_box p > :last-child");
    // Add search episode links for day pages
    fabiencrassat.main.controller.addExternalLink(fabiencrassat.page.day, ".overbox > h4 > a");
    // Add search episode links for summary page
    fabiencrassat.main.controller.addExternalLink(fabiencrassat.page.summary, "li.ep > strong > a");
    // Add search episode links for episode page
    fabiencrassat.main.controller.addExternalLink(fabiencrassat.page.episode, "h3.sdfsdf");
    // no page found
}, false);
<commit_msg>v1.3.5<commit_after>// ==UserScript==
// @name         Pogdesign-Widgets
// @namespace    https://github.com/fabiencrassat
// @version      1.3.5
// @description  Add links relative to the episode
// @author       Fabien Crassat <fabien@crassat.com>
// @match        https://www.pogdesign.co.uk/cat/
// @match        http://www.pogdesign.co.uk/cat/
// @include      /^https:\/\/www\.pogdesign\.co\.uk\/cat\/\d{1,}-\d{4}/
// @include      /^https:\/\/www\.pogdesign\.co\.uk\/cat\/day\/\d{1,}-\d{1,}-\d{4}/
// @include      /^https:\/\/www\.pogdesign\.co\.uk\/cat\/\w+(-*\w+)*\/Season-\d+\/Episode-\d+/
// @include      /^https:\/\/www\.pogdesign\.co\.uk\/cat\/\w+(-*\w+)*-summary/
// @require      https://greasyfork.org/scripts/35624-pogdesign-widgets-js/code/Pogdesign-Widgetsjs.js?version=608231
// @grant        none
// @run-at       document-start
// ==/UserScript==

/*global $, fabiencrassat */
"use strict";

var page = function() {
    var externalLinks = fabiencrassat.view.externalLinks;
    var controller = fabiencrassat.main.controller;
    var shared = fabiencrassat.main.shared;

    var page = {
        calendar: {
            stylesheets() {
                return `
                span.fcr-episodeContainer > :last-child {
                    float: right;
                }
                span.fcr-episodeContainer > :first-child {
                    float: left;
                }
                .ep.infochecked .fcr-externalLink-image {
                    filter: contrast(0);
                }
                .fcr-externalLink-image {
                    height: 12px;
                    width: 12px;
                    background-image: url('` + shared.linkImage + `');
                }`;
            },
            extractTitle(element) {
                return element.parent().prev().text();
            },
            extractSeasonAndEpisode(element) {
                return element.prev().text();
            },
            displayExternalLinksPopup(element) {
                var popup = externalLinks.create(element, "fcr-calendar-page", "block");
                element.parent().parent().parent().after(popup);
            },
            isInLocationPage() {
                /* The regex is the same than the @include in the header */
                return controller.isInLocationPage(/^https:\/\/www\.pogdesign\.co\.uk\/cat\/($|\d{1,}-\d{4})/g);
            },
            insertExternalLink(element) {
                $(element).wrap("");
                $("span.fcr-episodeContainer > :last-child").after(shared.externalImageLink());
            }
        },
        day: {
            stylesheets() {
                return `
                .overbox h4 a {
                    width: 35%;
                    padding-right: 0;
                    margin-right: 25%;
                }
                span.fcr-episodeContainer {
                    padding-top: 24px !important;
                    padding-left: 30px !important;
                    float: left !important;
                    width: 36px !important;
                }
                .fcr-externalLink-image {
                    height: 12px;
                    width: 12px !important;
                    padding: 0 !important;
                    background-image: url('` + shared.linkImage + `');
                }
                .fcr-external-links-popup #poptext > span > a {
                    color: #66bbff;
                }`;
            },
            extractTitle(element) {
                return element.parent().prev().text();
            },
            extractSeasonAndEpisode(element) {
                var seasonAndEpisode = element.parent().next().text();
                var regex = /^Season (\d{1,}), Episode (\d{1,})/g;
                return {
                    season: seasonAndEpisode.replace(regex, "$1"),
                    episode: seasonAndEpisode.replace(regex, "$2")
                };
            },
            displayExternalLinksPopup(element) {
                page.summary.displayExternalLinksPopup(element);
            },
            isInLocationPage() {
                /* The regex is the same than the @include in the header */
                return controller.isInLocationPage(/^https:\/\/www\.pogdesign\.co\.uk\/cat\/day\/\d{1,}-\d{1,}-\d{4}/g);
            },
            insertExternalLink(element) {
                $("").insertAfter(element);
                $(shared.externalImageLink()).appendTo("span.fcr-episodeContainer");
            }
        },
        summary: {
            stylesheets() {
                return `
                span.fcr-episodeContainer {
                    display: flex;
                }
                .fcr-externalLink-image {
                    height: 12px !important;
                    width: 12px !important;
                    filter: contrast(0);
                    margin: 9px -12px 9px 54px;
                    background-image: url('` + shared.linkImage + `');
                }
                .ep.infochecked .fcr-externalLink-image {
                    filter: contrast(0.4);
                }
                .fcr-external-links-popup #pop {
                    padding: 1px;
                    font-size: initial;
                    letter-spacing: initial;
                    line-height: 1.5;
                    border: 1px solid #000;
                    border-radius: 10px;
                    box-shadow: 0px 0px 21px rgba(0, 0, 0, 0.5);
                    text-shadow: 1px 1px 0 #000;
                    background-color: rgba(38, 38, 38, 0.9);
                    opacity: .95;
                }
                .fcr-external-links-popup #popheader {
                    background-color: rgba(0, 0, 0, 0.3);
                    color: #fff;
                    border-radius: 9px 9px 0 0;
                }
                .fcr-external-links-popup #poptext > span > a {
                    color: #66bbff;
                }
                .fcr-external-links-popup #popfooter {
                    background-color: rgba(0, 0, 0, 0.3);
                    color: #FF9326;
                    border-radius: 0 0 9px 9px;
                }`;
            },
            extractTitle() {
                return $("h2.sumhead > a").text();
            },
            extractSeasonAndEpisode(element) {
                var seasonAndEpisodeElement = element.parent().parent().parent();
                return {
                    season: seasonAndEpisodeElement.find("[itemprop=seasonNumber]").text(),
                    episode: seasonAndEpisodeElement.find("[itemprop=episodeNumber]").text()
                };
            },
            displayExternalLinksPopup(element) {
                var top = element.offset().top + 20;
                var left = element.offset().left - 200;
                var popup = externalLinks.create(element, "fcr-external-links-popup", "block", top, left);
                $("body > div:last").after(popup);
            },
            isInLocationPage() {
                /* The regex is the same than the @include in the header */
                return controller.isInLocationPage(/^https:\/\/www\.pogdesign\.co\.uk\/cat\/\w+(-*\w+)*-summary/g);
            },
            insertExternalLink(element) {
                $(element).wrap("");
                $(shared.externalImageLink()).appendTo("span.fcr-episodeContainer");
            }
        },
        episode: {
            stylesheets() {
                return page.summary.stylesheets();
            },
            extractTitle() {
                return $(".furtherinfo a:first").text();
            },
            extractSeasonAndEpisode() {
                return $("h3.sdfsdf").children().first().text();
            },
            displayExternalLinksPopup(element) {
                var popup = externalLinks.create(element, "fcr-external-links-popup", "inline-flex");
                element.after(popup);
            },
            isInLocationPage() {
                /* The regex is the same than the @include in the header */
                return controller.isInLocationPage(/^https:\/\/www\.pogdesign\.co\.uk\/cat\/\w+(-*\w+)*\/Season-\d+\/Episode-\d+/g);
            },
            insertExternalLink(element) {
                $(" " + shared.externalTextLink() + "").appendTo(element);
            }
        }
    };

    return {
        calendar: page.calendar,
        day: page.day,
        summary: page.summary,
        episode: page.episode
    };
};

var script = document.createElement("script");
script.appendChild(document.createTextNode("var fabiencrassat = fabiencrassat || {}; fabiencrassat.page = ("+ page +")();"));
(document.body || document.head || document.documentElement).appendChild(script);

window.addEventListener("load", function() {
    // Add search episode links for calendar pages
    fabiencrassat.main.controller.addExternalLink(fabiencrassat.page.calendar, "#month_box p > :last-child");
    // Add search episode links for day pages
    fabiencrassat.main.controller.addExternalLink(fabiencrassat.page.day, ".overbox > h4 > a");
    // Add search episode links for summary page
    fabiencrassat.main.controller.addExternalLink(fabiencrassat.page.summary, "li.ep > strong > a");
    // Add search episode links for episode page
    fabiencrassat.main.controller.addExternalLink(fabiencrassat.page.episode, "h3.sdfsdf");
    // no page found
}, false);
<|endoftext|>