<commit_before>/* global describe, it, before, after */
'use strict';

const path = require('path');
const lint = require('mocha-eslint');
const expect = require('chai').expect;
const session = require('express-session');
const firebase = require('firebase');
const FirebaseStore = require(path.normalize(`${__dirname}/../index.js`))(session);

require('dotenv').config({ silent: true });

const ref = firebase.initializeApp({
  serviceAccount: process.env.FIREBASE_SERVICE_ACCOUNT,
  databaseURL: process.env.FIREBASE_DATABASE_URL
});

const store = new FirebaseStore({
  database: ref.database()
});

describe('Code Standards', function () {
  this.slow(1000);

  lint(['**/*.js', '!node_modules/**']);
});

describe('FirebaseStore', function () {
  this.timeout(10000);
  this.slow(5000);

  after(() => {
    store.clear();
  });

  describe('Instantiation', () => {
    it('expect valid config to be successful', () => {
      expect(store).to.be.instanceof(FirebaseStore);
    });

    it('expect invalid config to throw an error', () => {
      expect(FirebaseStore).to.throw(Error);
    });
  });

  describe('Setting', () => {
    it('expect session to be saved', done => {
      store.set('1234_#$[]', {
        name: 'tj',
        cookie: { maxAge: 2000 }
      }, (err, res) => {
        done();
      });
    });
  });

  describe('Getting', () => {
    before(() => {
      store.set('1234', {
        name: 'tj',
        cookie: { maxAge: 2000 }
      }, () => {});
    });

    it('expect session to be fetched', done => {
      store.get('1234', (err, res) => {
        expect(res.name).to.eql('tj');
        expect(res.cookie).to.have.property('maxAge').and.to.eql(2000);

        done();
      });
    });
  });

  describe('Destroying', () => {
    before(() => {
      store.set('12345', {
        name: 'tj',
        cookie: { maxAge: 2000 }
      }, () => {});
    });

    it('expect a session to be removed', done => {
      store.destroy('12345', (err, res) => {
        store.get('12345', (err, res) => {
          expect(res).to.not.exist;
          done();
        });
      });
    });
  });

  describe('Clearing', () => {
    before(() => {
      store.set('abcd', {
        name: 'tj',
        cookie: { maxAge: 2000 }
      }, () => {});

      store.set('abcdef', {
        name: 'tj',
        cookie: { maxAge: 2000 }
      }, () => {});
    });

    it('expect all sessions to be removed', done => {
      store.clear((err, res) => {
        store.get('abcd', (err, res) => {
          expect(res).to.not.exist;
          store.get('abcdef', (err, res) => {
            expect(res).to.not.exist;
            done();
          });
        });
      });
    });
  });

  describe('Reaping', () => {
    before(done => {
      store.set('abcd', {
        name: 'tj',
        cookie: { maxAge: -2000 }
      }, done);
    });

    it('expect old sessions to be removed', done => {
      store.reap((err, res) => {
        store.get('abcd', (err, res) => {
          expect(res).to.not.exist;
          done();
        });
      });
    });
  });

  describe('Touching', () => {
    before(done => {
      store.set('abcd', {
        name: 'tj',
        cookie: { maxAge: 2000 }
      }, done);
    });

    it('expect sessions to be updated', done => {
      store.touch('abcd', {
        name: 'bn',
        cookie: { maxAge: 3000 }
      }, err => {
        store.get('abcd', (err, res) => {
          expect(res.name).to.eql('tj');
          expect(res.cookie).to.have.property('maxAge').and.to.eql(3000);

          done();
        });
      });
    });
  });
});
<commit_msg>Update test coverage<commit_after>/* global describe, context, it, before, after */
'use strict';

const path = require('path');
const lint = require('mocha-eslint');
const expect = require('chai').expect;
const session = require('express-session');
const firebase = require('firebase');
const FirebaseStore = require(path.normalize(`${__dirname}/../index.js`))(session);

require('dotenv').config({ silent: true });

const ref = firebase.initializeApp({
  serviceAccount: process.env.FIREBASE_SERVICE_ACCOUNT,
  databaseURL: process.env.FIREBASE_DATABASE_URL
});

const store = new FirebaseStore({
  database: ref.database()
});

describe('Code Standards', function () {
  this.slow(1000);

  lint(['**/*.js', '!node_modules/**']);
});

describe('FirebaseStore', function () {
  this.timeout(10000);
  this.slow(5000);

  after('clean up data', function (done) {
    store.clear(done);
  });

  after('close connection', function (done) {
    ref.delete();
    done();
  });

  context('when passed a valid config', function () {
    it('should be an instance of FirebaseStore', function (done) {
      expect(store).to.be.instanceof(FirebaseStore);
      done();
    });
  });

  context('when passed an invalid config', function () {
    it('should throw an error', function (done) {
      expect(() => new FirebaseStore({})).to.throw(Error);
      expect(() => new FirebaseStore([])).to.throw(Error);
      expect(() => new FirebaseStore('')).to.throw(Error);
      expect(() => new FirebaseStore()).to.throw(Error);
      done();
    });
  });

  describe('.set()', function () {
    it('should save a session', function (done) {
      store.set('1234_#$[]', {
        name: 'tj',
        cookie: { maxAge: 2000 }
      }, done);
    });
  });

  describe('.get()', function () {
    before('save a session', function (done) {
      store.set('1234', {
        name: 'tj',
        cookie: { maxAge: 2000 }
      }, done);
    });

    it('should fetch a session', function (done) {
      store.get('1234', function (err, res) {
        expect(res).to.have.property('name').and.to.eql('tj');
        expect(res).to.have.property('cookie').and.to.have.property('maxAge').and.to.eql(2000);
        done();
      });
    });
  });

  describe('.destroy()', function () {
    before('save a session', function (done) {
      store.set('12345', {
        name: 'tj',
        cookie: { maxAge: 2000 }
      }, done);
    });

    it('should remove a session', function (done) {
      store.destroy('12345', function (err, res) {
        store.get('12345', function (err, res) {
          expect(res).to.not.exist;
          done();
        });
      });
    });
  });

  describe('.clear()', function () {
    before('save the sessions', function (done) {
      store.set('abcd', {
        name: 'tj',
        cookie: { maxAge: 2000 }
      }, () => {
        store.set('abcdef', {
          name: 'tj',
          cookie: { maxAge: 2000 }
        }, done);
      });
    });

    it('should remove all sessions', function (done) {
      store.clear(function (err, res) {
        store.get('abcd', function (err, res) {
          expect(res).to.not.exist;
          store.get('abcdef', function (err, res) {
            expect(res).to.not.exist;
            done();
          });
        });
      });
    });
  });

  describe('.reap()', function () {
    before('save a session', function (done) {
      store.set('abcd', {
        name: 'tj',
        cookie: { maxAge: -2000 }
      }, done);
    });

    it('should remove expired sessions', function (done) {
      store.reap(function (err, res) {
        store.get('abcd', function (err, res) {
          expect(res).to.not.exist;
          done();
        });
      });
    });
  });

  describe('.touch()', function () {
    before('save a session', function (done) {
      store.set('abcd', {
        name: 'tj',
        cookie: { maxAge: 2000 }
      }, done);
    });

    it('should update a session', function (done) {
      store.touch('abcd', {
        name: 'bn',
        cookie: { maxAge: 3000 }
      }, function (err) {
        store.get('abcd', function (err, res) {
          expect(res).to.have.property('name').and.to.eql('tj');
          expect(res).to.have.property('cookie').and.to.have.property('maxAge').and.to.eql(3000);
          done();
        });
      });
    });
  });
});
<|endoftext|>


<commit_before>/**
 * Visual Blocks Editor
 *
 * Copyright 2011 Google Inc.
 * http://blockly.googlecode.com/
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @fileoverview Flyout tray containing blocks which may be created.
 * @author fraser@google.com (Neil Fraser)
 */
'use strict';

goog.provide('Blockly.Flyout');

goog.require('Blockly.Block');
goog.require('Blockly.Comment');
goog.require('goog.ui.Component');

/**
 * Class for a flyout.
 * @param {!Blockly.Workspace} workspace The workspace in which to create new
 *     blocks.
 * @param {!Function} workspaceMetrics Function which returns size information
 *     regarding the flyout's target workspace.
 * @param {boolean} withScrollbar True if a scrollbar should be displayed.
 * @constructor
 * @extends {goog.ui.Component}
 */
Blockly.Flyout = function(workspace, workspaceMetrics, withScrollbar) {
  Blockly.Flyout.superClass_.constructor.call(this);

  /**
   * @type {!Blockly.Workspace}
   * @private
   */
  this.workspace_ = new Blockly.Workspace(false);

  /**
   * @type {!Blockly.Workspace}
   * @private
   */
  this.targetWorkspace_ = workspace;

  /**
   * @type {!Function}
   * @private
   */
  this.targetWorkspaceMetrics_ = workspaceMetrics;

  /**
   * @type {!boolean}
   * @private
   */
  this.withScrollbar_ = withScrollbar;

  /**
   * @type {!number}
   * @private
   */
  this.width_ = 0;

  /**
   * @type {!number}
   * @private
   */
  this.height_ = 0;

  /**
   * List of background buttons that lurk behind each block to catch clicks
   * landing in the blocks' lakes and bays.
   * @type {!Array.<!Element>}
   * @private
   */
  this.buttons_ = [];
};
goog.inherits(Blockly.Flyout, goog.ui.Component);

/**
 * Does the flyout automatically close when a block is created?
 * @type {!boolean}
 */
Blockly.Flyout.prototype.autoClose = true;

/**
 * Corner radius of the flyout background.
 * @type {!number}
 * @const
 */
Blockly.Flyout.prototype.CORNER_RADIUS = 8;

/**
 * Creates the flyout's DOM.  Only needs to be called once.
 */
Blockly.Flyout.prototype.createDom = function() {
  /*
  <g>
    <path class="blocklyFlyoutBackground"/>
    <g></g>
  </g>
  */
  this.svgGroup_ = Blockly.createSvgElement('g', {}, null);
  this.svgBackground_ = Blockly.createSvgElement('path',
      {'class': 'blocklyFlyoutBackground'}, this.svgGroup_);
  this.svgOptions_ = Blockly.createSvgElement('g', {}, this.svgGroup_);
  this.addChild(this.workspace_);
  this.workspace_.render(this.svgOptions_);
  this.setElementInternal(this.svgGroup_);
};

/**
 * Dispose of this flyout.
 * Unlink from all DOM elements to prevent memory leaks.
 * @override
 */
Blockly.Flyout.prototype.disposeInternal = function() {
  if (this.scrollbar_) {
    this.scrollbar_.dispose();
    this.scrollbar_ = null;
  }
  this.workspace_ = null;
  if (this.svgGroup_) {
    goog.dom.removeNode(this.svgGroup_);
    this.svgGroup_ = null;
  }
  this.svgBackground_ = null;
  this.svgOptions_ = null;
  this.targetWorkspace_ = null;
  this.targetWorkspaceMetrics_ = null;
  this.buttons_ = null;

  Blockly.Flyout.superClass_.disposeInternal.call(this);
};

/**
 * Return an object with all the metrics required to size scrollbars for the
 * flyout.  The following properties are computed:
 * .viewHeight: Height of the visible rectangle,
 * .viewWidth: Width of the visible rectangle,
 * .contentHeight: Height of the contents,
 * .viewTop: Offset of top edge of visible rectangle from parent,
 * .contentTop: Offset of the top-most content from the y=0 coordinate,
 * .absoluteTop: Top-edge of view.
 * .absoluteLeft: Left-edge of view.
 * @return {Object} Contains size and position metrics of the flyout.
 */
Blockly.Flyout.prototype.getMetrics = function() {
  if (!this.isVisible()) {
    // Flyout is hidden.
    return null;
  }
  var viewHeight = this.height_ - 2 * this.CORNER_RADIUS;
  var viewWidth = this.width_;
  try {
    var optionBox = this.svgOptions_.getBBox();
  } catch (e) {
    // Firefox has trouble with hidden elements (Bug 528969).
    var optionBox = {height: 0, y: 0};
  }
  return {
    viewHeight: viewHeight,
    viewWidth: viewWidth,
    contentHeight: optionBox.height + optionBox.y,
    viewTop: -this.svgOptions_.scrollY,
    contentTop: 0,
    absoluteTop: this.CORNER_RADIUS,
    absoluteLeft: 0
  };
};

/**
 * Sets the Y translation of the flyout to match the scrollbars.
 * @param {!Object} yRatio Contains a y property which is a float
 *     between 0 and 1 specifying the degree of scrolling.
 */
Blockly.Flyout.prototype.setMetrics = function(yRatio) {
  var metrics = this.getMetrics();
  if (goog.isNumber(yRatio.y)) {
    this.svgOptions_.scrollY =
        -metrics.contentHeight * yRatio.y - metrics.contentTop;
  }
  var y = this.svgOptions_.scrollY + metrics.absoluteTop;
  this.svgOptions_.setAttribute('transform', 'translate(0,' + y + ')');
};

/**
 * Initializes the flyout.
 */
Blockly.Flyout.prototype.init = function() {
  // TODO(scr): when Blockly.Toolbox becomes a component, change this
  // to enterDocument and call its superclass method.
  // Blockly.Flyout.superClass_.enterDocument.call(this);

  // Add scrollbars.
  if (this.withScrollbar_) {
    /**
     * @type {Blockly.Scrollbar}
     * @private
     */
    this.scrollbar_ = new Blockly.Scrollbar(
        this.svgOptions_,
        goog.bind(this.getMetrics, this),
        goog.bind(this.setMetrics, this),
        false, false);
  }

  this.position_();
  this.hide();

  // If the document resizes, reposition the toolbox.
  this.getHandler().listen(
    goog.global, goog.events.EventType.RESIZE, this.position_);
};

/**
 * Move the toolbox to the edge of the workspace.
 * @private
 */
Blockly.Flyout.prototype.position_ = function() {
  var metrics = this.targetWorkspaceMetrics_();
  if (!metrics) {
    // Hidden components will return null.
    return;
  }
  var edgeWidth = this.width_ - this.CORNER_RADIUS;
  if (Blockly.RTL) {
    edgeWidth *= -1;
  }
  var path = ['M ' + (Blockly.RTL ? this.width_ : 0) + ',0'];
  path.push('h', edgeWidth);
  path.push('a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0,
      Blockly.RTL ? 0 : 1,
      Blockly.RTL ? -this.CORNER_RADIUS : this.CORNER_RADIUS,
      this.CORNER_RADIUS);
  path.push('v', Math.max(0, metrics.viewHeight - this.CORNER_RADIUS * 2));
  path.push('a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0,
      Blockly.RTL ? 0 : 1,
      Blockly.RTL ? this.CORNER_RADIUS : -this.CORNER_RADIUS,
      this.CORNER_RADIUS);
  path.push('h', -edgeWidth);
  path.push('z');
  this.svgBackground_.setAttribute('d', path.join(' '));
  var x = metrics.absoluteLeft;
  if (Blockly.RTL) {
    x -= this.width_;
  }
  this.svgGroup_.setAttribute('transform',
      'translate(' + x + ',' + metrics.absoluteTop + ')');

  // Record the height for Blockly.Flyout.getMetrics.
  this.height_ = metrics.viewHeight;
};

/**
 * Is the flyout visible?
 * @return {boolean} True if visible.
 */
Blockly.Flyout.prototype.isVisible = function() {
  return this.svgGroup_.style.display != 'none';
};

/**
 * Hide and empty the flyout.
 */
Blockly.Flyout.prototype.hide = function() {
  this.svgGroup_.style.display = 'none';
  // Delete all the blocks.
  var blocks = this.workspace_.getTopBlocks(false);
  for (var x = 0, block; block = blocks[x]; x++) {
    block.dispose(false, false);
  }
  // Delete all the background buttons.
  for (var x = 0, rect; rect = this.buttons_[x]; x++) {
    Blockly.unbindEvent_(rect.wrapper_);
    goog.dom.removeNode(rect);
  }
  this.buttons_ = [];
};

/**
 * Show and populate the flyout.
 * @param {!Array.<string>|string} names List of type names of blocks to show.
 *     Variables and procedures have a custom set of blocks.
 */
Blockly.Flyout.prototype.show = function(names) {
  var margin = this.CORNER_RADIUS;
  this.svgGroup_.style.display = 'block';

  // Create the blocks to be shown in this flyout.
  var blocks = [];
  var gaps = [];
  if (names == Blockly.MSG_VARIABLE_CATEGORY) {
    // Special category for variables.
    Blockly.Variables.flyoutCategory(blocks, gaps, margin,
        /** @type {!Blockly.Workspace} */ (this.workspace_));
  } else if (names == Blockly.MSG_PROCEDURE_CATEGORY) {
    // Special category for procedures.
    Blockly.Procedures.flyoutCategory(blocks, gaps, margin,
        /** @type {!Blockly.Workspace} */ (this.workspace_));
  } else {
    for (var i = 0, name; name = names[i]; i++) {
      var block = new Blockly.Block(
          /** @type {!Blockly.Workspace} */ (this.workspace_), name);
      block.initSvg();
      blocks[i] = block;
      gaps[i] = margin * 2;
    }
  }

  // Lay out the blocks vertically.
  var flyoutWidth = 0;
  var cursorY = margin;
  for (var i = 0, block; block = blocks[i]; i++) {
    // Mark blocks as being inside a flyout.  This is used to detect and prevent
    // the closure of the flyout if the user right-clicks on such a block.
    block.isInFlyout = true;
    // There is no good way to handle comment bubbles inside the flyout.
    // Blocks shouldn't come with predefined comments, but someone will
    // try this, I'm sure.  Kill the comment.
    Blockly.Comment && block.setCommentText(null);
    block.render();
    var bBox = block.getSvgRoot().getBBox();
    var x = Blockly.RTL ? 0 : margin + Blockly.BlockSvg.TAB_WIDTH;
    block.moveBy(x, cursorY);
    flyoutWidth = Math.max(flyoutWidth, bBox.width);
    cursorY += bBox.height + gaps[i];
    Blockly.bindEvent_(block.getSvgRoot(), 'mousedown', null,
                       Blockly.Flyout.createBlockFunc_(this, block));
  }
  flyoutWidth += margin + Blockly.BlockSvg.TAB_WIDTH + margin / 2 +
                 Blockly.Scrollbar.scrollbarThickness;

  for (var i = 0, block; block = blocks[i]; i++) {
    if (Blockly.RTL) {
      // With the flyoutWidth known, reposition the blocks to the right-aligned.
      block.moveBy(flyoutWidth - margin - Blockly.BlockSvg.TAB_WIDTH, 0);
    }
    // Create an invisible rectangle over the block to act as a button.  Just
    // using the block as a button is poor, since blocks have holes in them.
    var bBox = block.getSvgRoot().getBBox();
    var xy = block.getRelativeToSurfaceXY();
    var rect = Blockly.createSvgElement('rect',
        {'width': bBox.width, 'height': bBox.height,
        'x': xy.x + bBox.x, 'y': xy.y + bBox.y,
        'fill-opacity': 0}, null);
    // Add the rectangles under the blocks, so that the blocks' tooltips work.
    this.svgOptions_.insertBefore(rect, this.svgOptions_.firstChild);
    rect.wrapper_ = Blockly.bindEvent_(rect, 'mousedown', null,
        Blockly.Flyout.createBlockFunc_(this, block));
    this.buttons_[i] = rect;
  }
  // Record the width for .getMetrics and .position_.
  this.width_ = flyoutWidth;

  // Fire a resize event to update the flyout's scrollbar.
  Blockly.fireUiEvent(window, 'resize');
};

/**
 * Create a copy of this block on the workspace.
 * @param {!Blockly.Flyout} flyout Instance of the flyout.
 * @param {!Blockly.Block} originBlock The flyout block to copy.
 * @return {!Function} Function to call when block is clicked.
 * @private
 */
Blockly.Flyout.createBlockFunc_ = function(flyout, originBlock) {
  return function(e) {
    if (Blockly.isRightButton(e)) {
      // Right-click.  Don't create a block, let the context menu show.
      return;
    }
    // Create the new block by cloning the block in the flyout (via XML).
    var xml = Blockly.Xml.blockToDom_(originBlock);
    var block = Blockly.Xml.domToBlock_(flyout.targetWorkspace_, xml);
    // Place it in the same spot as the flyout copy.
    var svgRoot = originBlock.getSvgRoot();
    if (!svgRoot) {
      throw 'originBlock is not rendered.';
    }
    var xyOld = Blockly.getAbsoluteXY_(svgRoot);
    var xyNew = Blockly.getAbsoluteXY_(flyout.targetWorkspace_.getCanvas());
    block.moveBy(xyOld.x - xyNew.x, xyOld.y - xyNew.y);
    block.render();
    if (flyout.autoClose) {
      flyout.hide();
    }
    // Start a dragging operation on the new block.
    block.onMouseDown_(e);
  };
};
<commit_msg>Fixed wrapping style nit.<commit_after>/**
 * Visual Blocks Editor
 *
 * Copyright 2011 Google Inc.
 * http://blockly.googlecode.com/
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @fileoverview Flyout tray containing blocks which may be created.
 * @author fraser@google.com (Neil Fraser)
 */
'use strict';

goog.provide('Blockly.Flyout');

goog.require('Blockly.Block');
goog.require('Blockly.Comment');
goog.require('goog.ui.Component');

/**
 * Class for a flyout.
 * @param {!Blockly.Workspace} workspace The workspace in which to create new
 *     blocks.
 * @param {!Function} workspaceMetrics Function which returns size information
 *     regarding the flyout's target workspace.
 * @param {boolean} withScrollbar True if a scrollbar should be displayed.
 * @constructor
 * @extends {goog.ui.Component}
 */
Blockly.Flyout = function(workspace, workspaceMetrics, withScrollbar) {
  Blockly.Flyout.superClass_.constructor.call(this);

  /**
   * @type {!Blockly.Workspace}
   * @private
   */
  this.workspace_ = new Blockly.Workspace(false);

  /**
   * @type {!Blockly.Workspace}
   * @private
   */
  this.targetWorkspace_ = workspace;

  /**
   * @type {!Function}
   * @private
   */
  this.targetWorkspaceMetrics_ = workspaceMetrics;

  /**
   * @type {!boolean}
   * @private
   */
  this.withScrollbar_ = withScrollbar;

  /**
   * @type {!number}
   * @private
   */
  this.width_ = 0;

  /**
   * @type {!number}
   * @private
   */
  this.height_ = 0;

  /**
   * List of background buttons that lurk behind each block to catch clicks
   * landing in the blocks' lakes and bays.
   * @type {!Array.<!Element>}
   * @private
   */
  this.buttons_ = [];
};
goog.inherits(Blockly.Flyout, goog.ui.Component);

/**
 * Does the flyout automatically close when a block is created?
 * @type {!boolean}
 */
Blockly.Flyout.prototype.autoClose = true;

/**
 * Corner radius of the flyout background.
 * @type {!number}
 * @const
 */
Blockly.Flyout.prototype.CORNER_RADIUS = 8;

/**
 * Creates the flyout's DOM.  Only needs to be called once.
 */
Blockly.Flyout.prototype.createDom = function() {
  /*
  <g>
    <path class="blocklyFlyoutBackground"/>
    <g></g>
  </g>
  */
  this.svgGroup_ = Blockly.createSvgElement('g', {}, null);
  this.svgBackground_ = Blockly.createSvgElement('path',
      {'class': 'blocklyFlyoutBackground'}, this.svgGroup_);
  this.svgOptions_ = Blockly.createSvgElement('g', {}, this.svgGroup_);
  this.addChild(this.workspace_);
  this.workspace_.render(this.svgOptions_);
  this.setElementInternal(this.svgGroup_);
};

/**
 * Dispose of this flyout.
 * Unlink from all DOM elements to prevent memory leaks.
 * @override
 */
Blockly.Flyout.prototype.disposeInternal = function() {
  if (this.scrollbar_) {
    this.scrollbar_.dispose();
    this.scrollbar_ = null;
  }
  this.workspace_ = null;
  if (this.svgGroup_) {
    goog.dom.removeNode(this.svgGroup_);
    this.svgGroup_ = null;
  }
  this.svgBackground_ = null;
  this.svgOptions_ = null;
  this.targetWorkspace_ = null;
  this.targetWorkspaceMetrics_ = null;
  this.buttons_ = null;

  Blockly.Flyout.superClass_.disposeInternal.call(this);
};

/**
 * Return an object with all the metrics required to size scrollbars for the
 * flyout.  The following properties are computed:
 * .viewHeight: Height of the visible rectangle,
 * .viewWidth: Width of the visible rectangle,
 * .contentHeight: Height of the contents,
 * .viewTop: Offset of top edge of visible rectangle from parent,
 * .contentTop: Offset of the top-most content from the y=0 coordinate,
 * .absoluteTop: Top-edge of view.
 * .absoluteLeft: Left-edge of view.
 * @return {Object} Contains size and position metrics of the flyout.
 */
Blockly.Flyout.prototype.getMetrics = function() {
  if (!this.isVisible()) {
    // Flyout is hidden.
    return null;
  }
  var viewHeight = this.height_ - 2 * this.CORNER_RADIUS;
  var viewWidth = this.width_;
  try {
    var optionBox = this.svgOptions_.getBBox();
  } catch (e) {
    // Firefox has trouble with hidden elements (Bug 528969).
    var optionBox = {height: 0, y: 0};
  }
  return {
    viewHeight: viewHeight,
    viewWidth: viewWidth,
    contentHeight: optionBox.height + optionBox.y,
    viewTop: -this.svgOptions_.scrollY,
    contentTop: 0,
    absoluteTop: this.CORNER_RADIUS,
    absoluteLeft: 0
  };
};

/**
 * Sets the Y translation of the flyout to match the scrollbars.
 * @param {!Object} yRatio Contains a y property which is a float
 *     between 0 and 1 specifying the degree of scrolling.
 */
Blockly.Flyout.prototype.setMetrics = function(yRatio) {
  var metrics = this.getMetrics();
  if (goog.isNumber(yRatio.y)) {
    this.svgOptions_.scrollY =
        -metrics.contentHeight * yRatio.y - metrics.contentTop;
  }
  var y = this.svgOptions_.scrollY + metrics.absoluteTop;
  this.svgOptions_.setAttribute('transform', 'translate(0,' + y + ')');
};

/**
 * Initializes the flyout.
 */
Blockly.Flyout.prototype.init = function() {
  // TODO(scr): when Blockly.Toolbox becomes a component, change this
  // to enterDocument and call its superclass method.
  // Blockly.Flyout.superClass_.enterDocument.call(this);

  // Add scrollbars.
  if (this.withScrollbar_) {
    /**
     * @type {Blockly.Scrollbar}
     * @private
     */
    this.scrollbar_ = new Blockly.Scrollbar(
        this.svgOptions_,
        goog.bind(this.getMetrics, this),
        goog.bind(this.setMetrics, this),
        false, false);
  }

  this.position_();
  this.hide();

  // If the document resizes, reposition the toolbox.
  this.getHandler().listen(
      goog.global, goog.events.EventType.RESIZE, this.position_);
};

/**
 * Move the toolbox to the edge of the workspace.
 * @private
 */
Blockly.Flyout.prototype.position_ = function() {
  var metrics = this.targetWorkspaceMetrics_();
  if (!metrics) {
    // Hidden components will return null.
    return;
  }
  var edgeWidth = this.width_ - this.CORNER_RADIUS;
  if (Blockly.RTL) {
    edgeWidth *= -1;
  }
  var path = ['M ' + (Blockly.RTL ? this.width_ : 0) + ',0'];
  path.push('h', edgeWidth);
  path.push('a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0,
      Blockly.RTL ? 0 : 1,
      Blockly.RTL ? -this.CORNER_RADIUS : this.CORNER_RADIUS,
      this.CORNER_RADIUS);
  path.push('v', Math.max(0, metrics.viewHeight - this.CORNER_RADIUS * 2));
  path.push('a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0,
      Blockly.RTL ? 0 : 1,
      Blockly.RTL ? this.CORNER_RADIUS : -this.CORNER_RADIUS,
      this.CORNER_RADIUS);
  path.push('h', -edgeWidth);
  path.push('z');
  this.svgBackground_.setAttribute('d', path.join(' '));
  var x = metrics.absoluteLeft;
  if (Blockly.RTL) {
    x -= this.width_;
  }
  this.svgGroup_.setAttribute('transform',
      'translate(' + x + ',' + metrics.absoluteTop + ')');

  // Record the height for Blockly.Flyout.getMetrics.
  this.height_ = metrics.viewHeight;
};

/**
 * Is the flyout visible?
 * @return {boolean} True if visible.
 */
Blockly.Flyout.prototype.isVisible = function() {
  return this.svgGroup_.style.display != 'none';
};

/**
 * Hide and empty the flyout.
 */
Blockly.Flyout.prototype.hide = function() {
  this.svgGroup_.style.display = 'none';
  // Delete all the blocks.
  var blocks = this.workspace_.getTopBlocks(false);
  for (var x = 0, block; block = blocks[x]; x++) {
    block.dispose(false, false);
  }
  // Delete all the background buttons.
  for (var x = 0, rect; rect = this.buttons_[x]; x++) {
    Blockly.unbindEvent_(rect.wrapper_);
    goog.dom.removeNode(rect);
  }
  this.buttons_ = [];
};

/**
 * Show and populate the flyout.
 * @param {!Array.<string>|string} names List of type names of blocks to show.
 *     Variables and procedures have a custom set of blocks.
 */
Blockly.Flyout.prototype.show = function(names) {
  var margin = this.CORNER_RADIUS;
  this.svgGroup_.style.display = 'block';

  // Create the blocks to be shown in this flyout.
  var blocks = [];
  var gaps = [];
  if (names == Blockly.MSG_VARIABLE_CATEGORY) {
    // Special category for variables.
    Blockly.Variables.flyoutCategory(blocks, gaps, margin,
        /** @type {!Blockly.Workspace} */ (this.workspace_));
  } else if (names == Blockly.MSG_PROCEDURE_CATEGORY) {
    // Special category for procedures.
    Blockly.Procedures.flyoutCategory(blocks, gaps, margin,
        /** @type {!Blockly.Workspace} */ (this.workspace_));
  } else {
    for (var i = 0, name; name = names[i]; i++) {
      var block = new Blockly.Block(
          /** @type {!Blockly.Workspace} */ (this.workspace_), name);
      block.initSvg();
      blocks[i] = block;
      gaps[i] = margin * 2;
    }
  }

  // Lay out the blocks vertically.
  var flyoutWidth = 0;
  var cursorY = margin;
  for (var i = 0, block; block = blocks[i]; i++) {
    // Mark blocks as being inside a flyout.  This is used to detect and prevent
    // the closure of the flyout if the user right-clicks on such a block.
    block.isInFlyout = true;
    // There is no good way to handle comment bubbles inside the flyout.
    // Blocks shouldn't come with predefined comments, but someone will
    // try this, I'm sure.  Kill the comment.
    Blockly.Comment && block.setCommentText(null);
    block.render();
    var bBox = block.getSvgRoot().getBBox();
    var x = Blockly.RTL ? 0 : margin + Blockly.BlockSvg.TAB_WIDTH;
    block.moveBy(x, cursorY);
    flyoutWidth = Math.max(flyoutWidth, bBox.width);
    cursorY += bBox.height + gaps[i];
    Blockly.bindEvent_(block.getSvgRoot(), 'mousedown', null,
                       Blockly.Flyout.createBlockFunc_(this, block));
  }
  flyoutWidth += margin + Blockly.BlockSvg.TAB_WIDTH + margin / 2 +
                 Blockly.Scrollbar.scrollbarThickness;

  for (var i = 0, block; block = blocks[i]; i++) {
    if (Blockly.RTL) {
      // With the flyoutWidth known, reposition the blocks to the right-aligned.
      block.moveBy(flyoutWidth - margin - Blockly.BlockSvg.TAB_WIDTH, 0);
    }
    // Create an invisible rectangle over the block to act as a button.  Just
    // using the block as a button is poor, since blocks have holes in them.
    var bBox = block.getSvgRoot().getBBox();
    var xy = block.getRelativeToSurfaceXY();
    var rect = Blockly.createSvgElement('rect',
        {'width': bBox.width, 'height': bBox.height,
        'x': xy.x + bBox.x, 'y': xy.y + bBox.y,
        'fill-opacity': 0}, null);
    // Add the rectangles under the blocks, so that the blocks' tooltips work.
    this.svgOptions_.insertBefore(rect, this.svgOptions_.firstChild);
    rect.wrapper_ = Blockly.bindEvent_(rect, 'mousedown', null,
        Blockly.Flyout.createBlockFunc_(this, block));
    this.buttons_[i] = rect;
  }
  // Record the width for .getMetrics and .position_.
  this.width_ = flyoutWidth;

  // Fire a resize event to update the flyout's scrollbar.
  Blockly.fireUiEvent(window, 'resize');
};

/**
 * Create a copy of this block on the workspace.
 * @param {!Blockly.Flyout} flyout Instance of the flyout.
 * @param {!Blockly.Block} originBlock The flyout block to copy.
 * @return {!Function} Function to call when block is clicked.
 * @private
 */
Blockly.Flyout.createBlockFunc_ = function(flyout, originBlock) {
  return function(e) {
    if (Blockly.isRightButton(e)) {
      // Right-click.  Don't create a block, let the context menu show.
      return;
    }
    // Create the new block by cloning the block in the flyout (via XML).
    var xml = Blockly.Xml.blockToDom_(originBlock);
    var block = Blockly.Xml.domToBlock_(flyout.targetWorkspace_, xml);
    // Place it in the same spot as the flyout copy.
    var svgRoot = originBlock.getSvgRoot();
    if (!svgRoot) {
      throw 'originBlock is not rendered.';
    }
    var xyOld = Blockly.getAbsoluteXY_(svgRoot);
    var xyNew = Blockly.getAbsoluteXY_(flyout.targetWorkspace_.getCanvas());
    block.moveBy(xyOld.x - xyNew.x, xyOld.y - xyNew.y);
    block.render();
    if (flyout.autoClose) {
      flyout.hide();
    }
    // Start a dragging operation on the new block.
    block.onMouseDown_(e);
  };
};
<|endoftext|>


<commit_before>MockXHR.responses = {
  '/hello': function(xhr) {
    xhr.respond(200, '
hello
')
  },
  '/one-two': function(xhr) {
    xhr.respond(200, '
one

two
')
  },
  '/boom': function(xhr) {
    xhr.respond(500, 'boom')
  }
}

window.XMLHttpRequest = MockXHR

test('create from document.createElement', function() {
  var el = document.createElement('deferred-content')
  equal('DEFERRED-CONTENT', el.nodeName)
})

test('create from constructor', function() {
  var el = new window.DeferredContentElement()
  equal('DEFERRED-CONTENT', el.nodeName)
})

test('src property', function() {
  var el = document.createElement('deferred-content')
  equal(null, el.getAttribute('src'))
  equal('', el.src)

  el.src = 'content.html'
  equal('content.html', el.getAttribute('src'))
  var link = document.createElement('a')
  link.href = 'content.html'
  equal(link.href, el.src)
})

asyncTest('replaces element on 200 status', 2, function() {
  var div = document.createElement('div')
  div.innerHTML = '<deferred-content src="/hello">loading</deferred-content>'
  document.getElementById('qunit-fixture').appendChild(div)

  div.addEventListener('load', function(event) {
    equal(document.querySelector('deferred-content'), null)
    equal(document.querySelector('#replaced').textContent, 'hello')
    start()
  })
})

asyncTest('replaces with several new elements on 200 status', 3, function() {
  var div = document.createElement('div')
  div.innerHTML = '<deferred-content src="/one-two">loading</deferred-content>'
  document.getElementById('qunit-fixture').appendChild(div)

  div.addEventListener('load', function(event) {
    equal(document.querySelector('deferred-content'), null)
    equal(document.querySelector('#one').textContent, 'one')
    equal(document.querySelector('#two').textContent, 'two')
    start()
  })
})

asyncTest('adds is-error class on 500 status', 1, function() {
  var div = document.createElement('div')
  div.innerHTML = '<deferred-content src="/boom">loading</deferred-content>'
  document.getElementById('qunit-fixture').appendChild(div)

  div.addEventListener('error', function(event) {
    ok(document.querySelector('deferred-content').classList.contains('is-error'))
    start()
  })
})

asyncTest('adds is-error class on xhr error', 1, function() {
  var div = document.createElement('div')
  div.innerHTML = '<deferred-content src="/boom">loading</deferred-content>'
  document.getElementById('qunit-fixture').appendChild(div)

  div.addEventListener('error', function(event) {
    ok(document.querySelector('deferred-content').classList.contains('is-error'))
    start()
  })
})
<commit_msg>Prevent expected error event from failing the test.<commit_after>MockXHR.responses = {
  '/hello': function(xhr) {
    xhr.respond(200, '
hello
')
  },
  '/one-two': function(xhr) {
    xhr.respond(200, '
one

two
')
  },
  '/boom': function(xhr) {
    xhr.respond(500, 'boom')
  }
}

window.XMLHttpRequest = MockXHR

test('create from document.createElement', function() {
  var el = document.createElement('deferred-content')
  equal('DEFERRED-CONTENT', el.nodeName)
})

test('create from constructor', function() {
  var el = new window.DeferredContentElement()
  equal('DEFERRED-CONTENT', el.nodeName)
})

test('src property', function() {
  var el = document.createElement('deferred-content')
  equal(null, el.getAttribute('src'))
  equal('', el.src)

  el.src = 'content.html'
  equal('content.html', el.getAttribute('src'))
  var link = document.createElement('a')
  link.href = 'content.html'
  equal(link.href, el.src)
})

asyncTest('replaces element on 200 status', 2, function() {
  var div = document.createElement('div')
  div.innerHTML = '<deferred-content src="/hello">loading</deferred-content>'
  document.getElementById('qunit-fixture').appendChild(div)

  div.addEventListener('load', function(event) {
    equal(document.querySelector('deferred-content'), null)
    equal(document.querySelector('#replaced').textContent, 'hello')
    start()
  })
})

asyncTest('replaces with several new elements on 200 status', 3, function() {
  var div = document.createElement('div')
  div.innerHTML = '<deferred-content src="/one-two">loading</deferred-content>'
  document.getElementById('qunit-fixture').appendChild(div)

  div.addEventListener('load', function(event) {
    equal(document.querySelector('deferred-content'), null)
    equal(document.querySelector('#one').textContent, 'one')
    equal(document.querySelector('#two').textContent, 'two')
    start()
  })
})

asyncTest('adds is-error class on 500 status', 1, function() {
  var div = document.createElement('div')
  div.innerHTML = '<deferred-content src="/boom">loading</deferred-content>'
  document.getElementById('qunit-fixture').appendChild(div)

  div.addEventListener('error', function(event) {
    event.stopPropagation()
    ok(document.querySelector('deferred-content').classList.contains('is-error'))
    start()
  })
})

asyncTest('adds is-error class on xhr error', 1, function() {
  var div = document.createElement('div')
  div.innerHTML = '<deferred-content src="/boom">loading</deferred-content>'
  document.getElementById('qunit-fixture').appendChild(div)

  div.addEventListener('error', function(event) {
    event.stopPropagation()
    ok(document.querySelector('deferred-content').classList.contains('is-error'))
    start()
  })
})
<|endoftext|>


<commit_before>define([], function () {

    config.$inject=['$routeProvider'];

    function config($routeProvider) {
          $routeProvider
            .when('/home',
                  {templateUrl: 'home/home.html',
                   controller: 'HomeController'})
            .otherwise({redirectTo: '/home'});
      }

    return config;
});
<commit_msg>Changed the home url to / in app.config.js.<commit_after>define([], function () {

    config.$inject=['$routeProvider'];

    function config($routeProvider) {
          $routeProvider
            .when('/',
                  {templateUrl: 'app/home/home.html',
                   controller: 'HomeController'})
            .otherwise({redirectTo: '/'});
      }

    return config;
});
<|endoftext|>


<commit_before>var should = require('should'),
    fs = require('fs'),
    path = require('path'),
    rimraf = require('rimraf');

var util = require('../util.js');

var WORKSPACE_NAME = '.dotfiler',
    TEMP_FOLDER = 'tmp',
    LOCAL_FOLDER = 'local',
    CONFIG_FILE = 'config.json';

function userHome() {
    return process.env[(process.platform == 'win32') ? 'USERPROFILE' : 'HOME'];
}

describe('command', function() {
    describe('use', function() {});

    describe('revert', function() {});

    describe('status', function() {});
});

describe('util', function() {
    describe('setupTemp', function() {
        it('should create the workspace directory', function(done) {
            rimraf(path.join(userHome(), WORKSPACE_NAME), function() {
                util.setupTemp(function(err) {
                    if (err) done(err);
                    else {
                        fs.exists(path.join(userHome(), WORKSPACE_NAME), function(exists) {
                            should(exists).be.true;
                            done();
                        });
                    }
                });
            });
        });

        it('should create the temp directory', function(done) {
            rimraf(path.join(userHome(), WORKSPACE_NAME), function() {
                util.setupTemp(function(err) {
                    if (err) done(err);
                    else {
                        fs.exists(path.join(userHome(), WORKSPACE_NAME, TEMP_FOLDER), function(exists) {
                            should(exists).be.true;
                            done();
                        });
                    }
                });
            });
        });
    });

    describe('writeConfig', function() {
        var config = {
            a: 1,
            b: 2,
            c: 3
        };

        it('should create the workspace directory', function(done) {
            rimraf(path.join(userHome(), WORKSPACE_NAME), function() {
                util.writeConfig(config, function(err) {
                    if (err) done(err);
                    else {
                        fs.exists(path.join(userHome(), WORKSPACE_NAME), function(exists) {
                            should(exists).be.true;
                            done();
                        });
                    }
                });
            });
        });

        it('should write the config file', function(done) {
            rimraf(path.join(userHome(), WORKSPACE_NAME), function() {
                util.writeConfig(config, function(err) {
                    if (err) done(err);
                    else {
                        fs.readFile(path.join(userHome(), WORKSPACE_NAME, CONFIG_FILE), {
                            encoding: 'utf8'
                        }, function(err, data) {
                            if (err) done(err);
                            else {
                                data.should.equal(JSON.stringify(config));
                                done();
                            }
                        });
                    }
                });
            });
        });
    });

    describe('backupLocal', function() {
        it('should move the files', function(done) {
            fs.writeFileSync(path.join(userHome(), 'dotfilertestfile1'), '1');
            fs.writeFileSync(path.join(userHome(), 'dotfilertestfile2'), '2');
            fs.writeFileSync(path.join(userHome(), 'dotfilertestfile3'), '3');

            util.backupLocal(['dotfilertestfile1', 'dotfilertestfile2', 'dotfilertestfile3'], function(err) {
                if (err) done(err);
                else {
                    var opts = {
                        encoding: 'utf8'
                    };

                    fs.readFileSync(path.join(userHome(), WORKSPACE_NAME, LOCAL_FOLDER, 'dotfilertestfile1'), opts).should.equal('1');
                    fs.readFileSync(path.join(userHome(), WORKSPACE_NAME, LOCAL_FOLDER, 'dotfilertestfile2'), opts).should.equal('2');
                    fs.readFileSync(path.join(userHome(), WORKSPACE_NAME, LOCAL_FOLDER, 'dotfilertestfile3'), opts).should.equal('3');
                    done();
                }
            });
        });
    });

    describe('restoreLocal', function() {
        it('should move the files', function(done) {

            util.restoreLocal(['dotfilertestfile1', 'dotfilertestfile2', 'dotfilertestfile3'], function(err) {
                if (err) done(err);
                else {
                    var opts = {
                        encoding: 'utf8'
                    };

                    fs.readFileSync(path.join(userHome(), 'dotfilertestfile1'), opts).should.equal('1');
                    fs.readFileSync(path.join(userHome(), 'dotfilertestfile2'), opts).should.equal('2');
                    fs.readFileSync(path.join(userHome(), 'dotfilertestfile3'), opts).should.equal('3');
                    done();
                }
            });
        });
    });
});

after(function() {
    rimraf.sync(path.join(userHome(), WORKSPACE_NAME));
});<commit_msg>added more cleanup to the tests<commit_after>var should = require('should'),
    fs = require('fs'),
    path = require('path'),
    rimraf = require('rimraf');

var util = require('../util.js');

var WORKSPACE_NAME = '.dotfiler',
    TEMP_FOLDER = 'tmp',
    LOCAL_FOLDER = 'local',
    CONFIG_FILE = 'config.json';

function userHome() {
    return process.env[(process.platform == 'win32') ? 'USERPROFILE' : 'HOME'];
}

describe('command', function() {
    describe('use', function() {});

    describe('revert', function() {});

    describe('status', function() {});
});

describe('util', function() {
    describe('setupTemp', function() {
        it('should create the workspace directory', function(done) {
            rimraf(path.join(userHome(), WORKSPACE_NAME), function() {
                util.setupTemp(function(err) {
                    if (err) done(err);
                    else {
                        fs.exists(path.join(userHome(), WORKSPACE_NAME), function(exists) {
                            should(exists).be.true;
                            done();
                        });
                    }
                });
            });
        });

        it('should create the temp directory', function(done) {
            rimraf(path.join(userHome(), WORKSPACE_NAME), function() {
                util.setupTemp(function(err) {
                    if (err) done(err);
                    else {
                        fs.exists(path.join(userHome(), WORKSPACE_NAME, TEMP_FOLDER), function(exists) {
                            should(exists).be.true;
                            done();
                        });
                    }
                });
            });
        });
    });

    describe('writeConfig', function() {
        var config = {
            a: 1,
            b: 2,
            c: 3
        };

        it('should create the workspace directory', function(done) {
            rimraf(path.join(userHome(), WORKSPACE_NAME), function() {
                util.writeConfig(config, function(err) {
                    if (err) done(err);
                    else {
                        fs.exists(path.join(userHome(), WORKSPACE_NAME), function(exists) {
                            should(exists).be.true;
                            done();
                        });
                    }
                });
            });
        });

        it('should write the config file', function(done) {
            rimraf(path.join(userHome(), WORKSPACE_NAME), function() {
                util.writeConfig(config, function(err) {
                    if (err) done(err);
                    else {
                        fs.readFile(path.join(userHome(), WORKSPACE_NAME, CONFIG_FILE), {
                            encoding: 'utf8'
                        }, function(err, data) {
                            if (err) done(err);
                            else {
                                data.should.equal(JSON.stringify(config));
                                done();
                            }
                        });
                    }
                });
            });
        });
    });

    describe('backupLocal', function() {
        it('should move the files', function(done) {
            fs.writeFileSync(path.join(userHome(), 'dotfilertestfile1'), '1');
            fs.writeFileSync(path.join(userHome(), 'dotfilertestfile2'), '2');
            fs.writeFileSync(path.join(userHome(), 'dotfilertestfile3'), '3');

            util.backupLocal(['dotfilertestfile1', 'dotfilertestfile2', 'dotfilertestfile3'], function(err) {
                if (err) done(err);
                else {
                    var opts = {
                        encoding: 'utf8'
                    };

                    fs.readFileSync(path.join(userHome(), WORKSPACE_NAME, LOCAL_FOLDER, 'dotfilertestfile1'), opts).should.equal('1');
                    fs.readFileSync(path.join(userHome(), WORKSPACE_NAME, LOCAL_FOLDER, 'dotfilertestfile2'), opts).should.equal('2');
                    fs.readFileSync(path.join(userHome(), WORKSPACE_NAME, LOCAL_FOLDER, 'dotfilertestfile3'), opts).should.equal('3');
                    done();
                }
            });
        });
    });

    describe('restoreLocal', function() {
        it('should move the files', function(done) {

            util.restoreLocal(['dotfilertestfile1', 'dotfilertestfile2', 'dotfilertestfile3'], function(err) {
                if (err) done(err);
                else {
                    var opts = {
                        encoding: 'utf8'
                    };

                    fs.readFileSync(path.join(userHome(), 'dotfilertestfile1'), opts).should.equal('1');
                    fs.readFileSync(path.join(userHome(), 'dotfilertestfile2'), opts).should.equal('2');
                    fs.readFileSync(path.join(userHome(), 'dotfilertestfile3'), opts).should.equal('3');
                    done();
                }
            });
        });
    });
});

after(function() {
    rimraf.sync(path.join(userHome(), WORKSPACE_NAME));
    fs.unlinkSync(path.join(userHome(), 'dotfilertestfile1'));
    fs.unlinkSync(path.join(userHome(), 'dotfilertestfile2'));
    fs.unlinkSync(path.join(userHome(), 'dotfilertestfile3'));
});<|endoftext|>


<commit_before>'use strict';

const React = require('react');
const NicoAction = require('../../actions/NicoAction');
const NotificationAction = require('../../actions/NotificationAction');
const CommentAction = require('../../actions/CommentAction');
const SettingAction = require('../../actions/SettingAction');
const Appbar = require('material-ui/lib/app-bar');
const Colors = require('material-ui/lib/styles/colors');
const IconButton = require('material-ui/lib/icon-button');
const PlayIcon = require('material-ui/lib/svg-icons/av/airplay');
const SettingsIcon = require('material-ui/lib/svg-icons/action/settings');
const TextField = require('material-ui/lib/text-field');

let Header = React.createClass({
  displayName: 'Header',

  getInitialState() {
    return {
      lv: ''
    };
  },

  changeLiveid(e) {
    this.setState({lv: e.target.value});
  },

  handleConnect() {
    let liveId = this.state.lv.trim();
    if (! isNaN(liveId)) { liveId = `lv${liveId}`; }
    if (liveId === '' || liveId === 'lv') {
      NotificationAction.notify('生放送IDの書式ではありません');
      return;
    }
    CommentAction.resetAllComment();
    NicoAction.connect(liveId);
  },

  handleConfig() {
    SettingAction.open();
  },

  render() {
    return (

        <Appbar
          style={{position: 'fixed', top: '0', left: '0', right: '0'}}
          iconElementLeft={
}
          title={

              comelon
              <TextField
                className='LiveIdForm'
                value={this.state.lv}
                onChange={this.changeLiveid}
                style={{margin: '0 2em'}}
                hintStyle={{color: 'rgba(255,255,255,.5)'}}
                hintText='放送番号(lv00000)'
                inputStyle={{color: 'white'}}
              />

          }
          iconElementRight={

              <IconButton
                className='NicoLiveConnectButton'
                tooltip='接続'
                tooltipPosition='bottom-left'
                onMouseDown={this.handleConnect}
              ><PlayIcon color={Colors.white} hoverColor={Colors.cyanA100}/></IconButton>
              <IconButton
                className='AppSettingsButton'
                tooltip='設定'
                tooltipPosition='bottom-left'
                onMouseDown={this.handleConfig}
              ><SettingsIcon  color={Colors.white} hoverColor={Colors.cyanA100}/></IconButton>

          }
        />

    );
  }

});

module.exports = Header;

// vim:ft=javascript.jsx
<commit_msg>Refactoring Header Component by codeclimate<commit_after>'use strict';

const React = require('react');
const NicoAction = require('../../actions/NicoAction');
const NotificationAction = require('../../actions/NotificationAction');
const CommentAction = require('../../actions/CommentAction');
const SettingAction = require('../../actions/SettingAction');
const Appbar = require('material-ui/lib/app-bar');
const Colors = require('material-ui/lib/styles/colors');
const IconButton = require('material-ui/lib/icon-button');
const PlayIcon = require('material-ui/lib/svg-icons/av/airplay');
const SettingsIcon = require('material-ui/lib/svg-icons/action/settings');
const TextField = require('material-ui/lib/text-field');

const defaultIconButtonProps = { tooltipPosition: 'bottom-left' };
const play = <PlayIcon color={Colors.white} hoverColor={Colors.cyanA100}/>;
const setting = <SettingsIcon  color={Colors.white} hoverColor={Colors.cyanA100}/>;

let Header = React.createClass({
  displayName: 'Header',

  getInitialState() {
    return {
      lv: ''
    };
  },

  changeLiveid(e) {
    this.setState({lv: e.target.value});
  },

  handleConnect() {
    let liveId = this.state.lv.trim();
    if (! isNaN(liveId)) { liveId = `lv${liveId}`; }
    if (liveId === '' || liveId === 'lv') {
      NotificationAction.notify('生放送IDの書式ではありません');
      return;
    }
    CommentAction.resetAllComment();
    NicoAction.connect(liveId);
  },

  handleConfig() {
    SettingAction.open();
  },

  renderConnectButton() {
    return (
      <IconButton {...defaultIconButtonProps}
        className='NicoLiveConnectButton'
        tooltip='接続'
        onMouseDown={this.handleConnect}
      >{play}</IconButton>
    );
  },

  renderSettingButton() {
    return (
      <IconButton {...defaultIconButtonProps}
        className='AppSettingsButton'
        tooltip='設定'
        onMouseDown={this.handleConfig}
      >{setting}</IconButton>
    );
  },

  render() {
    const textFieldProps = {
      className: 'LiveIdForm',
      value: this.state.lv,
      onChange: this.changeLiveid,
      style: { margin: '0 2em' },
      inputStyle: { color: 'white' },
      hintStyle: { color: 'rgba(255,255,255,.5)' },
      hintText: '放送番号(lvXXXXXX)'
    };

    return (

        <Appbar style={{position: 'fixed', top: '0', left: '0', right: '0'}}
          iconElementLeft={
}
          title={

              comelon
              <TextField {...textFieldProps} />

          }
          iconElementRight={

              {this.renderConnectButton()}
              {this.renderSettingButton()}

          }
        />

    );
  }

});

module.exports = Header;

// vim:ft=javascript.jsx
<|endoftext|>


<commit_before>// Copyright (C) 2017 Louis de Charsonville
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License version 3 as
// published by the Free Software Foundation.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

var chai = require('chai');
var chaiHttp = require('chai-http');
var app = require('../server');
var should = chai.should();
chai.use(chaiHttp);

const urls = require('./urls.json');

for(var provider in urls.paths){
    for(var test in urls.paths[provider]){
        var desc = ' GET / ' + test,
            url = urls.paths[provider][test];
        console.log(url);
        describe(desc,function(){
            var str = 'status 200 for' + url;
            it(str, function(done) {
                chai.request(app)
                    .get(url)
                    .end(function(err,res) {
                        if (err) {
                            throw err;
                        }
                        res.should.have.status(200);
                        done();
                    });
            });
        });
    }
}
<commit_msg>increase timeout in unit test<commit_after>// Copyright (C) 2017 Louis de Charsonville
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License version 3 as
// published by the Free Software Foundation.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

var chai = require('chai');
var chaiHttp = require('chai-http');
var app = require('../server');
var should = chai.should();
chai.use(chaiHttp);

const urls = require('./urls.json');

for(var provider in urls.paths){
    for(var test in urls.paths[provider]){
        var desc = ' GET / ' + test,
            url = urls.paths[provider][test];
        console.log(url);
        describe(desc,function(){
            this.timeout(10000);
            var str = 'status 200 for' + url;
            it(str, function(done) {
                chai.request(app)
                    .get(url)
                    .end(function(err,res) {
                        if (err) {
                            throw err;
                        }
                        res.should.have.status(200);
                        done();
                    });
            });
        });
    }
}
<|endoftext|>


<commit_before>// TiSortable
// Copyright (c) 2013 Adam Paxton - Polanco Media, LLC
// http://github.com/adampax/TiSortable
// Licensed under the MIT License. See: /License.txt
function SortableView(args) {

	//mix in properties with the defaults
	args = extend({
		cellWidth : 95,
		cellHeight : 95,
		columnPadding : 10,
		rowPadding : 10,
		columns : 3
	}, args || {});

	var cells = []
		posArray = [],
		rowArray = [];

	var Draggable = require('ti.draggable'),
		self = Ti.UI.createView();

	populate();

	//FUNCTIONS

	function populate(){
		//clear out the parent view
	  	var viewChildren = self.children.slice(0);
		for (var i = 0; i < viewChildren.length; ++i) {
	        self.remove(viewChildren[i]);
		}

		var row = 0,
			rowCheck = '';

		for (var i = 0; i < args.data.length; i++) {

			var column = i % args.columns,
				top = row * (args.cellHeight + (2 * args.rowPadding)),
				left = column * (args.cellWidth + (2 * args.columnPadding));

			Ti.API.info('cell: ' + (i+1) + ' top: ' + top);

			var cell = Draggable.createView({
				title: i,
				position: i,
				index: i,
				top : top,
				left : left,
				height : args.cellHeight,
				width : args.cellWidth
			});
			cell.add(args.data[i]);
			cells.push(cell);

/*
			if(row !== rowCheck){
				rowCheck = row;
				rowArray = [];
				posArray.push(rowArray);

			}

			rowArray.push({top:top,left:left});*/

			posArray.push({top:top,left:left, cellIndex: i});

			self.add(cells[i]);

			if (column + 1 === args.columns) {
				row++;
			}

			//attach the event listener to each view
			(function(v) {

				v.addEventListener('end', function(e){

					//disable the touch
					enableTouch(false);

					var col = '';
					var row = '';

					//get the new row
					switch(true){
						case (e.top <= 60):
							row = 0;
							break;
						case (e.top > 60 && e.top < 160):
							row = 1;
							break;
						case (e.top >=160):
							row = 2;
							break;
					}

					//get the new column
					switch(true){
						case (e.left <= 60):
							col = 0;
							break;
						case (e.left > 60 && e.left < 160):
							col = 1;
							break;
						case (e.left >=160):
							col = 2;
							break;
					}

					var dPositionIndex = ((1*row)*args.columns)+col;
					var oPositionIndex = v.position;

					//set the new position to help with animation bouncing back
					v.left = e.left;
					v.top = e.top;

					animate({
						cellIndex: v.index,
						dPositionIndex: dPositionIndex
					});

					//move old cells
					if(dPositionIndex !== oPositionIndex){

						var dir =  (dPositionIndex > oPositionIndex) ? 1 : 0;

						var startPos = (dPositionIndex > oPositionIndex) ? oPositionIndex : dPositionIndex;

						var max = (dPositionIndex > oPositionIndex) ? ((dPositionIndex - oPositionIndex)+oPositionIndex) : ((oPositionIndex - dPositionIndex)+dPositionIndex);

						//splitting up the logic for now because it is hurting my brain
						if(dPositionIndex > oPositionIndex){
							//ascending
							for(var i = startPos; i < max; i++){

								animate({
									cellIndex: posArray[i+1].cellIndex,
									dPositionIndex: i,
									callback: (i+1) !== max ? '' : (function(){
										enableTouch(true)
									})
								});
							}
						} else {
							//descending
							for(var i = startPos; i < max; i++){

								animate({
									cellIndex: posArray[i].cellIndex,
									dPositionIndex: i+1,
									callback: (i+1) !== max ? '' : (function(){
										enableTouch(true)
									})
								});
							}
						}
					} else {
						enableTouch(true);
					}

				});

			})(cell);

		}
	}

	function animate(obj){

		cells[obj.cellIndex].animate({top: posArray[obj.dPositionIndex].top, left: posArray[obj.dPositionIndex].left, duration: 500}, function(){
			//handle cell array movements on completion callback
			//to prevent what appeared to be race conditions
			cells[obj.cellIndex].position = obj.dPositionIndex;
			posArray[obj.dPositionIndex].cellIndex = obj.cellIndex;

			//perform any callbacks
			if(typeof(obj.callback) === 'function'){
				obj.callback();
			}

		});
	}

	function enableTouch(enable){
		//enable = enable || true;
		for(var i = 0; i < cells.length; i++){
			cells[i].touchEnabled = enable;
		}
	}

	//helper function extend on object with the properties of one or more others (thanks, Dojo!)
	function extend(obj, props) {
		var empty = {};

		if(!obj) {
			obj = {};
		}
		for(var i = 1, l = arguments.length; i < l; i++) {
			mixin(obj, arguments[i]);
		}
		return obj;

		function mixin(target, source) {
			var name, s, i;
			for(name in source) {
				if(source.hasOwnProperty(name)) {
					s = source[name];
					if(!( name in target) || (target[name] !== s && (!( name in empty) || empty[name] !== s))) {
						target[name] = s;
					}
				}
			}
			return target;
			// Object
		}
	}

	return self;
}

module.exports = SortableView; <commit_msg>reworked and moved code to getPositionIndex<commit_after>// TiSortable
// Copyright (c) 2013 Adam Paxton - Polanco Media, LLC
// http://github.com/adampax/TiSortable
// Licensed under the MIT License. See: /License.txt
function SortableView(args) {

	//mix in properties with the defaults
	args = extend({
		cellWidth : 95,
		cellHeight : 95,
		columnPadding : 10,
		rowPadding : 10,
		columns : 3
	}, args || {});

	var cells = [],
		posArray = [],
		rowArray = [];

	var Draggable = require('ti.draggable'),
		self = Ti.UI.createView();

	populate();

	//FUNCTIONS

	function populate(){
		//clear out the parent view
	  	var viewChildren = self.children.slice(0);
		for (var i = 0; i < viewChildren.length; ++i) {
	        self.remove(viewChildren[i]);
		}

		var row = 0,
			rowCheck = '';

		for (var i = 0; i < args.data.length; i++) {

			var column = i % args.columns,
				top = row * (args.cellHeight + (2 * args.rowPadding)),
				left = column * (args.cellWidth + (2 * args.columnPadding));

			var cell = Draggable.createView({
				position: i,
				index: i,
				top : top,
				left : left,
				height : args.cellHeight,
				width : args.cellWidth
			});
			cell.add(args.data[i]);
			cells.push(cell);

			posArray.push({top:top,left:left, cellIndex: i});

			self.add(cells[i]);

			if (column + 1 === args.columns) {
				row++;
			}

			//attach the event listener to each view
			(function(v) {

				v.addEventListener('end', function(e){

					//disable the touch
					enableTouch(false);

					var dPositionIndex = getPositionIndex(e);
					var testpos = getPositionIndexOld(e);

					Ti.API.info('old get Position: ' + testpos + ' New getPos: ' + dPositionIndex);

					var oPositionIndex = v.position;

					//set the new position to help with animation bouncing back
					v.left = e.left;
					v.top = e.top;

					animate({
						cellIndex: v.index,
						dPositionIndex: dPositionIndex
					});

					//move old cells
					if(dPositionIndex !== oPositionIndex){

						var dir =  (dPositionIndex > oPositionIndex) ? 1 : 0;

						var startPos = (dPositionIndex > oPositionIndex) ? oPositionIndex : dPositionIndex;

						var max = (dPositionIndex > oPositionIndex) ? ((dPositionIndex - oPositionIndex)+oPositionIndex) : ((oPositionIndex - dPositionIndex)+dPositionIndex);

						//splitting up the logic for now because it is hurting my brain
						if(dPositionIndex > oPositionIndex){
							//ascending
							for(var i = startPos; i < max; i++){

								animate({
									cellIndex: posArray[i+1].cellIndex,
									dPositionIndex: i,
									callback: (i+1) !== max ? '' : (function(){
										enableTouch(true)
									})
								});
							}
						} else {
							//descending
							for(var i = startPos; i < max; i++){

								animate({
									cellIndex: posArray[i].cellIndex,
									dPositionIndex: i+1,
									callback: (i+1) !== max ? '' : (function(){
										enableTouch(true)
									})
								});
							}
						}
					} else {
						enableTouch(true);
					}

				});

			})(cell);

		}
	}

	function animate(obj){

		cells[obj.cellIndex].animate({top: posArray[obj.dPositionIndex].top, left: posArray[obj.dPositionIndex].left, duration: 500}, function(){
			//handle cell array movements on completion callback
			//to prevent what appeared to be race conditions
			cells[obj.cellIndex].position = obj.dPositionIndex;
			posArray[obj.dPositionIndex].cellIndex = obj.cellIndex;

			//perform any callbacks
			if(typeof(obj.callback) === 'function'){
				obj.callback();
			}

		});
	}

	function enableTouch(enable){
		//enable = enable || true;
		for(var i = 0; i < cells.length; i++){
			cells[i].touchEnabled = enable;
		}
	}

	function getPositionIndex(e){

		var totRows = cells.length / args.columns;
		var col = args.columns-1;
		var row = totRows-1;

		var heightMult = (args.cellHeight + (2 * args.rowPadding));
		var widthMult = (args.cellWidth + (2 * args.columnPadding));

		//get the new row
		for(var i = 0; i < totRows; i++){
			if(e.top < (i * heightMult) + (heightMult / 2)){
				row = i;
				break;
			}
		}

		//get the new column
		for(var i = 0; i < args.columns; i++){
			if(e.left < (i * widthMult)+(widthMult/2)){
				col = i;
				break;
			}
		}
		var dPositionIndex = ((1*row)*args.columns)+col;
		return 	dPositionIndex;
	}

	function getPositionIndexOld(e){
		var col = '';
		var row = '';

		//get the new row
		switch(true){
			case (e.top <= 60):
				row = 0;
				break;
			case (e.top > 60 && e.top < 160):
				row = 1;
				break;
			case (e.top >=160):
				row = 2;
				break;
		}

		//get the new column
		switch(true){
			case (e.left <= 60):
				col = 0;
				break;
			case (e.left > 60 && e.left < 160):
				col = 1;
				break;
			case (e.left >=160):
				col = 2;
				break;
		}
		var dPositionIndex = ((1*row)*args.columns)+col;
		return 	dPositionIndex;
	}

	//helper function extend on object with the properties of one or more others (thanks, Dojo!)
	function extend(obj, props) {
		var empty = {};

		if(!obj) {
			obj = {};
		}
		for(var i = 1, l = arguments.length; i < l; i++) {
			mixin(obj, arguments[i]);
		}
		return obj;

		function mixin(target, source) {
			var name, s, i;
			for(name in source) {
				if(source.hasOwnProperty(name)) {
					s = source[name];
					if(!( name in target) || (target[name] !== s && (!( name in empty) || empty[name] !== s))) {
						target[name] = s;
					}
				}
			}
			return target;
			// Object
		}
	}

	return self;
}

module.exports = SortableView; <|endoftext|>


<commit_before>/**
 * ngAuth 0.0.1
 * (c) 2014 Sahat Yalkabov <sahat@me.com>
 * License: MIT
 */

angular.module('ngAuth', [])
  .provider('Auth', function() {

    var config = this.config = {
      logoutRedirect: '/',
      loginRedirect: '/',
      loginUrl: '/auth/login',
      signupUrl: '/auth/signup',
      signupRedirect: '/login',
      userGlobal: 'currentUser',
      providers: {
        facebook: {
          baseUrl: 'https://www.facebook.com/dialog/oauth',
          scope: 'scope, email',
          requiredUrlParams: { display: 'popup' }
        }
      }
    };

    return {
      setProvider: function(params) {
        config.providers[params.name] = config.providers[params.name] || {};
        angular.extend(config.providers[params.name], params);
      },

      $get: function($interval, $timeout, $http, $location, $rootScope, $alert, $q, $injector, $window, $document, $cookieStore) {

        // BEGIN OAUTH

        function parseKeyValue(keyValue) {
          var obj = {}, key_value, key;
          angular.forEach((keyValue || "").split('&'), function(keyValue) {
            if (keyValue) {
              key_value = keyValue.split('=');
              key = decodeURIComponent(key_value[0]);
              obj[key] = angular.isDefined(key_value[1]) ? decodeURIComponent(key_value[1]) : true;
            }
          });
          return obj;
        }

        var Popup = function() {

          this.popup = null;

          this.open = function(url, keys, options) {
            var deferred = $q.defer();
            var lastPopup = this.popup;

            if (lastPopup) {
              this.close();
            }

            var optionsString = stringifyOptions(prepareOptions(options || {}));
            this.popup = window.open(url, 'ng-auth', optionsString);

            if (this.popup && !this.popup.closed) {
              this.popup.focus();
            } else {
              deferred.reject('Popup could not open or was closed');
            }

            $window.addEventListener('message', function(event) {
              console.log('handling postMessage');
              console.log(event);
              if (event.data.message === 'deliverCredenrials') {
                delete event.data.message;
              }
              deferred.resolve(event.data);
            }, false);

            var self = this;

            this.polling = $interval(function() {
              self.requestCredentials(self.popup);
            }, 35);

            return   deferred.promise;
          };

          this.close = function() {
            if (this.popup) {
              this.popup.close();
              this.popup = null;
              $rootScope.$emit('didClose');
            }
          };

          this.pollPopup = function() {
            console.log('pollin')
            if (!this.popup) {
              return;
            }
            if (this.popup.closed) {
              $timeout.cancel(this.polling);
            }
          };

          this.schedulePolling = function() {
            var self = this;
            this.polling = $timeout(function() {
              self.pollPopup();
              self.schedulePolling();
            }, 35);
          };

          this.stopPolling = function() {
            console.log('stopping pooling');
          };

          this.requestCredentials = function(authWindow) {
            var search = authWindow.location.search;
            if (search.match('code') || search.match('token')) {
              console.log('found code or token');
              var data = parseKeyValue(authWindow.location.search.substring(1));
              authWindow.postMessage(data, '*');
              $interval.cancel(this.polling);
            }
            console.log('requesting creds!!')

          };
        };

        function prepareOptions(options) {
          var width = options.width || 500;
          var height = options.height || 500;
          return angular.extend({
            left: ((screen.width / 2) - (width / 2)),
            top: ((screen.height / 2) - (height / 2)),
            width: width,
            height: height
          }, options);
        }

        function stringifyOptions(options) {
          var optionsStrings = [];
          for (var key in options) {
            if (options.hasOwnProperty(key)) {
              var value;
              switch (options[key]) {
                case true:
                  value = '1';
                  break;
                case false:
                  value = '0';
                  break;
                default:
                  value = options[key];
              }
              optionsStrings.push(
                  key + '=' + value
              );
            }
          }
          return optionsStrings.join(',');
        }

        var getRedirectUri = function() {
          return $window.location.href;
        };

        var oauthKeys = ['code', 'access_token', 'expires_in'];

        var OAuth2 = function() {
          this.name = null;
          this.clientId = null;
          this.scope = null;
          this.baseUrl = null;
          this.responseType = 'code';
        };

        OAuth2.prototype.getDefaultRequiredUrlParams = function() {
          return {
            response_type: this.responseType,
            client_id: this.clientId,
            redirect_uri: getRedirectUri()
          }
        };

        OAuth2.prototype.buildQueryString = function(obj) {
          var str = [];
          angular.forEach(obj, function(value, key) {
            str.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));
          });
          return str.join('&');
        };

        OAuth2.prototype.open = function() {
          var name = this.name;
          var url = this.buildUrl();
          var redirectUri = $window.location.href;

          var popup = new Popup();

          return popup.open(url, oauthKeys).then(function(authData) {
            return {
              authorizationCode: authData.code,
              provider: name,
              getRedirectUri: redirectUri
            }
          });
        };

        OAuth2.prototype.buildUrl = function(optionalUrlParams) {
          var defaultRequiredUrlParams = this.getDefaultRequiredUrlParams();
          if (this.requiredUrlParams) {
            angular.extend(defaultRequiredUrlParams, this.requiredUrlParams);
          }
          var base = this.baseUrl;
          var params = angular.extend(defaultRequiredUrlParams, optionalUrlParams);
          var qs = this.buildQueryString(params);
          return [base, qs].join('?');
        };

        function providerLookup(providerName) {
          var options = config.providers[providerName];
          var oauth2 = new OAuth2();
          var provider = angular.extend(oauth2, options);
          console.log('MAA', provider);
          return provider;
        }

        // END OAUTH

        var token = $window.localStorage.token;
        if (token) {
          var payload = JSON.parse($window.atob(token.split('.')[1]));
          $rootScope[config.userGlobal] = payload.user;
        }

        return {
          authenticate: function(provider, options) {
            var deferred = $q.defer;
            if (!provider) {
              throw new Error('Expected a provider named \'' + provider + '\', did you forget to add it?');
            } else {
              provider = providerLookup(provider);
            }
            provider.open(options);
          },

          loginOauth: function(provider) {
            provider = provider.trim().toLowerCase();

            switch (provider) {
              case 'facebook':
                var scope = config.providers.facebook.scope.join(',');
                FB.login(function(response) {
                  FB.api('/me', function(profile) {
                    // TODO normalize return properties like passport
                    var data = {
                      accessToken: response.authResponse.accessToken,
                      signedRequest: response.authResponse.signedRequest,
                      profile: profile
                    };
                    $http.post(config.providers.facebook.url, data).success(function(token) {
                      var payload = JSON.parse($window.atob(token.split('.')[1]));
                      $window.localStorage.token = token;
                      $rootScope[config.userGlobal] = payload.user;
                      $location.path(config.loginRedirect);
                    });
                  });
                }, { scope: scope });
                break;
              case 'google':
                gapi.auth.authorize({
                  client_id: config.providers.google.clientId,
                  scope: config.providers.google.scope,
                  immediate: false
                }, function(token) {
                  gapi.client.load('plus', 'v1', function() {
                    var request = gapi.client.plus.people.get({
                      userId: 'me'
                    });
                    request.execute(function(response) {
                      var data = {
                        accessToken: token.access_token,
                        profile: response
                      };
                      $http.post(config.providers.google.url, data).success(function(token) {
                        var payload = JSON.parse($window.atob(token.split('.')[1]));
                        $window.localStorage.token = token;
                        $rootScope.currentUser = payload.user;
                        $location.path(config.loginRedirect);
                      });
                    });
                  });
                });
                break;
              case 'linkedin':
                IN.UI.Authorize().place();
                IN.Event.on(IN, 'auth', function() {
                    IN.API.Profile('me').result(function(result) {
                      var profile = result.values[0];
                      $http.post(config.providers.linkedin.url, { profile: profile }).success(function(token) {
                        var payload = JSON.parse($window.atob(token.split('.')[1]));
                        $window.localStorage.token = token;
                        $rootScope.currentUser = payload.user;
                        $location.path(config.loginRedirect);
                      });
                    });
                  }
                );
                break;
              default:
                break;
            }
          },
          login: function(user) {
            return $http.post(config.loginUrl, user).success(function(data) {
              $window.localStorage.token = data.token;
              var payload = JSON.parse($window.atob(data.token.split('.')[1]));
              $rootScope[config.userGlobal] = payload.user;
              $location.path(config.loginRedirect);
            });
          },
          signup: function(user) {
            return $http.post(config.signupUrl, user).success(function() {
              $location.path(config.signupRedirect);
            });
          },
          logout: function() {
            delete $window.localStorage.token;
            $rootScope[config.userGlobal] = null;
            $location.path(config.logoutRedirect);
          },
          isAuthenticated: function() {
            return $rootScope[config.userGlobal];
          }
        };
      }
    };
  })
  .factory('authInterceptor', function($q, $window, $location) {
    return {
      request: function(config) {
        if ($window.localStorage.token) {
          config.headers.Authorization = 'Bearer ' + $window.localStorage.token;
        }
        return config;
      },
      responseError: function(response) {
        if (response.status === 401 || response.status === 403) {
          $location.path('/login');
        }
        return $q.reject(response);
      }
    }
  })
  .config(function($httpProvider) {
    $httpProvider.interceptors.push('authInterceptor');
  })
  .run(function($rootScope, $location) {
    $rootScope.$on('$routeChangeStart', function(event, current, previous) {
      if ($rootScope.currentUser &&
        (current.originalPath === '/login' || current.originalPath === '/signup')) {
        $location.path('/');
      }
      if (current.authenticated && !$rootScope.currentUser) {
        $location.path('/login');
      }
    });
  });
<commit_msg>move popup methods to Popup.prototype<commit_after>/**
 * ngAuth 0.0.1
 * (c) 2014 Sahat Yalkabov <sahat@me.com>
 * License: MIT
 */

angular.module('ngAuth', [])
  .provider('Auth', function() {

    var config = this.config = {
      logoutRedirect: '/',
      loginRedirect: '/',
      loginUrl: '/auth/login',
      signupUrl: '/auth/signup',
      signupRedirect: '/login',
      userGlobal: 'currentUser',
      providers: {
        facebook: {
          baseUrl: 'https://www.facebook.com/dialog/oauth',
          scope: 'scope, email',
          requiredUrlParams: { display: 'popup' }
        }
      }
    };

    return {
      setProvider: function(params) {
        config.providers[params.name] = config.providers[params.name] || {};
        angular.extend(config.providers[params.name], params);
      },

      $get: function($interval, $timeout, $http, $location, $rootScope, $alert, $q, $injector, $window, $document, $cookieStore) {

        // BEGIN OAUTH

        function parseKeyValue(keyValue) {
          var obj = {}, key_value, key;
          angular.forEach((keyValue || "").split('&'), function(keyValue) {
            if (keyValue) {
              key_value = keyValue.split('=');
              key = decodeURIComponent(key_value[0]);
              obj[key] = angular.isDefined(key_value[1]) ? decodeURIComponent(key_value[1]) : true;
            }
          });
          return obj;
        }

        var Popup = function() {

          this.popup = null;
        };

        Popup.prototype.open = function(url, keys, options) {
          var deferred = $q.defer();
          var lastPopup = this.popup;

          if (lastPopup) {
            this.close();
          }

          var optionsString = stringifyOptions(prepareOptions(options || {}));
          this.popup = window.open(url, 'ng-auth', optionsString);

          if (this.popup && !this.popup.closed) {
            this.popup.focus();
          } else {
            deferred.reject('Popup could not open or was closed');
          }

          $window.addEventListener('message', function(event) {
            console.log('handling postMessage');
            console.log(event);
            if (event.data.message === 'deliverCredenrials') {
              delete event.data.message;
            }
            deferred.resolve(event.data);
          }, false);

          var self = this;

          this.polling = $interval(function() {
            self.requestCredentials(self.popup);
          }, 35);

          return deferred.promise;
        };

        Popup.prototype.close = function() {
          if (this.popup) {
            this.popup.close();
            this.popup = null;
            $rootScope.$emit('didClose');
          }
        };

        Popup.prototype.pollPopup = function() {
          console.log('pollin');
          if (!this.popup) {
            return;
          }
          if (this.popup.closed) {
            $timeout.cancel(this.polling);
          }
        };

        Popup.prototype.requestCredentials = function(authWindow) {
          var search = authWindow.location.search;
          if (search.match('code') || search.match('token')) {
            console.log('found code or token');
            var data = parseKeyValue(authWindow.location.search.substring(1));
            authWindow.postMessage(data, '*');
            $interval.cancel(this.polling);
          }
          console.log('requesting creds!!')

        };

        function prepareOptions(options) {
          var width = options.width || 500;
          var height = options.height || 500;
          return angular.extend({
            left: ((screen.width / 2) - (width / 2)),
            top: ((screen.height / 2) - (height / 2)),
            width: width,
            height: height
          }, options);
        }

        function stringifyOptions(options) {
          var optionsStrings = [];
          for (var key in options) {
            if (options.hasOwnProperty(key)) {
              var value;
              switch (options[key]) {
                case true:
                  value = '1';
                  break;
                case false:
                  value = '0';
                  break;
                default:
                  value = options[key];
              }
              optionsStrings.push(
                  key + '=' + value
              );
            }
          }
          return optionsStrings.join(',');
        }

        var getRedirectUri = function() {
          return $window.location.href;
        };

        var oauthKeys = ['code', 'access_token', 'expires_in'];

        var OAuth2 = function() {
          this.name = null;
          this.clientId = null;
          this.scope = null;
          this.baseUrl = null;
          this.responseType = 'code';
        };

        OAuth2.prototype.getDefaultRequiredUrlParams = function() {
          return {
            response_type: this.responseType,
            client_id: this.clientId,
            redirect_uri: getRedirectUri()
          }
        };

        OAuth2.prototype.buildQueryString = function(obj) {
          var str = [];
          angular.forEach(obj, function(value, key) {
            str.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));
          });
          return str.join('&');
        };

        OAuth2.prototype.open = function() {
          var name = this.name;
          var url = this.buildUrl();
          var redirectUri = $window.location.href;

          var popup = new Popup();

          return popup.open(url, oauthKeys).then(function(authData) {
            return {
              authorizationCode: authData.code,
              provider: name,
              getRedirectUri: redirectUri
            }
          });
        };

        OAuth2.prototype.buildUrl = function(optionalUrlParams) {
          var defaultRequiredUrlParams = this.getDefaultRequiredUrlParams();
          if (this.requiredUrlParams) {
            angular.extend(defaultRequiredUrlParams, this.requiredUrlParams);
          }
          var base = this.baseUrl;
          var params = angular.extend(defaultRequiredUrlParams, optionalUrlParams);
          var qs = this.buildQueryString(params);
          return [base, qs].join('?');
        };
        function providerLookup(providerName) {
          var providerOptions = config.providers[providerName];
          var oauth2 = new OAuth2();
          var provider = angular.extend(oauth2, providerOptions);
          return provider;
        }

        // END OAUTH

        var token = $window.localStorage.token;
        if (token) {
          var payload = JSON.parse($window.atob(token.split('.')[1]));
          $rootScope[config.userGlobal] = payload.user;
        }

        return {
          authenticate: function(provider, options) {
            var deferred = $q.defer;
            if (!provider) {
              throw new Error('Expected a provider named \'' + provider + '\', did you forget to add it?');
            } else {
              provider = providerLookup(provider);
            }
            provider.open(options);
          },

          loginOauth: function(provider) {
            provider = provider.trim().toLowerCase();

            switch (provider) {
              case 'facebook':
                var scope = config.providers.facebook.scope.join(',');
                FB.login(function(response) {
                  FB.api('/me', function(profile) {
                    // TODO normalize return properties like passport
                    var data = {
                      accessToken: response.authResponse.accessToken,
                      signedRequest: response.authResponse.signedRequest,
                      profile: profile
                    };
                    $http.post(config.providers.facebook.url, data).success(function(token) {
                      var payload = JSON.parse($window.atob(token.split('.')[1]));
                      $window.localStorage.token = token;
                      $rootScope[config.userGlobal] = payload.user;
                      $location.path(config.loginRedirect);
                    });
                  });
                }, { scope: scope });
                break;
              case 'google':
                gapi.auth.authorize({
                  client_id: config.providers.google.clientId,
                  scope: config.providers.google.scope,
                  immediate: false
                }, function(token) {
                  gapi.client.load('plus', 'v1', function() {
                    var request = gapi.client.plus.people.get({
                      userId: 'me'
                    });
                    request.execute(function(response) {
                      var data = {
                        accessToken: token.access_token,
                        profile: response
                      };
                      $http.post(config.providers.google.url, data).success(function(token) {
                        var payload = JSON.parse($window.atob(token.split('.')[1]));
                        $window.localStorage.token = token;
                        $rootScope.currentUser = payload.user;
                        $location.path(config.loginRedirect);
                      });
                    });
                  });
                });
                break;
              case 'linkedin':
                IN.UI.Authorize().place();
                IN.Event.on(IN, 'auth', function() {
                    IN.API.Profile('me').result(function(result) {
                      var profile = result.values[0];
                      $http.post(config.providers.linkedin.url, { profile: profile }).success(function(token) {
                        var payload = JSON.parse($window.atob(token.split('.')[1]));
                        $window.localStorage.token = token;
                        $rootScope.currentUser = payload.user;
                        $location.path(config.loginRedirect);
                      });
                    });
                  }
                );
                break;
              default:
                break;
            }
          },
          login: function(user) {
            return $http.post(config.loginUrl, user).success(function(data) {
              $window.localStorage.token = data.token;
              var payload = JSON.parse($window.atob(data.token.split('.')[1]));
              $rootScope[config.userGlobal] = payload.user;
              $location.path(config.loginRedirect);
            });
          },
          signup: function(user) {
            return $http.post(config.signupUrl, user).success(function() {
              $location.path(config.signupRedirect);
            });
          },
          logout: function() {
            delete $window.localStorage.token;
            $rootScope[config.userGlobal] = null;
            $location.path(config.logoutRedirect);
          },
          isAuthenticated: function() {
            return $rootScope[config.userGlobal];
          }
        };
      }
    };
  })
  .factory('authInterceptor', function($q, $window, $location) {
    return {
      request: function(config) {
        if ($window.localStorage.token) {
          config.headers.Authorization = 'Bearer ' + $window.localStorage.token;
        }
        return config;
      },
      responseError: function(response) {
        if (response.status === 401 || response.status === 403) {
          $location.path('/login');
        }
        return $q.reject(response);
      }
    }
  })
  .config(function($httpProvider) {
    $httpProvider.interceptors.push('authInterceptor');
  })
  .run(function($rootScope, $location) {
    $rootScope.$on('$routeChangeStart', function(event, current, previous) {
      if ($rootScope.currentUser &&
        (current.originalPath === '/login' || current.originalPath === '/signup')) {
        $location.path('/');
      }
      if (current.authenticated && !$rootScope.currentUser) {
        $location.path('/login');
      }
    });
  });
<|endoftext|>


<commit_before>/* ScriptInclude
 * https://github.com/EvanHahn/ScriptInclude
 * by Evan Hahn
 * License: Unlicense
 */

;(function() {

	var doc = document;
	var head = doc.head || (doc.getElementsByTagName("head")[0]);

	var noop = function() {};

	var include = function() {

		var toLoad = arguments.length;

		var callback;
		var hasCallback = arguments[toLoad - 1] instanceof Function;
		if (hasCallback) {
			toLoad --;
			callback = arguments[arguments.length - 1];
		} else {
			callback = noop;
		}

		var script;
		for (var i = 0; i < toLoad; i ++) {

			script = doc.createElement("script");
			script.src = arguments[i];

			script.onload = script.onerror = function() {
				toLoad --;
				if (toLoad === 0)
					callback.call();
			};

			head.appendChild(script);

		}

	};

	if (typeof exports !== "undefined")
		exports = include;
	else
		this.include = include;

})();
<commit_msg>Changes to make jslint happy<commit_after>/*jslint browser: true*/

/* ScriptInclude
 * https://github.com/EvanHahn/ScriptInclude
 * by Evan Hahn
 * License: Unlicense
 */

(function (doc) {
    "use strict";

    var head = doc.head || (doc.getElementsByTagName("head")[0]),

        noop = function () {
            return;
        },

        include = function () {

            var toLoad = arguments.length,
                callback,
                hasCallback = arguments[toLoad - 1] instanceof Function,
                script,
                i,
                onloaded = function () {
                    toLoad -= 1;
                    if (toLoad === 0) {
                        callback.call();
                    }
                };

            if (hasCallback) {
                toLoad -= 1;
                callback = arguments[arguments.length - 1];
            } else {
                callback = noop;
            }

            for (i = 0; i < toLoad; i += 1) {
                script = doc.createElement("script");
                script.src = arguments[i];

                script.onload = script.onerror = onloaded;
                head.appendChild(script);
            }
        };

    if (typeof exports !== "undefined") {
        exports = include;
    } else {
        this.include = include;
    }

}(document));
<|endoftext|>