<commit_before>(function(){

    'use strict';

    // Works like Object.defineProperties
    const define = (obj, desc) => {
        for (const prop in desc)
            Object.defineProperty(obj, prop, desc[prop]);
    };

    // Create descriptor
    const describe = (value, writable = false, enumerable = false, configurable = false) => ({
        value, writable, enumerable, configurable
    });

    class VideoMaster {

        constructor(config){

            define(this, {
                state: describe({
                    inited: false,
                    sized: false,
                    resized: false,
                    playing: false,
                    ended: false,
                    lastTime: 0,
                    animationFrame: null
                }),
                config: describe({
                    container: null,
                    src: null,
                    loop: false,
                    delay: 0,
                    audio: true,
                    volume: 1,
                    useCanvas: false,
                    resetOnEnded: false,
                    trigger: 'click',
                    canPause: true,
                    objectFit: 'cover',
                    controls: true,
                    onended: function(){},
                    keyboard: true,
                    keyboardFactor: 5
                }),
                ctx: describe(null, true),
                element: describe(null, true),
                video: describe(null, true),
                canvas: describe(null, true),
                width: describe(0, true),
                height: describe(0, true)
            });

            // Use custom config
            for (const key in config){
                this.config[key] = config[key];
            }

            try {

                let err = [];

                const error = string => {
                    err.push(string)
                };
                const checkType = pair => {
                    for (const key in pair)
                        if (typeof this.config[key] !== pair[key])
                            error(`Invalid "${key}" value. Only ${pair[key]} accepted.`);
                };

                this.element =
                    typeof this.config.container === 'string'
                        ? document.querySelector(this.config.container)
                        : this.config.container;

                if (!this.element)
                    error('Container is not set or not found.');
                else if (Object.getPrototypeOf(this.element.constructor) !== HTMLElement)
                    error('Container is not a DOM Element.');

                if (!this.config.src)
                    error('Video source is not set.');
                else if (typeof this.config.src !== 'string')
                    error('Video source must be a string.');

                checkType({
                    loop: 'boolean',
                    delay: 'number',
                    audio: 'boolean',
                    volume: 'number',
                    useCanvas: 'boolean',
                    resetOnEnded: 'boolean',
                    trigger: 'string',
                    canPause: 'boolean',
                    objectFit: 'string',
                    controls: 'boolean',
                    onended: 'function',
                    keyboard: 'boolean',
                    keyboardFactor: 'number'
                });

                if (err.length)
                    throw err;

            } catch(err){
                for (const msg of err)
                    console.error(msg);
                return;
            }

            // Force canvas on iOS device
            const isiOS = /iphone|ipad|ipod/i.test(window.navigator.userAgent);
            this.config.useCanvas = isiOS || this.config.useCanvas;

            // Force this.element overflow and position style
            this.element.style.overflow = 'hidden';
            if (window.getComputedStyle(this.element).position === 'static')
                this.element.style.position = 'relative';

            // Creates video element
            const videoName = `${this.element.id ? `${this.element.id}-` : ''}VideoMaster`;
            const videoFormat = this.config.src.split('.').pop();

            this.video = document.createElement('video');
            this.video.setAttribute('id', videoName);
            this.video.style.position = 'absolute';
            this.video.innerHTML = `<source src="${this.config.src}" type="video/${videoFormat}">`;
            this.element.appendChild(this.video);

            // Creates canvas element if needed
            // In some system (i.e. iOS), this will not trigger system default video playing behaviour (i.e. fullscreen)
            if (this.config.useCanvas){
                // Canvas element to play frames
                const canvasName = `${videoName}-canvas`;
                this.canvas = document.createElement('canvas');
                this.canvas.setAttribute('id', canvasName);
                this.canvas.style.position = 'absolute';
                this.element.appendChild(this.canvas);

                // Audio element to play sound
                this.canvas.audio = document.createElement('audio');
                this.canvas.audio.innerHTML = this.video.innerHTML;
                this.element.insertBefore(this.canvas.audio, this.video);

                this.canvas.audio.load();
                this.ctx = this.canvas.getContext('2d');

                // To play frames
                this.video.addEventListener('timeupdate', this.drawFrame.bind(this));
                this.video.addEventListener('canplay', this.drawFrame.bind(this));
            }

            this.volume = this.config.volume;

            this.video.addEventListener('loadedmetadata', onMetaLoaded.bind(this));
            this.video.addEventListener('ended', onVideoEnded.bind(this));
            this.video.addEventListener('ended', this.config.onended.bind(this));
            this.element.addEventListener(this.config.trigger, this.init.bind(this));
            window.addEventListener('resize', this.updateSize.bind(this));

            if (this.config.keyboard === true)
                document.body.addEventListener('keydown', onKeyPress.bind(this));

            this.video.load();

            function onMetaLoaded(){
                this.updateSize();
            }

            function onVideoEnded(){
                this.state.playing = false;
                this.state.ended = true;

                if (this.config.loop === true){
                    this.goTo(0);
                    this.play();
                } else {
                    this.state.playing = false;
                    if (this.config.resetOnEnded === true)
                        this.goTo(0);
                }
            }

            function onKeyPress(e){
                if (e.which === 32)
                    this.togglePlay();
                else if (e.which === 37)
                    this.goTo(this.currentTime + this.config.keyboardFactor);
                else if (e.which === 39)
                    this.goTo(this.currentTime - this.config.keyboardFactor);
            }

        }

        init(e){
            if (!this.state.sized)
                this.updateSize();

            if (this.config.canPause === true && this.state.inited){
                this.togglePlay();
                return;
            }

            if (this.config.useCanvas)
                this.video.style.display = 'none';

            this.state.inited = true;
            this.play();
        }

        updateSize(){
            if (this.video.videoHeight === 0){
                this.state.resized = true;
                return;
            }

            let rw, rh, rt, rl, scale, t, l;
            const cw = this.element.clientWidth,
                  ch = this.element.clientHeight,
                  vw = this.video.videoWidth,
                  vh = this.video.videoHeight;

            let [adjustLeft, adjustTop] = [false, false];

            this.width = cw;
            this.height =
                this.config.objectFit !== 'cover'
                ? vh*(cw/vw)
                : ch;

            this.video.setAttribute('width', this.width);
            this.video.setAttribute('height', this.height);
            if (this.config.useCanvas){
                this.canvas.setAttribute('width', this.width);
                this.canvas.setAttribute('height', this.height);
            }

            if (this.config.objectFit === 'cover'){

                scale = cw/vw;
                if (vh*scale < ch){
                    scale = ch/vh;
                    rw = vw*scale;
                    rh = ch;
                    t = 0;
                    adjustLeft = true;
                } else {
                    rw = cw;
                    rh = vh*scale;
                    l = 0;
                    adjustTop = true;
                }

            } else if (this.config.objectFit === 'contain'){

                scale = cw/vw;
                if (vh*scale > ch){
                    scale = ch/vh;
                    rw = vw*scale;
                    rh = ch;
                    t = 0;
                    adjustLeft = true;
                } else {
                    rw = cw;
                    rh = vh*scale;
                    l = 0;
                    adjustTop = true;
                }

            }

            if (adjustTop)
                t = (ch - rh)/2;

            if (adjustLeft)
                l = (cw - rw)/2;

            if (!this.config.useCanvas)
                setSize.call(this, this.video);
            else {
                setSize.call(this, this.canvas);
                this.drawFrame();
                // Hide video element because it is not needed in layout anymore
                this.video.style.display = 'none';
            }

            this.state.sized = true;

            function setSize(element){
                element.style.top = t + 'px';
                element.style.left = l + 'px';
                if (this.config.objectFit === 'cover'){
                    element.style.width = rw + 'px';
                    element.style.height = rh + 'px';
                }
            }
        }

        play(){
            this.state.playing = true;

            if (!this.state.sized)
                this.updateSize();

            if (this.state.ended){
                this.state.ended = false;
                this.goTo(0);
            }

            if (!this.config.useCanvas){

                this.video.play();
                if (this.config.audio === false)
                    this.video.muted = true;

            } else {

                this.state.lastTime = Date.now();
                this.roll();
                this.canvas.audio.play();
                if (this.config.audio === false)
                    this.canvas.audio.muted = true;

            }
        }

        pause(){
            if (this.config.canPause === false) return;

            this.state.playing = false;

            if (!this.config.useCanvas)
                this.video.pause();
            else
                this.canvas.audio.pause();
        }

        togglePlay(){
            if (!this.state.playing)
                this.play();
            else
                this.pause();
        }

        goTo(second){
            this.video.currentTime = second;
            if (this.config.useCanvas)
                this.sync();
        }

        // Roll as in roll the frames like a movie film
        roll(){
            const time = Date.now(),
                  elapsed = (time - this.state.lastTime)/1000;

            // Move video frame forward
            if (elapsed >= (1/30)){
                this.video.currentTime += elapsed;
                this.state.lastTime = time;

                // Sync audio with current video frame
                if (
                    this.canvas.audio &&
                    Math.abs(this.canvas.audio.currentTime - this.video.currentTime) > 0.3
                )
                    this.sync();
            }

            // Loop this method to imitate video play
            if (this.state.playing)
                this.state.animationFrame = window.requestAnimationFrame(this.roll.bind(this));
            else
                window.cancelAnimationFrame(this.state.animationFrame);
        }

        sync(){
            this.canvas.audio.currentTime = this.video.currentTime;
        }

        drawFrame(){
            if (parseInt(this.width) === 0)
                this.updateSize();

            // Draw the current frame onto canvas
            this.ctx.drawImage(this.video, 0, 0, this.width, this.height);
        }

        // To imitate event listener binding, so you can call these methods to the instance instead of the object
        addEventListener(){
            const elem = this.config.useCanvas ? this.canvas : this.video;
            elem.addEventListener.apply(elem, arguments);
        }

        // Same reason as above
        removeEventListener(){
            const elem = this.config.useCanvas ? this.canvas : this.video;
            elem.removeEventListener.apply(elem, arguments);
        }

        // Just to be convenient to jQuery or other library users
        on(){
            this.addEventListener.apply(this, arguments);
        }

        // Same reason as above
        off(){
            this.removeEventListener.apply(this, arguments);
        }

        get volume(){
            return this.config.useCanvas ? this.canvas.audio.volume : this.video.volume;
        }

        set volume(vol){
            vol = parseFloat(vol);

            if (isNaN(vol) || vol > 1 || vol < 0)
                return console.error('Volume must be a number between 0 to 1');

            if (this.config.useCanvas)
                this.canvas.audio.volume = vol;
            else
                this.video.volume = vol;
        }

        get currentTime(){
            return this.video.currentTime;
        }

        set currentTime(second){
            this.goTo(second);
        }

        get paused(){
            return !this.state.playing;
        }

        get duration(){
            return this.video.duration;
        }

    }

    window.VideoMaster = VideoMaster;

})();<commit_msg>Code cleanup and fixed keyboard shortcut bugs<commit_after>(function(){

    'use strict';

    // Works like Object.defineProperties
    const define = (obj, desc) => {
        for (const prop in desc)
            Object.defineProperty(obj, prop, desc[prop]);
    };

    // Create descriptor
    const describe = (value, writable = false, enumerable = false, configurable = false) => ({
        value, writable, enumerable, configurable
    });

    class VideoMaster {

        constructor(config){

            define(this, {
                state: describe({
                    inited: false,
                    sized: false,
                    resized: false,
                    playing: false,
                    ended: false,
                    lastTime: 0,
                    animationFrame: null
                }),
                config: describe({
                    container: null,
                    src: null,
                    loop: false,
                    delay: 0,
                    audio: true,
                    volume: 1,
                    useCanvas: false,
                    resetOnEnded: false,
                    trigger: 'click',
                    canPause: true,
                    objectFit: 'cover',
                    controls: true,
                    onended: function(){},
                    keyboard: true,
                    keyboardFactor: 5
                }),
                ctx: describe(null, true),
                element: describe(null, true),
                video: describe(null, true),
                canvas: describe(null, true),
                width: describe(0, true),
                height: describe(0, true)
            });

            // Use custom config
            for (const key in config){
                this.config[key] = config[key];
            }

            try {

                let err = [];

                const error = string => {
                    err.push(string)
                };
                const checkType = pair => {
                    for (const key in pair)
                        if (typeof this.config[key] !== pair[key])
                            error(`Invalid "${key}" value. Only ${pair[key]} accepted.`);
                };

                this.element =
                    typeof this.config.container === 'string'
                        ? document.querySelector(this.config.container)
                        : this.config.container;

                if (!this.element)
                    error('Container is not set or not found.');
                else if (Object.getPrototypeOf(this.element.constructor) !== HTMLElement)
                    error('Container is not a DOM Element.');

                if (!this.config.src)
                    error('Video source is not set.');
                else if (typeof this.config.src !== 'string')
                    error('Video source must be a string.');

                checkType({
                    loop: 'boolean',
                    delay: 'number',
                    audio: 'boolean',
                    volume: 'number',
                    useCanvas: 'boolean',
                    resetOnEnded: 'boolean',
                    trigger: 'string',
                    canPause: 'boolean',
                    objectFit: 'string',
                    controls: 'boolean',
                    onended: 'function',
                    keyboard: 'boolean',
                    keyboardFactor: 'number'
                });

                if (err.length)
                    throw err;

            } catch(err){
                for (const msg of err)
                    console.error(msg);
                return;
            }

            // Force canvas on iOS device
            const isiOS = /iphone|ipad|ipod/i.test(window.navigator.userAgent);
            this.config.useCanvas = isiOS || this.config.useCanvas;

            // Force this.element overflow and position style
            this.element.style.overflow = 'hidden';
            if (window.getComputedStyle(this.element).position === 'static')
                this.element.style.position = 'relative';

            // Creates video element
            const videoName = `${this.element.id ? `${this.element.id}-` : ''}VideoMaster`;
            const videoFormat = this.config.src.split('.').pop();

            this.video = document.createElement('video');
            this.video.setAttribute('id', videoName);
            this.video.style.position = 'absolute';
            this.video.innerHTML = `<source src="${this.config.src}" type="video/${videoFormat}">`;
            this.element.appendChild(this.video);

            // Creates canvas element if needed
            // In some system (i.e. iOS), this will not trigger system default video playing behaviour (i.e. fullscreen)
            if (this.config.useCanvas){
                // Canvas element to play frames
                const canvasName = `${videoName}-canvas`;
                this.canvas = document.createElement('canvas');
                this.canvas.setAttribute('id', canvasName);
                this.canvas.style.position = 'absolute';
                this.element.appendChild(this.canvas);

                // Audio element to play sound
                this.canvas.audio = document.createElement('audio');
                this.canvas.audio.innerHTML = this.video.innerHTML;
                this.element.insertBefore(this.canvas.audio, this.video);

                this.canvas.audio.load();
                this.ctx = this.canvas.getContext('2d');

                // To play frames
                this.video.addEventListener('timeupdate', this.drawFrame.bind(this));
                this.video.addEventListener('canplay', this.drawFrame.bind(this));
            }

            this.volume = this.config.volume;

            this.video.addEventListener('loadedmetadata', onMetaLoaded.bind(this));
            this.video.addEventListener('ended', onVideoEnded.bind(this));
            this.video.addEventListener('ended', this.config.onended.bind(this));
            this.element.addEventListener(this.config.trigger, this.init.bind(this));
            window.addEventListener('resize', this.updateSize.bind(this));

            if (this.config.keyboard === true)
                document.body.addEventListener('keydown', onKeyPress.bind(this));

            this.video.load();

            function onMetaLoaded(){
                this.updateSize();
            }

            function onVideoEnded(){
                this.state.playing = false;
                this.state.ended = true;

                if (this.config.loop === true){
                    // Do not replay video if it is paused and progress is controlled by keyboard
                    if (this.state.playing !== true) return;
                    this.goTo(0);
                    this.play();
                } else {
                    this.state.playing = false;
                    if (this.config.resetOnEnded === true)
                        this.goTo(0);
                }
            }

            function onKeyPress(e){
                // Keyboard cannot control video before video is triggered.
                if (this.state.inited !== true) return;

                if (e.which === 32)
                    this.togglePlay();
                else if (e.which === 37)
                    this.goTo(this.currentTime - this.config.keyboardFactor);
                else if (e.which === 39)
                    this.goTo(this.currentTime + this.config.keyboardFactor);
            }

        }

        init(e){
            if (!this.state.sized)
                this.updateSize();

            if (this.config.canPause === true && this.state.inited){
                this.togglePlay();
                return;
            }

            if (this.config.useCanvas)
                this.video.style.display = 'none';

            this.state.inited = true;
            this.play();
        }

        updateSize(){
            if (this.video.videoHeight === 0){
                this.state.resized = true;
                return;
            }

            let rw, rh, rt, rl, scale, t, l;
            const cw = this.element.clientWidth,
                  ch = this.element.clientHeight,
                  vw = this.video.videoWidth,
                  vh = this.video.videoHeight;

            let [adjustLeft, adjustTop] = [false, false];

            this.width = cw;
            this.height =
                this.config.objectFit !== 'cover'
                ? vh*(cw/vw)
                : ch;

            this.video.setAttribute('width', this.width);
            this.video.setAttribute('height', this.height);
            if (this.config.useCanvas){
                this.canvas.setAttribute('width', this.width);
                this.canvas.setAttribute('height', this.height);
            }

            if (this.config.objectFit === 'cover'){

                scale = cw/vw;
                if (vh*scale < ch){
                    scale = ch/vh;
                    rw = vw*scale;
                    rh = ch;
                    t = 0;
                    adjustLeft = true;
                } else {
                    rw = cw;
                    rh = vh*scale;
                    l = 0;
                    adjustTop = true;
                }

            } else if (this.config.objectFit === 'contain'){

                scale = cw/vw;
                if (vh*scale > ch){
                    scale = ch/vh;
                    rw = vw*scale;
                    rh = ch;
                    t = 0;
                    adjustLeft = true;
                } else {
                    rw = cw;
                    rh = vh*scale;
                    l = 0;
                    adjustTop = true;
                }

            }

            if (adjustTop)
                t = (ch - rh)/2;

            if (adjustLeft)
                l = (cw - rw)/2;

            if (!this.config.useCanvas)
                setSize.call(this, this.video);
            else {
                setSize.call(this, this.canvas);
                this.drawFrame();
                // Hide video element because it is not needed in layout anymore
                this.video.style.display = 'none';
            }

            this.state.sized = true;

            function setSize(element){
                element.style.top = t + 'px';
                element.style.left = l + 'px';
                if (this.config.objectFit === 'cover'){
                    element.style.width = rw + 'px';
                    element.style.height = rh + 'px';
                }
            }
        }

        play(){
            this.state.playing = true;

            if (!this.state.sized)
                this.updateSize();

            if (this.state.ended){
                this.state.ended = false;
                this.goTo(0);
            }

            if (!this.config.useCanvas){

                this.video.play();
                if (this.config.audio === false)
                    this.video.muted = true;

            } else {

                this.state.lastTime = Date.now();
                this.roll();
                this.canvas.audio.play();
                if (this.config.audio === false)
                    this.canvas.audio.muted = true;

            }
        }

        pause(){
            if (this.config.canPause === false) return;

            this.state.playing = false;

            if (!this.config.useCanvas)
                this.video.pause();
            else
                this.canvas.audio.pause();
        }

        togglePlay(){
            if (!this.state.playing)
                this.play();
            else
                this.pause();
        }

        goTo(second){
            this.video.currentTime = second;
            if (this.config.useCanvas)
                this.sync();
        }

        // Roll as in roll the frames like a movie film
        roll(){
            const time = Date.now(),
                  elapsed = (time - this.state.lastTime)/1000;

            // Move video frame forward
            if (elapsed >= (1/30)){
                this.video.currentTime += elapsed;
                this.state.lastTime = time;

                // Sync audio with current video frame
                if (
                    this.canvas.audio &&
                    Math.abs(this.canvas.audio.currentTime - this.video.currentTime) > 0.3
                )
                    this.sync();
            }

            // Loop this method to imitate video play
            if (this.state.playing)
                this.state.animationFrame = window.requestAnimationFrame(this.roll.bind(this));
            else
                window.cancelAnimationFrame(this.state.animationFrame);
        }

        sync(){
            this.canvas.audio.currentTime = this.video.currentTime;
        }

        drawFrame(){
            // Draw the current frame onto canvas
            this.ctx.drawImage(this.video, 0, 0, this.width, this.height);
        }

        // To imitate event listener binding, so you can call these methods to the instance instead of the object
        addEventListener(){
            const elem = this.config.useCanvas ? this.canvas : this.video;
            elem.addEventListener.apply(elem, arguments);
        }

        // Same reason as above
        removeEventListener(){
            const elem = this.config.useCanvas ? this.canvas : this.video;
            elem.removeEventListener.apply(elem, arguments);
        }

        // Just to be convenient to jQuery or other library users
        on(){
            this.addEventListener.apply(this, arguments);
        }

        // Same reason as above
        off(){
            this.removeEventListener.apply(this, arguments);
        }

        get volume(){
            return this.config.useCanvas ? this.canvas.audio.volume : this.video.volume;
        }

        set volume(vol){
            vol = parseFloat(vol);

            if (isNaN(vol) || vol > 1 || vol < 0)
                return console.error('Volume must be a number between 0 to 1');

            if (this.config.useCanvas)
                this.canvas.audio.volume = vol;
            else
                this.video.volume = vol;
        }

        get currentTime(){
            return this.video.currentTime;
        }

        set currentTime(second){
            this.goTo(second);
        }

        get paused(){
            return !this.state.playing;
        }

        get duration(){
            return this.video.duration;
        }

    }

    window.VideoMaster = VideoMaster;

})();<|endoftext|>


<commit_before>import {escapeText} from "../../common"
export class ModNavigator {
    constructor(editor) {
        editor.mod.navigator = this
        this.editor = editor
        this.navigatorEl = document.querySelector('#navigator')
        this.listeners = {}
        this.render()
        this.bindEvents()
    }
    render(){
        this.navigatorEl.innerHTML = this.getNavigatorTemplate()
    }
    bindEvents(){
        this.listeners.onclick = event => this.onclick(event)
        document.addEventListener('click', this.listeners.onclick)
    }
    onclick(event){
        const target = event.target
        event.preventDefault()
        event.stopImmediatePropagation()
        if(target.matches('#navigator-button')){
            document.querySelector('#navigator-list').innerHTML = this.populateNavigator() || ""   //Populating the list
            if( target.firstElementChild.firstElementChild.classList.contains('rotate')){
                this.closeNavigator()
            }else{
                this.openNavigator()
            }
        }else if(target.matches('.fa-angle-right')){
            document.querySelector('#navigator-list').innerHTML = this.populateNavigator() || ""    //Populating the list
            if( target.classList.contains('rotate')){
                this.closeNavigator()
            }else{
                this.openNavigator()
            }
        }else if(target.matches('a')){
                let id = target.getAttribute('href').slice(1)
                document.getElementById(id).scrollIntoView({behavior:"smooth"})
        }else {
            this.closeNavigator()
        }
    }

    openNavigator(){
        document.getElementById('navigator-button').firstElementChild.firstElementChild.classList.add('rotate')
        document.getElementById('navigator').style.left = "0px"
    }
    closeNavigator(){
        document.getElementById('navigator-button').firstElementChild.firstElementChild.classList.remove('rotate')
        document.getElementById('navigator').style.left = "-265px"
    }
    populateNavigator(){
        let items = []
        this.editor.view.state.doc.descendants((node) => {
            if (node.attrs && node.attrs.hidden) {
                return false
            } else if (node.type.groups.includes('heading')) {
                items.push({id: node.attrs.id, textContent: node.textContent, type: node.type})
            }
        })
        if(items.length){
            return this.navigatorHTML(items)
        } else{
            return false
        }
    }
    navigatorHTML(items) {
        return `
        ${
            items.map(
                item => {
                    const level = item.type.name.substr(-1)
                    return `<h${level}><a href="#${item.id}">${escapeText(item.textContent)}</a></h${level}>`
                }
            ).join('')
        }`
    }
    getNavigatorTemplate(){
        return `

${gettext('Document Navigator')}

                `
    }

}

<commit_msg>fix spaces<commit_after>import {escapeText} from "../../common"
export class ModNavigator {
    constructor(editor) {
        editor.mod.navigator = this
        this.editor = editor
        this.navigatorEl = document.querySelector('#navigator')
        this.listeners = {}
        this.render()
        this.bindEvents()
    }
    render(){
        this.navigatorEl.innerHTML = this.getNavigatorTemplate()
    }
    bindEvents(){
        this.listeners.onclick = event => this.onclick(event)
        document.addEventListener('click', this.listeners.onclick)
    }
    onclick(event){
        const target = event.target
        event.preventDefault()
        event.stopImmediatePropagation()
        if (target.matches('#navigator-button')){
            document.querySelector('#navigator-list').innerHTML = this.populateNavigator() || ""   //Populating the list
            if (target.firstElementChild.firstElementChild.classList.contains('rotate')){
                this.closeNavigator()
            } else {
                this.openNavigator()
            }
        } else if (target.matches('.fa-angle-right')){
            document.querySelector('#navigator-list').innerHTML = this.populateNavigator() || ""    //Populating the list
            if (target.classList.contains('rotate')){
                this.closeNavigator()
            } else {
                this.openNavigator()
            }
        } else if (target.matches('a')){
                let id = target.getAttribute('href').slice(1)
                document.getElementById(id).scrollIntoView({behavior:"smooth"})
        } else {
            this.closeNavigator()
        }
    }

    openNavigator(){
        document.getElementById('navigator-button').firstElementChild.firstElementChild.classList.add('rotate')
        document.getElementById('navigator').style.left = "0px"
    }
    closeNavigator(){
        document.getElementById('navigator-button').firstElementChild.firstElementChild.classList.remove('rotate')
        document.getElementById('navigator').style.left = "-265px"
    }
    populateNavigator(){
        let items = []
        this.editor.view.state.doc.descendants((node) => {
            if (node.attrs && node.attrs.hidden) {
                return false
            } else if (node.type.groups.includes('heading')) {
                items.push({id: node.attrs.id, textContent: node.textContent, type: node.type})
            }
        })
        if (items.length){
            return this.navigatorHTML(items)
        } else {
            return false
        }
    }
    navigatorHTML(items) {
        return `
        ${
            items.map(
                item => {
                    const level = item.type.name.substr(-1)
                    return `<h${level}><a href="#${item.id}">${escapeText(item.textContent)}</a></h${level}>`
                }
            ).join('')
        }`
    }
    getNavigatorTemplate(){
        return `

${gettext('Document Navigator')}

                `
    }

}

<|endoftext|>


<commit_before>import { Observable } from 'rxjs';
import { ActionsObservable } from 'redux-observable';
import Hapi from 'hapi';
import Cookie from 'tough-cookie';
import TestUtils from 'react-addons-test-utils';
import {
	MOCK_MEANINGLESS_ACTION,
	MOCK_APP_STATE
} from './mocks/app';

export const findComponentsWithType = (tree, typeString) =>
	TestUtils.findAllInRenderedTree(
		tree,
		(component) => component && component.constructor.name === typeString
	);

export const createFakeStore = fakeData => ({
	getState() {
		return fakeData;
	},
	dispatch() {},
	subscribe() {},
});

export const middlewareDispatcher = middleware => (storeData, action) => {
	let dispatched = null;
	const dispatch = middleware(createFakeStore(storeData))(actionAttempt => dispatched = actionAttempt);
	dispatch(action);
	return dispatched;
};

export const parseCookieHeader = cookieHeader => {
	const cookies = (cookieHeader instanceof Array) ?
		cookieHeader.map(Cookie.parse) :
		[Cookie.parse(cookieHeader)];

	return cookies.reduce(
		(acc, cookie) => ({ ...acc, [cookie.key]: cookie.value }),
		{}
	);

};

export const getServer = connection => {
	const server = new Hapi.Server();
	server.connection(connection);

	// mock the anonAuthPlugin
	server.decorate(
		'request',
		'authorize',
		request => () => Observable.of(request),
		{ apply: true }
	);
	return server;
};

export const epicIgnoreAction = (epic, action=MOCK_MEANINGLESS_ACTION, store=createFakeStore(MOCK_APP_STATE)) => () => {
	const spyable = {
		notCalled: () => {}
	};
	spyOn(spyable, 'notCalled');
	const action$ = ActionsObservable.of(action);
	return epic(action$, store)
		.do(spyable.notCalled, null, expect(spyable.notCalled).not.toHaveBeenCalled())
		.toPromise();
};
<commit_msg>routeRenderer<commit_after>import React from 'react';
import { Observable } from 'rxjs';
import { ActionsObservable } from 'redux-observable';
import Hapi from 'hapi';
import Cookie from 'tough-cookie';
import TestUtils from 'react-addons-test-utils';
import RouterContext from 'react-router/lib/RouterContext';
import match from 'react-router/lib/match';
import { IntlProvider } from 'react-intl';
import { Provider } from 'react-redux';
import {
	MOCK_MEANINGLESS_ACTION,
	MOCK_APP_STATE
} from './mocks/app';

export const findComponentsWithType = (tree, typeString) =>
	TestUtils.findAllInRenderedTree(
		tree,
		(component) => component && component.constructor.name === typeString
	);

export const createFakeStore = fakeData => ({
	getState() {
		return fakeData;
	},
	dispatch() {},
	subscribe() {},
});

export const middlewareDispatcher = middleware => (storeData, action) => {
	let dispatched = null;
	const dispatch = middleware(createFakeStore(storeData))(actionAttempt => dispatched = actionAttempt);
	dispatch(action);
	return dispatched;
};

export const parseCookieHeader = cookieHeader => {
	const cookies = (cookieHeader instanceof Array) ?
		cookieHeader.map(Cookie.parse) :
		[Cookie.parse(cookieHeader)];

	return cookies.reduce(
		(acc, cookie) => ({ ...acc, [cookie.key]: cookie.value }),
		{}
	);

};

export const getServer = connection => {
	const server = new Hapi.Server();
	server.connection(connection);

	// mock the anonAuthPlugin
	server.decorate(
		'request',
		'authorize',
		request => () => Observable.of(request),
		{ apply: true }
	);
	return server;
};

export const epicIgnoreAction = (epic, action=MOCK_MEANINGLESS_ACTION, store=createFakeStore(MOCK_APP_STATE)) => () => {
	const spyable = {
		notCalled: () => {}
	};
	spyOn(spyable, 'notCalled');
	const action$ = ActionsObservable.of(action);
	return epic(action$, store)
		.do(spyable.notCalled, null, expect(spyable.notCalled).not.toHaveBeenCalled())
		.toPromise();
};

/**
 * Curry a function that takes a set of React Router routes and a location to
 * render, and return a Promise that resolves with the rendered React app
 *
 * @example
 * ```
 * const renderLocation = routeRenderer(routes);
 * renderLocation('/').then(app => ...);
 * renderLocation('/foo').then(app => ...);
 * ```
 */
export const routeRenderer = routes => {
	const FAKE_STORE = createFakeStore(MOCK_APP_STATE);
	return location =>
		new Promise((resolve, reject) => {
			match({ location, routes }, (err, redirectLocation, renderProps) => {
				const app = TestUtils.renderIntoDocument(
					<IntlProvider locale='en'>
						<Provider store={FAKE_STORE}>
							<RouterContext {...renderProps} />
						</Provider>
					</IntlProvider>
				);
				resolve(app);
			});
		});
};

<|endoftext|>


<commit_before>// adding Modernizr svgasimg method to check if an svg could be used inside img tag
Modernizr.addTest('svgasimg', document.implementation.hasFeature('http://www.w3.org/TR/SVG11/feature#Image', '1.1'));

$(document).ready(function(){

	// validating svg image
	// validate_document_img();

	// a bit of color
	var ciakObj = ciakWrapper;
	ciakObj.preActions();
	ciakObj.doAnimationEasy();
});

function validate_document_img() {
	// function to use .svg or .png image (depending on browser support)

	// if (!Modernizr.svgasimg) {
		$(".check_image").each(function(index) {
			var old_src_path;
			var new_src_path;
			old_src_path = $(this).attr("src");
			new_src_path = old_src_path.replace(".svg", ".png");
			$(this).attr("src", new_src_path);
		});
	// }

	return true;
}

var ciakWrapper = {

	_animationType: false,

	animationTypeName : {
		none_animation : "noneAnimation",
		simple_animation : "simpleAnimation",
		advanced_animation : "advancedAnimation"
	},

	doAnimationEasy : function() {
		this.detectAnimationType();
		this.animate();
	},

	preActions : function() {
		// $(".form_container").css("visibility", "hidden");
		// $(".old_browser_container").remove();
	},

	postActions : function() {
		$(".code_input").focus();
	},

	animateViaCssClass : function(className, animationName, duration, delay, nIteration, callback) {
		// method to animate an element by class name

		$(className).addClass('animated');

		// animation details
		$(className).addClass(animationName);
		$(className).css('animation-duration', duration);
		$(className).css('animation-delay', delay);
		$(className).css('animation-iteration-count', nIteration);

		if (callback) {
			$(className).one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function(param){
				callback();
			});
		}

		return true;
	},

	detectAnimationType : function() {
		// method to recognise animation type (simple or advanced)
		// TODO
		// debug only
		// if cool browser and no code via GET
		// than -> advanced_animation
		// else -> simple_animation
		this.setAnimationType(this.animationTypeName.simple_animation);
		// XXX ok this.setAnimationType(this.animationTypeName.advanced_animation);
	},

	setAnimationType : function(animationType) {
		if (animationType) {
			if (this.animationTypeName.none_animation == animationType) {
				this._animationType = this.animationTypeName.none_animation;
			} else if (this.animationTypeName.simple_animation == animationType) {
				this._animationType = this.animationTypeName.simple_animation;
			} else if (this.animationTypeName.advanced_animation == animationType) {
				this._animationType = this.animationTypeName.advanced_animation;
			}
		}
	},

	getAnimationType : function() {
		return this._animationType;
	},

	animate : function() {

		if (this.getAnimationType()) {
			eval("this." + this.getAnimationType() +"()");
		}
	},

	// eval functions {{{
	noneAnimation : function() {
		console.log("implement this!");
	},

	simpleAnimation : function() {
		// method to start simple animation
		console.log("implement this!");
		// scrolling universe to code form
		var scrollingObj = scrollingWrapper;
		scrollingObj.doScrollingEasy(scrollingObj.scrollTypeName.scrolling3, 500);
	},

	advancedAnimation : function() {
		// method to start advanced animation

		ciakWrapper.animateViaCssClass(".logo1AnimationAction", "bounceInDown", "3s", "1s", "1");
		$(".logo1AnimationAction").removeClass("transparent");

		$(".logo1AnimationAction").one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function(param){

			// adding body no_overflow_x class
			$("body").addClass("no_overflow_x");
			// $("html").addClass("no_overflow_x");

			// entpy logo tada
			$(".logo1AnimationAction").removeClass("bounceInDown");
			ciakWrapper.animateViaCssClass(".logo1AnimationAction", "tada", "2s", "1s", "1");

			$(".logo1AnimationAction").one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function(param){

				// entpy logo out
				$(".logo1AnimationAction").removeClass("tada");
				ciakWrapper.animateViaCssClass(".logo1AnimationAction", "lightSpeedOut", "0.8s", "1s", "1");

				// scrolling universe to the city
				var scrollingObj = scrollingWrapper;
				scrollingObj.doScrollingEasy(scrollingObj.scrollTypeName.scrolling1, 2500);
			});
		});

		return true;
	},
	// eval functions }}}
};

var scrollingWrapper = {

	_scrollType : false,

	scrollTypeName : {
		scrolling1 : "scrolling1",
		scrolling2 : "scrolling2",
		scrolling3 : "scrolling3"
	},

	scrollingDelay : false,

	doScrollingEasy : function(scrollName, delay) {
		this.scrollingDelay = delay;
		this.setScrollType(scrollName);
		this.scrollScene();
	},

	setScrollType : function(scrollName) {
		if (scrollName) {
			if (this.scrollTypeName.scrolling1 == scrollName) {
				this._scrollType = this.scrollTypeName.scrolling1;
			} else if (this.scrollTypeName.scrolling2 == scrollName) {
				this._scrollType = this.scrollTypeName.scrolling2;
			} else if (this.scrollTypeName.scrolling3 == scrollName) {
				this._scrollType = this.scrollTypeName.scrolling3;
			}
		}
	},

	getScrollType : function() { return this._scrollType; },

	scrollScene : function() {
		if (this.getScrollType()) {
			// scrolling delay
			setTimeout('scrollingWrapper.scrollDelay();', this.scrollingDelay);
		}
	},

	scrollDelay : function() {
		// must be safe
		eval("this." + this.getScrollType() + "()");
		return true;
	},

	// eval functions {{{
	scrolling1 : function() {
		// function to scroll at page bottom and than to entpy logo

		$.scrollTo('.scroll_to_bottom', 5500, { axis:'y', easing : 'easeInOutQuart', onAfter : function(){
				// ...at the end of bottom scrolling, return to logo pt2 animation
				var scrollingObj = scrollingWrapper;
				scrollingObj.doScrollingEasy(scrollingObj.scrollTypeName.scrolling2, 1000);
			}
		});

		return true;
	},

	scrolling2 : function() {
		// function to scroll directly to entpy logo
		$.scrollTo('.scroll_to_element1', 5000, { axis:'y', easing : 'easeInOutQuart', onAfter : function(){
				ciakWrapper.animateViaCssClass(".logoBottomTextAction", "fadeIn", "1.5s", "0s", "1");
				ciakWrapper.animateViaCssClass(".logo2AnimationAction", "lightSpeedIn", "1s", "2.8s", "1");
				ciakWrapper.animateViaCssClass(".form_container", "fadeIn", "3s", "4.5s", "1");

				// exec actions post animation
				ciakWrapper.postActions();
			}
		});
	},

	scrolling3 : function() {
		// function to scroll directly to entpy logo
		$.scrollTo('.scroll_to_element1', 2000, { axis:'y', easing : 'easeInOutQuart', onAfter : function(){
				/*$(".logoBottomTextAction").removeClass("transparent");
				$(".logo2AnimationAction").removeClass("transparent");
				$(".form_container").removeClass("transparent");*/
				ciakWrapper.animateViaCssClass(".logoBottomTextAction", "fadeIn", "1s", "0s", "1");
				ciakWrapper.animateViaCssClass(".logo2AnimationAction", "fadeIn", "1s", "0s", "1");
				ciakWrapper.animateViaCssClass(".form_container", "fadeIn", "1s", "0s", "1");

				// exec actions post animation
				ciakWrapper.postActions();
			}
		});
	}
	// eval functions }}}
};
<commit_msg>working on css and cross browser<commit_after>// adding Modernizr svgasimg method to check if an svg could be used inside img tag
Modernizr.addTest('svgasimg', document.implementation.hasFeature('http://www.w3.org/TR/SVG11/feature#Image', '1.1'));

$(document).ready(function(){

	// validating svg image
	// validate_document_img();

	// a bit of color
	var ciakObj = ciakWrapper;
	ciakObj.preActions();
	ciakObj.doAnimationEasy();
});

function validate_document_img() {
	// function to use .svg or .png image (depending on browser support)

	// if (!Modernizr.svgasimg) {
		$(".check_image").each(function(index) {
			var old_src_path;
			var new_src_path;
			old_src_path = $(this).attr("src");
			new_src_path = old_src_path.replace(".svg", ".png");
			$(this).attr("src", new_src_path);
		});
	// }

	return true;
}

var ciakWrapper = {

	_animationType: false,

	animationTypeName : {
		none_animation : "noneAnimation",
		simple_animation : "simpleAnimation",
		advanced_animation : "advancedAnimation"
	},

	doAnimationEasy : function() {
		this.detectAnimationType();
		this.animate();
	},

	preActions : function() {
		// $(".form_container").css("visibility", "hidden");
		// $(".old_browser_container").remove();
	},

	postActions : function() {
		$(".code_input").focus();
	},

	animateViaCssClass : function(className, animationName, duration, delay, nIteration, callback) {
		// method to animate an element by class name

		$(className).addClass('animated');

		// animation details
		$(className).addClass(animationName);
		$(className).css('animation-duration', duration);
		$(className).css('animation-delay', delay);
		$(className).css('animation-iteration-count', nIteration);

		if (callback) {
			$(className).one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function(param){
				callback();
			});
		}

		return true;
	},

	detectAnimationType : function() {
		// method to recognise animation type (simple or advanced)
		// TODO
		// debug only
		// if cool browser and no code via GET
		// than -> advanced_animation
		// else -> simple_animation
		this.setAnimationType(this.animationTypeName.simple_animation);
		// XXX ok this.setAnimationType(this.animationTypeName.advanced_animation);
		/*
			Come decidere il tipo di animazione
			===================================

			lato server:
				se si arriva in questa pagina con il codice via GET (a seguito della lettura del QRCode)
				se si arriva in per la seconda volta
				----------
				inserire un tag HTML come questo

1
 -> per forzare l'animazione semplice

			lato client:
				se il browser è obsoleto (e cioè??)
		*/
	},

	setAnimationType : function(animationType) {
		if (animationType) {
			if (this.animationTypeName.none_animation == animationType) {
				this._animationType = this.animationTypeName.none_animation;
			} else if (this.animationTypeName.simple_animation == animationType) {
				this._animationType = this.animationTypeName.simple_animation;
			} else if (this.animationTypeName.advanced_animation == animationType) {
				this._animationType = this.animationTypeName.advanced_animation;
			}
		}
	},

	getAnimationType : function() {
		return this._animationType;
	},

	animate : function() {

		if (this.getAnimationType()) {
			eval("this." + this.getAnimationType() +"()");
		}
	},

	// eval functions {{{
	noneAnimation : function() {
		console.log("implement this!");
	},

	simpleAnimation : function() {
		// method to start simple animation
		console.log("implement this!");
		// scrolling universe to code form
		var scrollingObj = scrollingWrapper;
		scrollingObj.doScrollingEasy(scrollingObj.scrollTypeName.scrolling3, 500);
	},

	advancedAnimation : function() {
		// method to start advanced animation

		ciakWrapper.animateViaCssClass(".logo1AnimationAction", "bounceInDown", "3s", "1s", "1");
		$(".logo1AnimationAction").removeClass("transparent");

		$(".logo1AnimationAction").one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function(param){

			// adding body no_overflow_x class
			$("body").addClass("no_overflow_x");
			// $("html").addClass("no_overflow_x");

			// entpy logo tada
			$(".logo1AnimationAction").removeClass("bounceInDown");
			ciakWrapper.animateViaCssClass(".logo1AnimationAction", "tada", "2s", "1s", "1");

			$(".logo1AnimationAction").one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function(param){

				// entpy logo out
				$(".logo1AnimationAction").removeClass("tada");
				ciakWrapper.animateViaCssClass(".logo1AnimationAction", "lightSpeedOut", "0.8s", "1s", "1");

				// scrolling universe to the city
				var scrollingObj = scrollingWrapper;
				scrollingObj.doScrollingEasy(scrollingObj.scrollTypeName.scrolling1, 2500);
			});
		});

		return true;
	},
	// eval functions }}}
};

var scrollingWrapper = {

	_scrollType : false,

	scrollTypeName : {
		scrolling1 : "scrolling1",
		scrolling2 : "scrolling2",
		scrolling3 : "scrolling3"
	},

	scrollingDelay : false,

	doScrollingEasy : function(scrollName, delay) {
		this.scrollingDelay = delay;
		this.setScrollType(scrollName);
		this.scrollScene();
	},

	setScrollType : function(scrollName) {
		if (scrollName) {
			if (this.scrollTypeName.scrolling1 == scrollName) {
				this._scrollType = this.scrollTypeName.scrolling1;
			} else if (this.scrollTypeName.scrolling2 == scrollName) {
				this._scrollType = this.scrollTypeName.scrolling2;
			} else if (this.scrollTypeName.scrolling3 == scrollName) {
				this._scrollType = this.scrollTypeName.scrolling3;
			}
		}
	},

	getScrollType : function() { return this._scrollType; },

	scrollScene : function() {
		if (this.getScrollType()) {
			// scrolling delay
			setTimeout('scrollingWrapper.scrollDelay();', this.scrollingDelay);
		}
	},

	scrollDelay : function() {
		// must be safe
		eval("this." + this.getScrollType() + "()");
		return true;
	},

	// eval functions {{{
	scrolling1 : function() {
		// function to scroll at page bottom and than to entpy logo

		$.scrollTo('.scroll_to_bottom', 5500, { axis:'y', easing : 'easeInOutQuart', onAfter : function(){
				// ...at the end of bottom scrolling, return to logo pt2 animation
				var scrollingObj = scrollingWrapper;
				scrollingObj.doScrollingEasy(scrollingObj.scrollTypeName.scrolling2, 1000);
			}
		});

		return true;
	},

	scrolling2 : function() {
		// function to scroll directly to entpy logo
		$.scrollTo('.scroll_to_element1', 5000, { axis:'y', easing : 'easeInOutQuart', onAfter : function(){
				ciakWrapper.animateViaCssClass(".logoBottomTextAction", "fadeIn", "1.5s", "0s", "1");
				ciakWrapper.animateViaCssClass(".logo2AnimationAction", "lightSpeedIn", "1s", "2.8s", "1");
				ciakWrapper.animateViaCssClass(".form_container", "fadeIn", "3s", "4.5s", "1");

				// exec actions post animation
				ciakWrapper.postActions();
			}
		});
	},

	scrolling3 : function() {
		// function to scroll directly to entpy logo
		$.scrollTo('.scroll_to_element1', 2000, { axis:'y', easing : 'easeInOutQuart', onAfter : function(){
				/*$(".logoBottomTextAction").removeClass("transparent");
				$(".logo2AnimationAction").removeClass("transparent");
				$(".form_container").removeClass("transparent");*/
				ciakWrapper.animateViaCssClass(".logoBottomTextAction", "fadeIn", "1s", "0s", "1");
				ciakWrapper.animateViaCssClass(".logo2AnimationAction", "fadeIn", "1s", "0s", "1");
				ciakWrapper.animateViaCssClass(".form_container", "fadeIn", "1s", "0s", "1");

				// exec actions post animation
				ciakWrapper.postActions();
			}
		});
	}
	// eval functions }}}
};
<|endoftext|>


<commit_before>steal('can/control/view','can/view/micro','funcunit/qunit')  //load qunit
 .then(function(){

	module("can/control/view");

	test("this.view", function(){

		can.Control.extend("can.Control.View.Test.Qunit",{
			init: function() {
				this.element.html(this.view('init'))
			}
		})
		can.view.ext = ".micro";
		$("#qunit-test-area").append("
");

		new can.Control.View.Test.Qunit( $('#cont_view') );

		ok(/Hello World/i.test($('#cont_view').text()),"view rendered")
	});

	test("test.suffix.doubling", function(){

		can.Control.extend("can.Control.View.Test.Qunit",{
			init: function() {
				this.element.html(this.view('init.micro'))
			}
		})

		can.view.ext = ".ejs"; // Reset view extension to default
		equal(".ejs", can.view.ext);

		$("#qunit-test-area").append("
");

		new can.Control.View.Test.Qunit( $('#suffix_test_cont_view') );

		ok(/Hello World/i.test($('#suffix_test_cont_view').text()),"view rendered")
	});

	test("complex paths nested inside a controller directory", function(){
		can.Control.extend("Myproject.Controllers.Foo.Bar");

		//var path = jQuery.Controller._calculatePosition(Myproject.Controllers.Foo.Bar, "init.ejs", "init")
		//equals(path, "//myproject/views/foo/bar/init.ejs", "view path is correct")

		can.Control.extend("Myproject.Controllers.FooBar");
		path = can.Control._calculatePosition(Myproject.Controllers.FooBar, "init.ejs", "init")
		equals(path, "//myproject/views/foo_bar/init.ejs", "view path is correct")
	})
});

<commit_msg>updated control/view tests for other frameworks<commit_after>steal('can/control/view','can/view/micro','funcunit/qunit')  //load qunit
 .then(function(){

	module("can/control/view");

	test("this.view", function(){

		can.Control.extend("can.Control.View.Test.Qunit",{
			init: function() {
				this.element.html(this.view('init'))
			}
		})
		can.view.ext = ".micro";
		can.$("#qunit-test-area").append("
");

		new can.Control.View.Test.Qunit( can.$('#cont_view') );

		ok(/Hello World/i.test(can.$('#cont_view').text()),"view rendered")
	});

	test("test.suffix.doubling", function(){

		can.Control.extend("can.Control.View.Test.Qunit",{
			init: function() {
				this.element.html(this.view('init.micro'))
			}
		})

		can.view.ext = ".ejs"; // Reset view extension to default
		equal(".ejs", can.view.ext);

		can.$("#qunit-test-area").append("
");

		new can.Control.View.Test.Qunit(can.$('#suffix_test_cont_view') );

		ok(/Hello World/i.test(can.$('#suffix_test_cont_view').text()),"view rendered")
	});

	test("complex paths nested inside a controller directory", function(){
		can.Control.extend("Myproject.Controllers.Foo.Bar");

		//var path = jQuery.Controller._calculatePosition(Myproject.Controllers.Foo.Bar, "init.ejs", "init")
		//equals(path, "//myproject/views/foo/bar/init.ejs", "view path is correct")

		can.Control.extend("Myproject.Controllers.FooBar");
		path = can.Control._calculatePosition(Myproject.Controllers.FooBar, "init.ejs", "init")
		equals(path, "//myproject/views/foo_bar/init.ejs", "view path is correct")
	})
});

<|endoftext|>


<commit_before>import { React, PropTypes, observer, useRef, useEffect, styled, css } from 'vendor';
import { Button } from 'react-bootstrap';
import { colors } from 'theme';
import { useState } from 'react';

const Name=styled.div`
  font-weight: bold;
`;
const StudentName = observer(({ ux, student, index }) => {
  if (ux.hideStudentNames) {
    return <Name>{`Student ${index + 1}`}</Name>;
  }
  return(
    <Name>{student.last_name}, {student.first_name}</Name>
  );
});
StudentName.propTypes = {
  student: PropTypes.object.isRequired,
};

const Box = styled.div`
 min-height: 7rem;
 padding: 2rem;
 display: flex;
 justify-content: space-between;
 border: 2px solid ${colors.neutral.pale};
 & + & {
   margin-top: 1rem;
 }
 ${props => props.onClick && css`
      cursor: pointer;
    `}
`;

const ScoreInput = styled.input`
  height: 4rem;
  display: flex;
  justify-content: center;
  text-align: center;
  width: 5rem;
  margin: 0 0.8rem;
  border: 2px solid ${colors.neutral.pale};
`;
const ScoreWrapper = styled.div`
  display: flex;
  align-items: center;
  margin-bottom: .8rem;
`;

const Points = React.forwardRef(({ response, onChange }, ref) => {
  return (
    <ScoreWrapper>
      Score:
      <ScoreInput
        autoFocus
        name="score"
        placeholder="0"
        ref={ref}
        onChange={(e) => onChange(e.target.value)}
        defaultValue={response.grader_points}
        disabled={Boolean(!onChange)}
      /> out of {response.availablePoints}
    </ScoreWrapper>
  );
});

Points.propTypes = {
  response: PropTypes.object.isRequired,
  onChange: PropTypes.func,
};

const Comment = styled.textarea`
  height: 8rem;
  width: 25rem;
  margin: 0.8rem 0;
  padding: 0.5rem;
  border: 1px solid ${colors.neutral.pale};
`;

const GradingStudentWrapper= styled(Box)`
  ${props => props.showShadow && css`
    box-shadow: 0 8px 10px 1px rgba(0,0,0,0.14), 0 3px 14px 3px rgba(0,0,0,0.12), 0 4px 5px 0 rgba(0,0,0,0.2);
    border: none;
  `}
  ${props => !props.showShadow && css`
    border: 1px solid ${colors.neutral.pale};
  `}
  margin: 2rem 0;
`;

const SaveButton = styled(Button)`
  &&& {
    width: fit-content;
    margin-top: 10px;
    padding: none;
    margin-left: 0;
  }
`;

const Panel=styled.div`
  display: flex;
  flex-direction: column;
  ${Name} {
    margin-bottom: 2rem;
  }
`;

const GradingStudent = observer(({ response, ux, index }) => {
  const [points, setPoints] = useState(response.grader_points);
  const pointRef = useRef();
  const commentsRef = useRef();

  useEffect(() => {
    pointRef.current.select();
    pointRef.current.focus();
  }, []);

  const { student } = response;
  const saveLabel = ux.isResponseGraded(response)
    ? 'Regrade'
    : ux.isLastStudent
      ? 'Save & open next question'
      : 'Save';

  return (
    <GradingStudentWrapper data-student-id={student.id} data-test-id="student-answer" showShadow={!ux.isResponseGraded(response)}>
      <Panel>
        <StudentName ux={ux} student={student} index={index} />

{response.free_response}

      </Panel>
      <Panel>
        <Points response={response} onChange={setPoints} ref={pointRef} />
        Comment:
        <Comment name="comment" defaultValue={response.gradedComments} ref={commentsRef} />
        {
          (!ux.isLastQuestion || !ux.isLastStudent || ux.isResponseGraded(response)) &&
          <SaveButton
            className="btn btn-standard btn-primary"
            disabled={isNaN(points) || parseInt(points, 10) > response.availablePoints}
            onClick={() => ux.saveScore({
              response, points, comment: commentsRef.current.value, doGoToOverview: false, doMoveNextQuestion: ux.isLastStudent ? true : false,
            })}>
            {saveLabel}
          </SaveButton>
        }
        {ux.isLastStudent && !ux.isResponseGraded(response) &&
          <SaveButton
            variant="plain"
            className="btn btn-standard"
            disabled={isNaN(points) || parseInt(points, 10) > response.availablePoints}
            onClick={() => ux.saveScore({
              response, points, comment: commentsRef.current.value, doGoToOverview: true,
            })}>
            {'Save & Exit'}
          </SaveButton>
        }
      </Panel>
    </GradingStudentWrapper>
  );
});

const CollapsedStudent = observer(({ ux, response, index }) => {
  return (
    <Box onClick={() => {
      if(ux)
        ux.selectedStudentIndex = index;
    }}
    >
      <StudentName ux={ux} student={response.student} />
      <Points response={response} />
    </Box>);
});

const Student = observer(({ index, response, ux, ...props }) => {
  let Component;
  const { student } = response;

  if (!ux) {
    Component = CollapsedStudent;
  }
  else if (ux.isResponseGraded(response))
    Component = GradingStudent;
  else
    Component = ux.selectedStudentIndex === index ? GradingStudent : CollapsedStudent;
  return (
    <Component
      key={response.task_step_id}
      ux={ux}
      index={index}
      response={response}
      student={student}
      {...props}
    />
  );
});

export default Student;
<commit_msg>add verification for points and save buttons<commit_after>import { React, PropTypes, observer, useRef, useEffect, styled, css } from 'vendor';
import { Button } from 'react-bootstrap';
import { colors } from 'theme';
import { useState } from 'react';
import { isNumber } from 'lodash';

const Name=styled.div`
  font-weight: bold;
`;
const StudentName = observer(({ ux, student, index }) => {
  if (ux.hideStudentNames) {
    return <Name>{`Student ${index + 1}`}</Name>;
  }
  return(
    <Name>{student.last_name}, {student.first_name}</Name>
  );
});
StudentName.propTypes = {
  student: PropTypes.object.isRequired,
};

const Box = styled.div`
 min-height: 7rem;
 padding: 2rem;
 display: flex;
 justify-content: space-between;
 border: 2px solid ${colors.neutral.pale};
 & + & {
   margin-top: 1rem;
 }
 ${props => props.onClick && css`
      cursor: pointer;
    `}
`;

const ScoreInput = styled.input`
  height: 4rem;
  display: flex;
  justify-content: center;
  text-align: center;
  width: 5rem;
  margin: 0 0.8rem;
  border: 2px solid ${colors.neutral.pale};
`;
const ScoreWrapper = styled.div`
  display: flex;
  align-items: center;
  margin-bottom: .8rem;
`;

const Points = React.forwardRef(({ response, onChange }, ref) => {
  return (
    <ScoreWrapper>
      Score:
      <ScoreInput
        autoFocus
        type="number"
        min="0"
        max={response.availablePoints}
        step="0.1"
        name="score"
        placeholder="0"
        ref={ref}
        onChange={(e) => {
          if(e.target.value === '') onChange(undefined);
          else onChange(parseFloat(e.target.value, 10));
        }}
        defaultValue={response.grader_points}
        disabled={Boolean(!onChange)}
      /> out of {response.availablePoints}
    </ScoreWrapper>
  );
});

Points.propTypes = {
  response: PropTypes.object.isRequired,
  onChange: PropTypes.func,
};

const Comment = styled.textarea`
  height: 8rem;
  width: 25rem;
  margin: 0.8rem 0;
  padding: 0.5rem;
  border: 1px solid ${colors.neutral.pale};
`;

const GradingStudentWrapper= styled(Box)`
  ${props => props.showShadow && css`
    box-shadow: 0 8px 10px 1px rgba(0,0,0,0.14), 0 3px 14px 3px rgba(0,0,0,0.12), 0 4px 5px 0 rgba(0,0,0,0.2);
    border: none;
  `}
  ${props => !props.showShadow && css`
    border: 1px solid ${colors.neutral.pale};
  `}
  margin: 2rem 0;
`;

const SaveButton = styled(Button)`
  &&& {
    width: fit-content;
    margin-top: 10px;
    padding: none;
    margin-left: 0;
  }
`;

const Panel=styled.div`
  display: flex;
  flex-direction: column;
  ${Name} {
    margin-bottom: 2rem;
  }
`;

const GradingStudent = observer(({ response, ux, index }) => {
  const [points, setPoints] = useState(response.grader_points);
  const pointRef = useRef();
  const commentsRef = useRef();

  useEffect(() => {
    pointRef.current.select();
    pointRef.current.focus();
  }, []);

  const { student } = response;
  const saveLabel = ux.isResponseGraded(response)
    ? 'Regrade'
    : ux.isLastStudent
      ? 'Save & open next question'
      : 'Save';

  return (
    <GradingStudentWrapper data-student-id={student.id} data-test-id="student-answer" showShadow={!ux.isResponseGraded(response)}>
      <Panel>
        <StudentName ux={ux} student={student} index={index} />

{response.free_response}

      </Panel>
      <Panel>
        <Points response={response} onChange={setPoints} ref={pointRef} />
        Comment:
        <Comment name="comment" defaultValue={response.gradedComments} ref={commentsRef} />
        {
          (!ux.isLastQuestion || !ux.isLastStudent || ux.isResponseGraded(response)) &&
          <SaveButton
            className="btn btn-standard btn-primary"
            disabled={!isNumber(points) || points > response.availablePoints || response.grader_points === points}
            onClick={() => ux.saveScore({
              response, points, comment: commentsRef.current.value, doGoToOverview: false, doMoveNextQuestion: ux.isLastStudent ? true : false,
            })}>
            {saveLabel}
          </SaveButton>
        }
        {ux.isLastStudent && !ux.isResponseGraded(response) &&
          <SaveButton
            variant="plain"
            className="btn btn-standard"
            disabled={!isNumber(points) || points > response.availablePoints || response.grader_points === points}
            onClick={() => ux.saveScore({
              response, points, comment: commentsRef.current.value, doGoToOverview: true,
            })}>
            {'Save & Exit'}
          </SaveButton>
        }
      </Panel>
    </GradingStudentWrapper>
  );
});

const CollapsedStudent = observer(({ ux, response, index }) => {
  return (
    <Box onClick={() => {
      if(ux)
        ux.selectedStudentIndex = index;
    }}
    >
      <StudentName ux={ux} student={response.student} />
      <Points response={response} />
    </Box>);
});

const Student = observer(({ index, response, ux, ...props }) => {
  let Component;
  const { student } = response;

  if (!ux) {
    Component = CollapsedStudent;
  }
  else if (ux.isResponseGraded(response))
    Component = GradingStudent;
  else
    Component = ux.selectedStudentIndex === index ? GradingStudent : CollapsedStudent;
  return (
    <Component
      key={response.task_step_id}
      ux={ux}
      index={index}
      response={response}
      student={student}
      {...props}
    />
  );
});

export default Student;
<|endoftext|>


<commit_before><commit_msg>added a filter for get configs<commit_after><|endoftext|>


<commit_before>import { expect } from 'chai';
import plugin from '../src';

let Adapter = new plugin.Service({
  paginate: {
    default: 10,
    max: 4
  }
});
describe('CollectionsApi', function() {
    this.timeout(10000);

  describe('List', function() {
    this.timeout(10000);
    it('contains collections `gettingstarted`', function(done) {
      this.timeout(10000);
      Adapter.client().collections().list()
            .then(function(res) {
                expect(res.responseHeader.status).to.be.equal(0);
                expect(res.collections).to.be.an('array').that.does.include('gettingstarted');
                done();
            })
            .catch(function(err) {
                done(err);
            });
    });
  });

  describe('Create', function() {
    this.timeout(10000);
    it('create collections `sajov`', function(done) {
      this.timeout(10000);
      Adapter.client()
            .collections()
            .create({
              name:'sajov',
              numShards:2,
              replicationFactor:1
            })
            .then(function(res) {
                expect(res.responseHeader.status).to.be.equal(0);
                done();
            })
            .catch(function(err) {
                done(err);
            });
    });

    it('contains collections `sajov`', function(done) {
      this.timeout(10000);
      Adapter.client().collections().list()
            .then(function(res) {
                expect(res.responseHeader.status).to.be.equal(0);
                expect(res.collections).to.be.an('array').that.does.include('sajov');
                done();
            })
            .catch(function(err) {
                done(err);
            });
    });
  });

  describe('Delete', function() {
    this.timeout(10000);
    it('delete collections `sajov`', function(done) {
      this.timeout(10000);
      Adapter.client()
            .collections()
            .delete({name:'sajov'})
            .then(function(res) {
                expect(res.responseHeader.status).to.be.equal(0);
                done();
            })
            .catch(function(err) {
                done(err);
            });
    });

    it('not contains collections `sajov`', function(done) {
      function(done) {
      Adapter.client().collections().list()
            .then(function(res) {
                expect(res.responseHeader.status).to.be.equal(0);
                expect(res.collections).to.be.an('array').that.does.not.include('sajov');
                done();
            })
            .catch(function(err) {
                done(err);
            });
    });

  });

});
<commit_msg>no message<commit_after>import { expect } from 'chai';
import plugin from '../src';

let Adapter = new plugin.Service({
  paginate: {
    default: 10,
    max: 4
  }
});
describe('CollectionsApi', function() {
    this.timeout(10000);

  describe('List', function() {
    this.timeout(10000);
    it('contains collections `gettingstarted`', function(done) {
      this.timeout(10000);
      Adapter.client().collections().list()
            .then(function(res) {
                expect(res.responseHeader.status).to.be.equal(0);
                expect(res.collections).to.be.an('array').that.does.include('gettingstarted');
                done();
            })
            .catch(function(err) {
                done(err);
            });
    });
  });

  describe('Create', function() {
    this.timeout(10000);
    it('create collections `sajov`', function(done) {
      this.timeout(10000);
      Adapter.client()
            .collections()
            .create({
              name:'sajov',
              numShards:2,
              replicationFactor:1
            })
            .then(function(res) {
                expect(res.responseHeader.status).to.be.equal(0);
                done();
            })
            .catch(function(err) {
                done(err);
            });
    });

    it('contains collections `sajov`', function(done) {
      this.timeout(10000);
      Adapter.client().collections().list()
            .then(function(res) {
                expect(res.responseHeader.status).to.be.equal(0);
                expect(res.collections).to.be.an('array').that.does.include('sajov');
                done();
            })
            .catch(function(err) {
                done(err);
            });
    });
  });

  describe('Delete', function() {
    this.timeout(10000);
    it('delete collections `sajov`', function(done) {
      this.timeout(10000);
      Adapter.client()
            .collections()
            .delete({name:'sajov'})
            .then(function(res) {
                expect(res.responseHeader.status).to.be.equal(0);
                done();
            })
            .catch(function(err) {
                done(err);
            });
    });

    it('not contains collections `sajov`', function(done) {
      this.timeout(10000);
      Adapter.client().collections().list()
            .then(function(res) {
                expect(res.responseHeader.status).to.be.equal(0);
                expect(res.collections).to.be.an('array').that.does.not.include('sajov');
                done();
            })
            .catch(function(err) {
                done(err);
            });
    });

  });

});
<|endoftext|>


<commit_before><commit_msg>add missing opt<commit_after><|endoftext|>


<commit_before><commit_msg>Formatting change<commit_after><|endoftext|>