<commit_before>/* eslint-env browser, mocha */
/* global expect, sinon, units */
/* eslint no-unused-expressions: 0 */

'use strict';

describe('units', function() {
  // Setup
  //------------------------------------------------------------------------------

  var lengthUnits = ['%', 'ch', 'cm', 'em', 'ex', 'in', 'mm', 'pc', 'pt', 'px', 'rem', 'vh', 'vmax', 'vmin', 'vw'];
  var angleUnits = ['deg', 'grad', 'rad', 'turn'];
  var MAX_SAFE_INTEGER = 9007199254740991;
  var VALUE = 10;
  var DOCUMENT_FONT_SIZE = parseFloat(getComputedStyle(document.documentElement, '').fontSize);
  var element = document.createElement('div');
  document.body.appendChild(element);
  document.body.style.height = '100px';
  element.style.width = '1in';
  var DPI = element.offsetWidth;
  var ELEMENT_FONT_SIZE = parseFloat(getComputedStyle(element, '').fontSize);
  var resetElement = function() {
    element.style.position = null;
    element.innerHTML = null;
    element.style.height = '100px';
    element.style.width = '100px';
  };
  resetElement();

  // Library
  //------------------------------------------------------------------------------

  it('should be defined as an object', function() {
    expect(units).to.be.an('object');
  });

  // units#parse
  //------------------------------------------------------------------------------

  var parse = function(value, unit, property, VALUENumber, VALUEUnit) {
    expect(units.parse(value + unit, property)).to.deep.equal({
      'value': typeof VALUENumber === 'number'
        ? VALUENumber
        : value,
      'unit': typeof VALUEUnit !== 'undefined'
        ? VALUEUnit
        : unit
    });
  };

  it('should parse valid length VALUEs in units#parse', function() {
    for (var i = 0; i < lengthUnits.length; i++) {
      parse(0, lengthUnits[i], 'width');
      parse(1, lengthUnits[i], 'width');
      parse(-1, lengthUnits[i], 'width');
      parse(MAX_SAFE_INTEGER, lengthUnits[i], 'width');
      parse(-MAX_SAFE_INTEGER, lengthUnits[i], 'width');
      parse(0.000001, lengthUnits[i], 'width');
      parse('.000001', lengthUnits[i], 'width', 0.000001);
      parse(-0.000001, lengthUnits[i], 'width');
      parse('-.000001', lengthUnits[i], 'width', -0.000001);
    }
  });

  it('should parse valid angle VALUEs in units#parse', function() {
    for (var i = 0; i < angleUnits.length; i++) {
      parse(0, angleUnits[i], 'rotateX');
      parse(1, angleUnits[i], 'rotateX');
      parse(-1, angleUnits[i], 'rotateX');
      parse(MAX_SAFE_INTEGER, angleUnits[i], 'rotateX');
      parse(-MAX_SAFE_INTEGER, angleUnits[i], 'rotateX');
      parse(0.000001, angleUnits[i], 'rotateX');
      parse('.000001', angleUnits[i], 'rotateX', 0.000001);
      parse(-0.000001, angleUnits[i], 'rotateX');
      parse('-.000001', angleUnits[i], 'rotateX', -0.000001);
    }
  });

  it('should use correct default units when numeric VALUEs are passed to units#parse', function() {
    parse(0, '', 'width', null, 'px');
    parse(0, '', 'opacity', null, '');
    parse(0, '', 'rotateX', null, 'deg');
    parse(0, '', 'rotateY', null, 'deg');
    parse(0, '', 'rotateZ', null, 'deg');
    parse(0, '', 'skewX', null, 'deg');
    parse(0, '', 'skewY', null, 'deg');
    parse(0, '', 'scaleX', null, '');
    parse(0, '', 'scaleY', null, '');
    parse(0, '', 'scaleZ', null, '');
    parse(0, '', 'lineHeight', null, '');
  });

  it('should use correct default VALUEs when non-numeric VALUEs are passed to units#parse', function() {
    parse('', 'px', 'width', 0, 'px');
    parse('', '', 'opacity', 1, '');
    parse('', '', 'scaleX', 1, '');
    parse('', '', 'scaleY', 1, '');
    parse('', '', 'scaleZ', 1, '');
    parse('', '', 'lineHeight', 1, '');
  });

  // units#getDefault
  //------------------------------------------------------------------------------

  it('should return correct defaults in units#getDefault', function() {
    expect(units.getDefault('width')).to.equal('0px');
    expect(units.getDefault('opacity')).to.equal('1');
    expect(units.getDefault('rotateX')).to.equal('0deg');
    expect(units.getDefault('rotateY')).to.equal('0deg');
    expect(units.getDefault('rotateZ')).to.equal('0deg');
    expect(units.getDefault('skewX')).to.equal('0deg');
    expect(units.getDefault('skewY')).to.equal('0deg');
    expect(units.getDefault('scaleX')).to.equal('1');
    expect(units.getDefault('scaleY')).to.equal('1');
    expect(units.getDefault('scaleZ')).to.equal('1');
    expect(units.getDefault('lineHeight')).to.equal('1');
  });

  // units#convert
  //------------------------------------------------------------------------------

  var convert = function(to, value, property, expectedValue) {
    expect(units.convert(to, value, element, property)).to.deep.equal({
      'value': expectedValue,
      'unit': to
    });
  };

  it('should convert valid px length units in units#convert', function() {
    convert('px', VALUE + 'px', 'width', VALUE);
    convert('', VALUE + 'px', 'width', VALUE / ELEMENT_FONT_SIZE);
    convert('%', VALUE + 'px', 'width', (VALUE / element.parentNode.offsetWidth) * 100);
    convert('cm', VALUE + 'px', 'width', VALUE / DPI * 2.54);
    convert('em', VALUE + 'px', 'width', VALUE / ELEMENT_FONT_SIZE);
    convert('in', VALUE + 'px', 'width', VALUE / DPI);
    convert('mm', VALUE + 'px', 'width', VALUE * 2.54 / DPI * 10);
    convert('pc', VALUE + 'px', 'width', VALUE / ((DPI / 72) * 12));
    convert('pt', VALUE + 'px', 'width', VALUE * 72 / DPI);
    convert('rem', VALUE + 'px', 'width', VALUE / DOCUMENT_FONT_SIZE);

    // Setup + tests + tear-down for units dependent on element content
    element.style.width = null;
    element.style.height = null;
    element.style.position = 'absolute';
    element.innerHTML = '0';
    convert('ch', VALUE + 'px', 'width', VALUE / element.offsetWidth);
    element.innerHTML = 'x';
    convert('ex', VALUE + 'px', 'width', VALUE / element.offsetHeight);
    resetElement();

    // Cover utilities#getRelativeElementDimension branches
    convert('%', VALUE + 'px', 'translateY', (VALUE / element.offsetHeight) * 100);
    element.style.position = 'absolute';
    convert('%', VALUE + 'px', 'width', (VALUE / element.offsetParent.offsetWidth) * 100);
    convert('%', VALUE + 'px', 'height', (VALUE / element.offsetParent.offsetHeight) * 100);
    resetElement();

    // Cover utilities#ifZeroThenOne branches
    document.documentElement.style.fontSize = 0;
    convert('rem', VALUE + 'px', 'width', VALUE);
    document.documentElement.style.fontSize = null;
  });

  it('should convert valid blank length units in units#convert', function() {
    var px = ELEMENT_FONT_SIZE * VALUE;

    convert('px', VALUE + '', 'lineHeight', px);
    convert('%', VALUE + '', 'lineHeight', (px / element.parentNode.offsetWidth) * 100);
  });

  it('should convert valid % length units in units#convert', function() {
    convert('px', VALUE + '%', 'width', (VALUE * element.parentNode.offsetWidth) / 100);
  });

  it('should convert valid ch length units in units#convert', function() {
    element.style.width = null;
    element.style.position = 'absolute';
    element.innerHTML = '0';
    convert('px', VALUE + 'ch', 'width', VALUE * element.offsetWidth);
    resetElement();
  });

  it('should convert valid cm length units in units#convert', function() {
    convert('px', VALUE + 'cm', 'width', VALUE / 2.54 * DPI);
  });

  it('should convert valid em length units in units#convert', function() {
    convert('px', VALUE + 'em', 'width', VALUE * ELEMENT_FONT_SIZE);
  });

  it('should convert valid ex length units in units#convert', function() {
    element.style.height = null;
    element.style.position = 'absolute';
    element.innerHTML = 'x';
    convert('px', VALUE + 'ex', 'width', VALUE * element.offsetHeight);
    resetElement();
  });

  it('should convert valid in length units in units#convert', function() {
    convert('px', VALUE + 'in', 'width', VALUE * DPI);
  });

  it('should convert valid mm length units in units#convert', function() {
    convert('px', VALUE + 'mm', 'width', VALUE / 2.54 * DPI / 10);
  });

  it('should convert valid pc length units in units#convert', function() {
    convert('px', VALUE + 'pc', 'width', VALUE * ((DPI / 72) * 12));
  });

  it('should convert valid pt length units in units#convert', function() {
    convert('px', VALUE + 'pt', 'width', VALUE * DPI / 72);
  });

  it('should convert valid rem length units in units#convert', function() {
    convert('px', VALUE + 'rem', 'width', VALUE * DOCUMENT_FONT_SIZE);
  });
});
<commit_msg>Add angle conversion tests<commit_after>/* eslint-env browser, mocha */
/* global expect, sinon, units */
/* eslint no-unused-expressions: 0 */

'use strict';

describe('units', function() {
  // Setup
  //------------------------------------------------------------------------------

  var lengthUnits = ['%', 'ch', 'cm', 'em', 'ex', 'in', 'mm', 'pc', 'pt', 'px', 'rem', 'vh', 'vmax', 'vmin', 'vw'];
  var angleUnits = ['deg', 'grad', 'rad', 'turn'];
  var MAX_SAFE_INTEGER = 9007199254740991;
  var VALUE = 10;
  var DOCUMENT_FONT_SIZE = parseFloat(getComputedStyle(document.documentElement, '').fontSize);
  var element = document.createElement('div');
  document.body.appendChild(element);
  document.body.style.height = '100px';
  element.style.width = '1in';
  var DPI = element.offsetWidth;
  var ELEMENT_FONT_SIZE = parseFloat(getComputedStyle(element, '').fontSize);
  var resetElement = function() {
    element.style.position = null;
    element.innerHTML = null;
    element.style.height = '100px';
    element.style.width = '100px';
  };
  resetElement();

  // Library
  //------------------------------------------------------------------------------

  it('should be defined as an object', function() {
    expect(units).to.be.an('object');
  });

  // units#parse
  //------------------------------------------------------------------------------

  var parse = function(value, unit, property, VALUENumber, VALUEUnit) {
    expect(units.parse(value + unit, property)).to.deep.equal({
      'value': typeof VALUENumber === 'number'
        ? VALUENumber
        : value,
      'unit': typeof VALUEUnit !== 'undefined'
        ? VALUEUnit
        : unit
    });
  };

  it('should parse valid length values in units#parse', function() {
    for (var i = 0; i < lengthUnits.length; i++) {
      parse(0, lengthUnits[i], 'width');
      parse(1, lengthUnits[i], 'width');
      parse(-1, lengthUnits[i], 'width');
      parse(MAX_SAFE_INTEGER, lengthUnits[i], 'width');
      parse(-MAX_SAFE_INTEGER, lengthUnits[i], 'width');
      parse(0.000001, lengthUnits[i], 'width');
      parse('.000001', lengthUnits[i], 'width', 0.000001);
      parse(-0.000001, lengthUnits[i], 'width');
      parse('-.000001', lengthUnits[i], 'width', -0.000001);
    }
  });

  it('should parse valid angle values in units#parse', function() {
    for (var i = 0; i < angleUnits.length; i++) {
      parse(0, angleUnits[i], 'rotateX');
      parse(1, angleUnits[i], 'rotateX');
      parse(-1, angleUnits[i], 'rotateX');
      parse(MAX_SAFE_INTEGER, angleUnits[i], 'rotateX');
      parse(-MAX_SAFE_INTEGER, angleUnits[i], 'rotateX');
      parse(0.000001, angleUnits[i], 'rotateX');
      parse('.000001', angleUnits[i], 'rotateX', 0.000001);
      parse(-0.000001, angleUnits[i], 'rotateX');
      parse('-.000001', angleUnits[i], 'rotateX', -0.000001);
    }
  });

  it('should use correct default units when numeric values are passed to units#parse', function() {
    parse(0, '', 'width', null, 'px');
    parse(0, '', 'opacity', null, '');
    parse(0, '', 'rotateX', null, 'deg');
    parse(0, '', 'rotateY', null, 'deg');
    parse(0, '', 'rotateZ', null, 'deg');
    parse(0, '', 'skewX', null, 'deg');
    parse(0, '', 'skewY', null, 'deg');
    parse(0, '', 'scaleX', null, '');
    parse(0, '', 'scaleY', null, '');
    parse(0, '', 'scaleZ', null, '');
    parse(0, '', 'lineHeight', null, '');
  });

  it('should use correct default values when non-numeric values are passed to units#parse', function() {
    parse('', 'px', 'width', 0, 'px');
    parse('', '', 'opacity', 1, '');
    parse('', '', 'scaleX', 1, '');
    parse('', '', 'scaleY', 1, '');
    parse('', '', 'scaleZ', 1, '');
    parse('', '', 'lineHeight', 1, '');
  });

  // units#getDefault
  //------------------------------------------------------------------------------

  it('should return correct defaults in units#getDefault', function() {
    expect(units.getDefault('width')).to.equal('0px');
    expect(units.getDefault('opacity')).to.equal('1');
    expect(units.getDefault('rotateX')).to.equal('0deg');
    expect(units.getDefault('rotateY')).to.equal('0deg');
    expect(units.getDefault('rotateZ')).to.equal('0deg');
    expect(units.getDefault('skewX')).to.equal('0deg');
    expect(units.getDefault('skewY')).to.equal('0deg');
    expect(units.getDefault('scaleX')).to.equal('1');
    expect(units.getDefault('scaleY')).to.equal('1');
    expect(units.getDefault('scaleZ')).to.equal('1');
    expect(units.getDefault('lineHeight')).to.equal('1');
  });

  // units#convert (length)
  //------------------------------------------------------------------------------

  var convert = function(to, value, property, expectedValue) {
    expect(units.convert(to, value, element, property)).to.deep.equal({
      'value': expectedValue,
      'unit': to
    });
  };

  it('should convert valid px (default) length units in units#convert', function() {
    convert('px', VALUE + 'px', 'width', VALUE);
    convert('', VALUE + 'px', 'width', VALUE / ELEMENT_FONT_SIZE);
    convert('%', VALUE + 'px', 'width', (VALUE / element.parentNode.offsetWidth) * 100);
    convert('cm', VALUE + 'px', 'width', VALUE / DPI * 2.54);
    convert('em', VALUE + 'px', 'width', VALUE / ELEMENT_FONT_SIZE);
    convert('in', VALUE + 'px', 'width', VALUE / DPI);
    convert('mm', VALUE + 'px', 'width', VALUE * 2.54 / DPI * 10);
    convert('pc', VALUE + 'px', 'width', VALUE / ((DPI / 72) * 12));
    convert('pt', VALUE + 'px', 'width', VALUE * 72 / DPI);
    convert('rem', VALUE + 'px', 'width', VALUE / DOCUMENT_FONT_SIZE);

    // Setup + tests + tear-down for units dependent on element content
    element.style.width = null;
    element.style.height = null;
    element.style.position = 'absolute';
    element.innerHTML = '0';
    convert('ch', VALUE + 'px', 'width', VALUE / element.offsetWidth);
    element.innerHTML = 'x';
    convert('ex', VALUE + 'px', 'width', VALUE / element.offsetHeight);
    resetElement();

    // Cover utilities#getRelativeElementDimension branches
    convert('%', VALUE + 'px', 'translateY', (VALUE / element.offsetHeight) * 100);
    element.style.position = 'absolute';
    convert('%', VALUE + 'px', 'width', (VALUE / element.offsetParent.offsetWidth) * 100);
    convert('%', VALUE + 'px', 'height', (VALUE / element.offsetParent.offsetHeight) * 100);
    resetElement();

    // Cover utilities#ifZeroThenOne branches
    document.documentElement.style.fontSize = 0;
    convert('rem', VALUE + 'px', 'width', VALUE);
    document.documentElement.style.fontSize = null;
  });

  it('should convert valid blank length units in units#convert', function() {
    var px = ELEMENT_FONT_SIZE * VALUE;

    convert('px', VALUE + '', 'lineHeight', px);
    convert('%', VALUE + '', 'lineHeight', (px / element.parentNode.offsetWidth) * 100);
  });

  it('should convert valid % length units in units#convert', function() {
    convert('px', VALUE + '%', 'width', (VALUE * element.parentNode.offsetWidth) / 100);
  });

  it('should convert valid ch length units in units#convert', function() {
    element.style.width = null;
    element.style.position = 'absolute';
    element.innerHTML = '0';
    convert('px', VALUE + 'ch', 'width', VALUE * element.offsetWidth);
    resetElement();
  });

  it('should convert valid cm length units in units#convert', function() {
    convert('px', VALUE + 'cm', 'width', VALUE / 2.54 * DPI);
  });

  it('should convert valid em length units in units#convert', function() {
    convert('px', VALUE + 'em', 'width', VALUE * ELEMENT_FONT_SIZE);
  });

  it('should convert valid ex length units in units#convert', function() {
    element.style.height = null;
    element.style.position = 'absolute';
    element.innerHTML = 'x';
    convert('px', VALUE + 'ex', 'width', VALUE * element.offsetHeight);
    resetElement();
  });

  it('should convert valid in length units in units#convert', function() {
    convert('px', VALUE + 'in', 'width', VALUE * DPI);
  });

  it('should convert valid mm length units in units#convert', function() {
    convert('px', VALUE + 'mm', 'width', VALUE / 2.54 * DPI / 10);
  });

  it('should convert valid pc length units in units#convert', function() {
    convert('px', VALUE + 'pc', 'width', VALUE * ((DPI / 72) * 12));
  });

  it('should convert valid pt length units in units#convert', function() {
    convert('px', VALUE + 'pt', 'width', VALUE * DPI / 72);
  });

  it('should convert valid rem length units in units#convert', function() {
    convert('px', VALUE + 'rem', 'width', VALUE * DOCUMENT_FONT_SIZE);
  });

  // units#convert (angle)
  //------------------------------------------------------------------------------

  it('should convert valid deg (default) length units in units#convert', function() {
    convert('grad', VALUE + 'deg', 'rotateZ', VALUE / 0.9);
    convert('rad', VALUE + 'deg', 'rotateZ', VALUE * (Math.PI / 180));
    convert('turn', VALUE + 'deg', 'rotateZ', VALUE / 360);
  });

  it('should convert valid grad length units in units#convert', function() {
    convert('deg', VALUE + 'grad', 'rotateZ', VALUE * 0.9);
  });

  it('should convert valid rad length units in units#convert', function() {
    convert('deg', VALUE + 'rad', 'rotateZ', VALUE / (Math.PI / 180));
  });

  it('should convert valid turn length units in units#convert', function() {
    convert('deg', VALUE + 'turn', 'rotateZ', VALUE * 360);
  });
});
<|endoftext|>


<commit_before> (function () {
    'use strict'
    NodeList.prototype.forEach = Array.prototype.forEach;
    HTMLCollection.prototype.forEach = Array.prototype.forEach;

    var n = {
        Entry: {
            // a guard to not do read and current status checks on every scroll
            check_block: false,
            // the entry currently marked
            current_entry: 0,
            // amount of pixel from the top where an entry has to have reached until it is set as current
            current_marker_top: null,
            markRead: function(entryId) {
                if (! document.querySelector('#entry_' + entryId + ' h2').className.indexOf('readIcon') != -1) {
                    var http = new XMLHttpRequest();

                    http.onreadystatechange = function() {
                        if (http.readyState == 4 && http.status == 200) {
                            document.querySelector('#entry_' + http.response + ' h2').className += ' readIcon';
                        }
                    }
                    http.open('POST','/' + entryId + '/read', true);
                    http.send();
                }
            },
            markUnread: function(entryId) {
                if (document.querySelector('#entry_' + entryId + ' h2').className.indexOf('readIcon') != -1) {
                    var http = new XMLHttpRequest();

                    http.onreadystatechange = function() {
                        if (http.readyState == 4 && http.status == 200) {
                            document.querySelector('#entry_' + http.response + ' h2').classList.remove('readIcon');
                        }
                    }
                    http.open('POST','/' + entryId + '/unread', true);
                    http.send();
                }
            },
            checkRead: function(force) {
                if (! n.Entry.check_block) {
                    if (! force) {
                        n.Entry.check_block = true;
                        setTimeout(function() { n.Entry.check_block = false; n.Entry.checkRead(true) }, 300);
                    }
                    document.getElementsByClassName('read').forEach(function(el) {
                        if (el.isVisible()) {
                            n.Entry.markRead(el.dataset['entryid']);
                        }
                    });
                }
            },
            checkCurrent: function() {
                if (! n.Entry.check_block) {
                    if (! n.Entry.current_marker_top) {
                        n.Entry.current_marker_top = window.innerHeight * 0.15;
                        // it would be nicer to use clientHeight of #entries, but that does not work in FF 33 as it also returns overflow, contrary to what mdn says
                    }

                    document.getElementsByClassName('entry').forEach(function(el) {
                        if (el.isVisible()) {
                            var entryTop = el.getBoundingClientRect().top;
                            if (entryTop >= n.Entry.current_marker_top) {
                               n.Entry.setCurrent(el.querySelector('.read').dataset['entryid']);
                            }
                        };
                    });
                }
            },
            goto: function(nextEntry) {
                n.Entry.markRead(n.Entry.current_entry);
                n.Entry.setCurrent(nextEntry.querySelector('.read').dataset['entryid']);
                nextEntry.scrollIntoView();
            },
            gotoNext: function() {
                n.Entry.goto(document.querySelector('#entry_' + n.Entry.current_entry + " + .entry" ));
            },
            gotoPrev: function() {
                // the doubled previousChild is necessary because it also returns textnodes, there seems to be no alternative
                n.Entry.goto(document.querySelector('#entry_' + n.Entry.current_entry).previousSibling.previousSibling);
            },
            openCurrent: function() {
                window.open(document.querySelector('#entry_' + n.Entry.current_entry + ' h2 a').href);
            },
            toggleRead: function(entryId) {
                if (document.querySelector('#entry_' + entryId + ' h2').className.indexOf('readIcon') != -1) {
                    n.Entry.markUnread(entryId);
                } else {
                    n.Entry.markRead(entryId);
                }
            },
            toggleMarkButton: function(entryId) {
                var form = document.querySelector('#entry_' + entryId + ' .mark');
                var button = form.querySelector('button');
                if (form.action.endsWith('/mark')) {
                    form.action = form.action.replace(/mark/, 'unmark');
                    button.innerHTML = '★';
                } else {
                    form.action = form.action.replace('un', '');
                    button.innerHTML = '☆';
                }
            },
            setCurrent: function(entryId) {
                n.Entry.current_entry = entryId;
                try {
                    document.querySelector('.entry.current').classList.remove('current');
                } catch(e) {
		    if (e instanceof TypeError) {}
		}
                document.querySelector('#entry_' + entryId).classList.add('current');
            }
        },
        Feed: {
            current_feed: 0,
            loading_more: false,
            check_block: false,
            getUpdates: function() {
                var socket = new WebSocket('ws://' + location.host + '/updated' );

                socket.onopen = function() {
                    socket.send(JSON.stringify({feedid: n.Feed.current_feed }));
                }

                socket.onmessage = function(msg){
                    var data = JSON.parse(msg.data);
                    var updated_feed = data.updated_feed;
                    if (updated_feed && document.querySelector('#feed_' + updated_feed) == null) {
                        var http = new XMLHttpRequest();

                        http.onreadystatechange = function() {
                            if (http.readyState == 4 && http.status == 200) {
                                document.querySelector('#feedList').insertAdjacentHTML('afterbegin', http.response);
                            }
                        }
                        http.open('GET','/' + updated_feed + '/feedlink', true);
                        http.send();
                    }
                    var new_entry = data.new_entry;
                    if (new_entry) {
                        var http_ = new XMLHttpRequest();

                        http_.onreadystatechange = function() {
                            if (http_.readyState == 4 && http_.status == 200) {
                                n.Feed.appendEntry(http_.response);
                            }
                        }
                        http_.open('GET','/' + new_entry + '/entry', true);
                        http_.send();
                    }
                }
            },
            gotoNext: function() {
                if (n.Feed.current_feed != 0) {
                    window.location = document.querySelector('#feed_' + n.Feed.current_feed + ' + li a').href;
                } else {
                    window.location = document.querySelector('.feedlink a').href;
                }
            },
            gotoPrev: function() {
                if (n.Feed.current_feed != 0) {
                    // the doubled previousChild is necessary because it also returns textnodes, there seems to be no alternative
                    window.location = document.querySelector('#feed_' + n.Feed.current_feed).previousSibling.previousSibling.firstChild.href;
                } else {
                    window.location = document.querySelector('.feedlink:last-child a').href;
                }
            },
            appendEntry: function(entry) {
                document.querySelector('main ol').appendChild(document.createRange().createContextualFragment(entry));

            },
            loadMoreEntries: function() {
                if (! n.Feed.loading_more) {
                    n.Feed.loading_more = true;
                    var http = new XMLHttpRequest();

                    http.onreadystatechange = function() {
                        if (http.readyState == 4 && http.status == 200) {
                            var entries = JSON.parse(http.response)['entries'];
                            entries.forEach(function(entry) {
                                n.Feed.appendEntry(entry);
                            });
                            if (entries.length == 10) {
                                var allReads = document.querySelectorAll('.read');
                                document.querySelector('#moreEntries').dataset['start_id'] = allReads[allReads.length - 1].dataset['entryid'];
                            } else {
                                document.querySelector('#moreEntries').remove();
                            }
                            n.Feed.loading_more = false;
                        }
                    }
                    http.open('GET','/' + n.Feed.current_feed + '/entries?startId=' + document.querySelector('#moreEntries').dataset['start_id'], true);
                    http.send();
                }
            },
            checkLoadMore: function() {
                if (! n.Feed.check_block) {
                    n.Feed.check_block = true;
                    setTimeout(function() { n.Feed.check_block = false; }, 300);
                    var scrollPos = window.pageYOffset || document.documentElement.scrollTop;
                    var viewportHeight = Math.max(document.documentElement.clientHeight, window.innerHeight || 0)
                    var totalHeight = (document.height !== undefined) ? document.height : document.body.offsetHeight;

                    if (scrollPos + viewportHeight >= totalHeight - viewportHeight && document.querySelector('#moreEntries')) {
                        n.Feed.loadMoreEntries();
                    }
                }
            }
        }
    }

    function ajaxifyForm(selector, callback) {
        document.querySelectorAll(selector).forEach(function(el) {
            el.addEventListener('submit', function(evt) {
               evt.preventDefault();
               var http = new XMLHttpRequest();

                http.onreadystatechange = function() {
                    if (http.readyState == 4 && http.status == 200) {
                        callback(http);
                    }
                }
                http.open(evt.target.method, evt.target.action, true);
                http.send();
            });
        });
    }

    function addSelectAllButton() {
        var tagString = "<button type='button' id='toggleUnsubscribe'>all</button>";
        var range = document.createRange();
        //range.selectNode(document.querySelector("#unsubscribeList"));
        var documentFragment = range.createContextualFragment(tagString);
        var unsubscribeForm = document.querySelector("#unsubscribeForm form")
        unsubscribeForm.insertBefore(documentFragment, unsubscribeForm.firstChild);
        document.querySelector('#toggleUnsubscribe').addEventListener('click', function(evt) {
            var checkboxes = document.querySelectorAll('#unsubscribeList input');

            if (checkboxes[0].checked) {
                for (var i=0;i < checkboxes.length;i++) {
                    checkboxes[i].checked = false;
                }
            } else {
                for (var i=0;i < checkboxes.length;i++) {
                    checkboxes[i].checked = true;
                }
            }
        });
    }

    function addUserInputButton() {
        var tagString = "<button type='button' id='addUserInput'>+</button>";
        var range = document.createRange();
        //range.selectNode(document.querySelector("#unsubscribeList"));
        var documentFragment = range.createContextualFragment(tagString);
        var userForm = document.querySelector("#userForm ol")
        userForm.appendChild(documentFragment);
        document.querySelector('#addUserInput').addEventListener('click', function(evt) {
            this.parentNode.removeChild(this)
            var inputs = document.querySelectorAll('.userInput');
            var inputTagString = '
<input type="email" name="users[mail][' + inputs.length + ']" value="" />
';
            var inputFragment = range.createContextualFragment(inputTagString);
            userForm.appendChild(inputFragment);
            addUserInputButton();
        });
    }

    var contentLoaded = false;
    document.addEventListener('DOMContentLoaded', function() {
        var contentLoaded = true;
        n.Entry.checkRead(true);
        n.Feed.getUpdates();
        var main = document.querySelector('main');
        if (main.dataset['feedid']) {
            n.Feed.current_feed = main.dataset['feedid'];
            n.Entry.setCurrent(main.querySelector('.read').dataset['entryid']);
        }

        addEventListener('scroll', function() {
                                            n.Entry.checkCurrent();
                                            n.Entry.checkRead(false);
                                            n.Feed.checkLoadMore();
                                        }
        );
        addEventListener('keyup', function(evt) {
                                        if (evt.which == 74) { n.Entry.gotoNext(); } // j
                                        if (evt.which == 75) { n.Entry.gotoPrev(); } // k
                                        if (evt.which == 78) { n.Feed.gotoNext(); } // n
                                        if (evt.which == 80) { n.Feed.gotoPrev(); } // p
                                        if (evt.which == 86) { n.Entry.openCurrent(); } // v
                                        if (evt.which == 77) { n.Entry.toggleRead(n.Entry.current_entry); } // m
                                    }
        );
        ajaxifyForm('.mark', function(http) { n.Entry.toggleMarkButton(http.response) });
        var more = document.querySelector('#moreEntries');
        if (more) {
            more.addEventListener('click', function(evt) {
                evt.preventDefault();
                n.Feed.loadMoreEntries();
            });
        }
        if (document.querySelector('#unsubscribeForm') && ! document.querySelector('#toggleUnsubscribe')) {
            addSelectAllButton();
        }
        if (document.querySelector('#userForm') && ! document.querySelector('#addUserInput')) {
            addUserInputButton();
            document.querySelector('#userForm').addEventListener('keyup', function(evt) {
                // to disable the global feed hotkeys
                evt.stopPropagation();
            });
        }
    });

    if (document.readyState == 'complete' || document.readyState == 'loaded' || document.readyState == 'interactive') {
        // since we load this async, we need sometimes to fire the already passed load event manually
        var event = document.createEvent('HTMLEvents');
        event.initEvent('DOMContentLoaded', true, true);
        if (! contentLoaded) {
            document.dispatchEvent(event);
        }
    }
}());
<commit_msg>Move websocket from ws to wss<commit_after> (function () {
    'use strict'
    NodeList.prototype.forEach = Array.prototype.forEach;
    HTMLCollection.prototype.forEach = Array.prototype.forEach;

    var n = {
        Entry: {
            // a guard to not do read and current status checks on every scroll
            check_block: false,
            // the entry currently marked
            current_entry: 0,
            // amount of pixel from the top where an entry has to have reached until it is set as current
            current_marker_top: null,
            markRead: function(entryId) {
                if (! document.querySelector('#entry_' + entryId + ' h2').className.indexOf('readIcon') != -1) {
                    var http = new XMLHttpRequest();

                    http.onreadystatechange = function() {
                        if (http.readyState == 4 && http.status == 200) {
                            document.querySelector('#entry_' + http.response + ' h2').className += ' readIcon';
                        }
                    }
                    http.open('POST','/' + entryId + '/read', true);
                    http.send();
                }
            },
            markUnread: function(entryId) {
                if (document.querySelector('#entry_' + entryId + ' h2').className.indexOf('readIcon') != -1) {
                    var http = new XMLHttpRequest();

                    http.onreadystatechange = function() {
                        if (http.readyState == 4 && http.status == 200) {
                            document.querySelector('#entry_' + http.response + ' h2').classList.remove('readIcon');
                        }
                    }
                    http.open('POST','/' + entryId + '/unread', true);
                    http.send();
                }
            },
            checkRead: function(force) {
                if (! n.Entry.check_block) {
                    if (! force) {
                        n.Entry.check_block = true;
                        setTimeout(function() { n.Entry.check_block = false; n.Entry.checkRead(true) }, 300);
                    }
                    document.getElementsByClassName('read').forEach(function(el) {
                        if (el.isVisible()) {
                            n.Entry.markRead(el.dataset['entryid']);
                        }
                    });
                }
            },
            checkCurrent: function() {
                if (! n.Entry.check_block) {
                    if (! n.Entry.current_marker_top) {
                        n.Entry.current_marker_top = window.innerHeight * 0.15;
                        // it would be nicer to use clientHeight of #entries, but that does not work in FF 33 as it also returns overflow, contrary to what mdn says
                    }

                    document.getElementsByClassName('entry').forEach(function(el) {
                        if (el.isVisible()) {
                            var entryTop = el.getBoundingClientRect().top;
                            if (entryTop >= n.Entry.current_marker_top) {
                               n.Entry.setCurrent(el.querySelector('.read').dataset['entryid']);
                            }
                        };
                    });
                }
            },
            goto: function(nextEntry) {
                n.Entry.markRead(n.Entry.current_entry);
                n.Entry.setCurrent(nextEntry.querySelector('.read').dataset['entryid']);
                nextEntry.scrollIntoView();
            },
            gotoNext: function() {
                n.Entry.goto(document.querySelector('#entry_' + n.Entry.current_entry + " + .entry" ));
            },
            gotoPrev: function() {
                // the doubled previousChild is necessary because it also returns textnodes, there seems to be no alternative
                n.Entry.goto(document.querySelector('#entry_' + n.Entry.current_entry).previousSibling.previousSibling);
            },
            openCurrent: function() {
                window.open(document.querySelector('#entry_' + n.Entry.current_entry + ' h2 a').href);
            },
            toggleRead: function(entryId) {
                if (document.querySelector('#entry_' + entryId + ' h2').className.indexOf('readIcon') != -1) {
                    n.Entry.markUnread(entryId);
                } else {
                    n.Entry.markRead(entryId);
                }
            },
            toggleMarkButton: function(entryId) {
                var form = document.querySelector('#entry_' + entryId + ' .mark');
                var button = form.querySelector('button');
                if (form.action.endsWith('/mark')) {
                    form.action = form.action.replace(/mark/, 'unmark');
                    button.innerHTML = '★';
                } else {
                    form.action = form.action.replace('un', '');
                    button.innerHTML = '☆';
                }
            },
            setCurrent: function(entryId) {
                n.Entry.current_entry = entryId;
                try {
                    document.querySelector('.entry.current').classList.remove('current');
                } catch(e) {
		    if (e instanceof TypeError) {}
		}
                document.querySelector('#entry_' + entryId).classList.add('current');
            }
        },
        Feed: {
            current_feed: 0,
            loading_more: false,
            check_block: false,
            getUpdates: function() {
                var socket = new WebSocket('wss://' + location.host + '/updated' );

                socket.onopen = function() {
                    socket.send(JSON.stringify({feedid: n.Feed.current_feed }));
                }

                socket.onmessage = function(msg){
                    var data = JSON.parse(msg.data);
                    var updated_feed = data.updated_feed;
                    if (updated_feed && document.querySelector('#feed_' + updated_feed) == null) {
                        var http = new XMLHttpRequest();

                        http.onreadystatechange = function() {
                            if (http.readyState == 4 && http.status == 200) {
                                document.querySelector('#feedList').insertAdjacentHTML('afterbegin', http.response);
                            }
                        }
                        http.open('GET','/' + updated_feed + '/feedlink', true);
                        http.send();
                    }
                    var new_entry = data.new_entry;
                    if (new_entry) {
                        var http_ = new XMLHttpRequest();

                        http_.onreadystatechange = function() {
                            if (http_.readyState == 4 && http_.status == 200) {
                                n.Feed.appendEntry(http_.response);
                            }
                        }
                        http_.open('GET','/' + new_entry + '/entry', true);
                        http_.send();
                    }
                }
            },
            gotoNext: function() {
                if (n.Feed.current_feed != 0) {
                    window.location = document.querySelector('#feed_' + n.Feed.current_feed + ' + li a').href;
                } else {
                    window.location = document.querySelector('.feedlink a').href;
                }
            },
            gotoPrev: function() {
                if (n.Feed.current_feed != 0) {
                    // the doubled previousChild is necessary because it also returns textnodes, there seems to be no alternative
                    window.location = document.querySelector('#feed_' + n.Feed.current_feed).previousSibling.previousSibling.firstChild.href;
                } else {
                    window.location = document.querySelector('.feedlink:last-child a').href;
                }
            },
            appendEntry: function(entry) {
                document.querySelector('main ol').appendChild(document.createRange().createContextualFragment(entry));

            },
            loadMoreEntries: function() {
                if (! n.Feed.loading_more) {
                    n.Feed.loading_more = true;
                    var http = new XMLHttpRequest();

                    http.onreadystatechange = function() {
                        if (http.readyState == 4 && http.status == 200) {
                            var entries = JSON.parse(http.response)['entries'];
                            entries.forEach(function(entry) {
                                n.Feed.appendEntry(entry);
                            });
                            if (entries.length == 10) {
                                var allReads = document.querySelectorAll('.read');
                                document.querySelector('#moreEntries').dataset['start_id'] = allReads[allReads.length - 1].dataset['entryid'];
                            } else {
                                document.querySelector('#moreEntries').remove();
                            }
                            n.Feed.loading_more = false;
                        }
                    }
                    http.open('GET','/' + n.Feed.current_feed + '/entries?startId=' + document.querySelector('#moreEntries').dataset['start_id'], true);
                    http.send();
                }
            },
            checkLoadMore: function() {
                if (! n.Feed.check_block) {
                    n.Feed.check_block = true;
                    setTimeout(function() { n.Feed.check_block = false; }, 300);
                    var scrollPos = window.pageYOffset || document.documentElement.scrollTop;
                    var viewportHeight = Math.max(document.documentElement.clientHeight, window.innerHeight || 0)
                    var totalHeight = (document.height !== undefined) ? document.height : document.body.offsetHeight;

                    if (scrollPos + viewportHeight >= totalHeight - viewportHeight && document.querySelector('#moreEntries')) {
                        n.Feed.loadMoreEntries();
                    }
                }
            }
        }
    }

    function ajaxifyForm(selector, callback) {
        document.querySelectorAll(selector).forEach(function(el) {
            el.addEventListener('submit', function(evt) {
               evt.preventDefault();
               var http = new XMLHttpRequest();

                http.onreadystatechange = function() {
                    if (http.readyState == 4 && http.status == 200) {
                        callback(http);
                    }
                }
                http.open(evt.target.method, evt.target.action, true);
                http.send();
            });
        });
    }

    function addSelectAllButton() {
        var tagString = "<button type='button' id='toggleUnsubscribe'>all</button>";
        var range = document.createRange();
        //range.selectNode(document.querySelector("#unsubscribeList"));
        var documentFragment = range.createContextualFragment(tagString);
        var unsubscribeForm = document.querySelector("#unsubscribeForm form")
        unsubscribeForm.insertBefore(documentFragment, unsubscribeForm.firstChild);
        document.querySelector('#toggleUnsubscribe').addEventListener('click', function(evt) {
            var checkboxes = document.querySelectorAll('#unsubscribeList input');

            if (checkboxes[0].checked) {
                for (var i=0;i < checkboxes.length;i++) {
                    checkboxes[i].checked = false;
                }
            } else {
                for (var i=0;i < checkboxes.length;i++) {
                    checkboxes[i].checked = true;
                }
            }
        });
    }

    function addUserInputButton() {
        var tagString = "<button type='button' id='addUserInput'>+</button>";
        var range = document.createRange();
        //range.selectNode(document.querySelector("#unsubscribeList"));
        var documentFragment = range.createContextualFragment(tagString);
        var userForm = document.querySelector("#userForm ol")
        userForm.appendChild(documentFragment);
        document.querySelector('#addUserInput').addEventListener('click', function(evt) {
            this.parentNode.removeChild(this)
            var inputs = document.querySelectorAll('.userInput');
            var inputTagString = '
<input type="email" name="users[mail][' + inputs.length + ']" value="" />
';
            var inputFragment = range.createContextualFragment(inputTagString);
            userForm.appendChild(inputFragment);
            addUserInputButton();
        });
    }

    var contentLoaded = false;
    document.addEventListener('DOMContentLoaded', function() {
        var contentLoaded = true;
        n.Entry.checkRead(true);
        n.Feed.getUpdates();
        var main = document.querySelector('main');
        if (main.dataset['feedid']) {
            n.Feed.current_feed = main.dataset['feedid'];
            n.Entry.setCurrent(main.querySelector('.read').dataset['entryid']);
        }

        addEventListener('scroll', function() {
                                            n.Entry.checkCurrent();
                                            n.Entry.checkRead(false);
                                            n.Feed.checkLoadMore();
                                        }
        );
        addEventListener('keyup', function(evt) {
                                        if (evt.which == 74) { n.Entry.gotoNext(); } // j
                                        if (evt.which == 75) { n.Entry.gotoPrev(); } // k
                                        if (evt.which == 78) { n.Feed.gotoNext(); } // n
                                        if (evt.which == 80) { n.Feed.gotoPrev(); } // p
                                        if (evt.which == 86) { n.Entry.openCurrent(); } // v
                                        if (evt.which == 77) { n.Entry.toggleRead(n.Entry.current_entry); } // m
                                    }
        );
        ajaxifyForm('.mark', function(http) { n.Entry.toggleMarkButton(http.response) });
        var more = document.querySelector('#moreEntries');
        if (more) {
            more.addEventListener('click', function(evt) {
                evt.preventDefault();
                n.Feed.loadMoreEntries();
            });
        }
        if (document.querySelector('#unsubscribeForm') && ! document.querySelector('#toggleUnsubscribe')) {
            addSelectAllButton();
        }
        if (document.querySelector('#userForm') && ! document.querySelector('#addUserInput')) {
            addUserInputButton();
            document.querySelector('#userForm').addEventListener('keyup', function(evt) {
                // to disable the global feed hotkeys
                evt.stopPropagation();
            });
        }
    });

    if (document.readyState == 'complete' || document.readyState == 'loaded' || document.readyState == 'interactive') {
        // since we load this async, we need sometimes to fire the already passed load event manually
        var event = document.createEvent('HTMLEvents');
        event.initEvent('DOMContentLoaded', true, true);
        if (! contentLoaded) {
            document.dispatchEvent(event);
        }
    }
}());
<|endoftext|>


<commit_before><commit_msg>Create agario2.js<commit_after><|endoftext|>


<commit_before>$(document).ready(function () {

    var ws = new WebSocket("ws://localhost:1111");

    setTimeout(function () {
        var argv = BAT.argv()
          , title = argv[5]
          , description = argv[6]
          , icon = argv[7]
          , duration = argv[8]
          , scrSize = BAT.getScreenSize()
          , $not = $(".notification")
          , nSize = {
                width: $not.outerWidth(true)
              , height: $not.outerHeight(true)
            }
          , position = {
                left: scrSize.width - nSize.width
              , top: 35
            }
          ;

        ws.onmessage = function (event) {
            BAT.debug(event.data);
            event = JSON.parse(event.data);
            if (event.ev === "down") {
                BAT.setWindowPosition(position.left, position.top += nSize.height + 10);
            }

            if (event.ev === "up") {
                BAT.setWindowPosition(position.left, position.top -= nSize.height + 10);
            }
        };

        BAT.resize(nSize.width, nSize.height);
        BAT.setWindowPosition(position.left, position.top);

        if (!icon) {
            $("#icon", $not).hide();
        } else {
            $("#icon", $not).attr("src", icon);
        }

        $("#title").html(title);
        $("#description").html(description);
        ws.onopen = function () {
            ws.send(JSON.stringify({
                ev: "down"
              , id: argv.slice(-1)[0]
            }));
        };

        setTimeout(function() {
            $not.fadeIn();
            setTimeout(function() {
                $not.fadeOut(function () {
                    ws.send(JSON.stringify({
                        ev: "up"
                      , id: argv.slice(-1)[0]
                    }));
                    BAT.closeWindow();
                });
            }, parseInt(duration));
        }, 0);
    }, 0);
});
<commit_msg>Animate the window.<commit_after>$(document).ready(function () {

    // Connect to websocket
    var ws = new WebSocket("ws://localhost:1111");

    setTimeout(function () {

        // Prepare data
        var argv = BAT.argv()
          , title = argv[5]
          , description = argv[6]
          , icon = argv[7]
          , duration = argv[8]
          , scrSize = BAT.getScreenSize()
          , $not = $(".notification")
          ;

        // Set the window and the title
        $("#title").html(title);
        $("#description").html(description);

        // Set the icon
        if (!icon) {
            $("#icon", $not).hide();
        } else {
            $("#icon", $not).attr("src", icon);
        }

        // Compute positions
        var br = $not.get(0).getBoundingClientRect()
          , nSize = {
                width: $not.outerWidth(true)
              , height: $not.outerHeight(true) + 20
            }
          , position = {
                left: scrSize.width - nSize.width
              , top: 35
            }
          ;

        // WS Communication
        ws.onmessage = function (event) {
            event = JSON.parse(event.data);
            if (event.ev === "down") {

                $(position).animate({ top: position.top + nSize.height - 20 }, {
                    duration: 100,
                    step: function() {
                        BAT.setWindowPosition(this.left, this.top);
                    }
                });

            }
        };

        ws.onopen = function () {
            ws.send(JSON.stringify({
                ev: "down"
              , id: argv.slice(-1)[0]
            }));
        };

        // Resize the window
        BAT.resize(nSize.width, nSize.height);
        BAT.setWindowPosition(position.left, position.top);

        // Set timeout
        setTimeout(function() {
            $not.fadeIn();
            setTimeout(function() {
                $not.fadeOut(function () {
                    BAT.closeWindow();
                });
            }, parseInt(duration));
        }, 0);
    }, 0);
});
<|endoftext|>


<commit_before>var Timeline = function(client) {
	this.client = client;
};

Timeline.prototype = {
	getTimeline: function() {
		var self = this;
		var timelineVue = new Vue({
			el: '#main',
			data: {
				tweets: [],
				tweettext: ''
			},
			created: function() {
				var cls = this;
				self.client.get('statuses/home_timeline', function(error, tweets, response){
				  if (!error) {
				  	tweets.forEach(function(tweet) {
				  		if (tweet.created_at != null && tweet.text != null) {
					  		// 相対時間に変更
					  		tweet.created_at = moment(tweet.created_at).fromNow();

					  		// 改行コード
					  		tweet.text = tweet.text.replace(/[\n\r]/g, '
');
					  		cls.tweets.push(tweet);

				  		}
				  	});
				  	console.log(cls.tweets);
				  	// for (var i = 0; i < tweets.length; i++) {
				  	// 	cls.tweets.push(tweets[i]);
				  	// }
				  } else {
				  	console.log(error);
				  }
				});

				self.client.stream('user', function(stream) {
					stream.on('data', function(data) {

						// 新規tweet
				  		if (data.created_at != null && data.text != null) {
					  		// 相対時間に変更
					  		tweet.created_at = moment(data.created_at).fromNow();
					  		cls.tweets.unshift(data);

					  	// tweet削除
				  		} else if (data.delete != null) {
				  			for (var i = 0; i < cls.tweets.length; i++) {
				  				// 削除tweet id確認
				  				if (cls.tweets[i].id == data.delete.status.id) {
				  					cls.tweets.splice(i, 1);
				  				}
				  			}
				  		}
					});

					stream.on('error', function(error) {
						throw error;
					});
				});
			},
			methods: {
				tweet: function(event) {
					var cls = this;
					self.client.post('statuses/update', {status: this.tweettext},  function(error, tweet, response){
						  if (!error) {
							  cls.tweets.unshift(tweet);  // Tweet body.
							  console.log(response);  // Raw response object.
							  cls.tweettext = '';

						} else {
							console.log(error);
						}
					});
				},
				a: function(event) {
					console.log('a');
				}
			}
		});
	}
}<commit_msg>user_streamのtweetが取得できなかったバグを修正。tweet削除時にidとuser_idを見るように変更<commit_after>var Timeline = function(client) {
	this.client = client;
};

Timeline.prototype = {
	getTimeline: function() {
		var self = this;
		var timelineVue = new Vue({
			el: '#main',
			data: {
				tweets: [],
				tweettext: ''
			},
			created: function() {
				var cls = this;
				self.client.get('statuses/home_timeline', function(error, tweets, response){
				  if (!error) {
				  	tweets.forEach(function(tweet) {
				  		if (tweet.created_at != null && tweet.text != null) {
					  		// 相対時間に変更
					  		tweet.created_at = moment(tweet.created_at).fromNow();

					  		// 改行コード
					  		tweet.text = tweet.text.replace(/[\n\r]/g, '
');
					  		cls.tweets.push(tweet);

				  		}
				  	});
				  	console.log(cls.tweets);
				  	// for (var i = 0; i < tweets.length; i++) {
				  	// 	cls.tweets.push(tweets[i]);
				  	// }
				  } else {
				  	console.log(error);
				  }
				});

				self.client.stream('user', function(stream) {
					stream.on('data', function(data) {

						// 新規tweet
				  		if (data.created_at != null && data.text != null) {
					  		// 相対時間に変更
					  		data.created_at = moment(data.created_at).fromNow();
					  		cls.tweets.unshift(data);

					  	// tweet削除
				  		} else if (data.delete != null) {
				  			console.log(data);
				  			for (var i = 0; i < cls.tweets.length; i++) {
				  				// 削除tweet id確認
				  				if ((cls.tweets[i].id == data.delete.status.id) && (cls.tweets[i].user.id == data.delete.status.user_id)) {
				  					cls.tweets.splice(i, 1);
				  				}
				  			}
				  		}
					});

					stream.on('error', function(error) {
						throw error;
					});
				});
			},
			methods: {
				tweet: function(event) {
					var cls = this;
					self.client.post('statuses/update', {status: this.tweettext},  function(error, tweet, response){
						  if (!error) {
							  cls.tweets.unshift(tweet);  // Tweet body.
							  console.log(response);  // Raw response object.
							  cls.tweettext = '';

						} else {
							console.log(error);
						}
					});
				},
				a: function(event) {
					console.log('a');
				}
			}
		});
	}
}<|endoftext|>


<commit_before>/*
 * Copyright (C) 2018 - present Instructure, Inc.
 *
 * This file is part of Canvas.
 *
 * Canvas is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License as published by the Free
 * Software Foundation, version 3 of the License.
 *
 * Canvas 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 <http://www.gnu.org/licenses/>.
 */

import CoreTranslations from '../public/javascripts/translations/en.json'
import Enzyme from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'
import {filterUselessConsoleMessages} from '@instructure/js-utils'
import rceFormatMessage from '@instructure/canvas-rce/lib/format-message'
import plannerFormatMessage from '@instructure/canvas-planner/lib/format-message'
import {up as configureDateTime} from '../ui/boot/initializers/configureDateTime'
import {up as configureDateTimeMomentParser} from '../ui/boot/initializers/configureDateTimeMomentParser'
import {useTranslations} from '@canvas/i18n'

useTranslations('en', CoreTranslations)

rceFormatMessage.setup({
  locale: 'en',
  missingTranslation: 'ignore',
})

plannerFormatMessage.setup({
  locale: 'en',
  missingTranslation: 'ignore',
})

/**
 * We want to ensure errors and warnings get appropriate eyes. If
 * you are seeing an exception from here, it probably means you
 * have an unintended consequence from your changes. If you expect
 * the warning/error, add it to the ignore list below.
 */
/* eslint-disable no-console */
const globalError = global.console.error
const ignoredErrors = [
  /\[object Object\]/,
  /%s has a method called shouldComponentUpdate/,
  /`NaN` is an invalid value for the `%s` css style property/,
  /<Provider> does not support changing `store` on the fly/,
  /A component is changing a controlled input of type %s to be uncontrolled/,
  /A theme registry has already been initialized/,
  /An update to (%s|DefaultToolForm) inside a test was not wrapped in act/,
  /Can't perform a React state update on an unmounted component/,
  /Cannot read property '(activeElement|useRealTimers)' of undefined/,
  /Cannot read property 'name' of null/,
  /Cannot update during an existing state transition/,
  /ColorPicker: isMounted is deprecated/,
  /contextType was defined as an instance property on %s/,
  /Error writing result to store for query/,
  /Expected one of Group, Option in Select but found 'option'/,
  /Failed loading the language file for/,
  /Function components cannot be given refs/,
  /invalid messageType: (notSupported|undefined)/,
  /Invalid prop `children` supplied to `(Option|View)`/,
  /Invalid prop `editorOptions.plugins` of type `string` supplied to `(ForwardRef|RCEWrapper)`/, // https://instructure.atlassian.net/browse/MAT-453
  /Invalid prop `editorOptions.toolbar\[0\]` of type `string` supplied to `(ForwardRef|RCEWrapper)`/, // https://instructure.atlassian.net/browse/MAT-453
  /Invalid prop `heading` of type `object` supplied to `Billboard`/, // https://instructure.atlassian.net/browse/QUIZ-8870
  /Invalid prop `returnFocusTo` of type `DeprecatedComponent` supplied to `HomePagePromptContainer`/,
  /Invalid prop `selectedDate` of type `date` supplied to `CanvasDateInput`/,
  /Invariant Violation/,
  /It looks like you're using the wrong act/,
  /Prop `children` should be supplied unless/,
  /React does not recognize the `%s` prop on a DOM element/,
  /Render methods should be a pure function of props and state/,
  /The 'screenReaderOnly' prop must be used in conjunction with 'liveRegion'/,
  /The above error occurred in the <.*> component/,
  /The prop `currentUserRoles` is marked as required in `ObserverOptions`/,
  /The prop `focusOnInit` is marked as required in `(FileUpload|TextEntry|UrlEntry)`/,
  /The prop `groupTitle` is marked as required in `SearchBreadcrumb`/,
  /The prop `id` is marked as required in `(ColHeader|FormField|Option)`/,
  /The prop `label` is marked as required in `(FormField|FormFieldLayout|Modal)`/,
  /The prop `renderLabel` is marked as required in `Select`/,
  /validateDOMNesting\(...\): %s cannot appear as a child of <%s>/,
  /WARNING: heuristic fragment matching going on!/,
  /Warning: Failed prop type: Expected one of Checkbox in CheckboxGroup but found `View`/,
  /You are using the simple \(heuristic\) fragment matcher, but your queries contain union or interface types./,
  /You seem to have overlapping act\(\) calls/,
]
const globalWarn = global.console.warn
const ignoredWarnings = [
  /\[View|Button|Text\] .* in version 8.0.0/i,
  /Error getting \/media_objects\/dummy_media_id\/info/,
  /Exactly one focusable child is required/,
  /Please update the following components: %s/,
  /shared_brand_configs.* not called/,
  /value provided is not in a recognized RFC2822 or ISO format/,
]
global.console = {
  log: console.log,
  error: error => {
    if (ignoredErrors.some(regex => regex.test(error))) {
      return
    }
    globalError(error)
    throw new Error(
      `Looks like you have an unhandled error. Keep our test logs clean by handling or filtering it. ${error}`
    )
  },
  warn: warning => {
    if (ignoredWarnings.some(regex => regex.test(warning))) {
      return
    }
    globalWarn(warning)
    throw new Error(
      `Looks like you have an unhandled warning. Keep our test logs clean by handling or filtering it. ${warning}`
    )
  },
  info: console.info,
  debug: console.debug,
}
/* eslint-enable no-console */
filterUselessConsoleMessages(global.console)

require('jest-fetch-mock').enableFetchMocks()

window.scroll = () => {}
window.ENV = {
  use_rce_enhancements: true,
  FEATURES: {
    extended_submission_state: true,
  },
}

Enzyme.configure({adapter: new Adapter()})

// because InstUI themeable components need an explicit "dir" attribute on the <html> element
document.documentElement.setAttribute('dir', 'ltr')

configureDateTime()
configureDateTimeMomentParser()

// because everyone implements `flat()` and `flatMap()` except JSDOM 🤦🏼♂
if (!Array.prototype.flat) {
  // eslint-disable-next-line no-extend-native
  Object.defineProperty(Array.prototype, 'flat', {
    configurable: true,
    value: function flat(depth = 1) {
      if (depth === 0) return this.slice()
      return this.reduce(function (acc, cur) {
        if (Array.isArray(cur)) {
          acc.push(...flat.call(cur, depth - 1))
        } else {
          acc.push(cur)
        }
        return acc
      }, [])
    },
    writable: true,
  })
}

if (!Array.prototype.flatMap) {
  // eslint-disable-next-line no-extend-native
  Object.defineProperty(Array.prototype, 'flatMap', {
    configurable: true,
    value: function flatMap(_cb) {
      return Array.prototype.map.apply(this, arguments).flat()
    },
    writable: true,
  })
}

require('@instructure/ui-themes')

// set up mocks for native APIs
if (!('MutationObserver' in window)) {
  Object.defineProperty(window, 'MutationObserver', {
    value: require('@sheerun/mutationobserver-shim'),
  })
}

if (!('IntersectionObserver' in window)) {
  Object.defineProperty(window, 'IntersectionObserver', {
    writable: true,
    configurable: true,
    value: class IntersectionObserver {
      disconnect() {
        return null
      }

      observe() {
        return null
      }

      takeRecords() {
        return null
      }

      unobserve() {
        return null
      }
    },
  })
}

if (!('ResizeObserver' in window)) {
  Object.defineProperty(window, 'ResizeObserver', {
    writable: true,
    configurable: true,
    value: class IntersectionObserver {
      observe() {
        return null
      }

      unobserve() {
        return null
      }
    },
  })
}

if (!('matchMedia' in window)) {
  window.matchMedia = () => ({
    matches: false,
    addListener: () => {},
    removeListener: () => {},
  })
  window.matchMedia._mocked = true
}

if (!('scrollIntoView' in window.HTMLElement.prototype)) {
  window.HTMLElement.prototype.scrollIntoView = () => {}
}

// Suppress errors for APIs that exist in JSDOM but aren't implemented
Object.defineProperty(window, 'scrollTo', {configurable: true, writable: true, value: () => {}})

const locationProperties = Object.getOwnPropertyDescriptors(window.location)
Object.defineProperty(window, 'location', {
  configurable: true,
  enumerable: true,
  get: () =>
    Object.defineProperties(
      {},
      {
        ...locationProperties,
        href: {
          ...locationProperties.href,
          // Prevents JSDOM errors from doing window.location.href = ...
          set: () => {},
        },
        reload: {
          configurable: true,
          enumerable: true,
          writeable: true,
          // Prevents JSDOM errors from doing window.location.reload()
          value: () => {},
        },
      }
    ),
  // Prevents JSDOM errors from doing window.location = ...
  set: () => {},
})
<commit_msg>remove unnecessary SearchBreadcrumb warning supression<commit_after>/*
 * Copyright (C) 2018 - present Instructure, Inc.
 *
 * This file is part of Canvas.
 *
 * Canvas is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License as published by the Free
 * Software Foundation, version 3 of the License.
 *
 * Canvas 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 <http://www.gnu.org/licenses/>.
 */

import CoreTranslations from '../public/javascripts/translations/en.json'
import Enzyme from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'
import {filterUselessConsoleMessages} from '@instructure/js-utils'
import rceFormatMessage from '@instructure/canvas-rce/lib/format-message'
import plannerFormatMessage from '@instructure/canvas-planner/lib/format-message'
import {up as configureDateTime} from '../ui/boot/initializers/configureDateTime'
import {up as configureDateTimeMomentParser} from '../ui/boot/initializers/configureDateTimeMomentParser'
import {useTranslations} from '@canvas/i18n'

useTranslations('en', CoreTranslations)

rceFormatMessage.setup({
  locale: 'en',
  missingTranslation: 'ignore',
})

plannerFormatMessage.setup({
  locale: 'en',
  missingTranslation: 'ignore',
})

/**
 * We want to ensure errors and warnings get appropriate eyes. If
 * you are seeing an exception from here, it probably means you
 * have an unintended consequence from your changes. If you expect
 * the warning/error, add it to the ignore list below.
 */
/* eslint-disable no-console */
const globalError = global.console.error
const ignoredErrors = [
  /\[object Object\]/,
  /%s has a method called shouldComponentUpdate/,
  /`NaN` is an invalid value for the `%s` css style property/,
  /<Provider> does not support changing `store` on the fly/,
  /A component is changing a controlled input of type %s to be uncontrolled/,
  /A theme registry has already been initialized/,
  /An update to (%s|DefaultToolForm) inside a test was not wrapped in act/,
  /Can't perform a React state update on an unmounted component/,
  /Cannot read property '(activeElement|useRealTimers)' of undefined/,
  /Cannot read property 'name' of null/,
  /Cannot update during an existing state transition/,
  /ColorPicker: isMounted is deprecated/,
  /contextType was defined as an instance property on %s/,
  /Error writing result to store for query/,
  /Expected one of Group, Option in Select but found 'option'/,
  /Failed loading the language file for/,
  /Function components cannot be given refs/,
  /invalid messageType: (notSupported|undefined)/,
  /Invalid prop `children` supplied to `(Option|View)`/,
  /Invalid prop `editorOptions.plugins` of type `string` supplied to `(ForwardRef|RCEWrapper)`/, // https://instructure.atlassian.net/browse/MAT-453
  /Invalid prop `editorOptions.toolbar\[0\]` of type `string` supplied to `(ForwardRef|RCEWrapper)`/, // https://instructure.atlassian.net/browse/MAT-453
  /Invalid prop `heading` of type `object` supplied to `Billboard`/, // https://instructure.atlassian.net/browse/QUIZ-8870
  /Invalid prop `returnFocusTo` of type `DeprecatedComponent` supplied to `HomePagePromptContainer`/,
  /Invalid prop `selectedDate` of type `date` supplied to `CanvasDateInput`/,
  /Invariant Violation/,
  /It looks like you're using the wrong act/,
  /Prop `children` should be supplied unless/,
  /React does not recognize the `%s` prop on a DOM element/,
  /Render methods should be a pure function of props and state/,
  /The 'screenReaderOnly' prop must be used in conjunction with 'liveRegion'/,
  /The above error occurred in the <.*> component/,
  /The prop `currentUserRoles` is marked as required in `ObserverOptions`/,
  /The prop `focusOnInit` is marked as required in `(FileUpload|TextEntry|UrlEntry)`/,
  /The prop `id` is marked as required in `(ColHeader|FormField|Option)`/,
  /The prop `label` is marked as required in `(FormField|FormFieldLayout|Modal)`/,
  /The prop `renderLabel` is marked as required in `Select`/,
  /validateDOMNesting\(...\): %s cannot appear as a child of <%s>/,
  /WARNING: heuristic fragment matching going on!/,
  /Warning: Failed prop type: Expected one of Checkbox in CheckboxGroup but found `View`/,
  /You are using the simple \(heuristic\) fragment matcher, but your queries contain union or interface types./,
  /You seem to have overlapping act\(\) calls/,
]
const globalWarn = global.console.warn
const ignoredWarnings = [
  /\[View|Button|Text\] .* in version 8.0.0/i,
  /Error getting \/media_objects\/dummy_media_id\/info/,
  /Exactly one focusable child is required/,
  /Please update the following components: %s/,
  /shared_brand_configs.* not called/,
  /value provided is not in a recognized RFC2822 or ISO format/,
]
global.console = {
  log: console.log,
  error: error => {
    if (ignoredErrors.some(regex => regex.test(error))) {
      return
    }
    globalError(error)
    throw new Error(
      `Looks like you have an unhandled error. Keep our test logs clean by handling or filtering it. ${error}`
    )
  },
  warn: warning => {
    if (ignoredWarnings.some(regex => regex.test(warning))) {
      return
    }
    globalWarn(warning)
    throw new Error(
      `Looks like you have an unhandled warning. Keep our test logs clean by handling or filtering it. ${warning}`
    )
  },
  info: console.info,
  debug: console.debug,
}
/* eslint-enable no-console */
filterUselessConsoleMessages(global.console)

require('jest-fetch-mock').enableFetchMocks()

window.scroll = () => {}
window.ENV = {
  use_rce_enhancements: true,
  FEATURES: {
    extended_submission_state: true,
  },
}

Enzyme.configure({adapter: new Adapter()})

// because InstUI themeable components need an explicit "dir" attribute on the <html> element
document.documentElement.setAttribute('dir', 'ltr')

configureDateTime()
configureDateTimeMomentParser()

// because everyone implements `flat()` and `flatMap()` except JSDOM 🤦🏼♂
if (!Array.prototype.flat) {
  // eslint-disable-next-line no-extend-native
  Object.defineProperty(Array.prototype, 'flat', {
    configurable: true,
    value: function flat(depth = 1) {
      if (depth === 0) return this.slice()
      return this.reduce(function (acc, cur) {
        if (Array.isArray(cur)) {
          acc.push(...flat.call(cur, depth - 1))
        } else {
          acc.push(cur)
        }
        return acc
      }, [])
    },
    writable: true,
  })
}

if (!Array.prototype.flatMap) {
  // eslint-disable-next-line no-extend-native
  Object.defineProperty(Array.prototype, 'flatMap', {
    configurable: true,
    value: function flatMap(_cb) {
      return Array.prototype.map.apply(this, arguments).flat()
    },
    writable: true,
  })
}

require('@instructure/ui-themes')

// set up mocks for native APIs
if (!('MutationObserver' in window)) {
  Object.defineProperty(window, 'MutationObserver', {
    value: require('@sheerun/mutationobserver-shim'),
  })
}

if (!('IntersectionObserver' in window)) {
  Object.defineProperty(window, 'IntersectionObserver', {
    writable: true,
    configurable: true,
    value: class IntersectionObserver {
      disconnect() {
        return null
      }

      observe() {
        return null
      }

      takeRecords() {
        return null
      }

      unobserve() {
        return null
      }
    },
  })
}

if (!('ResizeObserver' in window)) {
  Object.defineProperty(window, 'ResizeObserver', {
    writable: true,
    configurable: true,
    value: class IntersectionObserver {
      observe() {
        return null
      }

      unobserve() {
        return null
      }
    },
  })
}

if (!('matchMedia' in window)) {
  window.matchMedia = () => ({
    matches: false,
    addListener: () => {},
    removeListener: () => {},
  })
  window.matchMedia._mocked = true
}

if (!('scrollIntoView' in window.HTMLElement.prototype)) {
  window.HTMLElement.prototype.scrollIntoView = () => {}
}

// Suppress errors for APIs that exist in JSDOM but aren't implemented
Object.defineProperty(window, 'scrollTo', {configurable: true, writable: true, value: () => {}})

const locationProperties = Object.getOwnPropertyDescriptors(window.location)
Object.defineProperty(window, 'location', {
  configurable: true,
  enumerable: true,
  get: () =>
    Object.defineProperties(
      {},
      {
        ...locationProperties,
        href: {
          ...locationProperties.href,
          // Prevents JSDOM errors from doing window.location.href = ...
          set: () => {},
        },
        reload: {
          configurable: true,
          enumerable: true,
          writeable: true,
          // Prevents JSDOM errors from doing window.location.reload()
          value: () => {},
        },
      }
    ),
  // Prevents JSDOM errors from doing window.location = ...
  set: () => {},
})
<|endoftext|>


<commit_before>/* ==========================/ EDITOR BOX /================================== */

var EditorBoxRenderer = $.inherit(

	IBoxRenderer, {

	__constructor: function() { },

	renderBox: function(clientId, moduleData, documentModel) {
		var editorWrapper = $('<div />')
				.attr('id', moduleData.holderId)
				.addClass(moduleData.styleClass);

		var editorElmId = this.getEditorElmId(clientId);

		editorWrapper.append(this.__prepareButtons(editorElmId, clientId));

		var documentEditor = new DocumentEditor(clientId, editorElmId, documentModel);

		editorWrapper.append(documentEditor.getEditorElm());
		editorWrapper.append(documentEditor.getPreviewElm());

		return editorWrapper;
	},

	__prepareButtons: function(elmId, clientId) {
		var buttonsContainer = $('<ul />')
				.addClass('editor-buttons');
		for (blockIdx in this.__self.EDITOR_BUTTONS) {
			var blockData = this.__self.EDITOR_BUTTONS[blockIdx];
			var blockWrapper = $('<li />');
			var buttonsBlock = $('<ul />')
					.addClass('editor-buttons-block');
			for (buttonAlias in blockData) {
				var buttonData = blockData[buttonAlias];
				var buttonWrapper = $('<li />');
				var button = $('<a />')
							.attr('id', 'editor-' + clientId + '-button' + buttonData.id_postfix)
							.attr('href', '#')
							.attr('title', buttonData.name)
							.attr('onclick', 'return ' +
									this.__self.CMD_BTN_HANDLER +
										"(" + clientId + ",'"
										    + buttonData.cmd + "','"
										    + elmId + "')")
							.addClass('editor-button')
							.text(buttonData.text);
				buttonWrapper.append(button);
				buttonsBlock.append(buttonWrapper);
			}
			blockWrapper.append(buttonsBlock);
			buttonsContainer.append(blockWrapper);
		}
		return buttonsContainer;
	},

	prepareUpdate: function(clientId) {
		// FIXME: use DocumentEditor lock method somehow
		$('#' + this.getEditorElmId(clientId)).attr('readonly', 'readonly');
	},

	afterUpdate: function(clientId) {
		// FIXME: use DocumentEditor unlock method somehow
		$('#' + this.getEditorElmId(clientId)).attr('readonly', '');
	},

	getEditorElmId: function(clientId) {
		return 'editor-content-' + clientId;
	}

}, {  // static

	CMD_BTN_HANDLER: 'cmdButtonOnClick',

	EDITOR_BUTTONS: [
 		{ 'bold': { id_postfix: '-bold', name: 'Bold', cmd: 'bold', text: 'B' },
 		  'italic': { id_postfix: '-italic', name: 'Italic', cmd: 'italic', text: 'I' },
 		  'underline': { id_postfix: '-uline', name: 'Underline', cmd: 'uline', text: 'U' } },
 		{ 'left': { id_postfix: '-left', name: 'Align Left', cmd: 'left', text: 'L' },
 		  'center': { id_postfix: '-center', name: 'Center Text', cmd: 'center', text: 'C' },
 		  'right': { id_postfix: '-right', name: 'Align Right', cmd: 'right', text: 'R' },
 		  'justify': { id_postfix: '-jtify', name: 'Justify Text', cmd: 'jtify', text: 'J'} },
 		{ 'put': { id_postfix:'-put', name: 'Put Text', cmd: 'put', text:'Put'} } ]

});

/* =======================/ DOCUMENT HANDLER /=============================== */

var DocumentEditor = $.inherit({

	__constructor: function(clientId, elmId, documentModel) {
		this.clientId = clientId;
		this.documentModel = documentModel;

		this.editorElm = this.createEditor(elmId, documentModel); // jQuery object
		this.previewElm = this.createPreview(elmId + '-result', documentModel); // jQuery object

		this.lock();

		this.editorElm.attr('client', clientId);
		this.previewElm.attr('client', clientId);

		this.initWithDocument(this.editorElm, documentModel, 'wiki');
		this.initWithDocument(this.previewElm, documentModel, 'styled');

		this.editorElm.keydown(createMethodReference(this, this.onKeyDown));
		this.editorElm.keyup(createMethodReference(this, this.onKeyUp));
		//this.editorElm.change(createMethodReference(this, this.onChange));
		this.editorElm.mouseup(createMethodReference(this, this.onMouseUp));

		this.editorElm.bind('cut', createMethodReference(this, this.onCut));
		this.editorElm.bind('paste', createMethodReference(this, this.onPaste));

		var timerEventHandler = createMethodReference(this, this.onTimer);

		setInterval(function() { timerEventHandler(); }, this.__self.COMMIT_CHECK_PERIOD);

		// this.unlock(); // unlock will be called after update

	},

	createEditor: function(elmId, documentModel) {
		return $('<textarea />')
			.addClass('editor-wiki-area')
			.attr('id', elmId);
	},

	createPreview: function(elmId, documentModel) {
		return $('<div />')
			.addClass('editor-document')
			.attr('id', elmId);
	},

	getEditorElm: function() {
		return this.editorElm;
	},

	getPreviewElm: function() {
		return this.previewElm;
	},

	onKeyDown: function(event) {
		var ev = event.originalEvent;
		console.log('keydown:', ev.which);
	},

	onKeyUp: function(event) {
		var ev = event.originalEvent;
	    console.log('keyup:', ev.which);
	},

	onMouseUp: function(event) {
		var ev = event.originalEvent;
		console.log('mouseup:', ev);
	},

	onCut: function(event) {
		var ev = event.originalEvent;
		console.log('cut:', ev);
	},

	onPaste: function(event) {
		var ev = event.originalEvent;
		console.log('paste:', ev);
	},

	onTimer: function() {
		//console.log('ontimer');
	},

	lock: function() {
		this.editorElm.attr('readonly', 'readonly');
	},

	unlock: function() {
		this.editorElm.attr('readonly', '');
	},

	initWithDocument: function(holderElm, documentModel, mode) {
		//holderElm.val('');
		for (textChunkIdx in documentModel) {
			var textChunk = documentModel[textChunkIdx];
			holderElm.append(textChunk.text);
			// textChunk.id; // textChunk.style; // textChunk.size;
			// textChunk.reserved; // textChunk.author;
		}
	}

}, { // static

	COMMIT_CHECK_PERIOD: 500

});<commit_msg>temporary commit: editor actions recording algorithm stub (without compiling)<commit_after>/* ==========================/ EDITOR BOX /================================== */

var EditorBoxRenderer = $.inherit(

	IBoxRenderer, {

	__constructor: function() { },

	renderBox: function(clientId, moduleData, documentModel) {
		var editorWrapper = $('<div />')
				.attr('id', moduleData.holderId)
				.addClass(moduleData.styleClass);

		var editorElmId = this.getEditorElmId(clientId);

		var documentEditor = new DocumentEditor(clientId, editorElmId, documentModel);

		editorWrapper.append(this.__prepareButtons(editorElmId, clientId,
					createMethodReference(documentEditor, documentEditor.execBtnCommand)));

		editorWrapper.append(documentEditor.getEditorElm());
		editorWrapper.append(documentEditor.getPreviewElm());

		return editorWrapper;
	},

	__prepareButtons: function(elmId, clientId, cmdExecHandler) {
		var buttonsContainer = $('<ul />')
				.addClass('editor-buttons');
		for (blockIdx in this.__self.EDITOR_BUTTONS) {
			var blockData = this.__self.EDITOR_BUTTONS[blockIdx];
			var blockWrapper = $('<li />');
			var buttonsBlock = $('<ul />')
					.addClass('editor-buttons-block');
			for (buttonAlias in blockData) {
				var buttonData = blockData[buttonAlias];
				var buttonWrapper = $('<li />');
				var button = $('<a />')
							.attr('id', 'editor-' + clientId + '-button' + buttonData.id_postfix)
							.attr('href', '#')
							.attr('title', buttonData.name)
							.click(function(event) {
										return cmdExecHandler(buttonData.cmd);
									})
							.addClass('editor-button')
							.text(buttonData.text);
				buttonWrapper.append(button);
				buttonsBlock.append(buttonWrapper);
			}
			blockWrapper.append(buttonsBlock);
			buttonsContainer.append(blockWrapper);
		}
		return buttonsContainer;
	},

	prepareUpdate: function(clientId) {
		// FIXME: use DocumentEditor lock method somehow
		console.log('update catched');
		$('#' + this.getEditorElmId(clientId)).attr('readonly', 'readonly');
	},

	afterUpdate: function(clientId) {
		// FIXME: use DocumentEditor unlock method somehow
		console.log('after-update catched');
		$('#' + this.getEditorElmId(clientId)).attr('readonly', '');
	},

	getEditorElmId: function(clientId) {
		return 'editor-content-' + clientId;
	}

}, {  // static

	EDITOR_BUTTONS: [
 		{ 'bold': { id_postfix: '-bold', name: 'Bold', cmd: 'bold', text: 'B' },
 		  'italic': { id_postfix: '-italic', name: 'Italic', cmd: 'italic', text: 'I' },
 		  'underline': { id_postfix: '-uline', name: 'Underline', cmd: 'uline', text: 'U' } },
 		{ 'left': { id_postfix: '-left', name: 'Align Left', cmd: 'left', text: 'L' },
 		  'center': { id_postfix: '-center', name: 'Center Text', cmd: 'center', text: 'C' },
 		  'right': { id_postfix: '-right', name: 'Align Right', cmd: 'right', text: 'R' },
 		  'justify': { id_postfix: '-jtify', name: 'Justify Text', cmd: 'jtify', text: 'J'} },
 		{ 'put': { id_postfix:'-put', name: 'Put Text', cmd: 'put', text:'Put'} } ]

});

/* =======================/ DOCUMENT HANDLER /=============================== */

var DocumentEditor = $.inherit({

	__constructor: function(clientId, elmId, documentModel) {
		this.clientId = clientId;
		this.elmId = elmId;

		this.inputCompleted = true; // do user finished pressing buttons, default is true
		this.actionsStore = [];

		this.documentText = this.parseDocModel(documentModel);
		this.editorElm = this.createEditor(elmId, documentModel); // jQuery object
		this.previewElm = this.createPreview(elmId + '-result', documentModel); // jQuery object

		this.lock();

		this.editorElm.attr('client', clientId);
		this.previewElm.attr('client', clientId);

		this.initWithDocument(this.editorElm, documentModel, 'wiki');
		this.initWithDocument(this.previewElm, documentModel, 'styled');

		this.editorElm.keydown(createMethodReference(this, this.onKeyDown));
		this.editorElm.keyup(createMethodReference(this, this.onKeyUp));
		//this.editorElm.change(createMethodReference(this, this.onChange));
		this.editorElm.mouseup(createMethodReference(this, this.onMouseUp));

		this.editorElm.bind('cut', createMethodReference(this, this.onCut));
		this.editorElm.bind('paste', createMethodReference(this, this.onPaste));

		var timerEventHandler = createMethodReference(this, this.onTimer);

		setInterval(function() { timerEventHandler(); }, this.__self.COMMIT_CHECK_PERIOD);

		// this.unlock(); // unlock will be called after update, so editor
				// will be locked all the time until first update is received

	},

	createEditor: function(elmId, documentModel) {
		return $('<textarea />')
			.addClass('editor-wiki-area')
			.attr('id', elmId);
	},

	createPreview: function(elmId, documentModel) {
		return $('<div />')
			.addClass('editor-document')
			.attr('id', elmId);
	},

	getEditorElm: function() {
		return this.editorElm;
	},

	getPreviewElm: function() {
		return this.previewElm;
	},

	onKeyDown: function(event) {
		if (!this.isLocked()) {
			this.inputCompleted = false;
			var ev = this.prepareEvent(event);
			this.actionsStore.push(
					[0, ev.which, ev.ctrlKey || ev.metaKey, ev.shiftKey,
					 	ev.cursorPos]);
			console.log('writing key-event: ', [0, ev.which, ev.ctrlKey || ev.metaKey, ev.shiftKey,
		                				    ev.cursorPos]);
		}
	},

	onKeyUp: function(/*event*/) {
		this.inputCompleted = true;
	},

	onMouseUp: function(event) {
		if (!this.isLocked()) {
			var ev = this.prepareEvent(event);
			this.actionsStore.push(
					[1, ev.cursorPos]); // ctrlKey/metaKey?
			console.log('writing mouse-event: ', [1, ev.cursorPos]);
		}
	},

	onCut: function(event) {
		if (!this.isLocked()) {
			var ev = this.prepareEvent(event);
			this.actionsStore.push(
					[2, ev.cursorPos]); // ctrlKey/metaKey?
			console.log('writing cut-event: ', [2, ev.cursorPos]);
		}
	},

	onPaste: function(event) {
		if (!this.isLocked()) {
			var ev = this.prepareEvent(event);
			this.actionsStore.push(
					[3, ev.cursorPos]); // ctrlKey/metaKey?
			console.log('writing paste-event: ', [3, ev.cursorPos]);
		}
	},

	onTimer: function() {
		if (this.inputCompleted && (this.actionsStore.length > 0)) {
			this.lock();
			this.sendCommands(this.compileCommands(this.actionsStore));
			this.actionsStore = [];
			this.unlock();
		}
		//console.log('ontimer');
	},

	prepareEvent: function(event) {
		event.cursorPos = this.editorElm.attr('selectionStart');
		/* FIXME: implement IE way */
		return event;
	},

	lock: function() {
		console.log('locking');
		this.editorElm.attr('readonly', true);
	},

	unlock: function() {
		console.log('unlocking');
		this.editorElm.attr('readonly', false);
	},

	isLocked: function() {
		return this.editorElm.attr('readonly');
	},

	execBtnCommand: function(cmdName) {
		console.log('exec cmd: ' + cmdName);
		return this.__self.CMD_BTN_HANDLER(this.clientId, cmdName, this.elmId);
	},

	parseDocModel: function(docModel) {
		var docText = "";
		for (textChunkIdx in docModel) {
			var textChunk = docModel[textChunkIdx];
			docText += textChunk.text;
		}
		return docText;
	},

	initWithDocument: function(holderElm, documentModel, mode) {
		//holderElm.val('');
		for (textChunkIdx in documentModel) {
			var textChunk = documentModel[textChunkIdx];
			holderElm.append(textChunk.text);
			// textChunk.id; // textChunk.style; // textChunk.size;
			// textChunk.reserved; // textChunk.author;
		}
	},

	compileCommands: function(actionsList) {
		// FIXME: implement
		console.log('compiling ', actionsList);
	},

	sendCommands: function(commands) {
		// FIXME: implement, send to cmdSequenceServlet
		console.log('sending ', commands);
	}

}, { // static

	COMMIT_CHECK_PERIOD: 2000,

	CMD_BTN_HANDLER: cmdButtonOnClick

});<|endoftext|>


<commit_before>'use strict';

const {Reader, Msg, Event, serialize, deserialize} = require('../lib/proto'),
      should = require('should');

describe('Reader', () => {
    let r;

    describe('with maxMessageLength', () => {
        beforeEach(() => {
            r = new Reader(30);
        });

        describe('#readMessagesFromBuffer()', () => {
            it('Returns a single message', () => {
                const input = new Msg({events: [new Event({service: 'test service', host: 'localhost'})]});
                const data = serialize(input);
                const [output] = r.readMessagesFromBuffer(data);
                deserialize(output).should.eql(input);
            });

            it('Returns a multiple messages', () => {
                const message = new Msg({events: [new Event({service: 'test service', host: 'localhost'})]});
                const input = [message, message];
                const data = Buffer.concat(input.map(serialize));
                const output = r.readMessagesFromBuffer(data);
                output.map(deserialize).should.eql(input);
            });

            it('Throws on long message', () => {
                const input = new Msg({events: [new Event({service: 'test service abc 123', host: 'localhost'})]});
                const data = serialize(input);
                (() => r.readMessagesFromBuffer(data)).should.throw('Message length exceeded max message length:35/30');
            });

            it('Handles parial messages', () => {
                const input = new Msg({events: [new Event({service: 'test service', host: 'localhost'})]});
                const data = serialize(input);
                const chunks = [data.slice(0, data.length - 2), data.slice(data.length - 2, data.length)];
                const messages = r.readMessagesFromBuffer(chunks[0]);
                messages.should.be.empty();
                const [output] = r.readMessagesFromBuffer(chunks[1]);
                deserialize(output).should.eql(input);
            });

            it('Handles parial message header', () => {
                const input = new Msg({events: [new Event({service: 'test service', host: 'localhost'})]});
                const data = serialize(input);
                const chunks = [data.slice(0, 2), data.slice(2, data.length)];
                const messages = r.readMessagesFromBuffer(chunks[0]);
                messages.should.be.empty();
                const [output] = r.readMessagesFromBuffer(chunks[1]);
                deserialize(output).should.eql(input);
            });
        });
    });
});
<commit_msg>fix exception turned to log test<commit_after>'use strict';

const {Reader, Msg, Event, serialize, deserialize} = require('../lib/proto'),
      should = require('should'),
      winston = require('winston');

describe('Reader', () => {
    let r;

    describe('with maxMessageLength', () => {
        beforeEach(() => {
            r = new Reader(30, new (winston.Logger));
        });

        describe('#readMessagesFromBuffer()', () => {
            it('Returns a single message', () => {
                const input = new Msg({events: [new Event({service: 'test service', host: 'localhost'})]});
                const data = serialize(input);
                const [output] = r.readMessagesFromBuffer(data);
                deserialize(output).should.eql(input);
            });

            it('Returns a multiple messages', () => {
                const message = new Msg({events: [new Event({service: 'test service', host: 'localhost'})]});
                const input = [message, message];
                const data = Buffer.concat(input.map(serialize));
                const output = r.readMessagesFromBuffer(data);
                output.map(deserialize).should.eql(input);
            });

            it('Skip on long message', () => {
                const input = new Msg({events: [new Event({service: 'test service abc 123', host: 'localhost'})]});
                const data = serialize(input);
                const output = r.readMessagesFromBuffer(data);
                output.map(deserialize).should.eql([]);
            });

            it('Handles parial messages', () => {
                const input = new Msg({events: [new Event({service: 'test service', host: 'localhost'})]});
                const data = serialize(input);
                const chunks = [data.slice(0, data.length - 2), data.slice(data.length - 2, data.length)];
                const messages = r.readMessagesFromBuffer(chunks[0]);
                messages.should.be.empty();
                const [output] = r.readMessagesFromBuffer(chunks[1]);
                deserialize(output).should.eql(input);
            });

            it('Handles parial message header', () => {
                const input = new Msg({events: [new Event({service: 'test service', host: 'localhost'})]});
                const data = serialize(input);
                const chunks = [data.slice(0, 2), data.slice(2, data.length)];
                const messages = r.readMessagesFromBuffer(chunks[0]);
                messages.should.be.empty();
                const [output] = r.readMessagesFromBuffer(chunks[1]);
                deserialize(output).should.eql(input);
            });
        });
    });
});
<|endoftext|>