<commit_before>/*global describe*/
var async = require('async'),
  assert = require('assert'),
  should = require('should'),
  sitemapper = require('./sitemapper.js'),
  isurl = require('is-url');

var sitemaps = ['http://www.walmart.com/sitemaps.xml', 'http://www.cbs.com/sitemaps.xml'];

(function () {
  sitemapper.getSites('https://www.google.com/work/sitemap.xml', function (err, sites) {
    if (sites) {
      sitemaps = sites;
      sites.should.be.Array;
    } else {
      console.log(err);
    }
  });
})();

var sitemaps;
describe('sitemap', function () {
  describe('getSites', function () {

    it('Google sitemaps should be an array', function (done) {
      this.timeout(30000);
      sitemapper.getSites('https://www.google.com/work/sitemap.xml', function (err, sites) {
        if (sites) {
          sitemaps = sites;
          sites.should.be.Array;
          sites.length.should.be.above(2);
        } else {
          console.log(err);
        }
        done();
      });
    });

    it('Walmart sitemaps should be an array', function (done) {
      this.timeout(30000);
      sitemapper.getSites('http://wp.seantburke.com/sitemap.xml', function (err, sites) {
        if (sites) {
          sitemaps = sites;
          sites.should.be.Array;
          sites.length.should.be.above(2);
        } else {
          console.log(err);
        }
        done();
      });
    });

    it('Seantburke.com sitemaps should be an array', function (done) {
      this.timeout(30000);
      sitemapper.getSites('http://www.walmart.com/sitemap_ip.xml', function (err, sites) {
        if (sites) {
          sitemaps = sites;
          sites.should.be.Array;
        } else {
          console.log(err);
        }
        done();
      });
    });
  });

  describe('URL checks', function () {
    for (var key in sitemaps) {
      (function (site) {
        it(site + ' should be a URL', function () {
          isurl(site).should.be.true;
        });
      })(sitemaps[key]);
    }
  });

  describe('Sitemapper class', function () {
    it('should have parse method', () => {
      sitemapper.parse.should.be.Function;
    });

    it('should have getSites method', function () {
      sitemapper.getSites.should.be.Function;
    });
  });
});
<commit_msg>skipping walmart xml test because tests are flakey<commit_after>/*global describe*/
var async = require('async'),
  assert = require('assert'),
  should = require('should'),
  sitemapper = require('./sitemapper.js'),
  isurl = require('is-url');

var sitemaps = ['http://www.walmart.com/sitemaps.xml', 'http://www.cbs.com/sitemaps.xml'];

(function () {
  sitemapper.getSites('https://www.google.com/work/sitemap.xml', function (err, sites) {
    if (sites) {
      sitemaps = sites;
      sites.should.be.Array;
    } else {
      console.log(err);
    }
  });
})();

var sitemaps;
describe('sitemap', function () {
  describe('getSites', function () {

    it('Google sitemaps should be an array', function (done) {
      this.timeout(30000);
      sitemapper.getSites('https://www.google.com/work/sitemap.xml', function (err, sites) {
        if (sites) {
          sitemaps = sites;
          sites.should.be.Array;
          sites.length.should.be.above(2);
        } else {
          console.log(err);
        }
        done();
      });
    });

    it('Seantburke.com sitemaps should be an array', function (done) {
      this.timeout(30000);
      sitemapper.getSites('http://wp.seantburke.com/sitemap.xml', function (err, sites) {
        if (sites) {
          sitemaps = sites;
          sites.should.be.Array;
          sites.length.should.be.above(2);
        } else {
          console.log(err);
        }
        done();
      });
    });
  });

  describe('URL checks', function () {
    for (var key in sitemaps) {
      (function (site) {
        it(site + ' should be a URL', function () {
          isurl(site).should.be.true;
        });
      })(sitemaps[key]);
    }
  });

  describe('Sitemapper class', function () {
    it('should have parse method', () => {
      sitemapper.parse.should.be.Function;
    });

    it('should have getSites method', function () {
      sitemapper.getSites.should.be.Function;
    });
  });
});
<|endoftext|>


<commit_before>CodeMirror.defineMode("htmlmixed", function(config, parserConfig) {
  var htmlMode = CodeMirror.getMode(config, {name: "xml", htmlMode: true});
  var cssMode = CodeMirror.getMode(config, "css");

  var scriptTypes = [], scriptTypesConf = parserConfig && parserConfig.scriptTypes;
  scriptTypes.push({matches: /^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^$/i,
                    mode: CodeMirror.getMode(config, "javascript")});
  if (scriptTypesConf) for (var i = 0; i < scriptTypesConf.length; ++i) {
    var conf = scriptTypesConf[i];
    scriptTypes.push({matches: conf.matches, mode: conf.mode && CodeMirror.getMode(config, conf.mode)});
  }
  scriptTypes.push({matches: /./,
                    mode: CodeMirror.getMode(config, "text/plain")});

  function html(stream, state) {
    var style = htmlMode.token(stream, state.htmlState);
    if (/(?:^|\s)tag(?:\s|$)/.test(style) && stream.current() == ">" && state.htmlState.context) {
      if (/^script$/i.test(state.htmlState.context.tagName)) {
        // Script block: mode to change to depends on type attribute
        var scriptType = stream.string.slice(Math.max(0, stream.pos - 100), stream.pos).match(/\btype\s*=\s*("[^"]+"|'[^']+'|\S+)[^<]*$/i);
        scriptType = scriptType ? scriptType[1] : "";
        for (var i = 0; i < scriptTypes.length; ++i) {
          var tp = scriptTypes[i];
          if (typeof tp.matches == "string" ? scriptType == tp.matches : tp.matches.test(scriptType)) {
            if (tp.mode) {
              state.token = script;
              state.localMode = tp.mode;
              state.localState = tp.mode.startState && tp.mode.startState(htmlMode.indent(state.htmlState, ""));
            }
            break;
          }
        }
      } else if (/^style$/i.test(state.htmlState.context.tagName)) {
        state.token = css;
        state.localMode = cssMode;
        state.localState = cssMode.startState(htmlMode.indent(state.htmlState, ""));
      }
    }
    return style;
  }
  function maybeBackup(stream, pat, style) {
    var cur = stream.current();
    var close = cur.search(pat), m;
    if (close > -1) stream.backUp(cur.length - close);
    else if (m = cur.match(/<\/?$/)) {
      stream.backUp(cur.length);
      if (!stream.match(pat, false)) stream.match(cur[0]);
    }
    return style;
  }
  function script(stream, state) {
    if (stream.match(/^<\/\s*script\s*>/i, false)) {
      state.token = html;
      state.localState = state.localMode = null;
      return html(stream, state);
    }
    return maybeBackup(stream, /<\/\s*script\s*>/,
                       state.localMode.token(stream, state.localState));
  }
  function css(stream, state) {
    if (stream.match(/^<\/\s*style\s*>/i, false)) {
      state.token = html;
      state.localState = state.localMode = null;
      return html(stream, state);
    }
    return maybeBackup(stream, /<\/\s*style\s*>/,
                       cssMode.token(stream, state.localState));
  }

  return {
    startState: function() {
      var state = htmlMode.startState();
      return {token: html, localMode: null, localState: null, htmlState: state};
    },

    copyState: function(state) {
      if (state.localState)
        var local = CodeMirror.copyState(state.localMode, state.localState);
      return {token: state.token, localMode: state.localMode, localState: local,
              htmlState: CodeMirror.copyState(htmlMode, state.htmlState)};
    },

    token: function(stream, state) {
      return state.token(stream, state);
    },

    indent: function(state, textAfter) {
      if (!state.localMode || /^\s*<\//.test(textAfter))
        return htmlMode.indent(state.htmlState, textAfter);
      else if (state.localMode.indent)
        return state.localMode.indent(state.localState, textAfter);
      else
        return CodeMirror.Pass;
    },

    electricChars: "/{}:",

    innerMode: function(state) {
      return {state: state.localState || state.htmlState, mode: state.localMode || htmlMode};
    }
  };
}, "xml", "javascript", "css");

CodeMirror.defineMIME("text/html", "htmlmixed");
<commit_msg>[htmlmixed mode] Fix bug in matching of script types<commit_after>CodeMirror.defineMode("htmlmixed", function(config, parserConfig) {
  var htmlMode = CodeMirror.getMode(config, {name: "xml", htmlMode: true});
  var cssMode = CodeMirror.getMode(config, "css");

  var scriptTypes = [], scriptTypesConf = parserConfig && parserConfig.scriptTypes;
  scriptTypes.push({matches: /^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^$/i,
                    mode: CodeMirror.getMode(config, "javascript")});
  if (scriptTypesConf) for (var i = 0; i < scriptTypesConf.length; ++i) {
    var conf = scriptTypesConf[i];
    scriptTypes.push({matches: conf.matches, mode: conf.mode && CodeMirror.getMode(config, conf.mode)});
  }
  scriptTypes.push({matches: /./,
                    mode: CodeMirror.getMode(config, "text/plain")});

  function html(stream, state) {
    var style = htmlMode.token(stream, state.htmlState);
    if (/(?:^|\s)tag(?:\s|$)/.test(style) && stream.current() == ">" && state.htmlState.context) {
      if (/^script$/i.test(state.htmlState.context.tagName)) {
        // Script block: mode to change to depends on type attribute
        var scriptType = stream.string.slice(Math.max(0, stream.pos - 100), stream.pos).match(/\btype\s*=\s*("[^"]+"|'[^']+'|\S+)[^<]*$/i);
        scriptType = scriptType ? scriptType[1] : "";
        if (scriptType && /[\"\']/.test(scriptType.charAt(0))) scriptType = scriptType.slice(1, scriptType.length - 1);
        for (var i = 0; i < scriptTypes.length; ++i) {
          var tp = scriptTypes[i];
          if (typeof tp.matches == "string" ? scriptType == tp.matches : tp.matches.test(scriptType)) {
            if (tp.mode) {
              state.token = script;
              state.localMode = tp.mode;
              state.localState = tp.mode.startState && tp.mode.startState(htmlMode.indent(state.htmlState, ""));
            }
            break;
          }
        }
      } else if (/^style$/i.test(state.htmlState.context.tagName)) {
        state.token = css;
        state.localMode = cssMode;
        state.localState = cssMode.startState(htmlMode.indent(state.htmlState, ""));
      }
    }
    return style;
  }
  function maybeBackup(stream, pat, style) {
    var cur = stream.current();
    var close = cur.search(pat), m;
    if (close > -1) stream.backUp(cur.length - close);
    else if (m = cur.match(/<\/?$/)) {
      stream.backUp(cur.length);
      if (!stream.match(pat, false)) stream.match(cur[0]);
    }
    return style;
  }
  function script(stream, state) {
    if (stream.match(/^<\/\s*script\s*>/i, false)) {
      state.token = html;
      state.localState = state.localMode = null;
      return html(stream, state);
    }
    return maybeBackup(stream, /<\/\s*script\s*>/,
                       state.localMode.token(stream, state.localState));
  }
  function css(stream, state) {
    if (stream.match(/^<\/\s*style\s*>/i, false)) {
      state.token = html;
      state.localState = state.localMode = null;
      return html(stream, state);
    }
    return maybeBackup(stream, /<\/\s*style\s*>/,
                       cssMode.token(stream, state.localState));
  }

  return {
    startState: function() {
      var state = htmlMode.startState();
      return {token: html, localMode: null, localState: null, htmlState: state};
    },

    copyState: function(state) {
      if (state.localState)
        var local = CodeMirror.copyState(state.localMode, state.localState);
      return {token: state.token, localMode: state.localMode, localState: local,
              htmlState: CodeMirror.copyState(htmlMode, state.htmlState)};
    },

    token: function(stream, state) {
      return state.token(stream, state);
    },

    indent: function(state, textAfter) {
      if (!state.localMode || /^\s*<\//.test(textAfter))
        return htmlMode.indent(state.htmlState, textAfter);
      else if (state.localMode.indent)
        return state.localMode.indent(state.localState, textAfter);
      else
        return CodeMirror.Pass;
    },

    electricChars: "/{}:",

    innerMode: function(state) {
      return {state: state.localState || state.htmlState, mode: state.localMode || htmlMode};
    }
  };
}, "xml", "javascript", "css");

CodeMirror.defineMIME("text/html", "htmlmixed");
<|endoftext|>


<commit_before>/* @flow */

import React, { Component, PropTypes } from 'react';
import ReactNative from 'react-native';
import shallowCompare from 'react-addons-shallow-compare';
import AppText from '../Core/AppText';
import TouchFeedback from '../Core/TouchFeedback';
import Loading from '../Core/Loading';
import Colors from '../../../Colors';

const {
	StyleSheet,
	View,
} = ReactNative;

const styles = StyleSheet.create({
	container: {
		marginVertical: 16,
	},
	loader: {
		height: 21,
		width: 21,
		marginHorizontal: 16,
	},
	button: {
		backgroundColor: Colors.info,
		padding: 12,
		borderRadius: 3,
		flexDirection: 'row',
		alignItems: 'center',
		justifyContent: 'center',
	},
	buttonText: {
		color: Colors.white,
		textAlign: 'center',
		paddingHorizontal: 4,
	},
});

type Props = {
	label: string;
	onPress: Function;
	spinner?: boolean;
	disabled?: boolean;
	style?: any;
}

export default class LargeButton extends Component<void, Props, void> {
	static propTypes = {
		label: PropTypes.string.isRequired,
		onPress: PropTypes.func.isRequired,
		spinner: PropTypes.bool,
		disabled: PropTypes.bool,
		style: View.propTypes.style,
	};

	shouldComponentUpdate(nextProps: Props, nextState: any): boolean {
		return shallowCompare(this, nextProps, nextState);
	}

	render() {
		return (
			<View style={styles.container}>
				<TouchFeedback onPress={this.props.disabled ? null : this.props.onPress}>
					<View style={[ styles.button, this.props.style ]}>
						{this.props.spinner ? <Loading style={styles.loader} color={Colors.white} /> : null}

						<AppText style={styles.buttonText}>{this.props.label.toUpperCase()}</AppText>
					</View>
				</TouchFeedback>
			</View>
		);
	}
}
<commit_msg>fix(ui): set height for large button to prevent jumping (#384)<commit_after>/* @flow */

import React, { Component, PropTypes } from 'react';
import ReactNative from 'react-native';
import shallowCompare from 'react-addons-shallow-compare';
import AppText from '../Core/AppText';
import TouchFeedback from '../Core/TouchFeedback';
import Loading from '../Core/Loading';
import Colors from '../../../Colors';

const {
	StyleSheet,
	View,
} = ReactNative;

const styles = StyleSheet.create({
	container: {
		marginVertical: 16,
	},
	loader: {
		marginHorizontal: 16,
	},
	button: {
		height: 44,
		flexDirection: 'row',
		alignItems: 'center',
		justifyContent: 'center',
		borderRadius: 3,
		backgroundColor: Colors.info,
	},
	buttonText: {
		color: Colors.white,
		textAlign: 'center',
		paddingHorizontal: 4,
	},
});

type Props = {
	label: string;
	onPress: Function;
	spinner?: boolean;
	disabled?: boolean;
	style?: any;
}

export default class LargeButton extends Component<void, Props, void> {
	static propTypes = {
		label: PropTypes.string.isRequired,
		onPress: PropTypes.func.isRequired,
		spinner: PropTypes.bool,
		disabled: PropTypes.bool,
		style: View.propTypes.style,
	};

	shouldComponentUpdate(nextProps: Props, nextState: any): boolean {
		return shallowCompare(this, nextProps, nextState);
	}

	render() {
		return (
			<View style={styles.container}>
				<TouchFeedback onPress={this.props.disabled ? null : this.props.onPress}>
					<View style={[ styles.button, this.props.style ]}>
						{this.props.spinner ? <Loading style={styles.loader} color={Colors.white} /> : null}

						<AppText style={styles.buttonText}>{this.props.label.toUpperCase()}</AppText>
					</View>
				</TouchFeedback>
			</View>
		);
	}
}
<|endoftext|>


<commit_before>import Ember from 'ember';
import Configuration from '../configuration';
import TokenAuthenticator from './token';

/**
  JWT (JSON Web Token) Authenticator that supports automatic token refresh.

  Inspired by [ember-simple-auth-oauth2](https://github.com/simplabs/ember-simple-auth/tree/master/packages/ember-simple-auth-oauth2)

  The factory for this authenticator is registered as
  'authenticator:jwt` in Ember's container.

  @class JWT
  @namespace SimpleAuth.Authenticators
  @module ember-simple-auth-token/authenticators/jwt
  @extends TokenAuthenticator
*/
export default TokenAuthenticator.extend({
  /**
    The endpoint on the server for refreshing a token.
    @property serverTokenRefreshEndpoint
    @type String
    @default '/api/token-refresh/'
  */
  serverTokenRefreshEndpoint: '/api/token-refresh/',

  /**
    Sets whether the authenticator automatically refreshes access tokens.
    @property refreshAccessTokens
    @type Boolean
    @default true
  */
  refreshAccessTokens: true,

  /**
    The number of seconds to subtract from the token's time of expiration when
    scheduling the automatic token refresh call.
    @property refreshLeeway
    @type Integer
    @default 0 (seconds)
  */
  refreshLeeway: 0,

  /**
    The amount of time to wait before refreshing the token - set automatically.
    @property refreshTokenTimeout
    @private
  */
  refreshTokenTimeout: null,

  /**
    The name for which decoded token field represents the token expire time.
    @property tokenExpireName
    @type String
    @default 'exp'
  */
  tokenExpireName: 'exp',

  /**
    Default time unit.
    @property timeFactor
    @type Integer
    @default 1 (seconds)
  */
  timeFactor: 1,

  /**
    @method init
    @private
  */
  init() {
    this.serverTokenEndpoint = Configuration.serverTokenEndpoint;
    this.serverTokenRefreshEndpoint = Configuration.serverTokenRefreshEndpoint;
    this.identificationField = Configuration.identificationField;
    this.passwordField = Configuration.passwordField;
    this.tokenPropertyName = Configuration.tokenPropertyName;
    this.refreshAccessTokens = Configuration.refreshAccessTokens;
    this.refreshLeeway = Configuration.refreshLeeway;
    this.tokenExpireName = Configuration.tokenExpireName;
    this.timeFactor = Configuration.timeFactor;
    this.headers = Configuration.headers;
  },

  /**
    Restores the session from a set of session properties.

    It will return a resolving promise if one of two conditions is met:

    1) Both `data.token` and `data.expiresAt` are non-empty and `expiresAt`
       is greater than the calculated `now`.
    2) If `data.token` is non-empty and the decoded token has a key for
       `tokenExpireName`.

    If `refreshAccessTokens` is true, `scheduleAccessTokenRefresh` will
    be called and an automatic token refresh will be initiated.

    @method restore
    @param {Object} data The data to restore the session from
    @return {Ember.RSVP.Promise} A promise that when it resolves results
                                 in the session being authenticated
  */
  restore(data) {
    const dataObject = Ember.Object.create(data);

    return new Ember.RSVP.Promise((resolve, reject) => {
      const now = this.getCurrentTime();
      const token = dataObject.get(this.tokenPropertyName);
      let expiresAt = this.resolveTime(dataObject.get(this.tokenExpireName));

      if (Ember.isEmpty(token)) {
        return reject(new Error('empty token'));
      }
      if (Ember.isEmpty(expiresAt)) {
        // Fetch the expire time from the token data since `expiresAt`
        // wasn't included in the data object that was passed in.
        const tokenData = this.getTokenData(Ember.get(token, this.tokenPropertyName));

        expiresAt = this.resolveTime(tokenData[this.tokenExpireName]);
        if (Ember.isEmpty(expiresAt)) {
          return resolve(data);
        }
      }

      if (expiresAt > now) {
        const wait = expiresAt - now - (this.refreshLeeway * 1000);

        if (wait > 0) {
          if (this.refreshAccessTokens) {
            this.scheduleAccessTokenRefresh(dataObject.get(this.tokenExpireName), token);
          }
          resolve(data);
        } else if (this.refreshAccessTokens) {
          resolve(this.refreshAccessToken(token));
        } else {
          reject(new Error('unable to refresh token'));
        }
      } else {
        reject(new Error('token is expired'));
      }
    });
  },

  /**
    Authenticates the session with the specified `credentials`.

    It will return a resolving promise if it successfully posts a request
    to the `JWT.serverTokenEndpoint` with the valid credentials.

    An automatic token refresh will be scheduled with the new expiration date
    from the returned refresh token. That expiration will be merged with the
    response and the promise resolved.

    @method authenticate
    @param {Object} credentials The credentials to authenticate the session with
    @param {Object} headers Additional headers to be sent to server
    @return {Ember.RSVP.Promise} A promise that resolves when an auth token is
                                 successfully acquired from the server and rejects
                                 otherwise
  */
  authenticate(credentials, headers) {

    return new Ember.RSVP.Promise((resolve, reject) => {
      const data = this.getAuthenticateData(credentials);

      this.makeRequest(this.serverTokenEndpoint, data, headers).then(response => {
        Ember.run(() => {
          const token = Ember.get(response, this.tokenPropertyName);
          const tokenData = this.getTokenData(token);
          const expiresAt = Ember.get(tokenData, this.tokenExpireName);
          const tokenExpireData = {};

          this.scheduleAccessTokenRefresh(expiresAt, token);

          tokenExpireData[this.tokenExpireName] = expiresAt;

          response = Ember.merge(response, tokenExpireData);

          resolve(this.getResponseData(response));
        });
      }, xhr => {
        Ember.run(() => { reject(xhr.responseJSON || xhr.responseText); });
      });
    });
  },

  /**
    Schedules a token refresh request to be sent to the backend after a calculated
    `wait` time has passed.

    If both `token` and `expiresAt` are non-empty, and `expiresAt` minus the optional
    refres leeway is greater than the calculated `now`, the token refresh will be scheduled
    through Ember.run.later.

    @method scheduleAccessTokenRefresh
    @private
  */
  scheduleAccessTokenRefresh(expiresAt, token) {
    if (this.refreshAccessTokens) {
      expiresAt = this.resolveTime(expiresAt);

      const now = this.getCurrentTime();
      const wait = expiresAt - now - (this.refreshLeeway * 1000);

      if (!Ember.isEmpty(token) && !Ember.isEmpty(expiresAt) && wait > 0) {
        Ember.run.cancel(this._refreshTokenTimeout);

        delete this._refreshTokenTimeout;

        this._refreshTokenTimeout = Ember.run.later(this, this.refreshAccessToken, token, wait);
      }
    }
  },

  /**
    Makes a refresh token request to grab a new authenticated JWT token from the server.

    It will return a resolving promise if a successful POST is made to the
    `JWT.serverTokenRefreshEndpoint`.

    After the new token is obtained it will schedule the next automatic token refresh
    based on the new `expiresAt` time.

    The session will be updated via the trigger `sessionDataUpdated`.

    @method refreshAccessToken
    @private
  */
  refreshAccessToken(token, headers) {
    let data = this.makeRefreshData(token);

    return new Ember.RSVP.Promise((resolve, reject) => {
      this.makeRequest(this.serverTokenRefreshEndpoint, data, headers).then(response => {
        Ember.run(() => {
          const resToken = Ember.get(response, this.tokenPropertyName);
          const tokenData = this.getTokenData(resToken);
          const expiresAt = Ember.get(tokenData, this.tokenExpireName);
          const tokenExpireData = {};

          tokenExpireData[this.tokenExpireName] = expiresAt;

          data = Ember.merge(response, tokenExpireData);

          this.scheduleAccessTokenRefresh(expiresAt, resToken);
          this.trigger('sessionDataUpdated', data);

          resolve(response);
        });
      }, (xhr, status, error) => {
        Ember.Logger.warn(`Access token could not be refreshed - server responded with ${error}.`);
        reject();
      });
    });
  },

  makeRefreshData(token) {
    let root = {};
    let lastObject = root;
    let nesting = this.tokenPropertyName.split('.');
    let tokenPropertyName = nesting.pop();

    nesting.forEach((nesting) => {
      lastObject[nesting] = {};
      lastObject = lastObject[nesting];
    });

    lastObject[tokenPropertyName] = token;

    return root;
  },

  /**
    Returns the decoded token with accessible returned values.

    @method getTokenData
    @return {object} An object with properties for the session.
  */
  getTokenData(token) {
    const payload = token.split('.')[1];
    const tokenData = decodeURIComponent(window.escape(atob(payload)));

    try {
      return JSON.parse(tokenData);
    } catch (e) {
      return tokenData;
    }
  },

  /**
    Accepts a `url` and `data` to be used in an ajax server request.

    @method makeRequest
    @private
  */
  makeRequest(url, data, headers) {
    return Ember.$.ajax({
      url: url,
      method: 'POST',
      data: JSON.stringify(data),
      dataType: 'json',
      contentType: 'application/json',
      headers: this.headers,
      beforeSend: (xhr, settings) => {
        xhr.setRequestHeader('Accept', settings.accepts.json);

        if (headers) {
          Object.keys(headers).forEach(key => {
            xhr.setRequestHeader(key, headers[key]);
          });
        }
      }
    });
  },

  /**
    Cancels any outstanding automatic token refreshes and returns a resolving
    promise.
    @method invalidate
    @param {Object} data The data of the session to be invalidated
    @return {Ember.RSVP.Promise} A resolving promise
  */
  invalidate() {
    Ember.run.cancel(this._refreshTokenTimeout);

    delete this._refreshTokenTimeout;

    return new Ember.RSVP.resolve();
  },

  getCurrentTime() {
    return (new Date()).getTime();
  },

  /**
    Handles converting between time units for data between different systems.
    Default: seconds(1)
    @method resolveTime
    @private
  */
  resolveTime(time) {
    if (Ember.isEmpty(time)) {
      return time;
    }
    return new Date(time * this.timeFactor).getTime();
  }
});
<commit_msg>Removed duplication: authenticate and refreshAccessToken.<commit_after>import Ember from 'ember';
import Configuration from '../configuration';
import TokenAuthenticator from './token';

/**
  JWT (JSON Web Token) Authenticator that supports automatic token refresh.

  Inspired by [ember-simple-auth-oauth2](https://github.com/simplabs/ember-simple-auth/tree/master/packages/ember-simple-auth-oauth2)

  The factory for this authenticator is registered as
  'authenticator:jwt` in Ember's container.

  @class JWT
  @namespace SimpleAuth.Authenticators
  @module ember-simple-auth-token/authenticators/jwt
  @extends TokenAuthenticator
*/
export default TokenAuthenticator.extend({
  /**
    The endpoint on the server for refreshing a token.
    @property serverTokenRefreshEndpoint
    @type String
    @default '/api/token-refresh/'
  */
  serverTokenRefreshEndpoint: '/api/token-refresh/',

  /**
    Sets whether the authenticator automatically refreshes access tokens.
    @property refreshAccessTokens
    @type Boolean
    @default true
  */
  refreshAccessTokens: true,

  /**
    The number of seconds to subtract from the token's time of expiration when
    scheduling the automatic token refresh call.
    @property refreshLeeway
    @type Integer
    @default 0 (seconds)
  */
  refreshLeeway: 0,

  /**
    The amount of time to wait before refreshing the token - set automatically.
    @property refreshTokenTimeout
    @private
  */
  refreshTokenTimeout: null,

  /**
    The name for which decoded token field represents the token expire time.
    @property tokenExpireName
    @type String
    @default 'exp'
  */
  tokenExpireName: 'exp',

  /**
    Default time unit.
    @property timeFactor
    @type Integer
    @default 1 (seconds)
  */
  timeFactor: 1,

  /**
    @method init
    @private
  */
  init() {
    this.serverTokenEndpoint = Configuration.serverTokenEndpoint;
    this.serverTokenRefreshEndpoint = Configuration.serverTokenRefreshEndpoint;
    this.identificationField = Configuration.identificationField;
    this.passwordField = Configuration.passwordField;
    this.tokenPropertyName = Configuration.tokenPropertyName;
    this.refreshAccessTokens = Configuration.refreshAccessTokens;
    this.refreshLeeway = Configuration.refreshLeeway;
    this.tokenExpireName = Configuration.tokenExpireName;
    this.timeFactor = Configuration.timeFactor;
    this.headers = Configuration.headers;
  },

  /**
    Restores the session from a set of session properties.

    It will return a resolving promise if one of two conditions is met:

    1) Both `data.token` and `data.expiresAt` are non-empty and `expiresAt`
       is greater than the calculated `now`.
    2) If `data.token` is non-empty and the decoded token has a key for
       `tokenExpireName`.

    If `refreshAccessTokens` is true, `scheduleAccessTokenRefresh` will
    be called and an automatic token refresh will be initiated.

    @method restore
    @param {Object} data The data to restore the session from
    @return {Ember.RSVP.Promise} A promise that when it resolves results
                                 in the session being authenticated
  */
  restore(data) {
    const dataObject = Ember.Object.create(data);

    return new Ember.RSVP.Promise((resolve, reject) => {
      const now = this.getCurrentTime();
      const token = dataObject.get(this.tokenPropertyName);
      let expiresAt = this.resolveTime(dataObject.get(this.tokenExpireName));

      if (Ember.isEmpty(token)) {
        return reject(new Error('empty token'));
      }
      if (Ember.isEmpty(expiresAt)) {
        // Fetch the expire time from the token data since `expiresAt`
        // wasn't included in the data object that was passed in.
        const tokenData = this.getTokenData(Ember.get(token, this.tokenPropertyName));

        expiresAt = this.resolveTime(tokenData[this.tokenExpireName]);
        if (Ember.isEmpty(expiresAt)) {
          return resolve(data);
        }
      }

      if (expiresAt > now) {
        const wait = expiresAt - now - (this.refreshLeeway * 1000);

        if (wait > 0) {
          if (this.refreshAccessTokens) {
            this.scheduleAccessTokenRefresh(dataObject.get(this.tokenExpireName), token);
          }
          resolve(data);
        } else if (this.refreshAccessTokens) {
          resolve(this.refreshAccessToken(token));
        } else {
          reject(new Error('unable to refresh token'));
        }
      } else {
        reject(new Error('token is expired'));
      }
    });
  },

  /**
    Authenticates the session with the specified `credentials`.

    It will return a resolving promise if it successfully posts a request
    to the `JWT.serverTokenEndpoint` with the valid credentials.

    An automatic token refresh will be scheduled with the new expiration date
    from the returned refresh token. That expiration will be merged with the
    response and the promise resolved.

    @method authenticate
    @param {Object} credentials The credentials to authenticate the session with
    @param {Object} headers Additional headers to be sent to server
    @return {Ember.RSVP.Promise} A promise that resolves when an auth token is
                                 successfully acquired from the server and rejects
                                 otherwise
  */
  authenticate(credentials, headers) {
    return new Ember.RSVP.Promise((resolve, reject) => {
      let data = this.getAuthenticateData(credentials);

      this.makeRequest(this.serverTokenEndpoint, data, headers).then(response => {
        Ember.run(() => {
          const sessionData = this.handleAuthResponse(response);
          resolve(sessionData);
        });
      }, xhr => {
        Ember.run(() => { reject(xhr.responseJSON || xhr.responseText); });
      });
    });
  },

  /**
    Schedules a token refresh request to be sent to the backend after a calculated
    `wait` time has passed.

    If both `token` and `expiresAt` are non-empty, and `expiresAt` minus the optional
    refres leeway is greater than the calculated `now`, the token refresh will be scheduled
    through Ember.run.later.

    @method scheduleAccessTokenRefresh
    @private
  */
  scheduleAccessTokenRefresh(expiresAt, token) {
    if (this.refreshAccessTokens) {
      expiresAt = this.resolveTime(expiresAt);

      const now = this.getCurrentTime();
      const wait = expiresAt - now - (this.refreshLeeway * 1000);

      if (!Ember.isEmpty(token) && !Ember.isEmpty(expiresAt) && wait > 0) {
        Ember.run.cancel(this._refreshTokenTimeout);

        delete this._refreshTokenTimeout;

        this._refreshTokenTimeout = Ember.run.later(this, this.refreshAccessToken, token, wait);
      }
    }
  },

  /**
    Makes a refresh token request to grab a new authenticated JWT token from the server.

    It will return a resolving promise if a successful POST is made to the
    `JWT.serverTokenRefreshEndpoint`.

    After the new token is obtained it will schedule the next automatic token refresh
    based on the new `expiresAt` time.

    The session will be updated via the trigger `sessionDataUpdated`.

    @method refreshAccessToken
    @private
  */
  refreshAccessToken(token, headers) {
    let data = this.makeRefreshData(token);

    return new Ember.RSVP.Promise((resolve, reject) => {
      this.makeRequest(this.serverTokenRefreshEndpoint, data, headers).then(response => {
        Ember.run(() => {
          const sessionData = this.handleAuthResponse(response);
          this.trigger('sessionDataUpdated', sessionData);
          resolve(sessionData);
        });
      }, (xhr, status, error) => {
        Ember.Logger.warn(`Access token could not be refreshed - server responded with ${error}.`);
        reject();
      });
    });
  },

  makeRefreshData(token) {
    let root = {};
    let lastObject = root;
    let nesting = this.tokenPropertyName.split('.');
    let tokenPropertyName = nesting.pop();

    nesting.forEach((nesting) => {
      lastObject[nesting] = {};
      lastObject = lastObject[nesting];
    });

    lastObject[tokenPropertyName] = token;

    return root;
  },

  /**
    Returns the decoded token with accessible returned values.

    @method getTokenData
    @return {object} An object with properties for the session.
  */
  getTokenData(token) {
    const payload = token.split('.')[1];
    const tokenData = decodeURIComponent(window.escape(atob(payload)));

    try {
      return JSON.parse(tokenData);
    } catch (e) {
      return tokenData;
    }
  },

  /**
    Accepts a `url` and `data` to be used in an ajax server request.

    @method makeRequest
    @private
  */
  makeRequest(url, data, headers) {
    return Ember.$.ajax({
      url: url,
      method: 'POST',
      data: JSON.stringify(data),
      dataType: 'json',
      contentType: 'application/json',
      headers: this.headers,
      beforeSend: (xhr, settings) => {
        xhr.setRequestHeader('Accept', settings.accepts.json);

        if (headers) {
          Object.keys(headers).forEach(key => {
            xhr.setRequestHeader(key, headers[key]);
          });
        }
      }
    });
  },

  /**
    Cancels any outstanding automatic token refreshes and returns a resolving
    promise.
    @method invalidate
    @param {Object} data The data of the session to be invalidated
    @return {Ember.RSVP.Promise} A resolving promise
  */
  invalidate() {
    Ember.run.cancel(this._refreshTokenTimeout);

    delete this._refreshTokenTimeout;

    return new Ember.RSVP.resolve();
  },

  getCurrentTime() {
    return (new Date()).getTime();
  },

  /**
    Handles converting between time units for data between different systems.
    Default: seconds(1)
    @method resolveTime
    @private
  */
  resolveTime(time) {
    if (Ember.isEmpty(time)) {
      return time;
    }
    return new Date(time * this.timeFactor).getTime();
  },

  /**
    Handles authentication response from server, and returns session data

    @method handleAuthResponse
    @private
   */
  handleAuthResponse(response) {
    const token = Ember.get(response, this.tokenPropertyName);
    const tokenData = this.getTokenData(token);
    const expiresAt = Ember.get(tokenData, this.tokenExpireName);
    const tokenExpireData = {};
    tokenExpireData[this.tokenExpireName] = expiresAt;

    this.scheduleAccessTokenRefresh(expiresAt, token);

    return Ember.merge(this.getResponseData(response), tokenExpireData);
  }
});
<|endoftext|>


<commit_before>var Thermostat = (function() {
  function Thermostat() {
    this.temperature = 20;
    this.powerSaving = true;
  }

  Thermostat.prototype.up = function() {
    if (this.powerSaving) {
      return this.temperature >= 25 ? this.temperature = 25 : ++this.temperature;
    } else {
      return this.temperature >= 32 ? this.temperature = 32 : ++this.temperature;
    }
  };

  Thermostat.prototype.down = function() {
    if(this.temperature > 10){
      return --this.temperature;
    }
  };

  Thermostat.prototype.switchPowerSaving = function() {
    this.powerSaving = !this.powerSaving;
  };

  return Thermostat;

}());
<commit_msg>Refactors setting a max temperature limit<commit_after>function Thermostat() {
  this.temperature = 20;
  this.powerSaving = true;
}

Thermostat.prototype.up = function() {
  if (this.powerSaving) {
    return this._setMaxTemp(25);
  } else {
    return this._setMaxTemp(32);
  }
};

Thermostat.prototype.down = function() {
  if(this.temperature > 10){
    return --this.temperature;
  }
};

Thermostat.prototype.switchPowerSaving = function() {
  this.powerSaving = !this.powerSaving;
};

Thermostat.prototype._setMaxTemp = function(maximum) {
  return this.temperature >= maximum ? this.temperature = maximum : ++this.temperature;
};
<|endoftext|>


<commit_before>import Ember from 'ember';

const { Component, on, observer } = Ember;

export default Component.extend({
  tagName: 'g',
  attributeBindings: ['transform'],

  init() {
    this.set('axis', d3.svg.axis());
    this._super.apply(this, arguments);
  },

  updateOritntation: on('init', observer('orientation', function() {
    let orientation = this.get('orientation');

    if(orientation) {
      this.get('axis').orient(orientation);
      Ember.run.once(this, this.updateAxis);
    }
  })),

  updateScale: on('init', observer('scale.scale', function() {
    let scale = this.get('scale.scale');

    if(scale) {
      this.get('axis').scale(scale);
      Ember.run.once(this, this.updateAxis);
    }
  })),

  updateTicks: on('init', observer('ticks', function() {
    let ticks = this.get('ticks');

    if(ticks) {
      this.get('axis').ticks(ticks);
      Ember.run.once(this, this.updateAxis);
    }
  })),

  updateTickSubdivide: on('init', observer('tickSubdivide', function() {
    let tickSubdivide = this.get('tickSubdivide');

    if(tickSubdivide) {
      this.get('axis').tickSubdivide(tickSubdivide);
      Ember.run.once(this, this.updateAxis);
    }
  })),

  updateTickFormat: on('init', observer('tickFormat', function() {
    let tickFormat = this.get('tickFormat');

    if(tickFormat) {
      this.get('axis').tickFormat(tickFormat);
      Ember.run.once(this, this.updateAxis);
    }
  })),

  updateTickPadding: on('init', observer('tickPadding', function() {
    let tickPadding = this.get('tickPadding');

    if(tickPadding) {
      this.get('axis').tickPadding(tickPadding);
      Ember.run.once(this, this.updateAxis);
    }
  })),

  gridChanged: on('init', observer('grid', function() {
    Ember.run.once(this, this.updateAxis);
  })),

  updateAxis() {
    var id = "#" + this.elementId;
    d3.select(id).transition().call(this.get('axis'));

    if(this.get('grid')) {
      this.updateGrid();
    }
  },

  updateGrid() {
    var id = "#" + this.elementId;
    d3.selectAll(id + " g.tick").select("line.grid-line").remove();

    if(this.get('grid')) {
      var x1 = this.get('grid.x1');
      var x2 = this.get('grid.x2');
      var y1 = this.get('grid.y1');
      var y2 = this.get('grid.y2');

      d3.selectAll(id + " g.tick").append("line").classed("grid-line", true).attr("x1", x1).attr("y1", y1).attr("x2", x2).attr("y2", y2);
    }
  }
});
<commit_msg>cleanup<commit_after>import Ember from 'ember';

const { Component, on, observer } = Ember;

export default Component.extend({
  tagName: 'g',
  attributeBindings: ['transform'],

  init() {
    this.set('axis', d3.svg.axis());
    this._super.apply(this, arguments);
  },

  oritntationChanged: on('init', observer('orientation', function() {
    let orientation = this.get('orientation');

    if(orientation) {
      this.get('axis').orient(orientation);
      Ember.run.once(this, this.updateAxis);
    }
  })),

  scaleChanged: on('init', observer('scale.scale', function() {
    let scale = this.get('scale.scale');

    if(scale) {
      this.get('axis').scale(scale);
      Ember.run.once(this, this.updateAxis);
    }
  })),

  ticksChanged: on('init', observer('ticks', function() {
    let ticks = this.get('ticks');

    if(ticks) {
      this.get('axis').ticks(ticks);
      Ember.run.once(this, this.updateAxis);
    }
  })),

  tickSubdivideChanged: on('init', observer('tickSubdivide', function() {
    let tickSubdivide = this.get('tickSubdivide');

    if(tickSubdivide) {
      this.get('axis').tickSubdivide(tickSubdivide);
      Ember.run.once(this, this.updateAxis);
    }
  })),

  tickFormatChanged: on('init', observer('tickFormat', function() {
    let tickFormat = this.get('tickFormat');

    if(tickFormat) {
      this.get('axis').tickFormat(tickFormat);
      Ember.run.once(this, this.updateAxis);
    }
  })),

  tickPaddingChanged: on('init', observer('tickPadding', function() {
    let tickPadding = this.get('tickPadding');

    if(tickPadding) {
      this.get('axis').tickPadding(tickPadding);
      Ember.run.once(this, this.updateAxis);
    }
  })),

  gridChanged: on('init', observer('grid', function() {
    Ember.run.once(this, this.updateAxis);
  })),

  updateAxis() {
    var id = "#" + this.elementId;
    d3.select(id).transition().call(this.get('axis'));

    if(this.get('grid')) {
      d3.selectAll(id + " g.tick").select("line.grid-line").remove();
      let x1 = this.get('grid.x1');
      let x2 = this.get('grid.x2');
      let y1 = this.get('grid.y1');
      let y2 = this.get('grid.y2');
      d3.selectAll(id + " g.tick").append("line").classed("grid-line", true).attr("x1", x1).attr("y1", y1).attr("x2", x2).attr("y2", y2);
    }
  }
});
<|endoftext|>


<commit_before>'use strict';

var packJS = require('./pack.js');
var StringIO = require('./stringio.js');
var BigNumber = require('bignumber.js');
BigNumber.config({
	DECIMAL_PLACES: 43,
	EXPONENTIAL_AT: 50
});

class ByteReader {
	constructor(io) {
		this.io = io;
	}

	get read_int64() {
		var temp = this.io.read(8);
		var unpacked = packJS.unpack("C*", temp);
		var result = new BigNumber(0);
		Object.keys(unpacked).forEach(function(key) {
			var index = key - 1;
			var byte = unpacked[key];

			var a = new BigNumber(256).toPower(new BigNumber(index));
			var b = new BigNumber(byte).times(a);

			result = result.plus(b)
		});
		return result.toString();
	}

	get read_short() {
		var temp = this.io.read(2);
		var unpacked = packJS.unpack("S*", temp);
		return unpacked[''].toString();
	}
}

class SharecodeDecoder {
	constructor(code) {
		this.code = this.sanitize_code(code);
		this.originalCode = code;

		this.DICTIONARY = "ABCDEFGHJKLMNOPQRSTUVWXYZabcdefhijkmnopqrstuvwxyz23456789";
		this.DICTIONARY_LENGTH = this.DICTIONARY.length
	}

	decode() {
		var reader 		= new ByteReader(this.io);
		var matchId 	= reader.read_int64;
		var outcomeId	= reader.read_int64;
		var tokenId 	= reader.read_short;

		return {
			matchId: matchId,
			outcomeId: outcomeId,
			tokenId: tokenId
		};
	}

	sanitize_code(str) {
		return str.replace(/CSGO|\-/g, '');
	}

	get io() {
		return new StringIO.StringIO(packJS.pack("H*", this.decoded_code.toString(16)))
	}

	get decoded_code() {
		var self = this;
		var reversed = this.code.split('').reverse();
		var result = new BigNumber(0);
		reversed.forEach(function(char, index) {
			result = (result.times(new BigNumber(self.DICTIONARY_LENGTH))).plus(new BigNumber(self.DICTIONARY.indexOf(char)));
		});
		return result;
	}
}

exports.SharecodeDecoder = SharecodeDecoder;<commit_msg>Line by line port to handle edge cases<commit_after>'use strict';

var packJS = require('./pack.js');
var StringIO = require('./stringio.js');
var BigNumber = require('bignumber.js');
BigNumber.config({
	DECIMAL_PLACES: 43,
	EXPONENTIAL_AT: 50
});

class ByteReader {
	constructor(io) {
		this.io = io;
	}

	get read_int64() {
		var temp = this.io.read(8);
		var unpacked = packJS.unpack("C*", temp);
		var result = new BigNumber(0);
		Object.keys(unpacked).forEach(function(key) {
			var index = key - 1;
			var byte = unpacked[key];

			var a = new BigNumber(256).toPower(new BigNumber(index));
			var b = new BigNumber(byte).times(a);

			result = result.plus(b)
		});
		return result.toString();
	}

	get read_short() {
		var temp = this.io.read(2);
		var unpacked = packJS.unpack("S*", temp);
		return unpacked[''].toString();
	}
}

class SharecodeDecoder {
	constructor(code) {
		this.code = this.sanitize_code(code);
		this.originalCode = code;

		this.DICTIONARY = "ABCDEFGHJKLMNOPQRSTUVWXYZabcdefhijkmnopqrstuvwxyz23456789";
		this.DICTIONARY_LENGTH = this.DICTIONARY.length
	}

	decode() {
		var reader 		= new ByteReader(this.io);
		var matchId 	= reader.read_int64;
		var outcomeId	= reader.read_int64;
		var tokenId 	= reader.read_short;

		return {
			matchId: matchId,
			outcomeId: outcomeId,
			tokenId: tokenId
		};
	}

	sanitize_code(str) {
		return str.replace(/CSGO|\-/g, '');
	}

	get io() {
		return new StringIO.StringIO(this.decoded_code);
	}

	get decoded_code() {
		var self = this;
		var result = Array.apply(null, new Array(18)).map(Number.prototype.valueOf, 0);
		var reversed = this.code.split('').reverse();
		reversed.forEach(function(char, index) {
			var addval = self.DICTIONARY.indexOf(char);
			var tmp = Array.apply(null, new Array(18)).map(Number.prototype.valueOf, 0);
			var carry = 0;
			var v = 0;
			for(var t = 17; t >= 0; t--) {
				carry = 0;
				for(var s = t; s >= 0; s--) {
					if(t - s == 0) {
						v = tmp[s] + result[t] * 57;
					}else {
						v = 0;
					}
					v = v + carry;
					carry = v >> 8;
					tmp[s] = v & 0xFF;
				}
			}
			result = tmp;
			carry = 0;

			for(var t = 17; t >= 0; t--) {
				if(t == 17) {
					v = result[t] + addval;
				}else {
					v = result[t];
				}
				v = v + carry;
				carry = v >> 8;
				result[t] = v & 0xFF;
			}
		});

		result.unshift('C*');
		return packJS.pack.apply(this, result);
	}
}

exports.SharecodeDecoder = SharecodeDecoder;
<|endoftext|>


<commit_before>import Ember from 'ember';
import layout from 'ember-light-table/templates/components/lt-body';
import callAction from 'ember-light-table/utils/call-action';

const {
  Component,
  computed,
  run
} = Ember;

/**
 * @module Light Table
 */

/**
 * ```hbs
 * {{#light-table table as |t|}}
 *   {{#t.body multiSelect=true onRowClick=(action 'rowClicked')}}
 *     {{#body.expanded-row as |row|}}
 *       Hello <b>{{row.firstName}}</b>
 *     {{/body.expanded-row}}
 *
 *     {{#if isLoading}}
 *       {{#body.loader}}
 *         Loading...
 *       {{/body.loader}}
 *     {{/if}}
 *
 *     {{#if table.isEmpty}}
 *       {{#body.no-data}}
 *         No users found.
 *       {{/body.no-data}}
 *     {{/if}}
 *   {{/t.body}}
 * {{/light-table}}
 * ```
 *
 * @class t.body
 */

export default Component.extend({
  layout,
  classNames: ['lt-body-wrap'],
  classNameBindings: ['canSelect', 'multiSelect', 'canExpand'],

  /**
   * @property table
   * @type {Table}
   * @private
   */
  table: null,

  /**
   * @property sharedOptions
   * @type {Object}
   * @private
   */
  sharedOptions: null,

  /**
   * @property tableActions
   * @type {Object}
   */
  tableActions: null,

  /**
   * Allows a user to select a row on click. All this will do is apply the necessary
   * CSS classes and add the row to `table.selectedRows`. If `multiSelect` is disabled
   * only one row will be selected at a time.
   *
   * @property canSelect
   * @type {Boolean}
   * @default true
   */
  canSelect: true,

  /**
   * Allows for expanding row. This will create a new row under the row that was
   * clicked with the template provided by `body.expanded-row`.
   *
   * ```hbs
   * {{#body.expanded-row as |row|}}
   *  This is the content of the expanded row for {{row.firstName}}
   * {{/body.expanded-row}}
   * ```
   *
   * @property canExpand
   * @type {Boolean}
   * @default false
   */
  canExpand: false,

  /**
   * Allows a user to select multiple rows with the `ctrl`, `cmd`, and `shift` keys.
   * These rows can be easily accessed via `table.get('selectedRows')`
   *
   * @property multiSelect
   * @type {Boolean}
   * @default false
   */
  multiSelect: false,

  /**
   * When multiSelect is true, this property determines whether or not `ctrl`
   * (or `cmd`) is required to select additional rows, one by one. When false,
   * simply clicking on subsequent rows will select or deselect them.
   *
   * `shift` to select many consecutive rows is unaffected by this property.
   *
   * @property multiSelectRequiresKeyboard
   * @type {Boolean}
   * @default true
   */
  multiSelectRequiresKeyboard: true,

  /**
   * Hide scrollbar when not scrolling
   *
   * @property autoHideScrollbar
   * @type {Boolean}
   * @default true
   */
  autoHideScrollbar: true,

  /**
   * Allows multiple rows to be expanded at once
   *
   * @property multiRowExpansion
   * @type {Boolean}
   * @default true
   */
  multiRowExpansion: true,

  /**
   * Expand a row on click
   *
   * @property expandOnClick
   * @type {Boolean}
   * @default true
   */
  expandOnClick: true,

  /**
   * If true, the body block will yield columns and rows, allowing you
   * to define your own table body
   *
   * @property overwrite
   * @type {Boolean}
   * @default false
   */
  overwrite: false,

  /**
   * ID of main table component. Used to generate divs for ember-wormhole
   *
   * @property tableId
   * @type {String}
   * @private
   */
  tableId: null,

  /**
   * @property scrollBuffer
   * @type {Number}
   * @default 500
   */
  scrollBuffer: 500,

  /**
   * @property useVirtualScrollbar
   * @type {Boolean}
   * @default false
   * @private
   */
  useVirtualScrollbar: false,

  /**
   * Allows to customize the component used to render rows
   *
   * ```hbs
   * {{#light-table table as |t|}}
   *    {{t.body rowComponent=(component 'my-row')}}
   * {{/light-table}}
   * ```
   * @property rowComponent
   * @type {Ember.Component}
   * @default null
   */
  rowComponent: null,

  /**
   * Allows to customize the component used to render spanned rows
   *
   * ```hbs
   * {{#light-table table as |t|}}
   *    {{t.body spannedRowComponent=(component 'my-spanned-row')}}
   * {{/light-table}}
   * ```
   * @property spannedRowComponent
   * @type {Ember.Component}
   * @default null
   */
  spannedRowComponent: null,

  /**
   * Allows to customize the component used to render infinite loader
   *
   * ```hbs
   * {{#light-table table as |t|}}
   *    {{t.body infinityComponent=(component 'my-infinity')}}
   * {{/light-table}}
   * ```
   * @property infinityComponent
   * @type {Ember.Component}
   * @default null
   */
  infinityComponent: null,

  rows: computed.readOnly('table.visibleRows'),
  columns: computed.readOnly('table.visibleColumns'),
  colspan: computed.readOnly('columns.length'),

  _currSelectedIndex: -1,
  _prevSelectedIndex: -1,

  init() {
    this._super(...arguments);

    /*
      We can only set `useVirtualScrollbar` once all contextual components have
      been initialized since fixedHeader and fixedFooter are set on t.head and t.foot
      initialization.
     */
    run.once(this, this._setupVirtualScrollbar);
  },

  _setupVirtualScrollbar() {
    const { fixedHeader, fixedFooter } = this.get('sharedOptions');
    this.set('useVirtualScrollbar', fixedHeader || fixedFooter);
  },

  togglExpandedRow(row) {
    let multi = this.get('multiRowExpansion');
    let shouldExpand = !row.expanded;

    if (multi) {
      row.toggleProperty('expanded');
    } else {
      this.get('table.expandedRows').setEach('expanded', false);
      row.set('expanded', shouldExpand);
    }
  },

  actions: {
    /**
     * onRowClick action. Handles selection, and row expansion.
     * @event onRowClick
     * @param  {Row}   row The row that was clicked
     * @param  {Event}   event   The click event
     */
    onRowClick(row, e) {
      let rows = this.get('table.rows');
      let multiSelect = this.get('multiSelect');
      let multiSelectRequiresKeyboard = this.get('multiSelectRequiresKeyboard');
      let canSelect = this.get('canSelect');
      let isSelected = row.get('selected');
      let currIndex = rows.indexOf(row);
      let prevIndex = this._prevSelectedIndex === -1 ? currIndex : this._prevSelectedIndex;

      this._currSelectedIndex = currIndex;
      this._prevSelectedIndex = prevIndex;

      if (canSelect) {
        if (e.shiftKey && multiSelect) {
          rows.slice(Math.min(currIndex, prevIndex), Math.max(currIndex, prevIndex) + 1).forEach(r => r.set('selected', !isSelected));
          this._prevSelectedIndex = currIndex;
        } else if ((!multiSelectRequiresKeyboard || (e.ctrlKey || e.metaKey)) && multiSelect) {
          row.toggleProperty('selected');
        } else {
          this.get('table.selectedRows').setEach('selected', false);
          row.set('selected', !isSelected);

          if (this.get('canExpand') && this.get('expandOnClick')) {
            this.togglExpandedRow(row);
          }
        }
        this._prevSelectedIndex = currIndex;
      } else {
        if (this.get('canExpand') && this.get('expandOnClick')) {
          this.togglExpandedRow(row);
        }
      }

      callAction(this, 'onRowClick', ...arguments);
    },

    /**
     * onRowDoubleClick action.
     * @event onRowDoubleClick
     * @param  {Row}   row The row that was clicked
     * @param  {Event}   event   The click event
     */
    onRowDoubleClick(/* row */) {
      callAction(this, 'onRowDoubleClick', ...arguments);
    },

    /**
     * onScrolledToBottom action - sent when user scrolls to the bottom
     *
     * @event onScrolledToBottom
     */
    onScrolledToBottom() {
      callAction(this, 'onScrolledToBottom');
    }
  }
});
<commit_msg>Fixing typo (#188)<commit_after>import Ember from 'ember';
import layout from 'ember-light-table/templates/components/lt-body';
import callAction from 'ember-light-table/utils/call-action';

const {
  Component,
  computed,
  run
} = Ember;

/**
 * @module Light Table
 */

/**
 * ```hbs
 * {{#light-table table as |t|}}
 *   {{#t.body multiSelect=true onRowClick=(action 'rowClicked')}}
 *     {{#body.expanded-row as |row|}}
 *       Hello <b>{{row.firstName}}</b>
 *     {{/body.expanded-row}}
 *
 *     {{#if isLoading}}
 *       {{#body.loader}}
 *         Loading...
 *       {{/body.loader}}
 *     {{/if}}
 *
 *     {{#if table.isEmpty}}
 *       {{#body.no-data}}
 *         No users found.
 *       {{/body.no-data}}
 *     {{/if}}
 *   {{/t.body}}
 * {{/light-table}}
 * ```
 *
 * @class t.body
 */

export default Component.extend({
  layout,
  classNames: ['lt-body-wrap'],
  classNameBindings: ['canSelect', 'multiSelect', 'canExpand'],

  /**
   * @property table
   * @type {Table}
   * @private
   */
  table: null,

  /**
   * @property sharedOptions
   * @type {Object}
   * @private
   */
  sharedOptions: null,

  /**
   * @property tableActions
   * @type {Object}
   */
  tableActions: null,

  /**
   * Allows a user to select a row on click. All this will do is apply the necessary
   * CSS classes and add the row to `table.selectedRows`. If `multiSelect` is disabled
   * only one row will be selected at a time.
   *
   * @property canSelect
   * @type {Boolean}
   * @default true
   */
  canSelect: true,

  /**
   * Allows for expanding row. This will create a new row under the row that was
   * clicked with the template provided by `body.expanded-row`.
   *
   * ```hbs
   * {{#body.expanded-row as |row|}}
   *  This is the content of the expanded row for {{row.firstName}}
   * {{/body.expanded-row}}
   * ```
   *
   * @property canExpand
   * @type {Boolean}
   * @default false
   */
  canExpand: false,

  /**
   * Allows a user to select multiple rows with the `ctrl`, `cmd`, and `shift` keys.
   * These rows can be easily accessed via `table.get('selectedRows')`
   *
   * @property multiSelect
   * @type {Boolean}
   * @default false
   */
  multiSelect: false,

  /**
   * When multiSelect is true, this property determines whether or not `ctrl`
   * (or `cmd`) is required to select additional rows, one by one. When false,
   * simply clicking on subsequent rows will select or deselect them.
   *
   * `shift` to select many consecutive rows is unaffected by this property.
   *
   * @property multiSelectRequiresKeyboard
   * @type {Boolean}
   * @default true
   */
  multiSelectRequiresKeyboard: true,

  /**
   * Hide scrollbar when not scrolling
   *
   * @property autoHideScrollbar
   * @type {Boolean}
   * @default true
   */
  autoHideScrollbar: true,

  /**
   * Allows multiple rows to be expanded at once
   *
   * @property multiRowExpansion
   * @type {Boolean}
   * @default true
   */
  multiRowExpansion: true,

  /**
   * Expand a row on click
   *
   * @property expandOnClick
   * @type {Boolean}
   * @default true
   */
  expandOnClick: true,

  /**
   * If true, the body block will yield columns and rows, allowing you
   * to define your own table body
   *
   * @property overwrite
   * @type {Boolean}
   * @default false
   */
  overwrite: false,

  /**
   * ID of main table component. Used to generate divs for ember-wormhole
   *
   * @property tableId
   * @type {String}
   * @private
   */
  tableId: null,

  /**
   * @property scrollBuffer
   * @type {Number}
   * @default 500
   */
  scrollBuffer: 500,

  /**
   * @property useVirtualScrollbar
   * @type {Boolean}
   * @default false
   * @private
   */
  useVirtualScrollbar: false,

  /**
   * Allows to customize the component used to render rows
   *
   * ```hbs
   * {{#light-table table as |t|}}
   *    {{t.body rowComponent=(component 'my-row')}}
   * {{/light-table}}
   * ```
   * @property rowComponent
   * @type {Ember.Component}
   * @default null
   */
  rowComponent: null,

  /**
   * Allows to customize the component used to render spanned rows
   *
   * ```hbs
   * {{#light-table table as |t|}}
   *    {{t.body spannedRowComponent=(component 'my-spanned-row')}}
   * {{/light-table}}
   * ```
   * @property spannedRowComponent
   * @type {Ember.Component}
   * @default null
   */
  spannedRowComponent: null,

  /**
   * Allows to customize the component used to render infinite loader
   *
   * ```hbs
   * {{#light-table table as |t|}}
   *    {{t.body infinityComponent=(component 'my-infinity')}}
   * {{/light-table}}
   * ```
   * @property infinityComponent
   * @type {Ember.Component}
   * @default null
   */
  infinityComponent: null,

  rows: computed.readOnly('table.visibleRows'),
  columns: computed.readOnly('table.visibleColumns'),
  colspan: computed.readOnly('columns.length'),

  _currSelectedIndex: -1,
  _prevSelectedIndex: -1,

  init() {
    this._super(...arguments);

    /*
      We can only set `useVirtualScrollbar` once all contextual components have
      been initialized since fixedHeader and fixedFooter are set on t.head and t.foot
      initialization.
     */
    run.once(this, this._setupVirtualScrollbar);
  },

  _setupVirtualScrollbar() {
    const { fixedHeader, fixedFooter } = this.get('sharedOptions');
    this.set('useVirtualScrollbar', fixedHeader || fixedFooter);
  },

  toggleExpandedRow(row) {
    let multi = this.get('multiRowExpansion');
    let shouldExpand = !row.expanded;

    if (multi) {
      row.toggleProperty('expanded');
    } else {
      this.get('table.expandedRows').setEach('expanded', false);
      row.set('expanded', shouldExpand);
    }
  },

  actions: {
    /**
     * onRowClick action. Handles selection, and row expansion.
     * @event onRowClick
     * @param  {Row}   row The row that was clicked
     * @param  {Event}   event   The click event
     */
    onRowClick(row, e) {
      let rows = this.get('table.rows');
      let multiSelect = this.get('multiSelect');
      let multiSelectRequiresKeyboard = this.get('multiSelectRequiresKeyboard');
      let canSelect = this.get('canSelect');
      let isSelected = row.get('selected');
      let currIndex = rows.indexOf(row);
      let prevIndex = this._prevSelectedIndex === -1 ? currIndex : this._prevSelectedIndex;

      this._currSelectedIndex = currIndex;
      this._prevSelectedIndex = prevIndex;

      if (canSelect) {
        if (e.shiftKey && multiSelect) {
          rows.slice(Math.min(currIndex, prevIndex), Math.max(currIndex, prevIndex) + 1).forEach(r => r.set('selected', !isSelected));
          this._prevSelectedIndex = currIndex;
        } else if ((!multiSelectRequiresKeyboard || (e.ctrlKey || e.metaKey)) && multiSelect) {
          row.toggleProperty('selected');
        } else {
          this.get('table.selectedRows').setEach('selected', false);
          row.set('selected', !isSelected);

          if (this.get('canExpand') && this.get('expandOnClick')) {
            this.toggleExpandedRow(row);
          }
        }
        this._prevSelectedIndex = currIndex;
      } else {
        if (this.get('canExpand') && this.get('expandOnClick')) {
          this.toggleExpandedRow(row);
        }
      }

      callAction(this, 'onRowClick', ...arguments);
    },

    /**
     * onRowDoubleClick action.
     * @event onRowDoubleClick
     * @param  {Row}   row The row that was clicked
     * @param  {Event}   event   The click event
     */
    onRowDoubleClick(/* row */) {
      callAction(this, 'onRowDoubleClick', ...arguments);
    },

    /**
     * onScrolledToBottom action - sent when user scrolls to the bottom
     *
     * @event onScrolledToBottom
     */
    onScrolledToBottom() {
      callAction(this, 'onScrolledToBottom');
    }
  }
});
<|endoftext|>


<commit_before>import Ember from 'ember';
import MagicCrud from './magic-crud';

const {
  getProperties
} = Ember;

let capitalize = function(string){
  return string.charAt(0).toUpperCase() + string.slice(1);
};

export default Ember.Mixin.create(MagicCrud, {

  // This is for the objects not to change and mess up the observers
  editDone: false,

  // Validation Object name
  validationObject: 'validations',

  // Definitions Object name
  definitionObject: 'formDefinitionsMC',

  // Magic Crud Options object name
  magicCrudObject: 'magicCrud',

  // Route that corresponds to editing
  editRoute: 'edit',

  // Route that corresponds to adding
  addRoute: 'add',

  // Template for the form
  formTemplate: 'magic-crud/form',

  // Template for the table
  tableTemplate: 'magic-crud/table',

  // Save success message
  saveMessage: 'Record saved successfully',

  // Delete success message
  deleteMessageSuccess: 'Record deleted',

  // Delete fail message
  deleteMessageFailed: 'The record couldn\'t be deleted',

  canRollbackModel: true,

  // Split route name
  routeSplit: Ember.computed('routeName', function(){
    return this.get('routeName').split('.');
  }),

  // Route base name
  routeBase: Ember.computed('routeSplit', function(){
    return this.get('routeSplit')[0];
  }),

  // Route method name
  routeMethod: Ember.computed('routeSplit', function(){
    return this.get('routeSplit')[1];
  }),

  // Route's model
  model: function(param){
    const{
      addRoute,
      editRoute,
      routeBase,
      routeMethod
    } = getProperties(this, 'addRoute', 'editRoute', 'routeBase', 'routeMethod');

    switch (routeMethod) {
      case addRoute:
        return this.store.createRecord(routeBase);
      case editRoute:
        return this.store.findRecord(routeBase, param.id);
      default:
        return this.store.findAll(routeBase);
    }
  },

  // Sets controller's route name related properties
  setControllerRouteNameMethod(){
    const{
      controller,
      routeBase,
      routeMethod,
    } = getProperties(this, 'controller', 'routeBase', 'routeMethod');

    controller.setProperties({
      capitalModelName: (routeBase) ? capitalize(routeBase) : null,
      capitalMethodName: (routeMethod) ? capitalize(routeMethod) : null
    });
  },

  // Mixin and set controller definitions
  mixinAndSetControllerDefinitionObjects(){
    const{
      controller,
      routeBase,
      validationObject,
      definitionObject,
      magicCrudObject,
    } = getProperties(this, 'controller', 'routeBase', 'validationObject', 'definitionObject', 'magicCrudObject');

    controller.reopen(MagicCrud);

    if(!controller.get(validationObject)){
      controller.set(validationObject, this.controllerFor(routeBase).get(validationObject));
    }

    if(!controller.get(definitionObject)){
      controller.set(definitionObject, this.controllerFor(routeBase).get(definitionObject));
    }

    if(!controller.get(magicCrudObject)){
      controller.set(magicCrudObject, this.controllerFor(routeBase).get(magicCrudObject));
    }

    if(!controller.get('sortProperties')){
      controller.set('sortProperties', []);
    }
  },

  // Set templates for controller rendering
  setTemplatesToRender(){
    const{
      controller,
      formTemplate,
      tableTemplate
    } = getProperties(this, 'controller', 'formTemplate', 'tableTemplate');

    let formTemplateRenderer = function(){
      this.render(formTemplate, {
        outlet: 'magic-form',
        controller: controller
      });
    };

    let tableTemplateRenderer = function(){
      this.render(tableTemplate, {
        controller: controller
      });
    };

    if(this.isAnActionRoute()){
      this.set('renderTemplate', formTemplateRenderer);
    }
    else{
      this.set('renderTemplate', tableTemplateRenderer);
    }
  },

  // True if route is edit or add
  isAnActionRoute(){
    const{
      routeMethod,
      addRoute,
      editRoute,
    } = getProperties(this, 'routeMethod', 'addRoute', 'editRoute');

    return routeMethod === addRoute || routeMethod === editRoute;
  },

  // Sets up the Route's Controller
  setupController(controller, model) {
    const{
      editRoute,
      routeMethod,
      editDone
    } = getProperties(this, 'editRoute', 'routeMethod', 'editDone');

    this._super(controller, model);
    this.setControllerRouteNameMethod();
    this.setTemplatesToRender();

    if(this.isAnActionRoute()){
      if(editDone && routeMethod === editRoute){
        return;
      }
      this.mixinAndSetControllerDefinitionObjects();
      this.set('editDone', true);
    }
    this.controller.init();
  },

  // Success saving record promise callback
  saveRecordSuccess(){
    let controller = this.get('controller');
    let routeBase = this.get('routeBase');
    let saveMessage = this.get('saveMessage');
    let flashMessages = Ember.get(this, 'flashMessages');

    controller.get('model').save().then(() => {
      let routeAfter;
      if(controller.get('magicCrud') && (routeAfter = controller.get('magicCrud.routeAfter'))){
        controller.transitionTo(routeAfter);
      }
      else{
        controller.transitionTo(routeBase);
      }
      flashMessages.success(saveMessage);
    });
  },

  // Fail saving record promise callback
  saveRecordFail(){
    let controller = this.get('controller');
    let flashMessages = Ember.get(this, 'flashMessages');
    let definitionObject = this.get('definitionObject');

    let errors = controller.get('errors.model');
    for(let item in errors){
      if(errors.hasOwnProperty(item)){
        let definitions = controller.get(definitionObject);
        for(let def in definitions){
          if(definitions[def] && 'model.'+item === definitions[def].attribute && errors.get(item).length){
            flashMessages.danger(definitions[def].label + ' ' + errors.get(item));
          }
        }
      }
    }
  },

  // Route Actions
  actions: {
    //Delete record from store
    deleteRecord(item){
      const{
        routeBase,
        deleteMessageSuccess,
        deleteMessageFailed
      } = getProperties(this, 'routeBase', 'deleteMessageSuccess', 'deleteMessageFailed');

      this.transitionTo(routeBase);
      let flashMessages = Ember.get(this, 'flashMessages');

      item.deleteRecord();
      item.save().then(() => {
        flashMessages.success(deleteMessageSuccess);
      },() => {
        flashMessages.danger(deleteMessageFailed);
      });
    },

    // Transition to edit route
    editRecord(item){
      const{
        routeBase,
        editRoute
      } = getProperties(this, 'routeBase', 'editRoute');

      this.transitionTo(routeBase + '.' + editRoute, item);
    },

    // Transition to add route
    addRecord(){
      const{
        routeBase,
        addRoute
      } = getProperties(this, 'routeBase', 'addRoute');

      this.transitionTo(routeBase + '.' + addRoute);
    },

    // Save record
    saveRecord(){
      const{
        controller
      } = getProperties(this, 'controller');

      this.set('canRollbackModel', false);

      controller.set('submitted', true);
      controller.validate().then(() => {
        this.saveRecordSuccess();
      }, () => {
        this.saveRecordFail();
      });
    },

    // Rollback model
    willTransition() {
      const{
        controller
      } = getProperties(this, 'controller');

      if(this.isAnActionRoute() && this.get('canRollbackModel')){
        controller.get('model').rollback();
        if(controller.get('model').rollbackAttributes){
          controller.get('model').rollbackAttributes();
        }
      }

      this.set('canRollbackModel', true);
    }
  }
});
<commit_msg>Change transitionTo to transitionToRoute for ember 2<commit_after>import Ember from 'ember';
import MagicCrud from './magic-crud';

const {
  getProperties
} = Ember;

let capitalize = function(string){
  return string.charAt(0).toUpperCase() + string.slice(1);
};

export default Ember.Mixin.create(MagicCrud, {

  // This is for the objects not to change and mess up the observers
  editDone: false,

  // Validation Object name
  validationObject: 'validations',

  // Definitions Object name
  definitionObject: 'formDefinitionsMC',

  // Magic Crud Options object name
  magicCrudObject: 'magicCrud',

  // Route that corresponds to editing
  editRoute: 'edit',

  // Route that corresponds to adding
  addRoute: 'add',

  // Template for the form
  formTemplate: 'magic-crud/form',

  // Template for the table
  tableTemplate: 'magic-crud/table',

  // Save success message
  saveMessage: 'Record saved successfully',

  // Delete success message
  deleteMessageSuccess: 'Record deleted',

  // Delete fail message
  deleteMessageFailed: 'The record couldn\'t be deleted',

  canRollbackModel: true,

  // Split route name
  routeSplit: Ember.computed('routeName', function(){
    return this.get('routeName').split('.');
  }),

  // Route base name
  routeBase: Ember.computed('routeSplit', function(){
    return this.get('routeSplit')[0];
  }),

  // Route method name
  routeMethod: Ember.computed('routeSplit', function(){
    return this.get('routeSplit')[1];
  }),

  // Route's model
  model: function(param){
    const{
      addRoute,
      editRoute,
      routeBase,
      routeMethod
    } = getProperties(this, 'addRoute', 'editRoute', 'routeBase', 'routeMethod');

    switch (routeMethod) {
      case addRoute:
        return this.store.createRecord(routeBase);
      case editRoute:
        return this.store.findRecord(routeBase, param.id);
      default:
        return this.store.findAll(routeBase);
    }
  },

  // Sets controller's route name related properties
  setControllerRouteNameMethod(){
    const{
      controller,
      routeBase,
      routeMethod,
    } = getProperties(this, 'controller', 'routeBase', 'routeMethod');

    controller.setProperties({
      capitalModelName: (routeBase) ? capitalize(routeBase) : null,
      capitalMethodName: (routeMethod) ? capitalize(routeMethod) : null
    });
  },

  // Mixin and set controller definitions
  mixinAndSetControllerDefinitionObjects(){
    const{
      controller,
      routeBase,
      validationObject,
      definitionObject,
      magicCrudObject,
    } = getProperties(this, 'controller', 'routeBase', 'validationObject', 'definitionObject', 'magicCrudObject');

    controller.reopen(MagicCrud);

    if(!controller.get(validationObject)){
      controller.set(validationObject, this.controllerFor(routeBase).get(validationObject));
    }

    if(!controller.get(definitionObject)){
      controller.set(definitionObject, this.controllerFor(routeBase).get(definitionObject));
    }

    if(!controller.get(magicCrudObject)){
      controller.set(magicCrudObject, this.controllerFor(routeBase).get(magicCrudObject));
    }

    if(!controller.get('sortProperties')){
      controller.set('sortProperties', []);
    }
  },

  // Set templates for controller rendering
  setTemplatesToRender(){
    const{
      controller,
      formTemplate,
      tableTemplate
    } = getProperties(this, 'controller', 'formTemplate', 'tableTemplate');

    let formTemplateRenderer = function(){
      this.render(formTemplate, {
        outlet: 'magic-form',
        controller: controller
      });
    };

    let tableTemplateRenderer = function(){
      this.render(tableTemplate, {
        controller: controller
      });
    };

    if(this.isAnActionRoute()){
      this.set('renderTemplate', formTemplateRenderer);
    }
    else{
      this.set('renderTemplate', tableTemplateRenderer);
    }
  },

  // True if route is edit or add
  isAnActionRoute(){
    const{
      routeMethod,
      addRoute,
      editRoute,
    } = getProperties(this, 'routeMethod', 'addRoute', 'editRoute');

    return routeMethod === addRoute || routeMethod === editRoute;
  },

  // Sets up the Route's Controller
  setupController(controller, model) {
    const{
      editRoute,
      routeMethod,
      editDone
    } = getProperties(this, 'editRoute', 'routeMethod', 'editDone');

    this._super(controller, model);
    this.setControllerRouteNameMethod();
    this.setTemplatesToRender();

    if(this.isAnActionRoute()){
      if(editDone && routeMethod === editRoute){
        return;
      }
      this.mixinAndSetControllerDefinitionObjects();
      this.set('editDone', true);
    }
    this.controller.init();
  },

  // Success saving record promisse callback
  saveRecordSuccess(){
    let controller = this.get('controller');
    let routeBase = this.get('routeBase');
    let saveMessage = this.get('saveMessage');
    let flashMessages = Ember.get(this, 'flashMessages');

    controller.get('model').save().then(() => {
      let routeAfter;
      if(controller.get('magicCrud') && (routeAfter = controller.get('magicCrud.routeAfter'))){
        controller.transitionToRoute(routeAfter);
      }
      else{
        controller.transitionToRoute(routeBase);
      }
      flashMessages.success(saveMessage);
    });
  },

  // Fail saving record promisse callback
  saveRecordFail(){
    let controller = this.get('controller');
    let flashMessages = Ember.get(this, 'flashMessages');
    let definitionObject = this.get('definitionObject');

    let errors = controller.get('errors.model');
    for(let item in errors){
      if(errors.hasOwnProperty(item)){
        let definitions = controller.get(definitionObject);
        for(let def in definitions){
          if(definitions[def] && 'model.'+item === definitions[def].attribute && errors.get(item).length){
            flashMessages.danger(definitions[def].label + ' ' + errors.get(item));
          }
        }
      }
    }
  },

  // Route Actions
  actions: {
    //Delete record from store
    deleteRecord(item){
      const{
        routeBase,
        deleteMessageSuccess,
        deleteMessageFailed
      } = getProperties(this, 'routeBase', 'deleteMessageSuccess', 'deleteMessageFailed');

      this.transitionTo(routeBase);
      let flashMessages = Ember.get(this, 'flashMessages');

      item.deleteRecord();
      item.save().then(() => {
        flashMessages.success(deleteMessageSuccess);
      },() => {
        flashMessages.danger(deleteMessageFailed);
      });
    },

    // Transition to edit route
    editRecord(item){
      const{
        routeBase,
        editRoute
      } = getProperties(this, 'routeBase', 'editRoute');

      this.transitionTo(routeBase + '.' + editRoute, item);
    },

    // Transition to add route
    addRecord(){
      const{
        routeBase,
        addRoute
      } = getProperties(this, 'routeBase', 'addRoute');

      this.transitionTo(routeBase + '.' + addRoute);
    },

    // Save record
    saveRecord(){
      const{
        controller
      } = getProperties(this, 'controller');

      this.set('canRollbackModel', false);

      controller.set('submitted', true);
      controller.validate().then(() => {
        this.saveRecordSuccess();
      }, () => {
        this.saveRecordFail();
      });
    },

    // Rollback model
    willTransition() {
      const{
        controller
      } = getProperties(this, 'controller');

      if(this.isAnActionRoute() && this.get('canRollbackModel')){
        controller.get('model').rollback();
        if(controller.get('model').rollbackAttributes){
          controller.get('model').rollbackAttributes();
        }
      }

      this.set('canRollbackModel', true);
    }
  }
});
<|endoftext|>


<commit_before>import Ember from 'ember';
import DS from 'ember-data';

import OsfModel from './osf-model';

/**
 * @module ember-osf
 * @submodule models
 */

/**
 * Model for OSF APIv2 contributors. Primarily accessed via relationship fields.
 * For field and usage information, see:
 * * https://api.osf.io/v2/docs/#!/v2/Node_Contributors_List_GET
 * @class Contributor
 */
export default OsfModel.extend({
    bibliographic: DS.attr('boolean'),
    permission: DS.attr('string'),
    userId: Ember.computed('id', function() {
	return this.get('id').split('-').pop();
    }),
    nodeId: Ember.computed('id', function() {
	return this.get('id').split('-').shift();
    }),
    users: DS.belongsTo('user'),
    unregisteredContributor: DS.attr('string')
});
<commit_msg>Fix the JS style<commit_after>import Ember from 'ember';
import DS from 'ember-data';

import OsfModel from './osf-model';

/**
 * @module ember-osf
 * @submodule models
 */

/**
 * Model for OSF APIv2 contributors. Primarily accessed via relationship fields.
 * For field and usage information, see:
 * * https://api.osf.io/v2/docs/#!/v2/Node_Contributors_List_GET
 * @class Contributor
 */
export default OsfModel.extend({
    bibliographic: DS.attr('boolean'),
    permission: DS.attr('string'),
    userId: Ember.computed('id', function() {
        return this.get('id').split('-').pop();
    }),
    nodeId: Ember.computed('id', function() {
        return this.get('id').split('-').shift();
    }),
    users: DS.belongsTo('user'),
    unregisteredContributor: DS.attr('string')
});
<|endoftext|>


<commit_before>var runtil = /Until$/,
	rparentsprev = /^(?:parents|prevUntil|prevAll)/,
	// Note: This RegExp should be improved, or likely pulled from Sizzle
	rmultiselector = /,/,
	isSimple = /^.[^:#\[\.,]*$/,
	slice = Array.prototype.slice;

jQuery.fn.extend({
	find: function( selector ) {
		var ret = this.pushStack( "", "find", selector ), length = 0;

		for ( var i = 0, l = this.length; i < l; i++ ) {
			length = ret.length;
			jQuery.find( selector, this[i], ret );

			if ( i > 0 ) {
				// Make sure that the results are unique
				for ( var n = length; n < ret.length; n++ ) {
					for ( var r = 0; r < length; r++ ) {
						if ( ret[r] === ret[n] ) {
							ret.splice(n--, 1);
							break;
						}
					}
				}
			}
		}

		return ret;
	},

	has: function( target ) {
		var targets = jQuery( target );
		return this.filter(function() {
			for ( var i = 0, l = targets.length; i < l; i++ ) {
				if ( jQuery.contains( this, targets[i] ) ) {
					return true;
				}
			}
		});
	},

	not: function( selector ) {
		return this.pushStack( winnow(this, selector, false), "not", selector);
	},

	filter: function( selector ) {
		return this.pushStack( winnow(this, selector, true), "filter", selector );
	},

	is: function( selector ) {
		return !!selector && jQuery.filter( selector, this ).length > 0;
	},

	closest: function( selectors, context ) {
		if ( jQuery.isArray( selectors ) ) {
			var ret = [], cur = this[0], match, matches = {}, selector, level = 1;

			if ( cur && selectors.length ) {
				for ( var i = 0, l = selectors.length; i < l; i++ ) {
					selector = selectors[i];

					if ( !matches[selector] ) {
						matches[selector] = jQuery.expr.match.POS.test( selector ) ?
							jQuery( selector, context || this.context ) :
							selector;
					}
				}

				while ( cur && cur.ownerDocument && cur !== context ) {
					for ( selector in matches ) {
						match = matches[selector];

						if ( match.jquery ? match.index(cur) > -1 : jQuery(cur).is(match) ) {
							ret.push({ selector: selector, elem: cur, level: level });
						}
					}
					cur = cur.parentNode;
					level++;
				}
			}

			return ret;
		}

		var pos = jQuery.expr.match.POS.test( selectors ) ?
			jQuery( selectors, context || this.context ) : null;

		return this.map(function( i, cur ) {
			while ( cur && cur.ownerDocument && cur !== context ) {
				if ( pos ? pos.index(cur) > -1 : jQuery(cur).is(selectors) ) {
					return cur;
				}
				cur = cur.parentNode;
			}
			return null;
		});
	},

	// Determine the position of an element within
	// the matched set of elements
	index: function( elem ) {
		if ( !elem || typeof elem === "string" ) {
			return jQuery.inArray( this[0],
				// If it receives a string, the selector is used
				// If it receives nothing, the siblings are used
				elem ? jQuery( elem ) : this.parent().children() );
		}
		// Locate the position of the desired element
		return jQuery.inArray(
			// If it receives a jQuery object, the first element is used
			elem.jquery ? elem[0] : elem, this );
	},

	add: function( selector, context ) {
		var set = typeof selector === "string" ?
				jQuery( selector, context || this.context ) :
				jQuery.makeArray( selector ),
			all = jQuery.merge( this.get(), set );

		return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ?
			all :
			jQuery.unique( all ) );
	},

	andSelf: function() {
		return this.add( this.prevObject );
	}
});

// A painfully simple check to see if an element is disconnected
// from a document (should be improved, where feasible).
function isDisconnected( node ) {
	return !node || !node.parentNode || node.parentNode.nodeType === 11;
}

jQuery.each({
	parent: function( elem ) {
		var parent = elem.parentNode;
		return parent && parent.nodeType !== 11 ? parent : null;
	},
	parents: function( elem ) {
		return jQuery.dir( elem, "parentNode" );
	},
	parentsUntil: function( elem, i, until ) {
		return jQuery.dir( elem, "parentNode", until );
	},
	next: function( elem ) {
		return jQuery.nth( elem, 2, "nextSibling" );
	},
	prev: function( elem ) {
		return jQuery.nth( elem, 2, "previousSibling" );
	},
	nextAll: function( elem ) {
		return jQuery.dir( elem, "nextSibling" );
	},
	prevAll: function( elem ) {
		return jQuery.dir( elem, "previousSibling" );
	},
	nextUntil: function( elem, i, until ) {
		return jQuery.dir( elem, "nextSibling", until );
	},
	prevUntil: function( elem, i, until ) {
		return jQuery.dir( elem, "previousSibling", until );
	},
	siblings: function( elem ) {
		return jQuery.sibling( elem.parentNode.firstChild, elem );
	},
	children: function( elem ) {
		return jQuery.sibling( elem.firstChild );
	},
	contents: function( elem ) {
		return jQuery.nodeName( elem, "iframe" ) ?
			elem.contentDocument || elem.contentWindow.document :
			jQuery.makeArray( elem.childNodes );
	}
}, function( name, fn ) {
	jQuery.fn[ name ] = function( until, selector ) {
		var ret = jQuery.map( this, fn, until );

		if ( !runtil.test( name ) ) {
			selector = until;
		}

		if ( selector && typeof selector === "string" ) {
			ret = jQuery.filter( selector, ret );
		}

		ret = this.length > 1 ? jQuery.unique( ret ) : ret;

		if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {
			ret = ret.reverse();
		}

		return this.pushStack( ret, name, slice.call(arguments).join(",") );
	};
});

jQuery.extend({
	filter: function( expr, elems, not ) {
		if ( not ) {
			expr = ":not(" + expr + ")";
		}

		return jQuery.find.matches(expr, elems);
	},

	dir: function( elem, dir, until ) {
		var matched = [], cur = elem[dir];
		while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
			if ( cur.nodeType === 1 ) {
				matched.push( cur );
			}
			cur = cur[dir];
		}
		return matched;
	},

	nth: function( cur, result, dir, elem ) {
		result = result || 1;
		var num = 0;

		for ( ; cur; cur = cur[dir] ) {
			if ( cur.nodeType === 1 && ++num === result ) {
				break;
			}
		}

		return cur;
	},

	sibling: function( n, elem ) {
		var r = [];

		for ( ; n; n = n.nextSibling ) {
			if ( n.nodeType === 1 && n !== elem ) {
				r.push( n );
			}
		}

		return r;
	}
});

// Implement the identical functionality for filter and not
function winnow( elements, qualifier, keep ) {
	if ( jQuery.isFunction( qualifier ) ) {
		return jQuery.grep(elements, function( elem, i ) {
			var retVal = !!qualifier.call( elem, i, elem );
			return retVal === keep;
		});

	} else if ( qualifier.nodeType ) {
		return jQuery.grep(elements, function( elem, i ) {
			return (elem === qualifier) === keep;
		});

	} else if ( typeof qualifier === "string" ) {
		var filtered = jQuery.grep(elements, function( elem ) {
			return elem.nodeType === 1;
		});

		if ( isSimple.test( qualifier ) ) {
			return jQuery.filter(qualifier, filtered, !keep);
		} else {
			qualifier = jQuery.filter( qualifier, filtered );
		}
	}

	return jQuery.grep(elements, function( elem, i ) {
		return (jQuery.inArray( elem, qualifier ) >= 0) === keep;
	});
};<commit_msg>Removed extra semicolon leftover from recent tweaking.<commit_after>var runtil = /Until$/,
	rparentsprev = /^(?:parents|prevUntil|prevAll)/,
	// Note: This RegExp should be improved, or likely pulled from Sizzle
	rmultiselector = /,/,
	isSimple = /^.[^:#\[\.,]*$/,
	slice = Array.prototype.slice;

jQuery.fn.extend({
	find: function( selector ) {
		var ret = this.pushStack( "", "find", selector ), length = 0;

		for ( var i = 0, l = this.length; i < l; i++ ) {
			length = ret.length;
			jQuery.find( selector, this[i], ret );

			if ( i > 0 ) {
				// Make sure that the results are unique
				for ( var n = length; n < ret.length; n++ ) {
					for ( var r = 0; r < length; r++ ) {
						if ( ret[r] === ret[n] ) {
							ret.splice(n--, 1);
							break;
						}
					}
				}
			}
		}

		return ret;
	},

	has: function( target ) {
		var targets = jQuery( target );
		return this.filter(function() {
			for ( var i = 0, l = targets.length; i < l; i++ ) {
				if ( jQuery.contains( this, targets[i] ) ) {
					return true;
				}
			}
		});
	},

	not: function( selector ) {
		return this.pushStack( winnow(this, selector, false), "not", selector);
	},

	filter: function( selector ) {
		return this.pushStack( winnow(this, selector, true), "filter", selector );
	},

	is: function( selector ) {
		return !!selector && jQuery.filter( selector, this ).length > 0;
	},

	closest: function( selectors, context ) {
		if ( jQuery.isArray( selectors ) ) {
			var ret = [], cur = this[0], match, matches = {}, selector, level = 1;

			if ( cur && selectors.length ) {
				for ( var i = 0, l = selectors.length; i < l; i++ ) {
					selector = selectors[i];

					if ( !matches[selector] ) {
						matches[selector] = jQuery.expr.match.POS.test( selector ) ?
							jQuery( selector, context || this.context ) :
							selector;
					}
				}

				while ( cur && cur.ownerDocument && cur !== context ) {
					for ( selector in matches ) {
						match = matches[selector];

						if ( match.jquery ? match.index(cur) > -1 : jQuery(cur).is(match) ) {
							ret.push({ selector: selector, elem: cur, level: level });
						}
					}
					cur = cur.parentNode;
					level++;
				}
			}

			return ret;
		}

		var pos = jQuery.expr.match.POS.test( selectors ) ?
			jQuery( selectors, context || this.context ) : null;

		return this.map(function( i, cur ) {
			while ( cur && cur.ownerDocument && cur !== context ) {
				if ( pos ? pos.index(cur) > -1 : jQuery(cur).is(selectors) ) {
					return cur;
				}
				cur = cur.parentNode;
			}
			return null;
		});
	},

	// Determine the position of an element within
	// the matched set of elements
	index: function( elem ) {
		if ( !elem || typeof elem === "string" ) {
			return jQuery.inArray( this[0],
				// If it receives a string, the selector is used
				// If it receives nothing, the siblings are used
				elem ? jQuery( elem ) : this.parent().children() );
		}
		// Locate the position of the desired element
		return jQuery.inArray(
			// If it receives a jQuery object, the first element is used
			elem.jquery ? elem[0] : elem, this );
	},

	add: function( selector, context ) {
		var set = typeof selector === "string" ?
				jQuery( selector, context || this.context ) :
				jQuery.makeArray( selector ),
			all = jQuery.merge( this.get(), set );

		return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ?
			all :
			jQuery.unique( all ) );
	},

	andSelf: function() {
		return this.add( this.prevObject );
	}
});

// A painfully simple check to see if an element is disconnected
// from a document (should be improved, where feasible).
function isDisconnected( node ) {
	return !node || !node.parentNode || node.parentNode.nodeType === 11;
}

jQuery.each({
	parent: function( elem ) {
		var parent = elem.parentNode;
		return parent && parent.nodeType !== 11 ? parent : null;
	},
	parents: function( elem ) {
		return jQuery.dir( elem, "parentNode" );
	},
	parentsUntil: function( elem, i, until ) {
		return jQuery.dir( elem, "parentNode", until );
	},
	next: function( elem ) {
		return jQuery.nth( elem, 2, "nextSibling" );
	},
	prev: function( elem ) {
		return jQuery.nth( elem, 2, "previousSibling" );
	},
	nextAll: function( elem ) {
		return jQuery.dir( elem, "nextSibling" );
	},
	prevAll: function( elem ) {
		return jQuery.dir( elem, "previousSibling" );
	},
	nextUntil: function( elem, i, until ) {
		return jQuery.dir( elem, "nextSibling", until );
	},
	prevUntil: function( elem, i, until ) {
		return jQuery.dir( elem, "previousSibling", until );
	},
	siblings: function( elem ) {
		return jQuery.sibling( elem.parentNode.firstChild, elem );
	},
	children: function( elem ) {
		return jQuery.sibling( elem.firstChild );
	},
	contents: function( elem ) {
		return jQuery.nodeName( elem, "iframe" ) ?
			elem.contentDocument || elem.contentWindow.document :
			jQuery.makeArray( elem.childNodes );
	}
}, function( name, fn ) {
	jQuery.fn[ name ] = function( until, selector ) {
		var ret = jQuery.map( this, fn, until );

		if ( !runtil.test( name ) ) {
			selector = until;
		}

		if ( selector && typeof selector === "string" ) {
			ret = jQuery.filter( selector, ret );
		}

		ret = this.length > 1 ? jQuery.unique( ret ) : ret;

		if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {
			ret = ret.reverse();
		}

		return this.pushStack( ret, name, slice.call(arguments).join(",") );
	};
});

jQuery.extend({
	filter: function( expr, elems, not ) {
		if ( not ) {
			expr = ":not(" + expr + ")";
		}

		return jQuery.find.matches(expr, elems);
	},

	dir: function( elem, dir, until ) {
		var matched = [], cur = elem[dir];
		while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
			if ( cur.nodeType === 1 ) {
				matched.push( cur );
			}
			cur = cur[dir];
		}
		return matched;
	},

	nth: function( cur, result, dir, elem ) {
		result = result || 1;
		var num = 0;

		for ( ; cur; cur = cur[dir] ) {
			if ( cur.nodeType === 1 && ++num === result ) {
				break;
			}
		}

		return cur;
	},

	sibling: function( n, elem ) {
		var r = [];

		for ( ; n; n = n.nextSibling ) {
			if ( n.nodeType === 1 && n !== elem ) {
				r.push( n );
			}
		}

		return r;
	}
});

// Implement the identical functionality for filter and not
function winnow( elements, qualifier, keep ) {
	if ( jQuery.isFunction( qualifier ) ) {
		return jQuery.grep(elements, function( elem, i ) {
			var retVal = !!qualifier.call( elem, i, elem );
			return retVal === keep;
		});

	} else if ( qualifier.nodeType ) {
		return jQuery.grep(elements, function( elem, i ) {
			return (elem === qualifier) === keep;
		});

	} else if ( typeof qualifier === "string" ) {
		var filtered = jQuery.grep(elements, function( elem ) {
			return elem.nodeType === 1;
		});

		if ( isSimple.test( qualifier ) ) {
			return jQuery.filter(qualifier, filtered, !keep);
		} else {
			qualifier = jQuery.filter( qualifier, filtered );
		}
	}

	return jQuery.grep(elements, function( elem, i ) {
		return (jQuery.inArray( elem, qualifier ) >= 0) === keep;
	});
}
<|endoftext|>


<commit_before>var React = require('react');
var hyphenateStyleName = require('react/lib/hyphenateStyleName');
var forEach = require('lodash.foreach');
var reduce = require('lodash.reduce');

function buildCssString (selector, rules) {
  // TODO: Better error checking for rules object
  if (!selector || !rules) {
    return;
  }

  var cssString = selector + "{";

  // Turn rules into css properties
  cssString += reduce(rules, function (s, val, styleName) {
    return s + hyphenateStyleName(styleName) + ":" + val + ";"
  }, "");

  // Close selector
  cssString += "}";

  return cssString;
}

var Style = React.createClass({
  render: function () {
    if (!this.props.selector) {
      throw new Error("Style tag requires a 'selector' property");
    }

    // Build styles from standard
    var styles = buildCssString(this.props.selector, this.props.standard)

    forEach(this.props.states, function (rules, state) {
      styles += buildCssString(ownerSelector + ":" + state, rules);
    });

    return (
      <style dangerouslySetInnerHTML={{__html: styles}}>
      </style>
    );
  }
});

module.exports = Style;
<commit_msg>add better error checking to style component<commit_after>var React = require('react');
var hyphenateStyleName = require('react/lib/hyphenateStyleName');
var forEach = require('lodash.foreach');
var reduce = require('lodash.reduce');

function buildCssString (selector, rules) {
  // TODO: Better error checking for rules object
  if (!selector || !rules) {
    return;
  }

  var cssString = selector + "{";

  // Turn rules into css properties
  cssString += reduce(rules, function (s, val, styleName) {
    return s + hyphenateStyleName(styleName) + ":" + val + ";"
  }, "");

  // Close selector
  cssString += "}";

  return cssString;
}

var Style = React.createClass({
  render: function () {
    if (!this.props.selector || typeof this.props.selector !== "string") {
      throw new Error("Style tag requires a 'selector' string");
    }

    if (!this.props.styles || typeof this.props.styles !== "object") {
      throw new Error("Style tag requires a 'styles' object");
    }

    // Build styles from standard
    var styles = buildCssString(this.props.selector, this.props.styles.standard)

    forEach(this.props.styles.states, function (rules, state) {
      styles += buildCssString(ownerSelector + ":" + state, rules);
    });

    return (
      <style dangerouslySetInnerHTML={{__html: styles}}>
      </style>
    );
  }
});

module.exports = Style;
<|endoftext|>