<commit_before>/* global DOM, CloudFunc, CloudCmd */

'use strict';

const exec = require('execon');
const itype = require('itype/legacy');

module.exports.init = () => {
    contextMenu();
    dragndrop();
    unload();
    pop();
    resize();
    config();
    header();
};

CloudCmd.Listeners = module.exports;

const Info = DOM.CurrentInfo;
const Storage = DOM.Storage;
const Events = DOM.Events;
const EventsFiles = {
    mousedown: exec.with(execIfNotUL, setCurrentFileByEvent),
    click: onClick,
    dragstart: exec.with(execIfNotUL, onDragStart),
    dblclick: exec.with(execIfNotUL, onDblClick),
    touchstart: exec.with(execIfNotUL, onTouch)
};

let EXT;

function header() {
    const fm = DOM.getFM();

    const isDataset = (el) => el.dataset;

    var isPanel = (el) => {
        return /^js-(left|right)$/.test(el.dataset.name);
    };

    Events.addClick(fm, (event) => {
        const el = event.target;
        const parent = el.parentElement;

        if (parent.dataset.name !== 'js-fm-header')
            return;

        const name = (el.dataset.name || '')
            .replace('js-', '');

        if (!/^(name|size|date)$/.test(name))
            return;

        const panel = getPath(el)
            .filter(isDataset)
            .filter(isPanel)
            .pop();

        CloudCmd.sortPanel(name, panel);
    });
}

function getPath(el, path = []) {
    if (!el)
        return path;

    return getPath(el.parentElement, path.concat(el));
}

function config() {
    DOM.Files.get('config', (e, config) => {
        const type = config && config.packer;
        EXT = DOM.getPackerExt(type);
    });
}

module.exports.initKeysPanel = () => {
    const keysElement = DOM.getById('js-keyspanel');

    if (!keysElement)
        return;

    Events.addClick(keysElement, ({target}) => {
        const id = target.id;
        const operation = (name) => {
            const Operation = CloudCmd.Operation;
            const fn = Operation.show.bind(null, name);

            return fn;
        };

        const clickFuncs = {
            'f1'        : CloudCmd.Help.show,
            'f2'        : DOM.renameCurrent,
            'f3'        : CloudCmd.View.show,
            'f4'        : CloudCmd.EditFile.show,
            'f5'        : operation('copy'),
            'f6'        : operation('move'),
            'f7'        : DOM.promptNewDir,
            'f8'        : operation('delete'),
            'f9'        : CloudCmd.Menu.show,
            'f10'       : CloudCmd.Config.show,
            '~'         : CloudCmd.Konsole.show,
            'contact'   : CloudCmd.Contact.show,
        };

        exec(clickFuncs[id]);
    });
};

module.exports.setOnPanel = (side) => {
    let panel;
    if (itype.string(side))
        panel = DOM.getByDataName('js-' + side);
    else
        panel = side;

    const filesElement = DOM.getByDataName('js-files', panel);
    const pathElement = DOM.getByDataName('js-path', panel);

    /* ставим загрузку гифа на клик*/
    Events.addClick(pathElement, getPathListener(panel));
    Events.add(filesElement, EventsFiles);
};

function getPathListener(panel) {
    return  onPathElementClick.bind(null, panel);
}

function isNoCurrent(panel) {
    const infoPanel = Info.panel;
    const namePanel = panel.getAttribute('data-name');
    const nameInfoPanel = infoPanel.getAttribute('data-name');

    if (namePanel !== nameInfoPanel)
        return true;

    return false;
}

function onPathElementClick(panel, event) {
    let link, href, url, noCurrent;

    const fs = CloudFunc.FS;
    const prefix = CloudCmd.PREFIX;
    const element = event.target;
    const attr = element.getAttribute('data-name');

    switch (attr) {
    case 'js-clear-storage':
        Storage.clear();
        break;

    case 'js-refresh':
        noCurrent = isNoCurrent(panel);

        CloudCmd.refresh(panel, {
            noCurrent
        });

        event.preventDefault();
        break;

    case 'js-path-link':
        url         = CloudCmd.HOST;
        href        = element.href;
        link        = href.replace(url, '');
        /**
         * browser doesn't replace % -> %25%
         * do it for him
         */
        link        = link.replace('%%', '%25%');
        link        = decodeURI(link);
        link        = link.replace(RegExp('^' + prefix + fs), '') || '/';

        noCurrent   = isNoCurrent(panel);

        CloudCmd.loadDir({
            path        : link,
            isRefresh   : false,
            panel       : noCurrent ? panel : Info.panel
        });

        event.preventDefault();
    }
}

function execIfNotUL(callback, event) {
    const {target} = event;
    const {tagName} = target;

    if (tagName !== 'UL')
        callback(event);
}

function onClick(event) {
    const ctrl = event.ctrlKey;

    if (!ctrl)
        event.preventDefault();

    changePanel(event.target);
}

function toggleSelect(key, files) {
    const isMac = /Mac/.test(window.navigator.platform);

    if (!key)
        throw Error('key should not be undefined!');

    if (isMac && key.meta || key.ctrl)
        DOM.toggleSelectedFile(files[0]);
    else if (key.shift)
        files.forEach((current) => {
            if (!DOM.isSelected(current))
                DOM.toggleSelectedFile(current);
        });
    else
        DOM.unselectFiles();
}

function changePanel(element) {
    const {panel} = Info;
    const files = DOM.getByDataName('js-files', panel);
    const ul = getULElement(element);

    if (ul !== files)
        DOM.changePanel();
}

function onDblClick(event) {
    const current = getLIElement(event.target);
    const isDir = DOM.isCurrentIsDir(current);
    const path = DOM.getCurrentPath(current);

    if (isDir) {
        CloudCmd.loadDir({
            path: path === '/' ? '/' : path + '/'
        });

        event.preventDefault();
    }
}

function onTouch(event) {
    const current = getLIElement(event.target);
    const isDir = DOM.isCurrentIsDir(current);

    if (!isDir)
        return;

    const isCurrent = DOM.isCurrentFile(current);

    if (!isCurrent)
        return;

    CloudCmd.loadDir({
        path: DOM.getCurrentPath(current)
    });

    event.preventDefault();
}

 /*
  * download file from browser to desktop
  * in Chrome (HTML5)
  */
function onDragStart(event) {
    const apiURL = CloudFunc.apiURL;
    const element = getLIElement(event.target);
    const isDir = Info.isDir;
    let link = DOM.getCurrentLink(element);
    let name = DOM.getCurrentName(element);

    /* if it's directory - adding json extension */
    if (isDir) {
        name += EXT;
        link = document.createElement('a');
        link.textContent = name;
        link.href = apiURL + '/pack' + Info.path + EXT;
    }

    event.dataTransfer.setData('DownloadURL',
        'application/octet-stream'  + ':' +
        name                        + ':' +
        link);
}

function getLIElement(element) {
    if (!element)
        return element;

    while (element.tagName !== 'LI')
        element = element.parentElement;

    return element;
}

function getULElement(element) {
    while (element.tagName !== 'UL')
        element = element.parentElement;

    return element;
}

function setCurrentFileByEvent(event) {
    const BUTTON_LEFT = 0;

    let fromName;
    let toName;
    let files = [];
    let key = {
        ctrl: event.ctrlKey,
        meta: event.metaKey,
        shift: event.shiftKey
    };

    let element     = getLIElement(event.target);

    fromName = Info.name;
    DOM.setCurrentFile(element);
    toName = Info.name;

    if (key.shift)
        files = getFilesRange(fromName, toName);
    else
        files.push(Info.element);

    if (event.button === BUTTON_LEFT)
        toggleSelect(key, files);
}

function getFilesRange(from, to) {
    let i           = 0,
        delta       = 0,
        result      = [],
        files       = DOM.getFiles(),
        names       = DOM.getFilenames(files),
        indexFrom,
        indexTo;

    if (names[0] === '..') {
        names.shift();
        delta = 1;
    }

    indexFrom   = names.indexOf(from);
    indexTo     = names.indexOf(to);

    if (indexFrom < indexTo)
        for (i = indexFrom; i <= indexTo; i++)
            result.push(files[i + delta]);
    else if (indexFrom > indexTo)
        for (i = indexFrom; i >= indexTo; i--)
            result.push(files[i + delta]);
    else
        result.push(to);

    return result;
}

function contextMenu() {
    const fm = DOM.getFM();

    Events.addOnce('contextmenu', fm, (event) => {
        CloudCmd.Menu.show({
            x: event.clientX,
            y: event.clientY
        });
    });

    Events.addContextMenu(fm, (event) => {
        CloudCmd.Menu.ENABLED || event.preventDefault();
    });
}

function dragndrop() {
    const panels = DOM.getByClassAll('panel');
    const select = () => {
        [...panels].forEach((panel) => {
            panel.classList.add('selected-panel');
        });
    };

    const unselect = () => {
        [...panels].forEach((panel) => {
            panel.classList.remove('selected-panel');
        });
    };
    const onDrop = (event) => {
        const files = event.dataTransfer.files;
        const items = event.dataTransfer.items;

        event.preventDefault();

        if (!items || !items.length || !items[0].webkitGetAsEntry)
            return DOM.uploadFiles(files);

        const dirFiles = [...items].filter((item) => {
            return item.kind === 'file';
        });

        DOM.uploadDirectory(dirFiles);
    };

    /**
     * In Mac OS Chrome dropEffect = 'none'
     * so drop do not firing up when try
     * to upload file from download bar
     */
    const onDragOver = (event) => {
        const dataTransfer = event.dataTransfer;
        const effectAllowed = dataTransfer.effectAllowed;

        if (/move|linkMove/.test(effectAllowed))
            dataTransfer.dropEffect = 'move';
        else
            dataTransfer.dropEffect = 'copy';

        event.preventDefault();
    };

    Events.add('dragenter', select);
    Events.add(['dragleave', 'drop'], unselect);

    [...panels].forEach((panel) => {
        Events.add('dragover', panel, onDragOver)
              .add('drop', panel, onDrop);
    });
}

function unload() {
    DOM.Events.add(['unload', 'beforeunload'], function (event) {
        var ret,
            Key     = CloudCmd.Key,
            isBind  = Key && Key.isBind();

        if (!isBind) {
            event.preventDefault();
            ret = 'Please make sure that you saved all work.';
        }

        return ret;
    });
}

function pop() {
    Events.add('popstate', (event) => {
        const path = event.state || ''
            .replace(CloudFunc.FS, '');

        if (!path)
            return CloudCmd.route(location.hash);

        CloudCmd.loadDir({
            path        : path,
            history     : false
        });
    });
}

function resize() {
    Events.add('resize', () => {
        const is = window.innerWidth < CloudCmd.MIN_ONE_PANEL_WIDTH;

        if (!is)
            return;

        const {panel} = Info;

        const name = panel.getAttribute('data-name');
        const isLeft = name === 'js-left';

        if (isLeft)
            return;

        DOM.changePanel();
    });
}

<commit_msg>fix(listeners) resize: empty root<commit_after>/* global DOM, CloudFunc, CloudCmd */

'use strict';

const exec = require('execon');
const itype = require('itype/legacy');

module.exports.init = () => {
    contextMenu();
    dragndrop();
    unload();
    pop();
    resize();
    config();
    header();
};

CloudCmd.Listeners = module.exports;

const Info = DOM.CurrentInfo;
const Storage = DOM.Storage;
const Events = DOM.Events;
const EventsFiles = {
    mousedown: exec.with(execIfNotUL, setCurrentFileByEvent),
    click: onClick,
    dragstart: exec.with(execIfNotUL, onDragStart),
    dblclick: exec.with(execIfNotUL, onDblClick),
    touchstart: exec.with(execIfNotUL, onTouch)
};

let EXT;

function header() {
    const fm = DOM.getFM();

    const isDataset = (el) => el.dataset;

    var isPanel = (el) => {
        return /^js-(left|right)$/.test(el.dataset.name);
    };

    Events.addClick(fm, (event) => {
        const el = event.target;
        const parent = el.parentElement;

        if (parent.dataset.name !== 'js-fm-header')
            return;

        const name = (el.dataset.name || '')
            .replace('js-', '');

        if (!/^(name|size|date)$/.test(name))
            return;

        const panel = getPath(el)
            .filter(isDataset)
            .filter(isPanel)
            .pop();

        CloudCmd.sortPanel(name, panel);
    });
}

function getPath(el, path = []) {
    if (!el)
        return path;

    return getPath(el.parentElement, path.concat(el));
}

function config() {
    DOM.Files.get('config', (e, config) => {
        const type = config && config.packer;
        EXT = DOM.getPackerExt(type);
    });
}

module.exports.initKeysPanel = () => {
    const keysElement = DOM.getById('js-keyspanel');

    if (!keysElement)
        return;

    Events.addClick(keysElement, ({target}) => {
        const id = target.id;
        const operation = (name) => {
            const Operation = CloudCmd.Operation;
            const fn = Operation.show.bind(null, name);

            return fn;
        };

        const clickFuncs = {
            'f1'        : CloudCmd.Help.show,
            'f2'        : DOM.renameCurrent,
            'f3'        : CloudCmd.View.show,
            'f4'        : CloudCmd.EditFile.show,
            'f5'        : operation('copy'),
            'f6'        : operation('move'),
            'f7'        : DOM.promptNewDir,
            'f8'        : operation('delete'),
            'f9'        : CloudCmd.Menu.show,
            'f10'       : CloudCmd.Config.show,
            '~'         : CloudCmd.Konsole.show,
            'contact'   : CloudCmd.Contact.show,
        };

        exec(clickFuncs[id]);
    });
};

module.exports.setOnPanel = (side) => {
    let panel;
    if (itype.string(side))
        panel = DOM.getByDataName('js-' + side);
    else
        panel = side;

    const filesElement = DOM.getByDataName('js-files', panel);
    const pathElement = DOM.getByDataName('js-path', panel);

    /* ставим загрузку гифа на клик*/
    Events.addClick(pathElement, getPathListener(panel));
    Events.add(filesElement, EventsFiles);
};

function getPathListener(panel) {
    return  onPathElementClick.bind(null, panel);
}

function isNoCurrent(panel) {
    const infoPanel = Info.panel;
    const namePanel = panel.getAttribute('data-name');
    const nameInfoPanel = infoPanel.getAttribute('data-name');

    if (namePanel !== nameInfoPanel)
        return true;

    return false;
}

function onPathElementClick(panel, event) {
    let link, href, url, noCurrent;

    const fs = CloudFunc.FS;
    const prefix = CloudCmd.PREFIX;
    const element = event.target;
    const attr = element.getAttribute('data-name');

    switch (attr) {
    case 'js-clear-storage':
        Storage.clear();
        break;

    case 'js-refresh':
        noCurrent = isNoCurrent(panel);

        CloudCmd.refresh(panel, {
            noCurrent
        });

        event.preventDefault();
        break;

    case 'js-path-link':
        url         = CloudCmd.HOST;
        href        = element.href;
        link        = href.replace(url, '');
        /**
         * browser doesn't replace % -> %25%
         * do it for him
         */
        link        = link.replace('%%', '%25%');
        link        = decodeURI(link);
        link        = link.replace(RegExp('^' + prefix + fs), '') || '/';

        noCurrent   = isNoCurrent(panel);

        CloudCmd.loadDir({
            path        : link,
            isRefresh   : false,
            panel       : noCurrent ? panel : Info.panel
        });

        event.preventDefault();
    }
}

function execIfNotUL(callback, event) {
    const {target} = event;
    const {tagName} = target;

    if (tagName !== 'UL')
        callback(event);
}

function onClick(event) {
    const ctrl = event.ctrlKey;

    if (!ctrl)
        event.preventDefault();

    changePanel(event.target);
}

function toggleSelect(key, files) {
    const isMac = /Mac/.test(window.navigator.platform);

    if (!key)
        throw Error('key should not be undefined!');

    if (isMac && key.meta || key.ctrl)
        DOM.toggleSelectedFile(files[0]);
    else if (key.shift)
        files.forEach((current) => {
            if (!DOM.isSelected(current))
                DOM.toggleSelectedFile(current);
        });
    else
        DOM.unselectFiles();
}

function changePanel(element) {
    const {panel} = Info;
    const files = DOM.getByDataName('js-files', panel);
    const ul = getULElement(element);

    if (ul !== files)
        DOM.changePanel();
}

function onDblClick(event) {
    const current = getLIElement(event.target);
    const isDir = DOM.isCurrentIsDir(current);
    const path = DOM.getCurrentPath(current);

    if (isDir) {
        CloudCmd.loadDir({
            path: path === '/' ? '/' : path + '/'
        });

        event.preventDefault();
    }
}

function onTouch(event) {
    const current = getLIElement(event.target);
    const isDir = DOM.isCurrentIsDir(current);

    if (!isDir)
        return;

    const isCurrent = DOM.isCurrentFile(current);

    if (!isCurrent)
        return;

    CloudCmd.loadDir({
        path: DOM.getCurrentPath(current)
    });

    event.preventDefault();
}

 /*
  * download file from browser to desktop
  * in Chrome (HTML5)
  */
function onDragStart(event) {
    const apiURL = CloudFunc.apiURL;
    const element = getLIElement(event.target);
    const isDir = Info.isDir;
    let link = DOM.getCurrentLink(element);
    let name = DOM.getCurrentName(element);

    /* if it's directory - adding json extension */
    if (isDir) {
        name += EXT;
        link = document.createElement('a');
        link.textContent = name;
        link.href = apiURL + '/pack' + Info.path + EXT;
    }

    event.dataTransfer.setData('DownloadURL',
        'application/octet-stream'  + ':' +
        name                        + ':' +
        link);
}

function getLIElement(element) {
    if (!element)
        return element;

    while (element.tagName !== 'LI')
        element = element.parentElement;

    return element;
}

function getULElement(element) {
    while (element.tagName !== 'UL')
        element = element.parentElement;

    return element;
}

function setCurrentFileByEvent(event) {
    const BUTTON_LEFT = 0;

    let fromName;
    let toName;
    let files = [];
    let key = {
        ctrl: event.ctrlKey,
        meta: event.metaKey,
        shift: event.shiftKey
    };

    let element     = getLIElement(event.target);

    fromName = Info.name;
    DOM.setCurrentFile(element);
    toName = Info.name;

    if (key.shift)
        files = getFilesRange(fromName, toName);
    else
        files.push(Info.element);

    if (event.button === BUTTON_LEFT)
        toggleSelect(key, files);
}

function getFilesRange(from, to) {
    let i           = 0,
        delta       = 0,
        result      = [],
        files       = DOM.getFiles(),
        names       = DOM.getFilenames(files),
        indexFrom,
        indexTo;

    if (names[0] === '..') {
        names.shift();
        delta = 1;
    }

    indexFrom   = names.indexOf(from);
    indexTo     = names.indexOf(to);

    if (indexFrom < indexTo)
        for (i = indexFrom; i <= indexTo; i++)
            result.push(files[i + delta]);
    else if (indexFrom > indexTo)
        for (i = indexFrom; i >= indexTo; i--)
            result.push(files[i + delta]);
    else
        result.push(to);

    return result;
}

function contextMenu() {
    const fm = DOM.getFM();

    Events.addOnce('contextmenu', fm, (event) => {
        CloudCmd.Menu.show({
            x: event.clientX,
            y: event.clientY
        });
    });

    Events.addContextMenu(fm, (event) => {
        CloudCmd.Menu.ENABLED || event.preventDefault();
    });
}

function dragndrop() {
    const panels = DOM.getByClassAll('panel');
    const select = () => {
        [...panels].forEach((panel) => {
            panel.classList.add('selected-panel');
        });
    };

    const unselect = () => {
        [...panels].forEach((panel) => {
            panel.classList.remove('selected-panel');
        });
    };
    const onDrop = (event) => {
        const files = event.dataTransfer.files;
        const items = event.dataTransfer.items;

        event.preventDefault();

        if (!items || !items.length || !items[0].webkitGetAsEntry)
            return DOM.uploadFiles(files);

        const dirFiles = [...items].filter((item) => {
            return item.kind === 'file';
        });

        DOM.uploadDirectory(dirFiles);
    };

    /**
     * In Mac OS Chrome dropEffect = 'none'
     * so drop do not firing up when try
     * to upload file from download bar
     */
    const onDragOver = (event) => {
        const dataTransfer = event.dataTransfer;
        const effectAllowed = dataTransfer.effectAllowed;

        if (/move|linkMove/.test(effectAllowed))
            dataTransfer.dropEffect = 'move';
        else
            dataTransfer.dropEffect = 'copy';

        event.preventDefault();
    };

    Events.add('dragenter', select);
    Events.add(['dragleave', 'drop'], unselect);

    [...panels].forEach((panel) => {
        Events.add('dragover', panel, onDragOver)
              .add('drop', panel, onDrop);
    });
}

function unload() {
    DOM.Events.add(['unload', 'beforeunload'], function (event) {
        var ret,
            Key     = CloudCmd.Key,
            isBind  = Key && Key.isBind();

        if (!isBind) {
            event.preventDefault();
            ret = 'Please make sure that you saved all work.';
        }

        return ret;
    });
}

function pop() {
    Events.add('popstate', (event) => {
        const path = event.state || ''
            .replace(CloudFunc.FS, '');

        if (!path)
            return CloudCmd.route(location.hash);

        CloudCmd.loadDir({
            path        : path,
            history     : false
        });
    });
}

function resize() {
    Events.add('resize', () => {
        const is = window.innerWidth < CloudCmd.MIN_ONE_PANEL_WIDTH;

        if (!is)
            return;

        const {panel} = Info;
        const isEmptyRoot = !panel;

        if (isEmptyRoot)
            return;

        const name = panel.getAttribute('data-name');
        const isLeft = name === 'js-left';

        if (isLeft)
            return;

        DOM.changePanel();
    });
}

<|endoftext|>


<commit_before>import {inject, Container} from 'aurelia-dependency-injection';
import {DOM} from 'aurelia-pal';
import {
  ViewCompiler,
  ViewResources,
  BehaviorInstruction,
  TargetInstruction,
  BoundViewFactory,
  ViewSlot
} from 'aurelia-templating';

let emptyArray = Object.freeze([]);

@inject(Container, ViewCompiler, ViewResources)
export class ComponentRegistry {
  _lookup = {};

  constructor(container, viewCompiler, viewResources) {
    this.container = container;
    this.viewCompiler = viewCompiler;
    this.viewResources = viewResources;
  }

  registerBehavior(behavior, tagName?:string) {
    let proto = this._createWebComponentPrototypeFromBehavior(behavior);
    tagName = this._determineTagName(behavior, tagName);
    this._lookup[tagName] = {
      tagName: tagName,
      behavior: behavior,
      proto: proto
    };

    document.register(tagName, { prototype: proto });
  }

  _determineTagName(behavior, tagName) {
    return tagName || behavior.elementName
  }

  _createWebComponentPrototypeFromBehavior(behavior) {
    let viewResources = this.viewResources;
    let compiler = this.viewCompiler;
    let container = this.container;

    let proto = Object.create(HTMLElement.prototype, {
      createdCallback: {
        value: function() {
          let behaviorInstruction = BehaviorInstruction.element(this, behavior);
          let attributes = this.attributes;
          let children = this._children = [];
          let bindings = this._bindings = [];

          //TODO: processAttributes

          for (let i = 0, ii = attributes.length; i < ii; ++i) {
            attr = attributes[i];
            behaviorInstruction.attributes[attr.name] = attr.value;
          }

          behavior.compile(compiler, viewResources, this, behaviorInstruction, this.parentNode);

          let targetInstruction = TargetInstruction.normal(
            0,
            0,
            [behavior.target],
            [behaviorInstruction],
            emptyArray,
            behaviorInstruction
          );

          let childContainer = createElementContainer(
            container,
            this,
            targetInstruction,
            behaviorInstruction.partReplacements,
            children,
            viewResources
          );

          let controller = behavior.create(childContainer, behaviorInstruction, this, bindings);
          controller.created(null);
        }
      },
      attachedCallback: {
        value: function() {
          this.au.controller.bind();
          this._bindings.forEach(x => x.bind());
          this._children.forEach(x => x.bind());

          this.au.controller.attached();
          this._children.forEach(x => x.attached());
        }
      },
      detachedCallback: {
        value: function() {
          this.au.controller.detached();
          this._children.forEach(x => x.detached());

          this.au.controller.unbind();
          this._bindings.forEach(x => x.unbind());
          this._children.forEach(x => x.unbind());
        }
      },
      attributeChangedCallback: {
        value: function(attrName, oldValue, newValue) {
          let bindable = behavior.attributes[attrName];
          if (bindable) {
            this.au.controller.viewModel[bindable.name] = newValue;
          }
        }
      }
    });

    behavior.properties.forEach(prop => {
      let descriptor = {
        get: function() {
          return this.au.controller.viewModel[prop.name];
        },
        set: function(value) {
          this.au.controller.viewModel[prop.name] = value;
        }
      };

      descriptor.get.getObserver = function(obj) {
        return getObserver(behavior, obj.au.controller.viewModel, prop.name);
      };

      Object.defineProperty(proto, prop.name, descriptor);
    });

    Object.keys(behavior.target.prototype).forEach(key => {
      let value = behavior.target.prototype[key];

      if(typeof value === 'function') {
        proto[key] = function(...args) {
          return this.au.controller.viewModel[key](...args);
        };
      }
    });

    return proto;
  }
}

function getObserver(behavior, instance, name) {
  let lookup = instance.__observers__;

  if (lookup === undefined) {
    if (!behavior.isInitialized) {
      behavior.initialize(Container.instance || new Container(), instance.constructor);
    }

    lookup = behavior.observerLocator.getOrCreateObserversLookup(instance);
    behavior._ensurePropertiesDefined(instance, lookup);
  }

  return lookup[name];
}

function elementContainerGet(key) {
  if (key === DOM.Element) {
    return this.element;
  }

  if (key === BoundViewFactory) {
    if (this.boundViewFactory) {
      return this.boundViewFactory;
    }

    let factory = this.instruction.viewFactory;
    let partReplacements = this.partReplacements;

    if (partReplacements) {
      factory = partReplacements[factory.part] || factory;
    }

    this.boundViewFactory = new BoundViewFactory(this, factory, partReplacements);
    return this.boundViewFactory;
  }

  if (key === ViewSlot) {
    if (this.viewSlot === undefined) {
      this.viewSlot = new ViewSlot(this.element, this.instruction.anchorIsContainer);
      this.element.isContentProjectionSource = this.instruction.lifting;
      this.children.push(this.viewSlot);
    }

    return this.viewSlot;
  }

  if (key === ViewResources) {
    return this.viewResources;
  }

  if (key === TargetInstruction) {
    return this.instruction;
  }

  return this.superGet(key);
}

function createElementContainer(parent, element, instruction, children, partReplacements, resources) {
  let container = parent.createChild();
  let provider = instruction.providers[0];

  container.element = element;
  container.instruction = instruction;
  container.children = children;
  container.viewResources = resources;
  container.partReplacements = partReplacements;

  container.registerSingleton(provider, provider);

  container.superGet = container.get;
  container.get = elementContainerGet;

  return container;
}
<commit_msg>feat(all): update to v1 Custom Elements spec<commit_after>import {inject, Container} from 'aurelia-dependency-injection';
import {DOM} from 'aurelia-pal';
import {
  ViewCompiler,
  ViewResources,
  BehaviorInstruction,
  TargetInstruction,
  BoundViewFactory,
  ViewSlot
} from 'aurelia-templating';

let emptyArray = Object.freeze([]);

@inject(Container, ViewCompiler, ViewResources)
export class ComponentRegistry {
  _lookup = {};

  constructor(container, viewCompiler, viewResources) {
    this.container = container;
    this.viewCompiler = viewCompiler;
    this.viewResources = viewResources;
  }

  registerBehavior(behavior, tagName?:string) {
    let classDefinition = this._createWebComponentClassFromBehavior(behavior);
    tagName = tagName || this._determineTagNameFromBehavior(behavior);

    this._lookup[tagName] = {
      tagName: tagName,
      behavior: behavior,
      classDefinition: classDefinition
    };

    customElements.define(tagName, classDefinition);
  }

  _determineTagNameFromBehavior(behavior) {
    return behavior.elementName;
  }

  _createWebComponentClassFromBehavior(behavior) {
    let viewResources = this.viewResources;
    let compiler = this.viewCompiler;
    let container = this.container;

    let CustomElement = class extends HTMLElement {
      constructor() {
        let behaviorInstruction = BehaviorInstruction.element(this, behavior);
        let attributes = this.attributes;
        let children = this._children = [];
        let bindings = this._bindings = [];

        //TODO: processAttributes

        for (let i = 0, ii = attributes.length; i < ii; ++i) {
          attr = attributes[i];
          behaviorInstruction.attributes[attr.name] = attr.value;
        }

        behavior.compile(compiler, viewResources, this, behaviorInstruction, this.parentNode);

        let targetInstruction = TargetInstruction.normal(
          0,
          0,
          [behavior.target],
          [behaviorInstruction],
          emptyArray,
          behaviorInstruction
        );

        let childContainer = createElementContainer(
          container,
          this,
          targetInstruction,
          behaviorInstruction.partReplacements,
          children,
          viewResources
        );

        let controller = behavior.create(childContainer, behaviorInstruction, this, bindings);
        controller.created(null);
      }

      connectedCallback() {
        this.au.controller.bind();
        this._bindings.forEach(x => x.bind());
        this._children.forEach(x => x.bind());

        this.au.controller.attached();
        this._children.forEach(x => x.attached());
      }

      disconnectedCallback() {
        this.au.controller.detached();
        this._children.forEach(x => x.detached());

        this.au.controller.unbind();
        this._bindings.forEach(x => x.unbind());
        this._children.forEach(x => x.unbind());
      }

      attributeChangedCallback(attrName, oldValue, newValue) {
        let bindable = behavior.attributes[attrName];
        if (bindable) {
          this.au.controller.viewModel[bindable.name] = newValue;
        }
      }
    }

    let proto = CustomElement.prototype;
    let observedAttributes = [];

    behavior.properties.forEach(prop => {
      let descriptor = {
        get: function() {
          return this.au.controller.viewModel[prop.name];
        },
        set: function(value) {
          this.au.controller.viewModel[prop.name] = value;
        }
      };

      descriptor.get.getObserver = function(obj) {
        return getObserver(behavior, obj.au.controller.viewModel, prop.name);
      };

      observedAttributes.push(prop.attribute);
      Object.defineProperty(proto, prop.name, descriptor);
    });

    Object.defineProperty(CustomElement, 'observedAttributes', {
      get: function() {
        return observedAttributes;
      }
    });

    Object.keys(behavior.target.prototype).forEach(key => {
      let value = behavior.target.prototype[key];

      if(typeof value === 'function') {
        proto[key] = function(...args) {
          return this.au.controller.viewModel[key](...args);
        };
      }
    });

    return CustomElement;
  }
}

function getObserver(behavior, instance, name) {
  let lookup = instance.__observers__;

  if (lookup === undefined) {
    if (!behavior.isInitialized) {
      behavior.initialize(Container.instance || new Container(), instance.constructor);
    }

    lookup = behavior.observerLocator.getOrCreateObserversLookup(instance);
    behavior._ensurePropertiesDefined(instance, lookup);
  }

  return lookup[name];
}

function elementContainerGet(key) {
  if (key === DOM.Element) {
    return this.element;
  }

  if (key === BoundViewFactory) {
    if (this.boundViewFactory) {
      return this.boundViewFactory;
    }

    let factory = this.instruction.viewFactory;
    let partReplacements = this.partReplacements;

    if (partReplacements) {
      factory = partReplacements[factory.part] || factory;
    }

    this.boundViewFactory = new BoundViewFactory(this, factory, partReplacements);
    return this.boundViewFactory;
  }

  if (key === ViewSlot) {
    if (this.viewSlot === undefined) {
      this.viewSlot = new ViewSlot(this.element, this.instruction.anchorIsContainer);
      this.element.isContentProjectionSource = this.instruction.lifting;
      this.children.push(this.viewSlot);
    }

    return this.viewSlot;
  }

  if (key === ViewResources) {
    return this.viewResources;
  }

  if (key === TargetInstruction) {
    return this.instruction;
  }

  return this.superGet(key);
}

function createElementContainer(parent, element, instruction, children, partReplacements, resources) {
  let container = parent.createChild();
  let provider = instruction.providers[0];

  container.element = element;
  container.instruction = instruction;
  container.children = children;
  container.viewResources = resources;
  container.partReplacements = partReplacements;

  container.registerSingleton(provider, provider);

  container.superGet = container.get;
  container.get = elementContainerGet;

  return container;
}
<|endoftext|>


<commit_before>function updateHistogram (guests)
{
  var props=[];
  var i=0;
  for (var g in guests) {
    var parprop= guests[g]['parprop'];

    if (parprop > 0) {
      props[i]=parprop / 100;
      i++;
    }
  }

  var div= document.getElementById('dhistogram');
  var svg= genDistSVG(props);

  div.replaceChild(svg, div.firstElementChild);
}

function updateGuestList(guests)
{
  var table= document.createElement('table');
  table.setAttribute('id', 'guesttab');

  for (var g in guests) {
    var tr= document.createElement('tr');

    var tname=document.createElement('td');
    var tprop=document.createElement('td');
    var tlink=document.createElement('td');
    var tdel= document.createElement('td');

    var alink=document.createElement('a')

    tname.textContent= guests[g].name;
    tprop.textContent=
      (guests[g].parprop > 0) ? guests[g].parprop + '%' : '?';

    if(guests[g].token) {
      var gtoken= guests[g].token;

      alink.textContent='link'
      alink.href='/event#' + gtoken
      tlink.appendChild(alink);

      tdel.textContent= 'remove';
      tdel.onclick=
        'onDeleteGuestButton(' + gtoken + ')';
    }
    else {
      tlink.style.display='none';
      tdel.style.display='none'
    }

    tr.appendChild(tname);
    tr.appendChild(tprop);
    tr.appendChild(tlink);
    tr.appendChild(tdel);

    table.appendChild(tr);
  }

  var oldtable= document.getElementById('guesttab');

  oldtable.parentElement.replaceChild(table, oldtable);
}

function reloadMyInfo()
{
  function onReceiveMyInfo(guest) {
    var namein= document.getElementById('guestnamein');
    var propin= document.getElementById('guestpropin');

    namein.value= guest.name;
    propin.value= guest.parprop;

    var domObjs= document.getElementsByClassName('admin');
    for (var k=0; k<domObjs.length; k++) {
      domObjs[k].style.display= guest.admin ? '' : 'none';
    }
  }

  var token= window.location.hash.substring(1);

  ivGetMyInfo(token, onReceiveMyInfo);
}

function reloadChatMessages()
{
  function onReceiveMessages(ret) {
    var msgs= ret['msgs'];

    var div= document.createElement('div');
    div.setAttribute('id', 'dchatmessages');

    for (var m in msgs) {
      var p= document.createElement('p');

      var line= msgs[m].author + ': ' + msgs[m].content;

      p.textContent= line;

      div.appendChild(p);
    }

    var olddiv= document.getElementById('dchatmessages');

    //var oldHeight= olddiv.scrollHeight;

    olddiv.parentElement.replaceChild(div, olddiv);

    //if(oldHeight != div.scrollHeight) {
    //  div.scrollTop= div.scrollHeight;
    //}
  }

  var token= window.location.hash.substring(1);

  ivGetMessages(token, onReceiveMessages);
}

function reloadEventInfo()
{
  function onReceiveEventInfo(event) {

    var guests= event.guests;

    guests.sort(function (a,b) {
      return (b.parprop - a.parprop);
    });

    updateHistogram(guests);
    updateGuestList(guests);

    var headline= document.getElementById('headline');
    var pagetitle= document.getElementById('pagetitle');

    headline.textContent= event.name;
    pagetitle.textContent= event.name;

    var namein= document.getElementById('eventnamein');
    var descin= document.getElementById('eventdescin');

    namein.value= event.name;
    descin.value= event.description;

    var desclines= event.description.split('\n');

    var div= document.createElement('div');
    div.setAttribute('id', 'ddescription');
    div.setAttribute('class', 'framed');

    for (lne in desclines) {
      var p= document.createElement('p');

      p.textContent= desclines[lne];

      if(desclines[lne] == '.') {
        p.style.visibility='hidden';
      }

      div.appendChild(p);
    }

    var olddiv= document.getElementById('ddescription');
    olddiv.parentElement.replaceChild(div, olddiv);
  }

  var token= window.location.hash.substring(1);

  ivGetEventInfo(token, onReceiveEventInfo);
}

function reloadComplete()
{
  reloadMyInfo();
  reloadEventInfo();
  reloadChatMessages();
}

function onPageLoad()
{
  reloadComplete();

  setInterval(reloadChatMessages, 20000);

  window.onhashchange= reloadComplete();
}

function onEditGuestButton()
{
  function onGuestEdited() {
    reloadEventInfo();
  }

  var token= window.location.hash.substring(1);
  var namein= document.getElementById('guestnamein');
  var propin= document.getElementById('guestpropin');

  var info={};

  info['name']= namein.value;
  info['parprop']= parseInt(propin.value);

  ivSetMyInfo(token, info, onGuestEdited);
}

function onChatMsgButton()
{
  function onMessageAdded(loc) {
    reloadChatMessages();
  }

  var token= window.location.hash.substring(1);
  var msgin= document.getElementById('chatmsgin');

  var info={};

  info['content']= msgin.value;
  msgin.value='';

  ivCreateMsg(token, info, onMessageAdded);
}

function onAddGuestButton()
{
  function onGuestAdded(loc) {
    reloadEventInfo();
  }

  var token= window.location.hash.substring(1);
  var namein= document.getElementById('guestnamein');
  var propin= document.getElementById('guestpropin');

  var info={};

  info['name']= namein.value;
  info['parprop']= parseInt(propin.value);

  ivCreateGuest(token, info, onGuestAdded);
}

function onEditEventButton()
{
  function onEventEdited() {
    reloadEventInfo();
  }

  var token= window.location.hash.substring(1);
  var namein= document.getElementById('eventnamein');
  var descin= document.getElementById('eventdescin');

  var info={};

  info['name']= namein.value;
  info['description']= descin.value;

  ivSetEventInfo(token, info, onEventEdited);
}

function onAddEventButton()
{
  function onEventAdded(loc) {
    var locs= loc.split('/')

    var token= locs[locs.length-1];

    window.location= '/event#' + token;
  }

  var info={};

  info['admin']= true;

  ivCreateEvent(info, onEventAdded);
}
<commit_msg>Scrollen des Chat Fensters gefixt<commit_after>function updateHistogram (guests)
{
  var props=[];
  var i=0;
  for (var g in guests) {
    var parprop= guests[g]['parprop'];

    if (parprop > 0) {
      props[i]=parprop / 100;
      i++;
    }
  }

  var div= document.getElementById('dhistogram');
  var svg= genDistSVG(props);

  div.replaceChild(svg, div.firstElementChild);
}

function updateGuestList(guests)
{
  var table= document.createElement('table');
  table.setAttribute('id', 'guesttab');

  for (var g in guests) {
    var tr= document.createElement('tr');

    var tname=document.createElement('td');
    var tprop=document.createElement('td');
    var tlink=document.createElement('td');
    var tdel= document.createElement('td');

    var alink=document.createElement('a')

    tname.textContent= guests[g].name;
    tprop.textContent=
      (guests[g].parprop > 0) ? guests[g].parprop + '%' : '?';

    if(guests[g].token) {
      var gtoken= guests[g].token;

      alink.textContent='link'
      alink.href='/event#' + gtoken
      tlink.appendChild(alink);

      tdel.textContent= 'remove';
      tdel.onclick=
        'onDeleteGuestButton(' + gtoken + ')';
    }
    else {
      tlink.style.display='none';
      tdel.style.display='none'
    }

    tr.appendChild(tname);
    tr.appendChild(tprop);
    tr.appendChild(tlink);
    tr.appendChild(tdel);

    table.appendChild(tr);
  }

  var oldtable= document.getElementById('guesttab');

  oldtable.parentElement.replaceChild(table, oldtable);
}

function reloadMyInfo()
{
  function onReceiveMyInfo(guest) {
    var namein= document.getElementById('guestnamein');
    var propin= document.getElementById('guestpropin');

    namein.value= guest.name;
    propin.value= guest.parprop;

    var domObjs= document.getElementsByClassName('admin');
    for (var k=0; k<domObjs.length; k++) {
      domObjs[k].style.display= guest.admin ? '' : 'none';
    }
  }

  var token= window.location.hash.substring(1);

  ivGetMyInfo(token, onReceiveMyInfo);
}

function reloadChatMessages()
{
  function onReceiveMessages(ret) {
    var msgs= ret['msgs'];

    // check if new messages need drawing
    if ((msgs.length > 0) &&
        (msgs[msgs.length-1] != reloadChatMessages.lastMsg)) {

      reloadChatMessages.lastMsg= msgs[msgs.length-1];

      var div= document.createElement('div');
      div.setAttribute('id', 'dchatmessages');

      for (var m in msgs) {
        var p= document.createElement('p');

        var line= msgs[m].author + ': ' + msgs[m].content;

        p.textContent= line;

        div.appendChild(p);
      }

      var olddiv= document.getElementById('dchatmessages');

      olddiv.parentElement.replaceChild(div, olddiv);

      // scroll to the newest messages
      div.scrollTop= div.scrollHeight;
    }
  }

  var token= window.location.hash.substring(1);

  ivGetMessages(token, onReceiveMessages);
}

function reloadEventInfo()
{
  function onReceiveEventInfo(event) {

    var guests= event.guests;

    guests.sort(function (a,b) {
      return (b.parprop - a.parprop);
    });

    updateHistogram(guests);
    updateGuestList(guests);

    var headline= document.getElementById('headline');
    var pagetitle= document.getElementById('pagetitle');

    headline.textContent= event.name;
    pagetitle.textContent= event.name;

    var namein= document.getElementById('eventnamein');
    var descin= document.getElementById('eventdescin');

    namein.value= event.name;
    descin.value= event.description;

    var desclines= event.description.split('\n');

    var div= document.createElement('div');
    div.setAttribute('id', 'ddescription');
    div.setAttribute('class', 'framed');

    for (lne in desclines) {
      var p= document.createElement('p');

      p.textContent= desclines[lne];

      if(desclines[lne] == '.') {
        p.style.visibility='hidden';
      }

      div.appendChild(p);
    }

    var olddiv= document.getElementById('ddescription');
    olddiv.parentElement.replaceChild(div, olddiv);
  }

  var token= window.location.hash.substring(1);

  ivGetEventInfo(token, onReceiveEventInfo);
}

function reloadComplete()
{
  reloadMyInfo();
  reloadEventInfo();
  reloadChatMessages();
}

function onPageLoad()
{
  reloadComplete();

  setInterval(reloadChatMessages, 20000);

  window.onhashchange= reloadComplete;
}

function onEditGuestButton()
{
  function onGuestEdited() {
    reloadEventInfo();
  }

  var token= window.location.hash.substring(1);
  var namein= document.getElementById('guestnamein');
  var propin= document.getElementById('guestpropin');

  var info={};

  info['name']= namein.value;
  info['parprop']= parseInt(propin.value);

  ivSetMyInfo(token, info, onGuestEdited);
}

function onChatMsgButton()
{
  function onMessageAdded(loc) {
    reloadChatMessages();
  }

  var token= window.location.hash.substring(1);
  var msgin= document.getElementById('chatmsgin');

  var info={};

  info['content']= msgin.value;
  msgin.value='';

  ivCreateMsg(token, info, onMessageAdded);
}

function onAddGuestButton()
{
  function onGuestAdded(loc) {
    reloadEventInfo();
  }

  var token= window.location.hash.substring(1);
  var namein= document.getElementById('guestnamein');
  var propin= document.getElementById('guestpropin');

  var info={};

  info['name']= namein.value;
  info['parprop']= parseInt(propin.value);

  ivCreateGuest(token, info, onGuestAdded);
}

function onEditEventButton()
{
  function onEventEdited() {
    reloadEventInfo();
  }

  var token= window.location.hash.substring(1);
  var namein= document.getElementById('eventnamein');
  var descin= document.getElementById('eventdescin');

  var info={};

  info['name']= namein.value;
  info['description']= descin.value;

  ivSetEventInfo(token, info, onEventEdited);
}

function onAddEventButton()
{
  function onEventAdded(loc) {
    var locs= loc.split('/')

    var token= locs[locs.length-1];

    window.location= '/event#' + token;
  }

  var info={};

  info['admin']= true;

  ivCreateEvent(info, onEventAdded);
}
<|endoftext|>


<commit_before>(function (){
"use strict";

var BBM = require("./BBM.js");

//Serializes this subtree into BBM.
function toBBM()
{

}

BBM.prototype.toBBM = toBBM;

}());<commit_msg>Start authoring BBm.fn.toBBM() plugin.<commit_after>(function (){
"use strict";

var BBM = require("./BBM.js");
var ENUM = BBM.ENUM;
var REGSTR =
[
  "\"{3,}"
, "--"
, "\\*{2}"
, "\\^{2}"
, ",,"
, "__"
, "''"
, "\\?<"
, "!<"
, "#<"
, "#\\["
, "-\\["
, "\\]"
];

var REGEX = new RegExp(REGSTR.join("|"), "g");

//Serializes this subtree into BBM.
function toBBM()
{

}

BBM.prototype.toBBM = toBBM;

}());<|endoftext|>


<commit_before>/*
 * This file is part of the nivo project.
 *
 * Copyright 2016-present, Raphaël Benitte.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
import React from 'react'
import PropTypes from 'prop-types'
import { sortBy } from 'lodash'
import { line } from 'd3-shape'
import compose from 'recompose/compose'
import pure from 'recompose/pure'
import withPropsOnChange from 'recompose/withPropsOnChange'
import defaultProps from 'recompose/defaultProps'
import Nivo from '../../../Nivo'
import { marginPropType, motionPropTypes, curvePropMapping, curvePropType } from '../../../props'
import { getInheritedColorGenerator } from '../../../lib/colorUtils'
import { withTheme, withColors, withMargin } from '../../../hocs'
import Container from '../Container'
import SvgWrapper from '../SvgWrapper'
import {
    getScales,
    getStackedScales,
    generateLines,
    generateStackedLines,
} from '../../../lib/charts/line'
import Axes from '../../axes/Axes'
import Grid from '../../axes/Grid'
import LineLines from './LineLines'
import LineSlices from './LineSlices'
import LineMarkers from './LineMarkers'

const Line = ({
    lines,
    lineGenerator,
    xScale,
    yScale,
    slices,

    // dimensions
    margin,
    width,
    height,
    outerWidth,
    outerHeight,

    // axes & grid
    axisTop,
    axisRight,
    axisBottom,
    axisLeft,
    enableGridX,
    enableGridY,

    // markers
    enableMarkers,
    markersSize,
    markersColor,
    markersBorderWidth,
    markersBorderColor,
    enableMarkersLabel,
    markersLabel,
    markersLabelFormat,
    markersLabelYOffset,

    // theming
    theme,

    // motion
    animate,
    motionStiffness,
    motionDamping,

    isInteractive,
}) => {
    const motionProps = {
        animate,
        motionDamping,
        motionStiffness,
    }

    return (
        <Container isInteractive={isInteractive}>
            {({ showTooltip, hideTooltip }) =>
                <SvgWrapper width={outerWidth} height={outerHeight} margin={margin}>
                    <Grid
                        theme={theme}
                        width={width}
                        height={height}
                        xScale={enableGridX ? xScale : null}
                        yScale={enableGridY ? yScale : null}
                        {...motionProps}
                    />
                    <Axes
                        xScale={xScale}
                        yScale={yScale}
                        width={width}
                        height={height}
                        theme={theme}
                        top={axisTop}
                        right={axisRight}
                        bottom={axisBottom}
                        left={axisLeft}
                        {...motionProps}
                    />
                    <LineLines lines={lines} lineGenerator={lineGenerator} {...motionProps} />
                    {isInteractive &&
                        <LineSlices
                            slices={slices}
                            height={height}
                            showTooltip={showTooltip}
                            hideTooltip={hideTooltip}
                        />}
                    {enableMarkers &&
                        <LineMarkers
                            lines={lines}
                            size={markersSize}
                            color={getInheritedColorGenerator(markersColor)}
                            borderWidth={markersBorderWidth}
                            borderColor={getInheritedColorGenerator(markersBorderColor)}
                            enableLabel={enableMarkersLabel}
                            label={markersLabel}
                            labelFormat={markersLabelFormat}
                            labelYOffset={markersLabelYOffset}
                            theme={theme}
                            {...motionProps}
                        />}
                </SvgWrapper>}
        </Container>
    )
}

Line.propTypes = {
    // data
    data: PropTypes.arrayOf(
        PropTypes.shape({
            id: PropTypes.string.isRequired,
            data: PropTypes.arrayOf(
                PropTypes.shape({
                    x: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
                    y: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
                })
            ).isRequired,
        })
    ).isRequired,

    stacked: PropTypes.bool.isRequired,
    curve: curvePropType.isRequired,
    lineGenerator: PropTypes.func.isRequired,

    lines: PropTypes.array.isRequired,
    slices: PropTypes.array.isRequired,

    xScale: PropTypes.func.isRequired,
    yScale: PropTypes.func.isRequired,

    // dimensions
    width: PropTypes.number.isRequired,
    height: PropTypes.number.isRequired,
    margin: marginPropType,
    outerWidth: PropTypes.number.isRequired,
    outerHeight: PropTypes.number.isRequired,

    // axes & grid
    axisTop: PropTypes.object,
    axisRight: PropTypes.object,
    axisBottom: PropTypes.object,
    axisLeft: PropTypes.object,
    enableGridX: PropTypes.bool.isRequired,
    enableGridY: PropTypes.bool.isRequired,

    // markers
    enableMarkers: PropTypes.bool.isRequired,
    markersSize: PropTypes.number.isRequired,
    markersColor: PropTypes.any.isRequired,
    markersBorderWidth: PropTypes.number.isRequired,
    markersBorderColor: PropTypes.any.isRequired,
    enableMarkersLabel: PropTypes.bool.isRequired,

    // theming
    theme: PropTypes.object.isRequired,
    colors: PropTypes.any.isRequired,
    colorBy: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
    getColor: PropTypes.func.isRequired,

    // motion
    ...motionPropTypes,

    isInteractive: PropTypes.bool.isRequired,
}

export const LineDefaultProps = {
    stacked: false,
    curve: 'linear',

    // axes & grid
    axisBottom: {},
    axisLeft: {},
    enableGridX: true,
    enableGridY: true,

    // markers
    enableMarkers: true,
    markersSize: 6,
    markersColor: 'inherit',
    markersBorderWidth: 0,
    markersBorderColor: 'inherit',
    enableMarkersLabel: false,

    // theming
    theme: {},
    colors: 'nivo',
    colorBy: 'id',

    // motion
    animate: true,
    motionStiffness: Nivo.defaults.motionStiffness,
    motionDamping: Nivo.defaults.motionDamping,

    isInteractive: true,
}

const enhance = compose(
    defaultProps(LineDefaultProps),
    withTheme(),
    withColors(),
    withMargin(),
    withPropsOnChange(['curve'], ({ curve }) => ({
        lineGenerator: line().x(d => d.x).y(d => d.y).curve(curvePropMapping[curve]),
    })),
    withPropsOnChange(
        (props, nextProps) =>
            props.data !== nextProps.data ||
            props.stacked !== nextProps.stacked ||
            props.width !== nextProps.width ||
            props.height !== nextProps.height,
        ({ data, stacked, width, height, margin }) => {
            let scales
            if (stacked === true) {
                scales = getStackedScales(data, width, height)
            } else {
                scales = getScales(data, width, height)
            }

            return {
                margin,
                width,
                height,
                ...scales,
            }
        }
    ),
    withPropsOnChange(
        ['getColor', 'xScale', 'yScale'],
        ({ data, stacked, xScale, yScale, getColor }) => {
            let lines
            if (stacked === true) {
                lines = generateStackedLines(data, xScale, yScale, getColor)
            } else {
                lines = generateLines(data, xScale, yScale, getColor)
            }

            const slices = xScale.domain().map((id, i) => {
                let points = sortBy(
                    lines.map(line => ({
                        id: line.id,
                        value: line.points[i].value,
                        y: line.points[i].y,
                        color: line.color,
                    })),
                    'y'
                )

                return {
                    id,
                    x: xScale(id),
                    points,
                }
            })

            return { lines, slices }
        }
    ),
    pure
)

export default enhance(Line)
<commit_msg>feat(line): add ability to disable stack tooltip on line chart<commit_after>/*
 * This file is part of the nivo project.
 *
 * Copyright 2016-present, Raphaël Benitte.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
import React from 'react'
import PropTypes from 'prop-types'
import { sortBy } from 'lodash'
import { line } from 'd3-shape'
import compose from 'recompose/compose'
import pure from 'recompose/pure'
import withPropsOnChange from 'recompose/withPropsOnChange'
import defaultProps from 'recompose/defaultProps'
import Nivo from '../../../Nivo'
import { marginPropType, motionPropTypes, curvePropMapping, curvePropType } from '../../../props'
import { getInheritedColorGenerator } from '../../../lib/colorUtils'
import { withTheme, withColors, withMargin } from '../../../hocs'
import Container from '../Container'
import SvgWrapper from '../SvgWrapper'
import {
    getScales,
    getStackedScales,
    generateLines,
    generateStackedLines,
} from '../../../lib/charts/line'
import Axes from '../../axes/Axes'
import Grid from '../../axes/Grid'
import LineLines from './LineLines'
import LineSlices from './LineSlices'
import LineMarkers from './LineMarkers'

const Line = ({
    lines,
    lineGenerator,
    xScale,
    yScale,
    slices,

    // dimensions
    margin,
    width,
    height,
    outerWidth,
    outerHeight,

    // axes & grid
    axisTop,
    axisRight,
    axisBottom,
    axisLeft,
    enableGridX,
    enableGridY,

    // markers
    enableMarkers,
    markersSize,
    markersColor,
    markersBorderWidth,
    markersBorderColor,
    enableMarkersLabel,
    markersLabel,
    markersLabelFormat,
    markersLabelYOffset,

    // theming
    theme,

    // motion
    animate,
    motionStiffness,
    motionDamping,

    // interactivity
    isInteractive,

    // stackTooltip
    enableStackTooltip,
}) => {
    const motionProps = {
        animate,
        motionDamping,
        motionStiffness,
    }

    return (
        <Container isInteractive={isInteractive}>
            {({ showTooltip, hideTooltip }) =>
                <SvgWrapper width={outerWidth} height={outerHeight} margin={margin}>
                    <Grid
                        theme={theme}
                        width={width}
                        height={height}
                        xScale={enableGridX ? xScale : null}
                        yScale={enableGridY ? yScale : null}
                        {...motionProps}
                    />
                    <Axes
                        xScale={xScale}
                        yScale={yScale}
                        width={width}
                        height={height}
                        theme={theme}
                        top={axisTop}
                        right={axisRight}
                        bottom={axisBottom}
                        left={axisLeft}
                        {...motionProps}
                    />
                    <LineLines lines={lines} lineGenerator={lineGenerator} {...motionProps} />
                    {isInteractive &&
                        enableStackTooltip &&
                        <LineSlices
                            slices={slices}
                            height={height}
                            showTooltip={showTooltip}
                            hideTooltip={hideTooltip}
                        />}
                    {enableMarkers &&
                        <LineMarkers
                            lines={lines}
                            size={markersSize}
                            color={getInheritedColorGenerator(markersColor)}
                            borderWidth={markersBorderWidth}
                            borderColor={getInheritedColorGenerator(markersBorderColor)}
                            enableLabel={enableMarkersLabel}
                            label={markersLabel}
                            labelFormat={markersLabelFormat}
                            labelYOffset={markersLabelYOffset}
                            theme={theme}
                            {...motionProps}
                        />}
                </SvgWrapper>}
        </Container>
    )
}

Line.propTypes = {
    // data
    data: PropTypes.arrayOf(
        PropTypes.shape({
            id: PropTypes.string.isRequired,
            data: PropTypes.arrayOf(
                PropTypes.shape({
                    x: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
                    y: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
                })
            ).isRequired,
        })
    ).isRequired,

    stacked: PropTypes.bool.isRequired,
    curve: curvePropType.isRequired,
    lineGenerator: PropTypes.func.isRequired,

    lines: PropTypes.array.isRequired,
    slices: PropTypes.array.isRequired,

    xScale: PropTypes.func.isRequired,
    yScale: PropTypes.func.isRequired,

    // dimensions
    width: PropTypes.number.isRequired,
    height: PropTypes.number.isRequired,
    margin: marginPropType,
    outerWidth: PropTypes.number.isRequired,
    outerHeight: PropTypes.number.isRequired,

    // axes & grid
    axisTop: PropTypes.object,
    axisRight: PropTypes.object,
    axisBottom: PropTypes.object,
    axisLeft: PropTypes.object,
    enableGridX: PropTypes.bool.isRequired,
    enableGridY: PropTypes.bool.isRequired,

    // markers
    enableMarkers: PropTypes.bool.isRequired,
    markersSize: PropTypes.number.isRequired,
    markersColor: PropTypes.any.isRequired,
    markersBorderWidth: PropTypes.number.isRequired,
    markersBorderColor: PropTypes.any.isRequired,
    enableMarkersLabel: PropTypes.bool.isRequired,

    // theming
    theme: PropTypes.object.isRequired,
    colors: PropTypes.any.isRequired,
    colorBy: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
    getColor: PropTypes.func.isRequired,

    // motion
    ...motionPropTypes,

    // interactivity
    isInteractive: PropTypes.bool.isRequired,

    // stack tooltip
    enableStackTooltip: PropTypes.bool.isRequired,
}

export const LineDefaultProps = {
    stacked: false,
    curve: 'linear',

    // axes & grid
    axisBottom: {},
    axisLeft: {},
    enableGridX: true,
    enableGridY: true,

    // markers
    enableMarkers: true,
    markersSize: 6,
    markersColor: 'inherit',
    markersBorderWidth: 0,
    markersBorderColor: 'inherit',
    enableMarkersLabel: false,

    // theming
    theme: {},
    colors: 'nivo',
    colorBy: 'id',

    // motion
    animate: true,
    motionStiffness: Nivo.defaults.motionStiffness,
    motionDamping: Nivo.defaults.motionDamping,

    // interactivity
    isInteractive: true,

    // stack tooltip
    enableStackTooltip: true,
}

const enhance = compose(
    defaultProps(LineDefaultProps),
    withTheme(),
    withColors(),
    withMargin(),
    withPropsOnChange(['curve'], ({ curve }) => ({
        lineGenerator: line().x(d => d.x).y(d => d.y).curve(curvePropMapping[curve]),
    })),
    withPropsOnChange(
        (props, nextProps) =>
            props.data !== nextProps.data ||
            props.stacked !== nextProps.stacked ||
            props.width !== nextProps.width ||
            props.height !== nextProps.height,
        ({ data, stacked, width, height, margin }) => {
            let scales
            if (stacked === true) {
                scales = getStackedScales(data, width, height)
            } else {
                scales = getScales(data, width, height)
            }

            return {
                margin,
                width,
                height,
                ...scales,
            }
        }
    ),
    withPropsOnChange(
        ['getColor', 'xScale', 'yScale'],
        ({ data, stacked, xScale, yScale, getColor }) => {
            let lines
            if (stacked === true) {
                lines = generateStackedLines(data, xScale, yScale, getColor)
            } else {
                lines = generateLines(data, xScale, yScale, getColor)
            }

            const slices = xScale.domain().map((id, i) => {
                let points = sortBy(
                    lines.map(line => ({
                        id: line.id,
                        value: line.points[i].value,
                        y: line.points[i].y,
                        color: line.color,
                    })),
                    'y'
                )

                return {
                    id,
                    x: xScale(id),
                    points,
                }
            })

            return { lines, slices }
        }
    ),
    pure
)

export default enhance(Line)
<|endoftext|>


<commit_before>import React from 'react'
import * as R from 'ramda'
import debounce from 'lodash.debounce'
import AnkiExport from 'anki-apkg-export'
import { saveAs } from 'file-saver'

import normalizeWordData from '../../core/normalizeWordData/normalizeWordData'
import makeCard from '../../core/makeCard/makeCard'

import splitByWord from '../../utils/splitByWord/splitByWord'
import maybePluralize from '../../utils/maybePluralize/maybePluralize'
import wordToData from '../../utils/wordToData/wordToData'
import getDateString from '../../utils/getDateString/getDateString'

import GithubCorner from 'react-github-corner'
import LinearProgress from 'material-ui/LinearProgress'
import Header from '../Header/Header'
import ImportOptions from '../ImportOptions/ImportOptions'
import DownloadButton from '../DownloadButton/DownloadButton'
import ResultCards from '../ResultCards/ResultCards'
import UserWords from '../UserWords/UserWords'
import DeckName from '../DeckName/DeckName'

import './App.css'

const sanitizeForFilename = R.pipe(R.replace(/ /g, ''), R.replace(/,/g, '_'))

const template = {
    css: `
			.card { font-family: arial; font-size: 20px; text-align: center; color: black; background-color: white; }
			.lta-example { font-style: italic; }
			.lta-form { font-weight: bold; }
		`
}

export default class App extends React.Component {
    state = {
        inputValue: '',
        wordsDataArr: [],
        deckName: 'English words'
    }

    handleDeckNameChange = event => {
        this.setState({
            deckName: event.target.value
        })
    }

    handleInputChange = async event => {
        const inputValue = event.target.value

        this.setState({
            inputValue
        })

        this.debouncedComposeCards()
    }

    debouncedComposeCards = debounce(() => {
        this.setState({ wordsDataArr: [] })

        const words = splitByWord(this.state.inputValue)

        R.map(wordToData, words).forEach(async (request, i) => {
            const wordData = await request

            this.setState(prevState => {
                const newWordsDataArr = [...prevState.wordsDataArr]
                newWordsDataArr[i] = wordData
                return {
                    wordsDataArr: newWordsDataArr
                }
            })
        })
    }, 500)

    handleDownload = event => {
        event.preventDefault()

        const deck = new AnkiExport(this.state.deckName, template)

        const cardsArr = R.pipe(
            R.filter(Boolean), // reject items from wordsDataArr, which didn't recieve response yet
            R.map(normalizeWordData),
            R.flatten,
            R.reject(R.isEmpty),
            R.map(makeCard)
        )(this.state.wordsDataArr)

        cardsArr.forEach(card => {
            deck.addCard(card.front, card.back)
        })

        deck
            .save()
            .then(file => saveAs(file, `${this.state.deckName}.apkg`))
            .catch(console.error)
    }

    render() {
        const cardsArr = R.pipe(
            R.filter(Boolean), // reject non-existent word items and items, which didn't recieve response yet
            R.map(normalizeWordData),
            R.flatten,
            R.reject(R.isEmpty),
            R.map(makeCard),
            R.map(card => `${card.front}#${card.back}`)
        )(this.state.wordsDataArr)

        const cards = R.join('\n')(cardsArr)

        const wordsTotalNumber = this.state.wordsDataArr.length
        const cardsTotalNumber = cardsArr.length

        const wordsTotal = maybePluralize(wordsTotalNumber, 'word')
        const cardsTotal = maybePluralize(cardsTotalNumber, 'card')

        const totals = `${wordsTotal}, ${cardsTotal}`

        const date = getDateString()

        const wordsAmount = splitByWord(this.state.inputValue).length
        const wordsFetched = R.filter(Boolean)(this.state.wordsDataArr).length

        return (

                <GithubCorner
                    href="https://github.com/yakhinvadim/longman-to-anki"
                    bannerColor="#3f51b5"
                />

                <LinearProgress
                    mode="determinate"
                    value={wordsFetched}
                    max={wordsAmount}
                />

                <UserWords
                    value={this.state.inputValue}
                    onChange={this.handleInputChange}
                />

                {cards && <ResultCards value={cards} />}

                <DeckName
                    value={this.state.deckName}
                    onChange={this.handleDeckNameChange}
                />

                        {totals}

                    <DownloadButton
                        fileContent={encodeURIComponent(cards)}
                        fileName={`longman-to-anki_${date}_${sanitizeForFilename(
                            totals
                        )}`}
                        onClick={this.handleDownload}
                        disabled={!cards}
                    />

        )
    }
}
<commit_msg>fix: remove unused import<commit_after>import React from 'react'
import * as R from 'ramda'
import debounce from 'lodash.debounce'
import AnkiExport from 'anki-apkg-export'
import { saveAs } from 'file-saver'

import normalizeWordData from '../../core/normalizeWordData/normalizeWordData'
import makeCard from '../../core/makeCard/makeCard'

import splitByWord from '../../utils/splitByWord/splitByWord'
import maybePluralize from '../../utils/maybePluralize/maybePluralize'
import wordToData from '../../utils/wordToData/wordToData'
import getDateString from '../../utils/getDateString/getDateString'

import GithubCorner from 'react-github-corner'
import LinearProgress from 'material-ui/LinearProgress'
import Header from '../Header/Header'
import DownloadButton from '../DownloadButton/DownloadButton'
import ResultCards from '../ResultCards/ResultCards'
import UserWords from '../UserWords/UserWords'
import DeckName from '../DeckName/DeckName'

import './App.css'

const sanitizeForFilename = R.pipe(R.replace(/ /g, ''), R.replace(/,/g, '_'))

const template = {
    css: `
			.card { font-family: arial; font-size: 20px; text-align: center; color: black; background-color: white; }
			.lta-example { font-style: italic; }
			.lta-form { font-weight: bold; }
		`
}

export default class App extends React.Component {
    state = {
        inputValue: '',
        wordsDataArr: [],
        deckName: 'English words'
    }

    handleDeckNameChange = event => {
        this.setState({
            deckName: event.target.value
        })
    }

    handleInputChange = async event => {
        const inputValue = event.target.value

        this.setState({
            inputValue
        })

        this.debouncedComposeCards()
    }

    debouncedComposeCards = debounce(() => {
        this.setState({ wordsDataArr: [] })

        const words = splitByWord(this.state.inputValue)

        R.map(wordToData, words).forEach(async (request, i) => {
            const wordData = await request

            this.setState(prevState => {
                const newWordsDataArr = [...prevState.wordsDataArr]
                newWordsDataArr[i] = wordData
                return {
                    wordsDataArr: newWordsDataArr
                }
            })
        })
    }, 500)

    handleDownload = event => {
        event.preventDefault()

        const deck = new AnkiExport(this.state.deckName, template)

        const cardsArr = R.pipe(
            R.filter(Boolean), // reject items from wordsDataArr, which didn't recieve response yet
            R.map(normalizeWordData),
            R.flatten,
            R.reject(R.isEmpty),
            R.map(makeCard)
        )(this.state.wordsDataArr)

        cardsArr.forEach(card => {
            deck.addCard(card.front, card.back)
        })

        deck
            .save()
            .then(file => saveAs(file, `${this.state.deckName}.apkg`))
            .catch(console.error)
    }

    render() {
        const cardsArr = R.pipe(
            R.filter(Boolean), // reject non-existent word items and items, which didn't recieve response yet
            R.map(normalizeWordData),
            R.flatten,
            R.reject(R.isEmpty),
            R.map(makeCard),
            R.map(card => `${card.front}#${card.back}`)
        )(this.state.wordsDataArr)

        const cards = R.join('\n')(cardsArr)

        const wordsTotalNumber = this.state.wordsDataArr.length
        const cardsTotalNumber = cardsArr.length

        const wordsTotal = maybePluralize(wordsTotalNumber, 'word')
        const cardsTotal = maybePluralize(cardsTotalNumber, 'card')

        const totals = `${wordsTotal}, ${cardsTotal}`

        const date = getDateString()

        const wordsAmount = splitByWord(this.state.inputValue).length
        const wordsFetched = R.filter(Boolean)(this.state.wordsDataArr).length

        return (

                <GithubCorner
                    href="https://github.com/yakhinvadim/longman-to-anki"
                    bannerColor="#3f51b5"
                />

                <LinearProgress
                    mode="determinate"
                    value={wordsFetched}
                    max={wordsAmount}
                />

                <UserWords
                    value={this.state.inputValue}
                    onChange={this.handleInputChange}
                />

                {cards && <ResultCards value={cards} />}

                <DeckName
                    value={this.state.deckName}
                    onChange={this.handleDeckNameChange}
                />

                        {totals}

                    <DownloadButton
                        fileContent={encodeURIComponent(cards)}
                        fileName={`longman-to-anki_${date}_${sanitizeForFilename(
                            totals
                        )}`}
                        onClick={this.handleDownload}
                        disabled={!cards}
                    />

        )
    }
}
<|endoftext|>