<commit_before>describe("timelineManager", function() {
    var scope,
        $httpBackend;
    beforeEach(angular.mock.module("feedhoos"));
    beforeEach(angular.mock.inject(function($rootScope, _$httpBackend_) {
        scope = $rootScope.$new();
        $httpBackend = _$httpBackend_;
        $httpBackend.expect("GET", "/reader/feed/list/all/")
            .respond('[' +
                '{"url": "", "type": "feed", "link": "", "id": 0, "title": "すべてのFeed"},' +
                '{"url": "http://example.com/hotentry/it.rss", "type": "feed", "link": "http://b.example.com/hotentry/it", "id": 1, "title": "title1"},' +
                '{"url": "http://www.example.com/blog/feed", "type": "feed", "link": "http://www.example.com/blog", "id": 2, "title": "title2"},' +
                '{"url": "https://www.example.com/projects.xml", "type": "feed", "link": "https://www.example.com/projects", "id": 3, "title": "title3"}' +
            ']');
    }));

    it('should set',inject(function(timelineManager) {
        timelineManager.set(scope, function() {});
        $httpBackend.flush();
        expect(timelineManager.data.length).toEqual(4);
    }));

    it('should get_feed_ids_by_folder_id',inject(function(timelineManager, bookmarkManager) {
        $httpBackend.expect("GET", "/bookmark/list/")
            .respond('{' +
                '"0": {"rating": 6, "folder_id": 0},' +
                '"1": {"rating": 3, "folder_id": 2},' +
                '"2": {"rating": 0, "folder_id": 0},' +
                '"3": {"rating": 1, "folder_id": 2}' +
            '}');
        timelineManager.set(scope, function() {});
        bookmarkManager.set(scope, function() {});
        $httpBackend.flush();
        var data = timelineManager.get_data_by_folder_id(2);
        expect(data.length).toEqual(2);
        expect(data[0].id).toEqual(1);
        expect(data[1].id).toEqual(3);
    }));

    it('should attachRating is add rating property timeline feed data',inject(function(timelineManager, bookmarkManager) {
        $httpBackend.expect("GET", "/bookmark/list/")
            .respond('{' +
                '"0": {"rating": 6, "folder_id": 0},' +
                '"1": {"rating": 3, "folder_id": 2},' +
                '"2": {"rating": 0, "folder_id": 0},' +
                '"3": {"rating": 1, "folder_id": 2}' +
            '}');
        timelineManager.set(scope, function() {});
        bookmarkManager.set(scope, function() {});
        $httpBackend.flush();
        timelineManager.attachRating();
        var data =  timelineManager.data;
        var expecting_data = [
                {"rating": 6, "url": "", "type": "feed", "link": "", "id": 0, "title": "すべてのFeed"},
                {"rating": 3, "url": "http://example.com/hotentry/it.rss", "type": "feed", "link": "http://b.example.com/hotentry/it", "id": 1, "title": "title1"},
                {"rating": 0, "url": "http://www.example.com/blog/feed", "type": "feed", "link": "http://www.example.com/blog", "id": 2, "title": "title2"},
                {"rating": 1, "url": "https://www.example.com/projects.xml", "type": "feed", "link": "https://www.example.com/projects", "id": 3, "title": "title3"}
            ];
        expect(expecting_data).toEqual(data);
    }));

    it('should sortByRating sort data by rating of bookmarkManager by join id ',inject(function(timelineManager, bookmarkManager) {
        $httpBackend.expect("GET", "/bookmark/list/")
            .respond('{' +
                '"0": {"rating": 6, "folder_id": 0},' +
                '"1": {"rating": 3, "folder_id": 2},' +
                '"2": {"rating": 0, "folder_id": 0},' +
                '"3": {"rating": 1, "folder_id": 2}' +
            '}');
        timelineManager.set(scope, function() {});
        bookmarkManager.set(scope, function() {});
        $httpBackend.flush();
        var data = timelineManager.sortByRating(timelineManager.data);
        var expecting_data = [
                {"url": "", "type": "feed", "link": "", "id": 0, "title": "すべてのFeed"},
                {"url": "http://example.com/hotentry/it.rss", "type": "feed", "link": "http://b.example.com/hotentry/it", "id": 1, "title": "title1"},
                {"url": "https://www.example.com/projects.xml", "type": "feed", "link": "https://www.example.com/projects", "id": 3, "title": "title3"},
                {"url": "http://www.example.com/blog/feed", "type": "feed", "link": "http://www.example.com/blog", "id": 2, "title": "title2"},
            ];
        expect(expecting_data).toEqual(data);
    }));

    it('should add one data ',inject(function(timelineManager) {
        timelineManager.set(scope, function() {});
        $httpBackend.flush();
        timelineManager.add({"url": "http://www.example.com/blog9/feed", "type": "feed", "link": "http://www.example.com/blog9", "id": 9, "title": "title9"});
        var expecting_data = [
                {"url": "", "type": "feed", "link": "", "id": 0, "title": "すべてのFeed"},
                {"url": "http://example.com/hotentry/it.rss", "type": "feed", "link": "http://b.example.com/hotentry/it", "id": 1, "title": "title1"},
                {"url": "http://www.example.com/blog/feed", "type": "feed", "link": "http://www.example.com/blog", "id": 2, "title": "title2"},
                {"url": "https://www.example.com/projects.xml", "type": "feed", "link": "https://www.example.com/projects", "id": 3, "title": "title3"},
                {"url": "http://www.example.com/blog9/feed", "type": "feed", "link": "http://www.example.com/blog9", "id": 9, "title": "title9"}
            ];
        expect(expecting_data).toEqual(timelineManager.data);
    }));
});
<commit_msg>add test<commit_after>describe("timelineManager", function() {
    var scope,
        $httpBackend;
    beforeEach(angular.mock.module("feedhoos"));
    beforeEach(angular.mock.inject(function($rootScope, _$httpBackend_) {
        scope = $rootScope.$new();
        $httpBackend = _$httpBackend_;
        $httpBackend.expect("GET", "/reader/feed/list/all/")
            .respond('[' +
                '{"url": "", "type": "feed", "link": "", "id": 0, "title": "すべてのFeed"},' +
                '{"url": "http://example.com/hotentry/it.rss", "type": "feed", "link": "http://b.example.com/hotentry/it", "id": 1, "title": "title1"},' +
                '{"url": "http://www.example.com/blog/feed", "type": "feed", "link": "http://www.example.com/blog", "id": 2, "title": "title2"},' +
                '{"url": "https://www.example.com/projects.xml", "type": "feed", "link": "https://www.example.com/projects", "id": 3, "title": "title3"}' +
            ']');
    }));

    it('should set',inject(function(timelineManager) {
        timelineManager.set(scope, function() {});
        $httpBackend.flush();
        expect(timelineManager.data.length).toEqual(4);
    }));

    it('should get_feed_ids_by_folder_id',inject(function(timelineManager, bookmarkManager) {
        $httpBackend.expect("GET", "/bookmark/list/")
            .respond('{' +
                '"0": {"rating": 6, "folder_id": 0},' +
                '"1": {"rating": 3, "folder_id": 2},' +
                '"2": {"rating": 0, "folder_id": 0},' +
                '"3": {"rating": 1, "folder_id": 2}' +
            '}');
        timelineManager.set(scope, function() {});
        bookmarkManager.set(scope, function() {});
        $httpBackend.flush();
        var data = timelineManager.get_data_by_folder_id(2);
        expect(data.length).toEqual(2);
        expect(data[0].id).toEqual(1);
        expect(data[1].id).toEqual(3);
    }));

    it('should attachRating is add rating property timeline feed data',inject(function(timelineManager, bookmarkManager) {
        $httpBackend.expect("GET", "/bookmark/list/")
            .respond('{' +
                '"0": {"rating": 6, "folder_id": 0},' +
                '"1": {"rating": 3, "folder_id": 2},' +
                '"2": {"rating": 0, "folder_id": 0},' +
                '"3": {"rating": 1, "folder_id": 2}' +
            '}');
        timelineManager.set(scope, function() {});
        bookmarkManager.set(scope, function() {});
        $httpBackend.flush();
        timelineManager.attachRating();
        var data =  timelineManager.data;
        var expecting_data = [
                {"rating": 6, "url": "", "type": "feed", "link": "", "id": 0, "title": "すべてのFeed"},
                {"rating": 3, "url": "http://example.com/hotentry/it.rss", "type": "feed", "link": "http://b.example.com/hotentry/it", "id": 1, "title": "title1"},
                {"rating": 0, "url": "http://www.example.com/blog/feed", "type": "feed", "link": "http://www.example.com/blog", "id": 2, "title": "title2"},
                {"rating": 1, "url": "https://www.example.com/projects.xml", "type": "feed", "link": "https://www.example.com/projects", "id": 3, "title": "title3"}
            ];
        expect(expecting_data).toEqual(data);
    }));

    it('should sortByRating sort data by rating of bookmarkManager by join id ',inject(function(timelineManager, bookmarkManager) {
        $httpBackend.expect("GET", "/bookmark/list/")
            .respond('{' +
                '"0": {"rating": 6, "folder_id": 0},' +
                '"1": {"rating": 3, "folder_id": 2},' +
                '"2": {"rating": 0, "folder_id": 0},' +
                '"3": {"rating": 1, "folder_id": 2}' +
            '}');
        timelineManager.set(scope, function() {});
        bookmarkManager.set(scope, function() {});
        $httpBackend.flush();
        var data = timelineManager.sortByRating(timelineManager.data);
        var expecting_data = [
                {"url": "", "type": "feed", "link": "", "id": 0, "title": "すべてのFeed"},
                {"url": "http://example.com/hotentry/it.rss", "type": "feed", "link": "http://b.example.com/hotentry/it", "id": 1, "title": "title1"},
                {"url": "https://www.example.com/projects.xml", "type": "feed", "link": "https://www.example.com/projects", "id": 3, "title": "title3"},
                {"url": "http://www.example.com/blog/feed", "type": "feed", "link": "http://www.example.com/blog", "id": 2, "title": "title2"},
            ];
        expect(expecting_data).toEqual(data);
    }));

    it('should add one data ',inject(function(timelineManager) {
        timelineManager.set(scope, function() {});
        $httpBackend.flush();
        timelineManager.add({"url": "http://www.example.com/blog9/feed", "type": "feed", "link": "http://www.example.com/blog9", "id": 9, "title": "title9"});
        var expecting_data = [
                {"url": "", "type": "feed", "link": "", "id": 0, "title": "すべてのFeed"},
                {"url": "http://example.com/hotentry/it.rss", "type": "feed", "link": "http://b.example.com/hotentry/it", "id": 1, "title": "title1"},
                {"url": "http://www.example.com/blog/feed", "type": "feed", "link": "http://www.example.com/blog", "id": 2, "title": "title2"},
                {"url": "https://www.example.com/projects.xml", "type": "feed", "link": "https://www.example.com/projects", "id": 3, "title": "title3"},
                {"url": "http://www.example.com/blog9/feed", "type": "feed", "link": "http://www.example.com/blog9", "id": 9, "title": "title9"}
            ];
        expect(expecting_data).toEqual(timelineManager.data);
    }));

    it('should remove one data ',inject(function(timelineManager) {
        timelineManager.set(scope, function() {});
        $httpBackend.flush();
        timelineManager.remove(2);
        var expecting_data = [
                {"url": "", "type": "feed", "link": "", "id": 0, "title": "すべてのFeed"},
                {"url": "http://example.com/hotentry/it.rss", "type": "feed", "link": "http://b.example.com/hotentry/it", "id": 1, "title": "title1"},
                {"url": "https://www.example.com/projects.xml", "type": "feed", "link": "https://www.example.com/projects", "id": 3, "title": "title3"},
            ];
        expect(expecting_data).toEqual(timelineManager.data);
    }));
});
<|endoftext|>


<commit_before>const ioHook = require('../../index');
const robot = require('robotjs');

describe('Keyboard events', () => {
    it('receives the text "Hello World"', (done) => {
        let currentKey = 0;

        const actualCharacters = [];
        const expectedCharacters = ['H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'];

        ioHook.on('keydown', (event) => {
            actualCharacters.push(String.fromCharCode(event.keychar));

            if (currentKey === expectedCharacters.length) {
                expect(actualCharacters).toEqual(expectedCharacters);
            }

            currentKey += 1;
            done();
        });
        ioHook.start();

        robot.typeString('Hello World');
    });
});
<commit_msg>Updated test to check for keyup and keydown, based on the keycode<commit_after>const ioHook = require('../../index');
const robot = require('robotjs');

describe('Keyboard events', () => {
  afterEach(() => {
    ioHook.stop();
  });

  it('receives the text "hello world" on keyup event', (done) => {
    const chars = [
      { keycode: 35, value: 'h' },
      { keycode: 18, value: 'e' },
      { keycode: 38, value: 'l' },
      { keycode: 38, value: 'l' },
      { keycode: 24, value: 'o' },
      { keycode: 57, value: ' ' },
      { keycode: 17, value: 'w' },
      { keycode: 24, value: 'o' },
      { keycode: 19, value: 'r' },
      { keycode: 38, value: 'l' },
      { keycode: 32, value: 'd' }
    ];
    let i = 0;

    ioHook.on('keydown', (event) => {
      expect(event.keycode).toEqual(chars[i].keycode);
      expect(event.type).toEqual('keydown');
    });
    ioHook.on('keyup', (event) => {
      expect(event.keycode).toEqual(chars[i].keycode);
      expect(event.type).toEqual('keyup');

      if (i === chars.length - 1) {
        done();
      }

      i += 1;
    });
    ioHook.start();

    for (const char of chars) {
      robot.keyTap(char.value);
    }
  });
});
<|endoftext|>


<commit_before>(function($){

    /**
     * Copyright 2012, Digital Fusion
     * Licensed under the MIT license.
     * http://teamdf.com/jquery-plugins/license/
     *
     * @author Sam Sehnert
     * @desc A small plugin that checks whether elements are within
     *       the user visible viewport of a web browser.
     *       only accounts for vertical position, not horizontal.
     */
    var $w = $(window);
    $.fn.visible = function(partial,hidden,direction){

        var $t              = this.eq(0),
            t               = $t.get(0),
            viewTop         = $w.scrollTop(),
            viewBottom      = viewTop + $w.height(),
            viewLeft        = $w.scrollLeft(),
            viewRight       = viewLeft + $w.width(),
            offset          = $t.offset(),
            _top            = offset.top,
            _bottom         = _top + $t.height(),
            _left           = offset.left,
            _right          = _left + $t.width(),
            compareTop      = partial === true ? _bottom : _top,
            compareBottom   = partial === true ? _top : _bottom,
            compareLeft     = partial === true ? _right : _left,
            compareRight    = partial === true ? _left : _right,
            clientSize      = hidden === true ? t.offsetWidth * t.offsetHeight : true,
            direction       = (direction) ? direction : 'both';

        if(direction === 'both')
            return !!clientSize && ((compareBottom <= viewBottom) && (compareTop >= viewTop)) && ((compareRight <= viewRight) && (compareLeft >= viewLeft));
        else if(direction === 'vertical')
            return !!clientSize && ((compareBottom <= viewBottom) && (compareTop >= viewTop));
        else if(direction === 'horizontal')
            return !!clientSize && ((compareRight <= viewRight) && (compareLeft >= viewLeft));
    };

})(jQuery);<commit_msg>Use element.getBoundingClientRect() if available, which should be faster since it's a native method.<commit_after>(function($){

    /**
     * Copyright 2012, Digital Fusion
     * Licensed under the MIT license.
     * http://teamdf.com/jquery-plugins/license/
     *
     * @author Sam Sehnert
     * @desc A small plugin that checks whether elements are within
     *       the user visible viewport of a web browser.
     *       only accounts for vertical position, not horizontal.
     */
    var $w = $(window);
    $.fn.visible = function(partial,hidden,direction){

        if (this.length < 1)
            return;

        var $t        = this.length > 1 ? this.eq(0) : this,
            t         = $t.get(0),
            vpWidth   = $w.width(),
            vpHeight  = $w.height(),
            direction = (direction) ? direction : 'both',
            clientSize = hidden === true ? t.offsetWidth * t.offsetHeight : true;

        if (typeof t.getBoundingClientRect === 'function'){

            // Use this native browser method, if available.
            var rec = t.getBoundingClientRect(),
                tViz = rec.top    >= 0 && rec.top    < vpHeight,
                bViz = rec.bottom >= 0 && rec.bottom < vpHeight,
                lViz = rec.left   >= 0 && rec.left   < vpWidth,
                rViz = rec.right  >= 0 && rec.right  < vpWidth,
                vVisible   = partial ? tViz || bViz : tViz && bViz,
                hVisible   = partial ? lViz || lViz : lViz && rViz;

            if(direction === 'both')
                return clientSize && vVisible && hVisible;
            else if(direction === 'vertical')
                return clientSize && vVisible;
            else if(direction === 'horizontal')
                return clientSize && hVisible;
        } else {

            var viewTop         = $w.scrollTop(),
                viewBottom      = viewTop + vpHeight,
                viewLeft        = $w.scrollLeft(),
                viewRight       = viewLeft + vpWidth,
                offset          = $t.offset(),
                _top            = offset.top,
                _bottom         = _top + $t.height(),
                _left           = offset.left,
                _right          = _left + $t.width(),
                compareTop      = partial === true ? _bottom : _top,
                compareBottom   = partial === true ? _top : _bottom,
                compareLeft     = partial === true ? _right : _left,
                compareRight    = partial === true ? _left : _right;

            if(direction === 'both')
                return !!clientSize && ((compareBottom <= viewBottom) && (compareTop >= viewTop)) && ((compareRight <= viewRight) && (compareLeft >= viewLeft));
            else if(direction === 'vertical')
                return !!clientSize && ((compareBottom <= viewBottom) && (compareTop >= viewTop));
            else if(direction === 'horizontal')
                return !!clientSize && ((compareRight <= viewRight) && (compareLeft >= viewLeft));
        }
    };

})(jQuery);<|endoftext|>


<commit_before>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Molecule3d from 'molecule-3d-for-react'
import MoleculeMenu from './menu.js'

const elementSymbols = [
  "Xx", "H", "He", "Li", "Be", "B", "C", "N", "O", "F",
  "Ne", "Na", "Mg", "Al", "Si", "P", "S", "Cl", "Ar", "K",
  "Ca", "Sc", "Ti", "V", "Cr", "Mn", "Fe", "Co", "Ni", "Cu",
  "Zn", "Ga", "Ge", "As", "Se", "Br", "Kr", "Rb", "Sr", "Y",
  "Zr", "Nb", "Mo", "Tc", "Ru", "Rh", "Pd", "Ag", "Cd", "In",
  "Sn", "Sb", "Te", "I", "Xe", "Cs", "Ba", "La", "Ce", "Pr",
  "Nd", "Pm", "Sm", "Eu", "Gd", "Tb", "Dy", "Ho", "Er", "Tm",
  "Yb", "Lu", "Hf", "Ta", "W", "Re", "Os", "Ir", "Pt", "Au",
  "Hg", "Tl", "Pb", "Bi", "Po", "At", "Rn", "Fr", "Ra", "Ac",
  "Th", "Pa", "U", "Np", "Pu", "Am", "Cm", "Bk", "Cf", "Es",
  "Fm", "Md", "No", "Lr", "Rf", "Db", "Sg", "Bh", "Hs", "Mt",
  "Ds", "Rg", "Cn", "Uut", "Uuq", "Uup", "Uuh", "Uus", "Uuo" ];

class Molecule extends Component {

  static generateOrbitals(cjson) {
    if (!cjson) {
      return []
    }

    const electronCount = cjson.basisSet.electronCount;
    const orbitals = [];
    for (let i = 1; i <= electronCount; i += 1) {
        let text = '';
        if (i == electronCount / 2) {
            text = ' (HOMO)';
        }
        else if (i == electronCount / 2 + 1) {
            text = ' (LUMO)';
        }
        let oObj = { id: i, label: i + text };
        orbitals.push(oObj);
    }

    return orbitals;
  }

  constructor(props) {
    super(props)

    if (this.props.animation) {
      this.state = {
          animation: {...this.props.animation}
      }
    }
    else {
      this.state = {}
    }

    if (this.props.isoSurfaces) {
      this.state.isoSurfaces = this.props.isoSurfaces;
    }
    else {
      this.state.isoSurfaces = this.isoSurfaces();
    }
  }

  onAmplitude = (value) => {
    this.setState({
      animation: {
        amplitude: value
      }
    })
  }

  onIsoScale = (value) => {
    const isoSurfaces = this.isoSurfaces(value);
    this.setState({
      isoSurfaces: isoSurfaces
    })
  }

  render() {
    const animation = this.state.animation;
    const hasVolume = !!this.props.cjson && !!this.props.cjson.cube;
    const hasAnimation = !!animation && !!this.props.animateMode;

    return (

        { (hasAnimation || hasVolume || this.props.orbitalControls) && <MoleculeMenu onAmplitude={this.onAmplitude}
                                                       onIsoScale={this.onIsoScale}
                                                       animationControls={hasAnimation}
                                                       orbitalControls={hasVolume || this.props.orbitalControls}
                                                       isoValue={this.state.isoSurfaces[0].value}
                                                       orbitals={Molecule.generateOrbitals(this.props.cjson)}
                                                       onOrbital={this.props.onOrbital}
                                                       orbital={this.props.orbital}
                                                                            /> }
        <Molecule3d modelData={ moleculeToModelData(this.props.cjson, this.props.animateMode) }
                    volume={ this.props.cjson && this.props.cjson.cube ? this.props.cjson.cube : null }
                    isoSurfaces={ this.state.isoSurfaces }
                    backgroundColor='#ffffff' animation={{...animation}}/>

    );
  }

  isoSurfaces(scale = 42) {
    const iso = (scale + 1) / 2000.0;

    return [{
      value: iso,
      color: 'blue',
      opacity: 0.9,
    }, {
      value: -iso,
      color: 'red',
      opacity: 0.9
    }
    ];
  }

}

Molecule.propTypes = {
  cjson: PropTypes.object,
  isoSurfaces: PropTypes.array,
  animateMode: PropTypes.number
}

Molecule.defaultProps = {
  cjson: null,
  isoSurfaces: null,
  animateMode: null
}

function moleculeToModelData(cjson, mode) {
  let modelData = {
      atoms: [],
      bonds: []
  }
  let eigenVectors = null;

  if (cjson == null) {
    return modelData
  }

  if (mode != null) {
    eigenVectors = cjson.vibrations.eigenVectors[mode-1];
  }

  const atoms = cjson.atoms;
  for (let [i, element] of atoms.elements.number.entries()) {
    const coords = atoms.coords['3d'];
    const coordsIndex = i * 3;
    let positions = [coords[coordsIndex], coords[coordsIndex+1], coords[coordsIndex+2]];

    let atom = {
        elem: elementSymbols[element],
        serial: i,
        positions,
    }

    if (eigenVectors != null) {
      atom.dx = eigenVectors[coordsIndex];
      atom.dy = eigenVectors[coordsIndex+1];
      atom.dz = eigenVectors[coordsIndex+2];
    }

    modelData.atoms.push(atom);
  }

  const bonds = cjson.bonds;
  for (let [i, order] of bonds.order.entries()) {
    const connections = bonds.connections.index;
    const connectionIndex = i*2;
    let bond = {
      atom1_index: connections[connectionIndex],
      atom2_index: connections[connectionIndex+1],
      bond_order: order
    }
    modelData.bonds.push(bond);
  }

  return modelData;
}

export default Molecule
<commit_msg>Guard against empty basisSet<commit_after>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Molecule3d from 'molecule-3d-for-react'
import MoleculeMenu from './menu.js'

const elementSymbols = [
  "Xx", "H", "He", "Li", "Be", "B", "C", "N", "O", "F",
  "Ne", "Na", "Mg", "Al", "Si", "P", "S", "Cl", "Ar", "K",
  "Ca", "Sc", "Ti", "V", "Cr", "Mn", "Fe", "Co", "Ni", "Cu",
  "Zn", "Ga", "Ge", "As", "Se", "Br", "Kr", "Rb", "Sr", "Y",
  "Zr", "Nb", "Mo", "Tc", "Ru", "Rh", "Pd", "Ag", "Cd", "In",
  "Sn", "Sb", "Te", "I", "Xe", "Cs", "Ba", "La", "Ce", "Pr",
  "Nd", "Pm", "Sm", "Eu", "Gd", "Tb", "Dy", "Ho", "Er", "Tm",
  "Yb", "Lu", "Hf", "Ta", "W", "Re", "Os", "Ir", "Pt", "Au",
  "Hg", "Tl", "Pb", "Bi", "Po", "At", "Rn", "Fr", "Ra", "Ac",
  "Th", "Pa", "U", "Np", "Pu", "Am", "Cm", "Bk", "Cf", "Es",
  "Fm", "Md", "No", "Lr", "Rf", "Db", "Sg", "Bh", "Hs", "Mt",
  "Ds", "Rg", "Cn", "Uut", "Uuq", "Uup", "Uuh", "Uus", "Uuo" ];

class Molecule extends Component {

  static generateOrbitals(cjson) {
    if (!cjson) {
      return [];
    }

    if (!cjson.basisSet) {
      return [];
    }

    const electronCount = cjson.basisSet.electronCount;
    const orbitals = [];
    for (let i = 1; i <= electronCount; i += 1) {
        let text = '';
        if (i == electronCount / 2) {
            text = ' (HOMO)';
        }
        else if (i == electronCount / 2 + 1) {
            text = ' (LUMO)';
        }
        let oObj = { id: i, label: i + text };
        orbitals.push(oObj);
    }

    return orbitals;
  }

  constructor(props) {
    super(props)

    if (this.props.animation) {
      this.state = {
          animation: {...this.props.animation}
      }
    }
    else {
      this.state = {}
    }

    if (this.props.isoSurfaces) {
      this.state.isoSurfaces = this.props.isoSurfaces;
    }
    else {
      this.state.isoSurfaces = this.isoSurfaces();
    }
  }

  onAmplitude = (value) => {
    this.setState({
      animation: {
        amplitude: value
      }
    })
  }

  onIsoScale = (value) => {
    const isoSurfaces = this.isoSurfaces(value);
    this.setState({
      isoSurfaces: isoSurfaces
    })
  }

  render() {
    const animation = this.state.animation;
    const hasVolume = !!this.props.cjson && !!this.props.cjson.cube;
    const hasAnimation = !!animation && !!this.props.animateMode;

    return (

        { (hasAnimation || hasVolume || this.props.orbitalControls) && <MoleculeMenu onAmplitude={this.onAmplitude}
                                                       onIsoScale={this.onIsoScale}
                                                       animationControls={hasAnimation}
                                                       orbitalControls={hasVolume || this.props.orbitalControls}
                                                       isoValue={this.state.isoSurfaces[0].value}
                                                       orbitals={Molecule.generateOrbitals(this.props.cjson)}
                                                       onOrbital={this.props.onOrbital}
                                                       orbital={this.props.orbital}
                                                                            /> }
        <Molecule3d modelData={ moleculeToModelData(this.props.cjson, this.props.animateMode) }
                    volume={ this.props.cjson && this.props.cjson.cube ? this.props.cjson.cube : null }
                    isoSurfaces={ this.state.isoSurfaces }
                    backgroundColor='#ffffff' animation={{...animation}}/>

    );
  }

  isoSurfaces(scale = 42) {
    const iso = (scale + 1) / 2000.0;

    return [{
      value: iso,
      color: 'blue',
      opacity: 0.9,
    }, {
      value: -iso,
      color: 'red',
      opacity: 0.9
    }
    ];
  }

}

Molecule.propTypes = {
  cjson: PropTypes.object,
  isoSurfaces: PropTypes.array,
  animateMode: PropTypes.number
}

Molecule.defaultProps = {
  cjson: null,
  isoSurfaces: null,
  animateMode: null
}

function moleculeToModelData(cjson, mode) {
  let modelData = {
      atoms: [],
      bonds: []
  }
  let eigenVectors = null;

  if (cjson == null) {
    return modelData
  }

  if (mode != null) {
    eigenVectors = cjson.vibrations.eigenVectors[mode-1];
  }

  const atoms = cjson.atoms;
  for (let [i, element] of atoms.elements.number.entries()) {
    const coords = atoms.coords['3d'];
    const coordsIndex = i * 3;
    let positions = [coords[coordsIndex], coords[coordsIndex+1], coords[coordsIndex+2]];

    let atom = {
        elem: elementSymbols[element],
        serial: i,
        positions,
    }

    if (eigenVectors != null) {
      atom.dx = eigenVectors[coordsIndex];
      atom.dy = eigenVectors[coordsIndex+1];
      atom.dz = eigenVectors[coordsIndex+2];
    }

    modelData.atoms.push(atom);
  }

  const bonds = cjson.bonds;
  for (let [i, order] of bonds.order.entries()) {
    const connections = bonds.connections.index;
    const connectionIndex = i*2;
    let bond = {
      atom1_index: connections[connectionIndex],
      atom2_index: connections[connectionIndex+1],
      bond_order: order
    }
    modelData.bonds.push(bond);
  }

  return modelData;
}

export default Molecule
<|endoftext|>


<commit_before>/*global
	CKEDITOR,
	console,
	tesseractJS
	*/
(function () {
	'use strict';

	/**
	 *	OCRManager constructor
	 */
	function OCRManager(container, command, editor) {
		this.container = container;
		this.editor = editor;
		this.selectedImage = undefined;
		this.command = command;
		this.disable();
		this.dialog = undefined;
	}

	/**
	 *	 for now, no need to remove it
	 */
	OCRManager.prototype.attachListeners = function () {
		var self = this;

		this.container.on('click', function (evt) {
			self.onClick(evt.data);
		});
	};

	/**
	 * set the button to active state
	 */
	OCRManager.prototype.setActive = function () {
		this.editor.ui.get('Ocerisation').setState(CKEDITOR.TRISTATE_ON);
	};

	/**
	 * set the button to inactive state
	 */
	OCRManager.prototype.setInactive = function () {
		this.editor.ui.get('Ocerisation').setState(CKEDITOR.TRISTATE_OFF);
	};

	/**
	 * disable the button
	 */
	OCRManager.prototype.disable = function () {
		this.command.disable();
	};

	/**
	 * enable the button
	 */
	OCRManager.prototype.enable = function () {
		this.command.enable();
	};

	/**
	 *	returns true if the button is disabled
	 */
	OCRManager.prototype.isDisabled = function () {
		return this.editor.ui.get('Ocerisation').getState() === CKEDITOR.TRISTATE_DISABLED;
	};

	/**
	 * on click calback
	 *		check if click event is on an image
	 *		then check if the image is base64 encoded
	 */
	OCRManager.prototype.onClick = function (event) {
		var selectedElement = event.getTarget();
		if (selectedElement.getName() === 'img' && this.isDataUrl(selectedElement.getAttribute('src'))) {
			this.selectedImage = selectedElement;
			this.enable();
		} else {
			this.selectedImagSrc = undefined;
			this.disable();
		}

	};

	//https://gist.github.com/bgrins/6194623
	OCRManager.prototype.isDataUrl = function (str) {
		//https://gist.github.com/bgrins/6194623
		var rgx = /^\s*data:([a-z]+\/[a-z]+(;[a-z\-]+\=[a-z\-]+)?)?(;base64)?,[a-z0-9\!\$\&\'\,\(\)\*\+\,\;\=\-\.\_\~\:\@\/\?\%\s]*\s*$/i;
		return !!str.match(rgx);
	};

	/**
	 * ocerization entry method
	 */
	OCRManager.prototype.ocerize = function () {

		var self = this,
			dataToOcerize,
			oReq;
		if (this.selectedImage.getName() === 'img' && this.isDataUrl(this.selectedImage.getAttribute('src'))) {
			this.setActive();
			dataToOcerize = this.selectedImage.getAttribute('src');

			if (!this.dialog) {
				this.dialog = this.editor.openDialog('loading');
			} else {
				//if dialog already instanciated => show and remove listeners
				this.dialog.show();
				this.dialog.removeAllListeners();
			}

			this.dialog.on('show', function (evt) {
				//hide the close button
				self.dialog.parts.close.setStyle('display', 'none');
				var params = '{"id":"' + localStorage.getItem('compteId') + '","encodedImg":"' + dataToOcerize + '"}';
				oReq = new XMLHttpRequest();
				oReq.open('POST', '/oceriser', true);
				oReq.setRequestHeader("Content-Type", "application/json;charset=UTF-8");

				oReq.onload = function () {
					if(oReq.status === 401) {
						// retirer popup d'attente
						self.dialog.hide();
						// affichage dialog non autorisé.
						if (!self.unauthorizedDialog) {
							self.unauthorizedDialog = self.editor.openDialog('unauthorized');
						} else {
							//if dialog already instanciated => show and remove listeners
							self.unauthorizedDialog.show();
						}
					} else {
						// production
						//var imageOpt = oReq.response;
						//integration
						var imageOpt;
						// Gestion de la version de node. les nouvelles versions mettent les données dans data.
						// Les anciennes version le mettent directement (sans data).
						var response = JSON.parse(oReq.response);
						if(response.data) {
							imageOpt = response.data;
						} else {
							imageOpt = response;
						}
						var ocerisedTxt;
						// l'océrisation se passe ici
						tesseractJS.FS_createDataFile('/', 'tempInput.jpg', imageOpt, true, true);

						var fnct_TESSERACT_Minimal = tesseractJS.cwrap(
							// name of C function
							'TESSERACT_Minimal',
							// return type
							'number',
							// argument types
							['string', 'string', 'number', 'number']
						); // arguments

						//Renvoie de l'HOCR, mettre le 3eme pram à 0 pour UTF8
						var retSTRING_Pointer = fnct_TESSERACT_Minimal('tempInput.jpg', 'fra', 1, -1);
						// Convert the resulting string to a JS string
						var retSTRING = tesseractJS.Pointer_stringify(retSTRING_Pointer);

						// cleans the text
						retSTRING = self.cleanString(retSTRING);
						//Supprime le fichier temp
						try {
							tesseractJS.FS_unlink('/tempInput.jpg');
						} catch (e) {
							// catch fichier n'existe pas
							console.log(e);
						}
						self.appendOcerizedText(retSTRING);
						// retirer popup d'attente
						self.dialog.hide();
					}

					self.setInactive();
				};

				oReq.send(params);
			});
		}
	};

	/**
	 *	adds ocerized text on top of the clicked image
	 */
	OCRManager.prototype.appendOcerizedText = function (ocerisedTxt) {
		var txtNode = new CKEDITOR.dom.element('div');
		txtNode.appendHtml(ocerisedTxt);
		var childrenArray = [];
		var children = txtNode.getChildren();
		for(var i = 0; i < children.count(); i++) {
			childrenArray.push(children.getItem(i));
		}
		for(var j = 0; j < childrenArray.length; j++) {
			this.selectedImage.insertBeforeMe(childrenArray[j]);
		}
		document.getSelection().removeAllRanges();
	};

	OCRManager.prototype.initializeTesseract = function (ocerisedTxt) {
		var oReq = new XMLHttpRequest();
		oReq.open('GET', '/bower_components/tesseractJS/tesseract-ocr/tessdata/fra.traineddata', true);
		oReq.responseType = 'blob';

		oReq.onload = function () {
			var blob = oReq.response;
			if (blob) {
				var reader = new FileReader();
				reader.onloadend = function (evt) {
					if (evt.target.readyState === FileReader.DONE) {
						var binary = '';
						var bytes = new Uint8Array(evt.target.result);
						var len = bytes.byteLength;
						for (var i = 0; i < len; i++) {
							binary += String.fromCharCode(bytes[i]);
						}

						tesseractJS.FS_createDataFile('/tesseract-ocr/tessdata/', 'fra.traineddata', binary, true, true);
					}
				};
				reader.readAsArrayBuffer(blob);
			}
		};
		oReq.send(null);
	};

	OCRManager.prototype.cleanString = function (str) {
		if (str.length > 0) {
			//create a div and add the string as subelements
			var div = document.createElement('div');
			div.innerHTML = str;
			//select the Ps elements
			var ps = div.getElementsByTagName('p'),
				psToString = '';
			for (var i = 0; i < ps.length; i++){
				ps[i].innerHTML = ps[i].textContent || ps[i].innerText || '';
				//concat without the other html elements
				psToString = psToString + ps[i].outerHTML;
			}

			return this.lineBreakOptimisation(psToString);
		} else {
			return str;
		}
	};

	OCRManager.prototype.lineBreakOptimisation = function (text) {
		var wordArray = text.split(" ");

		var simpleWordCountere = 0;

		for (var i = 1; i < wordArray.length; i++) {

			if (wordArray[i].indexOf("
") == -1 || wordArray[i].indexOf(".") == -1 || wordArray[i].indexOf(":") == -1 || wordArray[i].indexOf(";") == -1) {
				simpleWordCountere++;

			} else {
				simpleWordCountere = 0;
			}

			if (wordArray[i].indexOf("
") > -1) {

				var count = (wordArray[i].match(/
/g) || []).length;

				if (simpleWordCountere > 4 && count < 2) {
					if (wordArray[i - 1].indexOf(".") == -1 && wordArray[i - 1].indexOf(":") == -1 && wordArray[i - 1].indexOf(";") == -1) {
						wordArray[i] = wordArray[i].replace(/((
)( *)){1,}/g, ' ')
					}
				}
			}

		}

		return wordArray.join(" ");
	};

	/**
	 *	Plugin initialization
	 */
	CKEDITOR.plugins.add('ocerisation', {
		icons: 'ocerisation',
		init: function (editor) {

			var dialog = CKEDITOR.dialog.add('loading', function (editor) {
				var dialogDefinition = {
					title: 'Traitement en cours...',
					minWidth: 100,
					minHeight: 60,
					resizable: CKEDITOR.DIALOG_RESIZE_NONE,
					contents: [{
						id: 'loading',
						label: 'Chargement',
						title: 'Traitement en cours...',
						elements: [
							{
								type: 'html',
								html: '
Le traitement de reconnaissance des caractères est en cours.
La durée de ce traitement peut être importante.

Veuillez patienter...
',
								align: 'center'
							}
						]
						}],
					// needs a hidden button to replace default ones
					buttons: [
						{
							type: 'button',
							id: 'hiddenBtn',
							label: 'none',
							hidden: true
						}
					]
				};
				return dialogDefinition;
			});

			var unauthorizedDialog = CKEDITOR.dialog.add('unauthorized', function (editor) {
				var dialogDefinition = {
					title: 'Traitement désactivé...',
					minWidth: 100,
					minHeight: 60,
					resizable: CKEDITOR.DIALOG_RESIZE_NONE,
					contents: [{
						id: 'unauthorized',
						label: 'Chargement',
						title: 'Traitement désactivé...',
						elements: [
							{
								type: 'html',
								html: '
La reconnaissance des caractères est désactivée.
Pour l\'activer, contactez l\'administrateur de l\'application.

',
								align: 'center'
							}
						]
						}],
					buttons: [ CKEDITOR.dialog.okButton ]
				};
				return dialogDefinition;
			});
			var manager;

			editor.ui.addButton('Ocerisation', {
				label: 'Lancer la reconnaissance des caractères',
				command: 'ocerisation',
				toolbar: 'insert' // TODO: change

			});

			editor.addCommand('ocerisation', {
				exec: function (editor) {
					manager.ocerize();
				},
				startDisabled: true
			});

			editor.on('contentDom', function (e) {
				manager = new OCRManager(this.container, editor.getCommand('ocerisation'), editor);
				manager.attachListeners();
				manager.initializeTesseract();
			});

		}
	});

})();
<commit_msg>Océrisation entièrement côté client.<commit_after>/*global
    CKEDITOR,
    console,
    tesseractJS
 */
(function() {
    'use strict';

    /**
     * OCRManager constructor
     */
    function OCRManager(container, command, editor) {
        this.container = container;
        this.editor = editor;
        this.selectedImage = undefined;
        this.command = command;
        this.disable();
        this.dialog = undefined;
    }

    /**
     * for now, no need to remove it
     */
    OCRManager.prototype.attachListeners = function() {
        var self = this;

        this.container.on('click', function(evt) {
            self.onClick(evt.data);
        });
    };

    /**
     * set the button to active state
     */
    OCRManager.prototype.setActive = function() {
        this.editor.ui.get('Ocerisation').setState(CKEDITOR.TRISTATE_ON);
    };

    /**
     * set the button to inactive state
     */
    OCRManager.prototype.setInactive = function() {
        this.editor.ui.get('Ocerisation').setState(CKEDITOR.TRISTATE_OFF);
    };

    /**
     * disable the button
     */
    OCRManager.prototype.disable = function() {
        this.command.disable();
    };

    /**
     * enable the button
     */
    OCRManager.prototype.enable = function() {
        this.command.enable();
    };

    /**
     * returns true if the button is disabled
     */
    OCRManager.prototype.isDisabled = function() {
        return this.editor.ui.get('Ocerisation').getState() === CKEDITOR.TRISTATE_DISABLED;
    };

    /**
     * on click calback check if click event is on an image then check if the
     * image is base64 encoded
     */
    OCRManager.prototype.onClick = function(event) {
        var selectedElement = event.getTarget();
        if (selectedElement.getName() === 'img' && this.isDataUrl(selectedElement.getAttribute('src'))) {
            this.selectedImage = selectedElement;
            this.enable();
        } else {
            this.selectedImagSrc = undefined;
            this.disable();
        }

    };

    // https://gist.github.com/bgrins/6194623
    OCRManager.prototype.isDataUrl = function(str) {
        // https://gist.github.com/bgrins/6194623
        var rgx = /^\s*data:([a-z]+\/[a-z]+(;[a-z\-]+\=[a-z\-]+)?)?(;base64)?,[a-z0-9\!\$\&\'\,\(\)\*\+\,\;\=\-\.\_\~\:\@\/\?\%\s]*\s*$/i;
        return !!str.match(rgx);
    };

    /**
     * ocerization entry method
     */
    OCRManager.prototype.ocerize = function() {

        var self = this;
        if (this.selectedImage.getName() === 'img' && this.isDataUrl(this.selectedImage.getAttribute('src'))) {
            this.setActive();

            if (!this.dialog) {
                this.dialog = this.editor.openDialog('loading');
            } else {
                // if dialog already instanciated => show and remove listeners
                this.dialog.show();
                this.dialog.removeAllListeners();
            }

            this.dialog.on('show', function(evt) {
                // hide the close button
                self.dialog.parts.close.setStyle('display', 'none');

                localforage.getItem('compteOffline').then(function(compte) {
                    if (!compte.local.authorisations.ocr) {
                        self.dialog.hide();
                        // affichage dialog non autorisé.
                        if (!self.unauthorizedDialog) {
                            self.unauthorizedDialog = self.editor.openDialog('unauthorized');
                        } else {
                            // if dialog already instanciated => show and remove
                            // listeners
                            self.unauthorizedDialog.show();
                        }
                    } else {

                        // image pretraitement
                        var imgOpt = optimizeImage(self);

                        var ocerisedTxt;
                        // l'océrisation se passe ici
                        var created = tesseractJS.FS_createDataFile('/', 'tempInput.jpg', imgOpt, true, true, true);

                        var fnct_TESSERACT_Minimal = tesseractJS.cwrap(
                        // name of C function
                        'TESSERACT_Minimal',
                        // return type
                        'number',
                        // argument types
                        [ 'string', 'string', 'number', 'number' ]); // arguments

                        // Renvoie de l'HOCR, mettre le 3eme pram à 0 pour UTF8
                        var retSTRING_Pointer = fnct_TESSERACT_Minimal('tempInput.jpg', 'fra', 1, -1);
                        // Convert the resulting string to a JS string
                        var retSTRING = tesseractJS.Pointer_stringify(retSTRING_Pointer);

                        // cleans the text
                        retSTRING = self.cleanString(retSTRING);
                        // Supprime le fichier temp
                        try {
                            tesseractJS.FS_unlink('/tempInput.jpg');
                        } catch (e) {
                            // catch fichier n'existe pas
                            console.log(e);
                        }
                        self.appendOcerizedText(retSTRING);
                        // retirer popup d'attente
                        self.dialog.hide();
                        self.setInactive();
                    }
                });
            });
        }
    };

    function optimizeImage(self) {
        var canvas = convertToImageData(self.selectedImage.$);
        desaturate(canvas);
        var dataURL = canvas.toDataURL('image/png');
        return convertDataURIToBinary(dataURL);
    }

    function desaturate(canvas) {

        var canvasContext = canvas.getContext('2d');

        var imgPixels = canvasContext.getImageData(0, 0, canvas.width, canvas.height);

        for (var y = 0; y < imgPixels.height; y++) {
            for (var x = 0; x < imgPixels.width; x++) {
                var i = (y * 4) * imgPixels.width + x * 4;
                var avg = (imgPixels.data[i] + imgPixels.data[i + 1] + imgPixels.data[i + 2]) / 3;
                imgPixels.data[i] = avg;
                imgPixels.data[i + 1] = avg;
                imgPixels.data[i + 2] = avg;
            }
        }

        canvasContext.putImageData(imgPixels, 0, 0, 0, 0, imgPixels.width, imgPixels.height);

        return canvas;
    }

    function convertToImageData(image) {
        if (image.getContext) {
            image = image.getContext('2d');
        } else if (image.tagName == "IMG" || image.tagName == "VIDEO") {
            var c = document.createElement('canvas');
            if (image.tagName == "IMG") {
                c.width = image.naturalWidth * 3;
                c.height = image.naturalHeight * 3;
            } else if (image.tagName == "VIDEO") {
                c.width = image.videoWidth;
                c.height = image.videoHeight;
            }
            var ctx = c.getContext('2d');
            ctx.scale(3, 3);
            ctx.drawImage(image, 0, 0);
            image = ctx;
        }
        if (image.getImageData)
            image = image.getImageData(0, 0, image.canvas.width, image.canvas.height);
        return c;
    }

    function convertDataURIToBinary(dataURI) {
        var base64Marker = ';base64,';
        var base64Index = dataURI.indexOf(base64Marker) + base64Marker.length;
        var base64 = dataURI.substring(base64Index);
        var raw = window.atob(base64);
        var rawLength = raw.length;
        var array = new Uint8Array(new ArrayBuffer(rawLength));

        for (var i = 0; i < rawLength; i++) {
            array[i] = raw.charCodeAt(i);
        }
        return array;
    }

    /**
     * adds ocerized text on top of the clicked image
     */
    OCRManager.prototype.appendOcerizedText = function(ocerisedTxt) {
        var txtNode = new CKEDITOR.dom.element('div');
        txtNode.appendHtml(ocerisedTxt);
        var childrenArray = [];
        var children = txtNode.getChildren();
        for (var i = 0; i < children.count(); i++) {
            childrenArray.push(children.getItem(i));
        }
        for (var j = 0; j < childrenArray.length; j++) {
            this.selectedImage.insertBeforeMe(childrenArray[j]);
        }
        document.getSelection().removeAllRanges();
    };

    OCRManager.prototype.initializeTesseract = function(ocerisedTxt) {
        var oReq = new XMLHttpRequest();
        oReq.open('GET', '/bower_components/tesseractJS/tesseract-ocr/tessdata/fra.traineddata', true);
        oReq.responseType = 'blob';

        oReq.onload = function() {
            var blob = oReq.response;
            if (blob) {
                var reader = new FileReader();
                reader.onloadend = function(evt) {
                    if (evt.target.readyState === FileReader.DONE) {
                        var binary = '';
                        var bytes = new Uint8Array(evt.target.result);
                        var len = bytes.byteLength;
                        for (var i = 0; i < len; i++) {
                            binary += String.fromCharCode(bytes[i]);
                        }

                        tesseractJS.FS_createDataFile('/tesseract-ocr/tessdata/', 'fra.traineddata', binary, true, true);
                    }
                };
                reader.readAsArrayBuffer(blob);
            }
        };
        oReq.send(null);
    };

    OCRManager.prototype.cleanString = function(str) {
        if (str.length > 0) {
            // create a div and add the string as subelements
            var div = document.createElement('div');
            div.innerHTML = str;
            // select the Ps elements
            var ps = div.getElementsByTagName('p'), psToString = '';
            for (var i = 0; i < ps.length; i++) {
                ps[i].innerHTML = ps[i].textContent || ps[i].innerText || '';
                // concat without the other html elements
                psToString = psToString + ps[i].outerHTML;
            }

            return this.lineBreakOptimisation(psToString);
        } else {
            return str;
        }
    };

    OCRManager.prototype.lineBreakOptimisation = function(text) {
        var wordArray = text.split(" ");

        var simpleWordCountere = 0;

        for (var i = 1; i < wordArray.length; i++) {

            if (wordArray[i].indexOf("
") == -1 || wordArray[i].indexOf(".") == -1 || wordArray[i].indexOf(":") == -1 || wordArray[i].indexOf(";") == -1) {
                simpleWordCountere++;

            } else {
                simpleWordCountere = 0;
            }

            if (wordArray[i].indexOf("
") > -1) {

                var count = (wordArray[i].match(/
/g) || []).length;

                if (simpleWordCountere > 4 && count < 2) {
                    if (wordArray[i - 1].indexOf(".") == -1 && wordArray[i - 1].indexOf(":") == -1 && wordArray[i - 1].indexOf(";") == -1) {
                        wordArray[i] = wordArray[i].replace(/((
)( *)){1,}/g, ' ')
                    }
                }
            }

        }

        return wordArray.join(" ");
    };

    /**
     * Plugin initialization
     */
    CKEDITOR.plugins.add('ocerisation', {
        icons : 'ocerisation',
        init : function(editor) {

            var dialog = CKEDITOR.dialog.add('loading', function(editor) {
                var dialogDefinition = {
                    title : 'Traitement en cours...',
                    minWidth : 100,
                    minHeight : 60,
                    resizable : CKEDITOR.DIALOG_RESIZE_NONE,
                    contents : [ {
                        id : 'loading',
                        label : 'Chargement',
                        title : 'Traitement en cours...',
                        elements : [ {
                            type : 'html',
                            html : '
Le traitement de reconnaissance des caractères est en cours.
La durée de ce traitement peut être importante.

Veuillez patienter...
',
                            align : 'center'
                        } ]
                    } ],
                    // needs a hidden button to replace default ones
                    buttons : [ {
                        type : 'button',
                        id : 'hiddenBtn',
                        label : 'none',
                        hidden : true
                    } ]
                };
                return dialogDefinition;
            });

            var unauthorizedDialog = CKEDITOR.dialog.add('unauthorized', function(editor) {
                var dialogDefinition = {
                    title : 'Traitement désactivé...',
                    minWidth : 100,
                    minHeight : 60,
                    resizable : CKEDITOR.DIALOG_RESIZE_NONE,
                    contents : [ {
                        id : 'unauthorized',
                        label : 'Chargement',
                        title : 'Traitement désactivé...',
                        elements : [ {
                            type : 'html',
                            html : '
La reconnaissance des caractères est désactivée.
Pour l\'activer, contactez l\'administrateur de l\'application.

',
                            align : 'center'
                        } ]
                    } ],
                    buttons : [ CKEDITOR.dialog.okButton ]
                };
                return dialogDefinition;
            });
            var manager;

            editor.ui.addButton('Ocerisation', {
                label : 'Lancer la reconnaissance des caractères',
                command : 'ocerisation',
                toolbar : 'insert' // TODO: change

            });

            editor.addCommand('ocerisation', {
                exec : function(editor) {
                    manager.ocerize();
                },
                startDisabled : true
            });

            editor.on('contentDom', function(e) {
                manager = new OCRManager(this.container, editor.getCommand('ocerisation'), editor);
                manager.attachListeners();
                manager.initializeTesseract();
            });

        }
    });

})();
<|endoftext|>


<commit_before>/* eslint-env node */

import express from 'express';
import http from 'http';
import socketIO from 'socket.io';
import uuid from 'uuid';
import { getRabbitConnection } from './rabbit-connection';

const app = express();
const server = http.createServer(app);
const io = socketIO(server, { path: '/' });
const corrToSock = {}; // correlation ID to socket ID map

server.listen(3001);

class Router {
  constructor(ch, socket) {
    this.ch = ch;
    this.socket = socket;
    this.nodeId = uuid.v4();
  }

  route(event, key) {
    this.ch.assertQueue(`${key}.listener.${this.nodeId}`, { exclusive: true })
      .then(q => {
        this.ch.consume(q.queue, msg => {
          const socketId = corrToSock[msg.properties.correlationId];
          const data = JSON.parse(msg.content.toString());
          io.to(socketId).emit(event, data);
        }, { noAck: true });

        this.socket.on(event, data => {
          const correlationId = uuid.v4();

          this.ch.assertExchange('events', 'topic', { durable: true });
          this.ch.publish(
            'events',
            key,
            new Buffer(JSON.stringify(typeof data === 'undefined' ? null : data)),
            { persistent: true, correlationId, replyTo: q.queue }
          );
          corrToSock[correlationId] = this.socket.id;
        });
      });
  }
}

io.on('connection', socket => {
  getRabbitConnection()
    .then(conn => conn.createChannel())
    .then(ch => {
      const router = new Router(ch, socket);
      router.route('LOAD_POLLS', 'polls.load');
      router.route('UPDATE_POLL', 'polls.update');
      router.route('CREATE_POLL', 'polls.create');
      router.route('DELETE_POLL', 'polls.delete');
      router.route('LOAD_FLATS', 'flats.load');
      router.route('UPDATE_FLAT', 'flats.update');
      router.route('CREATE_FLAT', 'flats.create');
      router.route('DELETE_FLAT', 'flats.delete');
      router.route('LOAD_HOUSES', 'houses.load');
      router.route('UPDATE_HOUSE', 'houses.update');
      router.route('CREATE_HOUSE', 'houses.create');
      router.route('DELETE_HOUSE', 'houses.delete');
      router.route('LOAD_SERVICES', 'services.load');
      router.route('UPDATE_SERVICE', 'services.update');
      router.route('CREATE_SERVICE', 'services.create');
      router.route('DELETE_SERVICE', 'services.delete');
      router.route('LOAD_USERS', 'users.load');
      router.route('UPDATE_USER', 'users.update');
      router.route('CREATE_USER', 'users.create');
      router.route('DELETE_USER', 'users.delete');
      router.route('LOAD_COOPERATIVES', 'cooperatives.load');
      router.route('UPDATE_COOPERATIVE', 'cooperatives.update');
      router.route('CREATE_COOPERATIVE', 'cooperatives.create');
      router.route('DELETE_COOPERATIVE', 'cooperatives.delete');
      router.route('LOGIN', 'auth.login');
      router.route('LOGOUT', 'auth.logout');
    });
});
<commit_msg>deferred calls<commit_after>/* eslint-env node */

import express from 'express';
import http from 'http';
import socketIO from 'socket.io';
import uuid from 'uuid';
import { getRabbitConnection } from './rabbit-connection';

const app = express();
const server = http.createServer(app);
const io = socketIO(server, { path: '/' });
const corrToSock = {}; // correlation ID to socket ID map

server.listen(3001);

class Router {
  constructor(ch, socket) {
    this.ch = ch;
    this.socket = socket;
    this.nodeId = uuid.v4();
  }

  route(event, key) {
    this.ch.assertQueue(`${key}.listener.${this.nodeId}`, { exclusive: true })
      .then(q => {
        this.ch.consume(q.queue, msg => {
          const socketId = corrToSock[msg.properties.correlationId];
          const data = JSON.parse(msg.content.toString());
          io.to(socketId).emit(event, { data, correlationId: msg.properties.correlationId });
        }, { noAck: true });

        this.socket.on(event, payload => {
          const correlationId = payload.correlationId || uuid.v4();
          const { data } = payload;

          this.ch.assertExchange('events', 'topic', { durable: true });
          this.ch.publish(
            'events',
            key,
            new Buffer(JSON.stringify(typeof data === 'undefined' ? null : data)),
            { persistent: true, correlationId, replyTo: q.queue }
          );
          corrToSock[correlationId] = this.socket.id;
        });
      });
  }
}

io.on('connection', socket => {
  getRabbitConnection()
    .then(conn => conn.createChannel())
    .then(ch => {
      const router = new Router(ch, socket);
      router.route('LOAD_POLLS', 'polls.load');
      router.route('UPDATE_POLL', 'polls.update');
      router.route('CREATE_POLL', 'polls.create');
      router.route('DELETE_POLL', 'polls.delete');
      router.route('LOAD_FLATS', 'flats.load');
      router.route('UPDATE_FLAT', 'flats.update');
      router.route('CREATE_FLAT', 'flats.create');
      router.route('DELETE_FLAT', 'flats.delete');
      router.route('LOAD_HOUSES', 'houses.load');
      router.route('UPDATE_HOUSE', 'houses.update');
      router.route('CREATE_HOUSE', 'houses.create');
      router.route('DELETE_HOUSE', 'houses.delete');
      router.route('LOAD_SERVICES', 'services.load');
      router.route('UPDATE_SERVICE', 'services.update');
      router.route('CREATE_SERVICE', 'services.create');
      router.route('DELETE_SERVICE', 'services.delete');
      router.route('LOAD_USERS', 'users.load');
      router.route('UPDATE_USER', 'users.update');
      router.route('CREATE_USER', 'users.create');
      router.route('DELETE_USER', 'users.delete');
      router.route('LOAD_COOPERATIVES', 'cooperatives.load');
      router.route('UPDATE_COOPERATIVE', 'cooperatives.update');
      router.route('CREATE_COOPERATIVE', 'cooperatives.create');
      router.route('DELETE_COOPERATIVE', 'cooperatives.delete');
      router.route('LOGIN', 'auth.login');
      router.route('LOGOUT', 'auth.logout');
    });
});
<|endoftext|>


<commit_before>nelliel.ui.hideShowThread = function(element, command) {
    var id = element.getAttribute("data-id");
    var thread_id = id.split('_')[0];
    var post_files = document.getElementById("post-files-container-" + id);
    var post_contents = document.getElementById("post-contents-" + id);
    var thread_container = document.getElementById("thread-expand-" + thread_id);

    if (command === "hide-thread") {
        dataBin.hidden_threads[id] = Date.now();
    } else if (command === "show-thread") {
        delete dataBin.hidden_threads[id];
    }

    if (thread_container !== null) {
        nelliel.ui.toggleHidden(thread_container);
    }

    if (post_files !== null) {
        nelliel.ui.toggleHidden(post_files);
    }

    if (post_contents !== null) {
        nelliel.ui.toggleHidden(post_contents);
    }

    nelliel.core.storeInLocalStorage(dataBin.hidden_threads_id, dataBin.hidden_threads);
    nelliel.ui.switchDataCommand(element, "hide-thread", "show-thread");
    nelliel.ui.swapContentAttribute(element, "data-alt-visual");
}

nelliel.ui.hideShowPost = function(element, command) {
    var id = element.getAttribute("data-id");
    var post_files = document.getElementById("post-files-container-" + id);
    var post_contents = document.getElementById("post-contents-" + id);

    if (command == "hide-post") {
        dataBin.hidden_posts[id] = Date.now();
    } else if (command == "show-post") {
        delete dataBin.hidden_posts[id];
    }

    if (post_files !== null) {
        nelliel.ui.toggleHidden(post_files);
    }

    if (post_contents !== null) {
        nelliel.ui.toggleHidden(post_contents);
    }

    nelliel.core.storeInLocalStorage(dataBin.hidden_posts_id, dataBin.hidden_posts);
    nelliel.ui.switchDataCommand(element, "hide-post", "show-post");
    nelliel.ui.swapContentAttribute(element, "data-alt-visual");
}

nelliel.ui.applyHidePostThread = function() {
    for (var id in dataBin.hidden_threads) {
        var thread_id = id.split('_')[0];
        var post_files = document.getElementById("post-files-container-" + id);
        var post_contents = document.getElementById("post-contents-" + id);
        var thread_container = document.getElementById("thread-expand-" + thread_id);
        var element = document.getElementById("hide-post-thread-" + id);

        if (thread_container !== null) {
            nelliel.ui.toggleHidden(thread_container);
        }

        if (post_files !== null) {
            nelliel.ui.toggleHidden(post_files);
        }

        if (post_contents !== null) {
            nelliel.ui.toggleHidden(post_contents);
        }

        nelliel.ui.switchDataCommand(element, "hide-thread", "show-thread");
        nelliel.ui.swapContentAttribute(element, "data-alt-visual");
    }

    for (var id in dataBin.hidden_posts) {
        var post_files = document.getElementById("post-files-container-" + id);
        var post_contents = document.getElementById("post-contents-" + id);
        var element = document.getElementById("hide-post-thread-" + id);

        if (post_files !== null) {
            nelliel.ui.toggleHidden(post_files);
        }

        if (post_contents !== null) {
            nelliel.ui.toggleHidden(post_contents);
        }

        nelliel.ui.switchDataCommand(element, "hide-post", "show-post");
        nelliel.ui.swapContentAttribute(element, "data-alt-visual");
    }
}

nelliel.ui.showHideFileMeta = function(element, command) {
    var full_id = element.getAttribute("data-id");
    var meta_element = document.getElementById("file-meta-" + full_id);
    nelliel.ui.swapContentAttribute(element, "data-alt-visual");
    nelliel.ui.toggleHidden(meta_element);
    nelliel.ui.switchDataCommand(element, "show-file-meta", "hide-file-meta");
}

nelliel.ui.expandCollapseThread = function(thread_id, command, element) {
    var target_element = document.getElementById("thread-expand-" + thread_id);

    if (!target_element) {
        return;
    }

    var url = "threads/" + thread_id + "/" + thread_id + "-" + command.split('-')[0] + ".html";
    var request = new XMLHttpRequest();
    request.open('GET', url);
    request.onload = function() {
        if (request.status === 200) {
            nelliel.ui.swapContentAttribute(element, "data-alt-visual");
            nelliel.ui.switchDataCommand(element, "expand-thread", "collapse-thread");
            target_element.innerHTML = request.responseText;
        }
    };

    request.send();
}

nelliel.ui.highlightPost = function(post_id) {
    var post_elements = document.getElementsByClassName("post-corral");
    var id_sub = post_id.split("_");
    var id_op = id_sub[0] == id_sub[1] ? true : false;

    for (i = 0; i < post_elements.length; i++) {
        var current_id = post_elements[i].id.replace("post-id-", "");
        var post_container = document.getElementById("post-container-" + current_id);

        if (post_elements[i].id == "post-id-" + post_id && !id_op) {
            post_container.className += " post-highlight";
        } else {
            post_container.className = post_container.className.replace(/\post-highlight\b/g, "");
        }
    }
}

nelliel.ui.inlineExpandReduce = function(element, command) {
    if (element.hasAttribute("data-other-dims")) {
        var new_location = element.getAttribute("data-other-loc");
        var old_location = element.getAttribute("src");
        var image_dims = element.getAttribute("data-other-dims");
        var width = image_dims.match(/w([0-9]+)/)[1];
        var height = image_dims.match(/h([0-9]+)/)[1];
        var old_width = element.getAttribute("width");
        var old_height = element.getAttribute("height");
        element.setAttribute("width", width);
        element.setAttribute("height", height);
        element.setAttribute("data-other-dims", 'w' + old_width + 'h' + old_height);
        element.setAttribute("src", new_location);
        element.setAttribute("data-other-loc", old_location);
        nelliel.ui.switchDataCommand(element, "inline-reduce", "inline-expand");
    }
}

nelliel.ui.showLinkedPost = function(element, event) {
    var href = element.getAttribute("href");
    var post_id = href.match(/#p([0-9_]+)/)[1];

    if (document.getElementById("post-quote-popup-" + post_id) !== null) {
        return;
    }

    var offsetY = window.pageYOffset || document.documentElement.scrollTop;
    var offsetX = window.pageXOffset || document.documentElement.scrollLeft;
    var popup_div = document.createElement("div");
    popup_div.id = "post-quote-popup-" + post_id;
    popup_div.setAttribute("class", "post-quote-popup");
    var element_rect = element.getBoundingClientRect();
    nelliel.ui.addBoundingClientRectProperties(element_rect);

    if (document.getElementById("post-container-" + post_id) !== null) {
        var quoted_post = document.getElementById("post-container-" + post_id).cloneNode(true);
        quoted_post.className = quoted_post.className.replace(/\op-post\b/g, "reply-post");
        quoted_post.className += " popup-mod";
        popup_div.appendChild(quoted_post);
        element.parentNode.insertBefore(popup_div, element);
        var popup_rect = quoted_post.getBoundingClientRect();
        nelliel.ui.addBoundingClientRectProperties(popup_rect);
        popup_div.style.left = (element_rect.right + offsetX + 10) + 'px';
        popup_div.style.top = ((element_rect.y + offsetY) - (popup_rect.height / 2)) + 'px';
    } else {
        var request = new XMLHttpRequest();
        request.open('GET', element.getAttribute("href"));
        request.responseType = "document";
        request.onload = function() {
            if (request.status === 200) {
                var quoted_post = request.response.getElementById("post-container-" + post_id);
                quoted_post.className = quoted_post.className.replace(/\op-post\b/g, "reply-post");
                quoted_post.className += " popup-mod";
                popup_div.appendChild(quoted_post);
                element.parentNode.insertBefore(popup_div, element);
                var popup_rect = quoted_post.getBoundingClientRect();
                nelliel.ui.addBoundingClientRectProperties(popup_rect);
                popup_div.style.left = (element_rect.right + offsetX + 5) + 'px';
                popup_div.style.top = ((element_rect.y + offsetY) - (popup_rect.height / 2)) + 'px';
            }
        };
        request.send();
    }
}

nelliel.ui.hideLinkedPost = function(element, event) {
    var href = element.getAttribute("href");
    var post_id = href.match(/#p([0-9_]+)/)[1];
    var target_popup = document.getElementById("post-quote-popup-" + post_id);

    if (target_popup !== null) {
        target_popup.remove();
    }
}

nelliel.ui.linkPost = function(post_number) {
    document.postingform.wordswordswords.value = document.postingform.wordswordswords.value + '>>' + post_number + '\n';
}

nelliel.ui.toggleHidden = function(element) {
    if(element.className.search("hidden") === -1) {
        element.className += " hidden";
    } else {
        element.className = element.className.replace(/\bhidden\b/g, "");
    }
}

nelliel.ui.swapContentAttribute = function(element, attribute_name) {
    var inner = element.innerHTML;
    element.innerHTML = element.getAttribute(attribute_name);
    element.setAttribute(attribute_name, inner);
}

nelliel.ui.switchDataCommand = function(element, option_one, option_two) {
    var data_command = element.getAttribute("data-command");

    if (data_command.indexOf(option_one) > -1 ) {
        element.setAttribute("data-command", option_two);
    }
    else if (data_command.indexOf(option_two) > -1 ) {
        element.setAttribute("data-command", option_one);
    }
}

nelliel.ui.addBoundingClientRectProperties = function(bounding_rect) {
    bounding_rect.width = bounding_rect.width || bounding_rect.right - bounding_rect.left;
    bounding_rect.height = bounding_rect.height || bounding_rect.bottom - bounding_rect.top;
    bounding_rect.x = bounding_rect.x || bounding_rect.left + (bounding_rect.width / 2);
    bounding_rect.y = bounding_rect.y || bounding_rect.top + (bounding_rect.height / 2);
}<commit_msg>And now works on expand/collapse too<commit_after>nelliel.ui.hideShowThread = function(element, command) {
    var id = element.getAttribute("data-id");
    var thread_id = id.split('_')[0];
    var post_files = document.getElementById("post-files-container-" + id);
    var post_contents = document.getElementById("post-contents-" + id);
    var thread_container = document.getElementById("thread-expand-" + thread_id);

    if (command === "hide-thread") {
        dataBin.hidden_threads[id] = Date.now();
    } else if (command === "show-thread") {
        delete dataBin.hidden_threads[id];
    }

    if (thread_container !== null) {
        nelliel.ui.toggleHidden(thread_container);
    }

    if (post_files !== null) {
        nelliel.ui.toggleHidden(post_files);
    }

    if (post_contents !== null) {
        nelliel.ui.toggleHidden(post_contents);
    }

    nelliel.core.storeInLocalStorage(dataBin.hidden_threads_id, dataBin.hidden_threads);
    nelliel.ui.switchDataCommand(element, "hide-thread", "show-thread");
    nelliel.ui.swapContentAttribute(element, "data-alt-visual");
}

nelliel.ui.hideShowPost = function(element, command) {
    var id = element.getAttribute("data-id");
    var post_files = document.getElementById("post-files-container-" + id);
    var post_contents = document.getElementById("post-contents-" + id);

    if (command == "hide-post") {
        dataBin.hidden_posts[id] = Date.now();
    } else if (command == "show-post") {
        delete dataBin.hidden_posts[id];
    }

    if (post_files !== null) {
        nelliel.ui.toggleHidden(post_files);
    }

    if (post_contents !== null) {
        nelliel.ui.toggleHidden(post_contents);
    }

    nelliel.core.storeInLocalStorage(dataBin.hidden_posts_id, dataBin.hidden_posts);
    nelliel.ui.switchDataCommand(element, "hide-post", "show-post");
    nelliel.ui.swapContentAttribute(element, "data-alt-visual");
}

nelliel.ui.applyHidePostThread = function() {
    for (var id in dataBin.hidden_threads) {
        var thread_id = id.split('_')[0];
        var post_files = document.getElementById("post-files-container-" + id);
        var post_contents = document.getElementById("post-contents-" + id);
        var thread_container = document.getElementById("thread-expand-" + thread_id);
        var element = document.getElementById("hide-post-thread-" + id);

        if (thread_container !== null) {
            nelliel.ui.toggleHidden(thread_container);
        }

        if (post_files !== null) {
            nelliel.ui.toggleHidden(post_files);
        }

        if (post_contents !== null) {
            nelliel.ui.toggleHidden(post_contents);
        }

        nelliel.ui.switchDataCommand(element, "hide-thread", "show-thread");
        nelliel.ui.swapContentAttribute(element, "data-alt-visual");
    }

    for (var id in dataBin.hidden_posts) {
        var post_files = document.getElementById("post-files-container-" + id);
        var post_contents = document.getElementById("post-contents-" + id);
        var element = document.getElementById("hide-post-thread-" + id);

        if (post_files !== null) {
            nelliel.ui.toggleHidden(post_files);
        }

        if (post_contents !== null) {
            nelliel.ui.toggleHidden(post_contents);
        }

        nelliel.ui.switchDataCommand(element, "hide-post", "show-post");
        nelliel.ui.swapContentAttribute(element, "data-alt-visual");
    }
}

nelliel.ui.showHideFileMeta = function(element, command) {
    var full_id = element.getAttribute("data-id");
    var meta_element = document.getElementById("file-meta-" + full_id);
    nelliel.ui.swapContentAttribute(element, "data-alt-visual");
    nelliel.ui.toggleHidden(meta_element);
    nelliel.ui.switchDataCommand(element, "show-file-meta", "hide-file-meta");
}

nelliel.ui.expandCollapseThread = function(thread_id, command, element) {
    var target_element = document.getElementById("thread-expand-" + thread_id);

    if (!target_element) {
        return;
    }

    var url = "threads/" + thread_id + "/" + thread_id + "-" + command.split('-')[0] + ".html";
    var request = new XMLHttpRequest();
    request.open('GET', url);
    request.onload = function() {
        if (request.status === 200) {
            nelliel.ui.swapContentAttribute(element, "data-alt-visual");
            nelliel.ui.switchDataCommand(element, "expand-thread", "collapse-thread");
            target_element.innerHTML = request.responseText;
            nelliel.ui.applyHidePostThread();
        }
    };

    request.send();
}

nelliel.ui.highlightPost = function(post_id) {
    var post_elements = document.getElementsByClassName("post-corral");
    var id_sub = post_id.split("_");
    var id_op = id_sub[0] == id_sub[1] ? true : false;

    for (i = 0; i < post_elements.length; i++) {
        var current_id = post_elements[i].id.replace("post-id-", "");
        var post_container = document.getElementById("post-container-" + current_id);

        if (post_elements[i].id == "post-id-" + post_id && !id_op) {
            post_container.className += " post-highlight";
        } else {
            post_container.className = post_container.className.replace(/\post-highlight\b/g, "");
        }
    }
}

nelliel.ui.inlineExpandReduce = function(element, command) {
    if (element.hasAttribute("data-other-dims")) {
        var new_location = element.getAttribute("data-other-loc");
        var old_location = element.getAttribute("src");
        var image_dims = element.getAttribute("data-other-dims");
        var width = image_dims.match(/w([0-9]+)/)[1];
        var height = image_dims.match(/h([0-9]+)/)[1];
        var old_width = element.getAttribute("width");
        var old_height = element.getAttribute("height");
        element.setAttribute("width", width);
        element.setAttribute("height", height);
        element.setAttribute("data-other-dims", 'w' + old_width + 'h' + old_height);
        element.setAttribute("src", new_location);
        element.setAttribute("data-other-loc", old_location);
        nelliel.ui.switchDataCommand(element, "inline-reduce", "inline-expand");
    }
}

nelliel.ui.showLinkedPost = function(element, event) {
    var href = element.getAttribute("href");
    var post_id = href.match(/#p([0-9_]+)/)[1];

    if (document.getElementById("post-quote-popup-" + post_id) !== null) {
        return;
    }

    var offsetY = window.pageYOffset || document.documentElement.scrollTop;
    var offsetX = window.pageXOffset || document.documentElement.scrollLeft;
    var popup_div = document.createElement("div");
    popup_div.id = "post-quote-popup-" + post_id;
    popup_div.setAttribute("class", "post-quote-popup");
    var element_rect = element.getBoundingClientRect();
    nelliel.ui.addBoundingClientRectProperties(element_rect);

    if (document.getElementById("post-container-" + post_id) !== null) {
        var quoted_post = document.getElementById("post-container-" + post_id).cloneNode(true);
        quoted_post.className = quoted_post.className.replace(/\op-post\b/g, "reply-post");
        quoted_post.className += " popup-mod";
        popup_div.appendChild(quoted_post);
        element.parentNode.insertBefore(popup_div, element);
        var popup_rect = quoted_post.getBoundingClientRect();
        nelliel.ui.addBoundingClientRectProperties(popup_rect);
        popup_div.style.left = (element_rect.right + offsetX + 10) + 'px';
        popup_div.style.top = ((element_rect.y + offsetY) - (popup_rect.height / 2)) + 'px';
    } else {
        var request = new XMLHttpRequest();
        request.open('GET', element.getAttribute("href"));
        request.responseType = "document";
        request.onload = function() {
            if (request.status === 200) {
                var quoted_post = request.response.getElementById("post-container-" + post_id);
                quoted_post.className = quoted_post.className.replace(/\op-post\b/g, "reply-post");
                quoted_post.className += " popup-mod";
                popup_div.appendChild(quoted_post);
                element.parentNode.insertBefore(popup_div, element);
                var popup_rect = quoted_post.getBoundingClientRect();
                nelliel.ui.addBoundingClientRectProperties(popup_rect);
                popup_div.style.left = (element_rect.right + offsetX + 5) + 'px';
                popup_div.style.top = ((element_rect.y + offsetY) - (popup_rect.height / 2)) + 'px';
            }
        };
        request.send();
    }
}

nelliel.ui.hideLinkedPost = function(element, event) {
    var href = element.getAttribute("href");
    var post_id = href.match(/#p([0-9_]+)/)[1];
    var target_popup = document.getElementById("post-quote-popup-" + post_id);

    if (target_popup !== null) {
        target_popup.remove();
    }
}

nelliel.ui.linkPost = function(post_number) {
    document.postingform.wordswordswords.value = document.postingform.wordswordswords.value + '>>' + post_number + '\n';
}

nelliel.ui.toggleHidden = function(element) {
    if(element.className.search("hidden") === -1) {
        element.className += " hidden";
    } else {
        element.className = element.className.replace(/\bhidden\b/g, "");
    }
}

nelliel.ui.swapContentAttribute = function(element, attribute_name) {
    var inner = element.innerHTML;
    element.innerHTML = element.getAttribute(attribute_name);
    element.setAttribute(attribute_name, inner);
}

nelliel.ui.switchDataCommand = function(element, option_one, option_two) {
    var data_command = element.getAttribute("data-command");

    if (data_command.indexOf(option_one) > -1 ) {
        element.setAttribute("data-command", option_two);
    }
    else if (data_command.indexOf(option_two) > -1 ) {
        element.setAttribute("data-command", option_one);
    }
}

nelliel.ui.addBoundingClientRectProperties = function(bounding_rect) {
    bounding_rect.width = bounding_rect.width || bounding_rect.right - bounding_rect.left;
    bounding_rect.height = bounding_rect.height || bounding_rect.bottom - bounding_rect.top;
    bounding_rect.x = bounding_rect.x || bounding_rect.left + (bounding_rect.width / 2);
    bounding_rect.y = bounding_rect.y || bounding_rect.top + (bounding_rect.height / 2);
}<|endoftext|>


<commit_before>angular
  .module('app')
  .controller('authController', [
    '$scope',
    'userService',
    'Facebook',
    'actionKitService',
    function($scope, userAPI, FB, actionKitService) {
      var inkBlob, inkBlobThumb;
      $scope.formErrors = {};
      $scope.formUser = userAPI.newUser();

      $scope.register = function() {
        _clearErrors();

        if ($scope.formUser.password !== $scope.formUser.passConfirmation) {
          _addError('password', 'Password mismatch');
          _addError('passConfirmation', 'Password mismatch');
        }

        if ($scope.formUser.password.length < 6) {
          _addError('password', 'Too short. Minimum of six characters.');
        }

        if ($scope.formUser.zip.toString().length != 5) {
          _addError('zip', 'Zip must be 5 digits long.');
        }

        if (Object.keys($scope.formErrors).length === 0) {

          // make a call to see if this user has already signed up with ActionKit
          actionKitService.getUser($scope.formUser.email).then(function(response) {

              // the user has not already signed up
              if(response === false) {

                  // make a call to add this user to ActionKit
                  var user = {
                      'email': $scope.formUser.email,
                      'first_name': $scope.formUser.first_name,
                      'last_name': $scope.formUser.last_name,
                      'city': $scope.formUser.city,
                      'state': $scope.formUser.state,
                      'zip': $scope.formUser.zip.toString()
                  };

                  actionKitService.createUser(user).then(function (userResponse) {
                      $scope.formUser.actionkitId = userResponse;
                      $scope.formUser.$save();
                  });

              } else {

                  // get the location of the current ActionKit user
                  $scope.formUser.actionkitId = response.id;
                  $scope.formUser.$save();
              }

              _close();
          });
        }
      };

      $scope.update = function() {
        _clearErrors();

        if (Object.keys($scope.formErrors).length === 0) {
          $scope.formUser.$save();
          _close();
        }
      };

      $scope.login = function() {
        _clearErrors();
        userAPI.login($scope.formUser).error(function(data, status) {
          _addError('extra', 'Login Invalid');
        }).success(function() {
          _close();
        });
      };

      $scope.logout = function() {
        _clearErrors();
        _close();
        userAPI.logout();
      };

      $scope.cancel = function() {
        if (inkBlob) {
          try {
            filepicker.remove(inkBlobThumb);
            filepicker.remove(inkBlob);
          } catch (err) {

          }
        }
        _close();
      };

      $scope.clear = function() {
        _clearUser();
        _clearErrors();
      };

      $scope.fbLogin = function() {
        _clearErrors();
        FB.login().then(function(user) {
          userAPI.facebookLogin(user);
          _close();
        }, function() {
          _addError('extra', "Facebook Login Fail");
        });
      };

      $scope.uploadAvatar = function() {
        filepicker.setKey('ACoTSGXT4Rj2XWKKTZAaJz');
        filepicker.pick({
          'mimetype': "image/*"
        }, function(InkBlob) {
          filepicker.convert(InkBlob, {
              width: 200,
              height: 200
            },
            function(InkThumb) {
              $scope.formUser.thumb = InkThumb.url;
              $scope.$digest();
              inkBlobThumb = InkThumb;
            });
          inkBlob = InkBlob;
          $scope.formUser.avatar = InkBlob.url;
        });
      };

      //private methods to handle common task

      function _close() {
        _clearErrors();
        if ($scope.closeModal) {
          $scope.closeModal();
        }
      }

      function _clearErrors() {
        $scope.formErrors = null;
        $scope.formErrors = {};
      }

      function _clearUser() {
        $scope.formUser = null;
        $scope.formUser = {};
      }

      function _addError(field, message) {
        $scope.formErrors[field] = message;
      }

      function _errored(response) {
        if (response.errors) {
          Object.each(response.errors, function(field, errors) {
            _addError(field, errors.first());
          });
        }
      }
    }
  ]);
<commit_msg>Log the user in after that register<commit_after>angular
  .module('app')
  .controller('authController', [
    '$scope',
    'userService',
    'Facebook',
    'actionKitService',
    function($scope, userAPI, FB, actionKitService) {
      var inkBlob, inkBlobThumb;
      $scope.formErrors = {};
      $scope.formUser = userAPI.newUser();

      $scope.register = function() {
        _clearErrors();

        if ($scope.formUser.password !== $scope.formUser.passConfirmation) {
          _addError('password', 'Password mismatch');
          _addError('passConfirmation', 'Password mismatch');
        }

        if ($scope.formUser.password.length < 6) {
          _addError('password', 'Too short. Minimum of six characters.');
        }

        if ($scope.formUser.zip.toString().length != 5) {
          _addError('zip', 'Zip must be 5 digits long.');
        }

        if (Object.keys($scope.formErrors).length === 0) {

          // make a call to see if this user has already signed up with ActionKit
          actionKitService.getUser($scope.formUser.email).then(function(response) {

              // the user has not already signed up
              if(response === false) {

                  // make a call to add this user to ActionKit
                  var user = {
                      'email': $scope.formUser.email,
                      'first_name': $scope.formUser.first_name,
                      'last_name': $scope.formUser.last_name,
                      'city': $scope.formUser.city,
                      'state': $scope.formUser.state,
                      'zip': $scope.formUser.zip.toString()
                  };

                  actionKitService.createUser(user).then(function (userResponse) {
                      $scope.formUser.actionkitId = userResponse;
                      $scope.formUser.$save();
                      $scope.login();
                  });

              } else {

                  // get the location of the current ActionKit user
                  $scope.formUser.actionkitId = response.id;
                  $scope.formUser.$save();
                  $scope.login();
              }

              _close();
          });
        }
      };

      $scope.update = function() {
        _clearErrors();

        if (Object.keys($scope.formErrors).length === 0) {
          $scope.formUser.$save();
          _close();
        }
      };

      $scope.login = function() {
        _clearErrors();
        userAPI.login($scope.formUser).error(function(data, status) {
          _addError('extra', 'Login Invalid');
        }).success(function() {
          _close();
        });
      };

      $scope.logout = function() {
        _clearErrors();
        _close();
        userAPI.logout();
      };

      $scope.cancel = function() {
        if (inkBlob) {
          try {
            filepicker.remove(inkBlobThumb);
            filepicker.remove(inkBlob);
          } catch (err) {

          }
        }
        _close();
      };

      $scope.clear = function() {
        _clearUser();
        _clearErrors();
      };

      $scope.fbLogin = function() {
        _clearErrors();
        FB.login().then(function(user) {
          userAPI.facebookLogin(user);
          _close();
        }, function() {
          _addError('extra', "Facebook Login Fail");
        });
      };

      $scope.uploadAvatar = function() {
        filepicker.setKey('ACoTSGXT4Rj2XWKKTZAaJz');
        filepicker.pick({
          'mimetype': "image/*"
        }, function(InkBlob) {
          filepicker.convert(InkBlob, {
              width: 200,
              height: 200
            },
            function(InkThumb) {
              $scope.formUser.thumb = InkThumb.url;
              $scope.$digest();
              inkBlobThumb = InkThumb;
            });
          inkBlob = InkBlob;
          $scope.formUser.avatar = InkBlob.url;
        });
      };

      //private methods to handle common task

      function _close() {
        _clearErrors();
        if ($scope.closeModal) {
          $scope.closeModal();
        }
      }

      function _clearErrors() {
        $scope.formErrors = null;
        $scope.formErrors = {};
      }

      function _clearUser() {
        $scope.formUser = null;
        $scope.formUser = {};
      }

      function _addError(field, message) {
        $scope.formErrors[field] = message;
      }

      function _errored(response) {
        if (response.errors) {
          Object.each(response.errors, function(field, errors) {
            _addError(field, errors.first());
          });
        }
      }
    }
  ]);
<|endoftext|>


<commit_before>/**
 * TagSpaces - universal file and folder organizer
 * Copyright (C) 2017-present TagSpaces UG (haftungsbeschraenkt)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License (version 3) as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 * @flow
 */

import React from 'react';
import uuidv1 from 'uuid';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import Launch from '@material-ui/icons/Launch';
import Edit from '@material-ui/icons/Edit';
import DeleteIcon from '@material-ui/icons/DeleteForever';
import ListItemIcon from '@material-ui/core/ListItemIcon';
import ListItemText from '@material-ui/core/ListItemText';
import Menu from '@material-ui/core/Menu';
import MenuItem from '@material-ui/core/MenuItem';
import ConfirmDialog from '../dialogs/ConfirmDialog';
import EditTagDialog from '../dialogs/EditTagDialog';
import { type Tag, type TagGroup } from '../../reducers/taglibrary';
import { actions as LocationIndexActions } from '../../reducers/location-index';
import i18n from '../../services/i18n';
import { type SearchQuery } from '../../services/search';
import { getMaxSearchResults } from '../../reducers/settings';

type Props = {
  anchorEl?: Object,
  open?: boolean,
  onClose: () => void,
  selectedTag?: Tag,
  selectedTagGroupEntry?: TagGroup,
  deleteTag: (uuid: string, tagGroupUuid: string) => void,
  searchLocationIndex: (searchQuery: SearchQuery) => void,
  editTag: () => void,
  maxSearchResults: number
};

type State = {
  isEditTagDialogOpened?: boolean,
  isDeleteTagDialogOpened?: boolean
};

class TagLibraryMenu extends React.Component<Props, State> {
  state = {
    isEditTagDialogOpened: false,
    isDeleteTagDialogOpened: false
  };

  tagSelectedFiles = () => {
    // TODO not implemented
    this.props.onClose();
  };

  showFilesWithThisTag = () => {
    if (this.props.selectedTag) {
      this.props.searchLocationIndex({
        tags: [this.props.selectedTag.title],
        maxSearchResults: this.props.maxSearchResults
      });
    }
    this.props.onClose();
  };

  showEditTagDialog = () => {
    this.props.onClose();
    this.setState({ isEditTagDialogOpened: true });
  };

  showDeleteTagDialog = () => {
    this.props.onClose();
    this.setState({ isDeleteTagDialogOpened: true });
  };

  handleCloseDialogs = () => {
    this.setState({
      isEditTagDialogOpened: false,
      isDeleteTagDialogOpened: false
    });
  };

  confirmDeleteTag = () => {
    if (this.props.selectedTag && this.props.selectedTagGroupEntry) {
      this.props.deleteTag(
        this.props.selectedTag.id,
        this.props.selectedTagGroupEntry.uuid
      );
    }
  };

  render = () => (

      <Menu
        anchorEl={this.props.anchorEl}
        open={this.props.open}
        onClose={this.props.onClose}
      >
        <MenuItem
          data-tid="showFilesWithThisTag"
          onClick={this.showFilesWithThisTag}
        >
          <ListItemIcon>
            <Launch />
          </ListItemIcon>
          <ListItemText inset primary={i18n.t('core:showFilesWithThisTag')} />
        </MenuItem>
        <MenuItem data-tid="editTagDialog" onClick={this.showEditTagDialog}>
          <ListItemIcon>
            <Edit />
          </ListItemIcon>
          <ListItemText inset primary={i18n.t('core:editTag')} />
        </MenuItem>
        <MenuItem data-tid="deleteTagDialog" onClick={this.showDeleteTagDialog}>
          <ListItemIcon>
            <DeleteIcon />
          </ListItemIcon>
          <ListItemText
            inset
            primary={i18n.t('core:deleteTagFromTagGroup')}
          />
        </MenuItem>
      </Menu>
      <EditTagDialog
        open={this.state.isEditTagDialogOpened}
        onClose={this.handleCloseDialogs}
        editTag={this.props.editTag}
        selectedTagGroupEntry={this.props.selectedTagGroupEntry}
        selectedTag={this.props.selectedTag}
      />
      <ConfirmDialog
        open={this.state.isDeleteTagDialogOpened}
        onClose={this.handleCloseDialogs}
        title={i18n.t('core:deleteTagFromTagGroup')}
        content={i18n.t('core:deleteTagFromTagGroupContentConfirm', {
          tagName: this.props.selectedTag ? this.props.selectedTag.title : ''
        })}
        confirmCallback={result => {
          if (result) {
            this.confirmDeleteTag();
          }
        }}
        cancelDialogTID={'cancelDeleteTagDialogTagMenu'}
        confirmDialogTID={'confirmDeleteTagDialogTagMenu'}
      />

  );
}

function mapStateToProps(state) {
  return {
    maxSearchResults: getMaxSearchResults(state)
  };
}

function mapDispatchToProps(dispatch) {
  return bindActionCreators({
    searchLocationIndex: LocationIndexActions.searchLocationIndex,
  }, dispatch);
}

export default connect(mapStateToProps, mapDispatchToProps)(TagLibraryMenu);
<commit_msg>Fixed showFilesWithThisTag function not working.<commit_after>/**
 * TagSpaces - universal file and folder organizer
 * Copyright (C) 2017-present TagSpaces UG (haftungsbeschraenkt)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License (version 3) as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 * @flow
 */

import React from 'react';
import uuidv1 from 'uuid';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import Launch from '@material-ui/icons/Launch';
import Edit from '@material-ui/icons/Edit';
import DeleteIcon from '@material-ui/icons/DeleteForever';
import ListItemIcon from '@material-ui/core/ListItemIcon';
import ListItemText from '@material-ui/core/ListItemText';
import Menu from '@material-ui/core/Menu';
import MenuItem from '@material-ui/core/MenuItem';
import ConfirmDialog from '../dialogs/ConfirmDialog';
import EditTagDialog from '../dialogs/EditTagDialog';
import { type Tag, type TagGroup } from '../../reducers/taglibrary';
import { actions as LocationIndexActions } from '../../reducers/location-index';
import i18n from '../../services/i18n';
import { type SearchQuery } from '../../services/search';
import { getMaxSearchResults } from '../../reducers/settings';

type Props = {
  anchorEl?: Object,
  open?: boolean,
  onClose: () => void,
  selectedTag?: Tag,
  selectedTagGroupEntry?: TagGroup,
  deleteTag: (uuid: string, tagGroupUuid: string) => void,
  searchLocationIndex: (searchQuery: SearchQuery) => void,
  editTag: () => void,
  maxSearchResults: number
};

type State = {
  isEditTagDialogOpened?: boolean,
  isDeleteTagDialogOpened?: boolean
};

class TagLibraryMenu extends React.Component<Props, State> {
  state = {
    isEditTagDialogOpened: false,
    isDeleteTagDialogOpened: false
  };

  tagSelectedFiles = () => {
    // TODO not implemented
    this.props.onClose();
  };

  showFilesWithThisTag = () => {
    if (this.props.selectedTag) {
      this.props.searchLocationIndex({
        tagsAND: [this.props.selectedTag.title],
        maxSearchResults: this.props.maxSearchResults
      });
    }
    this.props.onClose();
  };

  showEditTagDialog = () => {
    this.props.onClose();
    this.setState({ isEditTagDialogOpened: true });
  };

  showDeleteTagDialog = () => {
    this.props.onClose();
    this.setState({ isDeleteTagDialogOpened: true });
  };

  handleCloseDialogs = () => {
    this.setState({
      isEditTagDialogOpened: false,
      isDeleteTagDialogOpened: false
    });
  };

  confirmDeleteTag = () => {
    if (this.props.selectedTag && this.props.selectedTagGroupEntry) {
      this.props.deleteTag(
        this.props.selectedTag.id,
        this.props.selectedTagGroupEntry.uuid
      );
    }
  };

  render = () => (

      <Menu
        anchorEl={this.props.anchorEl}
        open={this.props.open}
        onClose={this.props.onClose}
      >
        <MenuItem
          data-tid="showFilesWithThisTag"
          onClick={this.showFilesWithThisTag}
        >
          <ListItemIcon>
            <Launch />
          </ListItemIcon>
          <ListItemText inset primary={i18n.t('core:showFilesWithThisTag')} />
        </MenuItem>
        <MenuItem data-tid="editTagDialog" onClick={this.showEditTagDialog}>
          <ListItemIcon>
            <Edit />
          </ListItemIcon>
          <ListItemText inset primary={i18n.t('core:editTag')} />
        </MenuItem>
        <MenuItem data-tid="deleteTagDialog" onClick={this.showDeleteTagDialog}>
          <ListItemIcon>
            <DeleteIcon />
          </ListItemIcon>
          <ListItemText
            inset
            primary={i18n.t('core:deleteTagFromTagGroup')}
          />
        </MenuItem>
      </Menu>
      <EditTagDialog
        open={this.state.isEditTagDialogOpened}
        onClose={this.handleCloseDialogs}
        editTag={this.props.editTag}
        selectedTagGroupEntry={this.props.selectedTagGroupEntry}
        selectedTag={this.props.selectedTag}
      />
      <ConfirmDialog
        open={this.state.isDeleteTagDialogOpened}
        onClose={this.handleCloseDialogs}
        title={i18n.t('core:deleteTagFromTagGroup')}
        content={i18n.t('core:deleteTagFromTagGroupContentConfirm', {
          tagName: this.props.selectedTag ? this.props.selectedTag.title : ''
        })}
        confirmCallback={result => {
          if (result) {
            this.confirmDeleteTag();
          }
        }}
        cancelDialogTID={'cancelDeleteTagDialogTagMenu'}
        confirmDialogTID={'confirmDeleteTagDialogTagMenu'}
      />

  );
}

function mapStateToProps(state) {
  return {
    maxSearchResults: getMaxSearchResults(state)
  };
}

function mapDispatchToProps(dispatch) {
  return bindActionCreators({
    searchLocationIndex: LocationIndexActions.searchLocationIndex,
  }, dispatch);
}

export default connect(mapStateToProps, mapDispatchToProps)(TagLibraryMenu);
<|endoftext|>