<commit_before>import EventEmitter2 from 'eventemitter2';
import * as events from './events';
import PluginError from './plugin-error';
import merge from 'merge';
import get from 'lodash.get';
import { defaults as _defaults, allowedEncodings } from './defaults';

export default class Client {
  constructor(defaults) {
    const encodingIsInvalid = () => defaults &&
      typeof defaults.encoding !== 'undefined' &&
      allowedEncodings.indexOf(defaults.encoding) === -1;

    if (encodingIsInvalid()) {
      throw new Error(`${defaults.encoding} is not an allowed encoding value.`);
    }

    this.defaults = merge.recursive(true, this._getDefaults(), defaults);

    if (this.defaults.url) {
      this.defaults.sep = this.defaults.url[this.defaults.url.length - 1] === '/' ? '' : '/';
    }

    this.eventEmitter = new EventEmitter2();
    this._plugins = [];
  }

  _getDefaults() {
    return _defaults;
  }

  _callPluginMethod(method, mutableArgIdx, earlyExit, ...args) {
    let i = 0;

    const shouldContinue = () => (earlyExit ? args[mutableArgIdx] : true);

    while (i < this._plugins.length && shouldContinue()) {
      if (this._plugins[i][method]) {
        args[mutableArgIdx] = this._plugins[i][method](...args);
      }
      i += 1;
    }

    return args[mutableArgIdx];
  }

  _callOnStarts(request) {
    return this._callPluginMethod('onStart', 0, true, request);
  }

  _callOnSuccesses(request, response) {
    return this._callPluginMethod('onSuccess', 1, false, request, response);
  }

  _callOnFails(request, response) {
    return this._callPluginMethod('onFail', 1, false, request, response);
  }

  _callOnErrors(request, response) {
    return this._callPluginMethod('onError', 1, false, request, response);
  }

  _addHelpers(helpers) {
    if (helpers) {
      Object.keys(helpers).forEach((key) => {
        this[key] = helpers[key];
      });
    }
  }

  _getRequest(path, options) {
    let fullPath = path;
    if (this.defaults && this.defaults.url) {
      fullPath = `${this.defaults.url}${this.defaults.sep}${path}`;
    }

    return new Request(fullPath, options);
  }

  fetch(path, options) {
    let request;
    let onStartError;

    if (path instanceof Request) {
      request = path;
    } else {
      request = this._getRequest(path, options);
    }

    this.eventEmitter.emit(events.REQUEST_START, request);
    try {
      request = this._callOnStarts(request);
    } catch (err) {
      onStartError = err;
    }

    let fetchPromise;
    if (request && !onStartError) {
      fetchPromise = fetch(request)
        .then(response => {
          let mutatedResponse;
          if (response.status >= 400) {
            mutatedResponse = this._callOnFails(request, response);
            this.eventEmitter.emit(events.REQUEST_FAILURE, request, mutatedResponse);
          } else {
            mutatedResponse = this._callOnSuccesses(request, response);
            this.eventEmitter.emit(events.REQUEST_SUCCESS, request, mutatedResponse);
          }

          return mutatedResponse;
        })
        .catch(err => {
          const mutatedError = this._callOnErrors(request, err);
          this.eventEmitter.emit(events.REQUEST_ERROR, request, mutatedError);
          throw mutatedError;
        });
    } else {
      const err = onStartError || new PluginError();
      fetchPromise = Promise.reject(err);
    }

    return fetchPromise;
  }

  addPlugin(plugin) {
    plugin.client = this;
    this._plugins.push(plugin);
    this._addHelpers(plugin.helpers);
    if (plugin.onAddPlugin) {
      plugin.onAddPlugin(this);
    }
  }

  removePlugin(name) {
    let i = 0;
    for (i; i < this._plugins.length; i++) {
      if (this._plugins[i].name === name) {
        this._plugins.splice(i, 1);
        i -= 1;
      }
    }
  }

  on(event, cb) {
    this.eventEmitter.on(event, cb);
  }

  /* ---- HELPERS ---- */

  _formAppendArrayOrObject(formObject, data, key, forQueryString) {
    if (Array.isArray(data)) {
      data.forEach((val) => {
        if (typeof(val) === 'object') {
          this._formAppendArrayOrObject(formObject, val, `${key}[]`);
        } else {
          if (! forQueryString || this.defaults.bracketStyleArrays) {
            formObject.append(`${key}[]`, val);
          } else {
            formObject.append(`${key}`, val);
          }
        }
      });
    } else {
      Object.keys(data).forEach(val => {
        if (typeof(data[val]) === 'object') {
          this._formAppendArrayOrObject(formObject, data[val], `${key}[${val}]`);
        } else {
          formObject.append(`${key}[${val}]`, data[val]);
        }
      });
    }
  }

  _encodeForm(body, formObject, forQueryString) {
    Object.keys(body).forEach((val) => {
      if (typeof(body[val]) === 'object') {
        this._formAppendArrayOrObject(formObject, body[val], `${val}`, forQueryString);
      } else {
        formObject.append(val, body[val]);
      }
    });

    return formObject;
  }

  _getEncodingTypeFromContentType(contentType) {
    let encodingType = false;
    if (contentType) {
      if (contentType.match(/text\/.+/i)) {
        encodingType = 'text';
      } else {
        switch (contentType) {
          case 'application/json':
            encodingType = 'json';
            break;
          case 'multipart/form-data':
            encodingType = 'form-data';
            break;
          case 'application/x-www-form-urlencoded':
            encodingType = 'x-www-form-urlencoded';
            break;
          default:
        }
      }
    }

    return encodingType;
  }

  _encode(body, contentType) {
    let _body = body;
    let _contentType = contentType;

    let encodingType = this._getEncodingTypeFromContentType(_contentType);
    encodingType = encodingType || this.defaults.encoding;

    if (_body instanceof FormData || _body instanceof URLSearchParams) {
      return { body: _body, contentType: false };
    }

    let formObject;
    switch (encodingType) {
      case 'json':
        _body = JSON.stringify(_body);
        _contentType = 'application/json';
        break;
      case 'text':
        _contentType = _contentType || 'text/plain';
        break;
      case 'form-data':
        formObject = new FormData();
        _body = this._encodeForm(_body, formObject);
        _contentType = undefined;
        break;
      case 'x-www-form-urlencoded':
        formObject = new URLSearchParams();
        _body = this._encodeForm(_body, formObject);
        _contentType = undefined;
        break;
      default:
    }

    return { body: _body, contentType: _contentType };
  }

  _buildOptionsWithBody(method, body, options) {
    let _options = { ...this.defaults[method] };
    _options = merge.recursive(true, _options, options);

    const { body: encodedBody, contentType } = this._encode(body, _options.headers['Content-Type']);
    if (contentType === false) {
      delete _options.headers['Content-Type'];
    } else {
      _options.headers['Content-Type'] = contentType;
    }

    _options.body = encodedBody;
    return _options;
  }

  get(path, body, options) {
    const _options = options || {};
    let queryString = '';

    _options.headers = merge(true, _options.headers, get(this.defaults, 'get.headers'));

    if (body && Object.keys(body).length) {
      queryString = this.defaults.queryStringifier.bind(this)(body);
    }

    _options.method = 'GET';
    return this.fetch(path + queryString, _options);
  }

  post(path, body, options) {
    const _options = this._buildOptionsWithBody('post', body, options);
    _options.method = 'POST';
    return this.fetch(path, _options);
  }

  put(path, body, options) {
    const _options = this._buildOptionsWithBody('put', body, options);
    _options.method = 'PUT';
    return this.fetch(path, _options);
  }

  patch(path, body, options) {
    const _options = this._buildOptionsWithBody('patch', body, options);
    _options.method = 'PATCH';
    return this.fetch(path, _options);
  }

  delete(path, options) {
    const _options = options || {};
    _options.method = 'DELETE';
    return this.fetch(path, _options);
  }
}
<commit_msg>Client won't add declared (but undefined) content type headers for form data and url encoded form values<commit_after>import EventEmitter2 from 'eventemitter2';
import * as events from './events';
import PluginError from './plugin-error';
import merge from 'merge';
import get from 'lodash.get';
import { defaults as _defaults, allowedEncodings } from './defaults';

export default class Client {
  constructor(defaults) {
    const encodingIsInvalid = () => defaults &&
      typeof defaults.encoding !== 'undefined' &&
      allowedEncodings.indexOf(defaults.encoding) === -1;

    if (encodingIsInvalid()) {
      throw new Error(`${defaults.encoding} is not an allowed encoding value.`);
    }

    this.defaults = merge.recursive(true, this._getDefaults(), defaults);

    if (this.defaults.url) {
      this.defaults.sep = this.defaults.url[this.defaults.url.length - 1] === '/' ? '' : '/';
    }

    this.eventEmitter = new EventEmitter2();
    this._plugins = [];
  }

  _getDefaults() {
    return _defaults;
  }

  _callPluginMethod(method, mutableArgIdx, earlyExit, ...args) {
    let i = 0;

    const shouldContinue = () => (earlyExit ? args[mutableArgIdx] : true);

    while (i < this._plugins.length && shouldContinue()) {
      if (this._plugins[i][method]) {
        args[mutableArgIdx] = this._plugins[i][method](...args);
      }
      i += 1;
    }

    return args[mutableArgIdx];
  }

  _callOnStarts(request) {
    return this._callPluginMethod('onStart', 0, true, request);
  }

  _callOnSuccesses(request, response) {
    return this._callPluginMethod('onSuccess', 1, false, request, response);
  }

  _callOnFails(request, response) {
    return this._callPluginMethod('onFail', 1, false, request, response);
  }

  _callOnErrors(request, response) {
    return this._callPluginMethod('onError', 1, false, request, response);
  }

  _addHelpers(helpers) {
    if (helpers) {
      Object.keys(helpers).forEach((key) => {
        this[key] = helpers[key];
      });
    }
  }

  _getRequest(path, options) {
    let fullPath = path;
    if (this.defaults && this.defaults.url) {
      fullPath = `${this.defaults.url}${this.defaults.sep}${path}`;
    }

    return new Request(fullPath, options);
  }

  fetch(path, options) {
    let request;
    let onStartError;

    if (path instanceof Request) {
      request = path;
    } else {
      request = this._getRequest(path, options);
    }

    this.eventEmitter.emit(events.REQUEST_START, request);
    try {
      request = this._callOnStarts(request);
    } catch (err) {
      onStartError = err;
    }

    let fetchPromise;
    if (request && !onStartError) {
      fetchPromise = fetch(request)
        .then(response => {
          let mutatedResponse;
          if (response.status >= 400) {
            mutatedResponse = this._callOnFails(request, response);
            this.eventEmitter.emit(events.REQUEST_FAILURE, request, mutatedResponse);
          } else {
            mutatedResponse = this._callOnSuccesses(request, response);
            this.eventEmitter.emit(events.REQUEST_SUCCESS, request, mutatedResponse);
          }

          return mutatedResponse;
        })
        .catch(err => {
          const mutatedError = this._callOnErrors(request, err);
          this.eventEmitter.emit(events.REQUEST_ERROR, request, mutatedError);
          throw mutatedError;
        });
    } else {
      const err = onStartError || new PluginError();
      fetchPromise = Promise.reject(err);
    }

    return fetchPromise;
  }

  addPlugin(plugin) {
    plugin.client = this;
    this._plugins.push(plugin);
    this._addHelpers(plugin.helpers);
    if (plugin.onAddPlugin) {
      plugin.onAddPlugin(this);
    }
  }

  removePlugin(name) {
    let i = 0;
    for (i; i < this._plugins.length; i++) {
      if (this._plugins[i].name === name) {
        this._plugins.splice(i, 1);
        i -= 1;
      }
    }
  }

  on(event, cb) {
    this.eventEmitter.on(event, cb);
  }

  /* ---- HELPERS ---- */

  _formAppendArrayOrObject(formObject, data, key, forQueryString) {
    if (Array.isArray(data)) {
      data.forEach((val) => {
        if (typeof(val) === 'object') {
          this._formAppendArrayOrObject(formObject, val, `${key}[]`);
        } else {
          if (! forQueryString || this.defaults.bracketStyleArrays) {
            formObject.append(`${key}[]`, val);
          } else {
            formObject.append(`${key}`, val);
          }
        }
      });
    } else {
      Object.keys(data).forEach(val => {
        if (typeof(data[val]) === 'object') {
          this._formAppendArrayOrObject(formObject, data[val], `${key}[${val}]`);
        } else {
          formObject.append(`${key}[${val}]`, data[val]);
        }
      });
    }
  }

  _encodeForm(body, formObject, forQueryString) {
    Object.keys(body).forEach((val) => {
      if (typeof(body[val]) === 'object') {
        this._formAppendArrayOrObject(formObject, body[val], `${val}`, forQueryString);
      } else {
        formObject.append(val, body[val]);
      }
    });

    return formObject;
  }

  _getEncodingTypeFromContentType(contentType) {
    let encodingType = false;
    if (contentType) {
      if (contentType.match(/text\/.+/i)) {
        encodingType = 'text';
      } else {
        switch (contentType) {
          case 'application/json':
            encodingType = 'json';
            break;
          case 'multipart/form-data':
            encodingType = 'form-data';
            break;
          case 'application/x-www-form-urlencoded':
            encodingType = 'x-www-form-urlencoded';
            break;
          default:
        }
      }
    }

    return encodingType;
  }

  _encode(body, contentType) {
    let _body = body;
    let _contentType = contentType;

    let encodingType = this._getEncodingTypeFromContentType(_contentType);
    encodingType = encodingType || this.defaults.encoding;

    if (_body instanceof FormData || _body instanceof URLSearchParams) {
      return { body: _body, contentType: false };
    }

    let formObject;
    switch (encodingType) {
      case 'json':
        _body = JSON.stringify(_body);
        _contentType = 'application/json';
        break;
      case 'text':
        _contentType = _contentType || 'text/plain';
        break;
      case 'form-data':
        formObject = new FormData();
        _body = this._encodeForm(_body, formObject);
        _contentType = false;
        break;
      case 'x-www-form-urlencoded':
        formObject = new URLSearchParams();
        _body = this._encodeForm(_body, formObject);
        _contentType = false;
        break;
      default:
    }

    return { body: _body, contentType: _contentType };
  }

  _buildOptionsWithBody(method, body, options) {
    let _options = { ...this.defaults[method] };
    _options = merge.recursive(true, _options, options);

    const { body: encodedBody, contentType } = this._encode(body, _options.headers['Content-Type']);
    if (contentType === false) {
      delete _options.headers['Content-Type'];
    } else {
      _options.headers['Content-Type'] = contentType;
    }

    _options.body = encodedBody;
    return _options;
  }

  get(path, body, options) {
    const _options = options || {};
    let queryString = '';

    _options.headers = merge(true, _options.headers, get(this.defaults, 'get.headers'));

    if (body && Object.keys(body).length) {
      queryString = this.defaults.queryStringifier.bind(this)(body);
    }

    _options.method = 'GET';
    return this.fetch(path + queryString, _options);
  }

  post(path, body, options) {
    const _options = this._buildOptionsWithBody('post', body, options);
    _options.method = 'POST';
    return this.fetch(path, _options);
  }

  put(path, body, options) {
    const _options = this._buildOptionsWithBody('put', body, options);
    _options.method = 'PUT';
    return this.fetch(path, _options);
  }

  patch(path, body, options) {
    const _options = this._buildOptionsWithBody('patch', body, options);
    _options.method = 'PATCH';
    return this.fetch(path, _options);
  }

  delete(path, options) {
    const _options = options || {};
    _options.method = 'DELETE';
    return this.fetch(path, _options);
  }
}
<|endoftext|>


<commit_before>import * as CounterActions from '../actions/counter';
import { bindActionCreators } from 'redux';

export default function counter() {
  return {
    restrict: 'E',
    controllerAs: 'vm',
    controller: CounterController,
    template: require('./counter.html'),
    scope: {}
  };
}

class CounterController {

  constructor($ngRedux, $scope) {
    $ngRedux.connect($scope, this.mapStateToScope, CounterActions, 'vm');
  }

  // Which part of the Redux global state does our component want to receive on $scope?
  mapStateToScope(state) {
    return {
      counter: state.counter
    };
  }
}<commit_msg>Removed unused import<commit_after>import * as CounterActions from '../actions/counter';

export default function counter() {
  return {
    restrict: 'E',
    controllerAs: 'vm',
    controller: CounterController,
    template: require('./counter.html'),
    scope: {}
  };
}

class CounterController {

  constructor($ngRedux, $scope) {
    $ngRedux.connect($scope, this.mapStateToScope, CounterActions, 'vm');
  }

  // Which part of the Redux global state does our component want to receive on $scope?
  mapStateToScope(state) {
    return {
      counter: state.counter
    };
  }
}<|endoftext|>


<commit_before>import 'babel-polyfill'
import 'normalize.css'
import DeviceProvider from './components/DeviceProvider'
import MobileDetect from 'mobile-detect'
import React from 'react'
import ReactDOM from 'react-dom'
import ReactGA from 'react-ga'
import configureStore from './store/configureStore'
import createRoutes from './routes'
import { Provider } from 'react-redux'
import { Router } from 'react-router'
import { colors, layout, letterSpace, lineHeight, typography } from './themes/common-variables'
import { injectGlobal } from 'styled-components'
import { match, browserHistory } from 'react-router'
import { screen as mq } from './themes/screen'
import { setupTokenInLocalStorage, deletAuthInfoAction, authUserByTokenAction, keys } from '@twreporter/registration'
import { syncHistoryWithStore } from 'react-router-redux'

// inject global styles into html
injectGlobal`
  html {
    font-size: ${typography.font.size.base};
    ::selection {
      background-color: ${colors.red.lightRed};
      color: $FFF;
    }
  }
  body {
    letter-spacing: ${letterSpace.generalLetterSpace};
    line-height: ${lineHeight.lineHeightMedium};
    font-family: "source-han-sans-traditional", "Noto Sans TC", "PingFang TC", "Apple LiGothic Medium", Roboto, "Microsoft JhengHei", "Lucida Grande", "Lucida Sans Unicode", sans-serif;
    abbr[title], abbr[data-original-title] {
      border-bottom: 0;
    }
    *, :before, :after {
      box-sizing: border-box;
    }

    a, a:link, a:visited {
      text-decoration: none;
    }

    img {
      vertical-align: middle;
    }

    .hidden {
      display: none !important;
    }

    .container {
      line-height: ${lineHeight.linHeightLarge};
    }

    .inner-max {
      ${mq.desktopAbove`
        max-width: ${layout.article.innerWidth};
      `}
    }

    .outer-max {
      ${mq.desktopAbove`
        max-width: ${layout.article.outerWidth};
      `}
    }

    .no-hover {
      border-bottom: 0 !important;
      &:after {
          display: none;
      }
      &:hover:after {
          width: 0;
          display: none;
      }
    }

    .text-justify {
      text-align: justify;
    }

    .text-center {
      text-align: center;
    }

    .center-block {
      display:block;
      margin-left:auto;
      margin-right:auto;
    }

    .visible-print {
      display: none;
    }

    figure, p {
      margin: 0;
    }

    @media print {
      .hidden-print {
        display: none !important;
      }
      .visible-print {
        display: block !important;
      }
      a[href]:after {
        content: '';
      }
    }
  }
`

let reduxState
if (window.__REDUX_STATE__) {
  reduxState = window.__REDUX_STATE__

  let md = new MobileDetect(window.navigator.userAgent)
  if (md.tablet()) {
    reduxState.device = 'tablet'
  } else if (md.mobile()) {
    reduxState.device = 'mobile'
  } else {
    reduxState.device = 'desktop'
  }
}

const store = configureStore(browserHistory, reduxState)

const history = syncHistoryWithStore(browserHistory, store)

// token can be stored in localStorage in two scenario
// 1. TWReporter account sign in
// 2. oAuth
// Acount: store auth info during signin action
// oAuth: cookie -> redux state -> localStorage -> delete authinfo in redux state
// The following procedure is only for oAuth
const { auth } = store.getState()
if(auth.authenticated && auth.authInfo && (auth.authType=== 'facebook' || auth.authType==='google')) {
  setupTokenInLocalStorage(auth.authInfo, keys.LOCALSTORAGE_KEY_AUTH)
  store.dispatch(deletAuthInfoAction())
}

// Check if token existed in localStorage and expired
// following preocedure is for both accoutn and oAuth SignIn
// 30 = 30 days
store.dispatch(authUserByTokenAction(30, auth.authType))

const device = store.getState().device

const routes = createRoutes(history)

if (typeof window !== 'undefined') {
  // add Google Analytics
  ReactGA.initialize('UA-69336956-1')
  ReactGA.set({ page: window.location.pathname })
}

function scrollAndFireTracking() {
  if(window) {
    window.scrollTo(0, 0)
    // send Google Analytics Pageview event on router changed
    ReactGA.pageview(window.location.pathname)
  }
}

// calling `match` is simply for side effects of
// loading route/component code for the initial location
// https://github.com/ReactTraining/react-router/blob/v3/docs/guides/ServerRendering.md#async-routes
match({ history, routes }, (error, redirectLocation, renderProps) => {
  ReactDOM.render((
    <Provider store={store}>
      <DeviceProvider device={device}>
        <Router {...renderProps} onUpdate={scrollAndFireTracking}/>
      </DeviceProvider>
    </Provider>
  ), document.getElementById('root'))
})

/* global __DEVTOOLS__ */
if (__DEVTOOLS__ && !window.__REDUX_DEVTOOLS_EXTENSION__) {
  match({ history, routes  }, (error, redirectLocation, renderProps) => {
    const DevTools = require('./containers/DevTools').default
    ReactDOM.render((
      <Provider store={store}>
        <DeviceProvider device={device}>

            <Router {...renderProps}/>
            <DevTools />

        </DeviceProvider>
      </Provider>
    ), document.getElementById('root'))
  })
}
<commit_msg>Fix duplicated imports<commit_after>import 'babel-polyfill'
import 'normalize.css'
import DeviceProvider from './components/DeviceProvider'
import MobileDetect from 'mobile-detect'
import React from 'react'
import ReactDOM from 'react-dom'
import ReactGA from 'react-ga'
import configureStore from './store/configureStore'
import createRoutes from './routes'
import { Provider } from 'react-redux'
import { Router, match, browserHistory } from 'react-router'
import { colors, layout, letterSpace, lineHeight, typography } from './themes/common-variables'
import { injectGlobal } from 'styled-components'
import { screen as mq } from './themes/screen'
import { setupTokenInLocalStorage, deletAuthInfoAction, authUserByTokenAction, keys } from '@twreporter/registration'
import { syncHistoryWithStore } from 'react-router-redux'

// inject global styles into html
injectGlobal`
  html {
    font-size: ${typography.font.size.base};
    ::selection {
      background-color: ${colors.red.lightRed};
      color: $FFF;
    }
  }
  body {
    letter-spacing: ${letterSpace.generalLetterSpace};
    line-height: ${lineHeight.lineHeightMedium};
    font-family: "source-han-sans-traditional", "Noto Sans TC", "PingFang TC", "Apple LiGothic Medium", Roboto, "Microsoft JhengHei", "Lucida Grande", "Lucida Sans Unicode", sans-serif;
    abbr[title], abbr[data-original-title] {
      border-bottom: 0;
    }
    *, :before, :after {
      box-sizing: border-box;
    }

    a, a:link, a:visited {
      text-decoration: none;
    }

    img {
      vertical-align: middle;
    }

    .hidden {
      display: none !important;
    }

    .container {
      line-height: ${lineHeight.linHeightLarge};
    }

    .inner-max {
      ${mq.desktopAbove`
        max-width: ${layout.article.innerWidth};
      `}
    }

    .outer-max {
      ${mq.desktopAbove`
        max-width: ${layout.article.outerWidth};
      `}
    }

    .no-hover {
      border-bottom: 0 !important;
      &:after {
          display: none;
      }
      &:hover:after {
          width: 0;
          display: none;
      }
    }

    .text-justify {
      text-align: justify;
    }

    .text-center {
      text-align: center;
    }

    .center-block {
      display:block;
      margin-left:auto;
      margin-right:auto;
    }

    .visible-print {
      display: none;
    }

    figure, p {
      margin: 0;
    }

    @media print {
      .hidden-print {
        display: none !important;
      }
      .visible-print {
        display: block !important;
      }
      a[href]:after {
        content: '';
      }
    }
  }
`

let reduxState
if (window.__REDUX_STATE__) {
  reduxState = window.__REDUX_STATE__

  let md = new MobileDetect(window.navigator.userAgent)
  if (md.tablet()) {
    reduxState.device = 'tablet'
  } else if (md.mobile()) {
    reduxState.device = 'mobile'
  } else {
    reduxState.device = 'desktop'
  }
}

const store = configureStore(browserHistory, reduxState)

const history = syncHistoryWithStore(browserHistory, store)

// token can be stored in localStorage in two scenario
// 1. TWReporter account sign in
// 2. oAuth
// Acount: store auth info during signin action
// oAuth: cookie -> redux state -> localStorage -> delete authinfo in redux state
// The following procedure is only for oAuth
const { auth } = store.getState()
if(auth.authenticated && auth.authInfo && (auth.authType=== 'facebook' || auth.authType==='google')) {
  setupTokenInLocalStorage(auth.authInfo, keys.LOCALSTORAGE_KEY_AUTH)
  store.dispatch(deletAuthInfoAction())
}

// Check if token existed in localStorage and expired
// following preocedure is for both accoutn and oAuth SignIn
// 30 = 30 days
store.dispatch(authUserByTokenAction(30, auth.authType))

const device = store.getState().device

const routes = createRoutes(history)

if (typeof window !== 'undefined') {
  // add Google Analytics
  ReactGA.initialize('UA-69336956-1')
  ReactGA.set({ page: window.location.pathname })
}

function scrollAndFireTracking() {
  if(window) {
    window.scrollTo(0, 0)
    // send Google Analytics Pageview event on router changed
    ReactGA.pageview(window.location.pathname)
  }
}

// calling `match` is simply for side effects of
// loading route/component code for the initial location
// https://github.com/ReactTraining/react-router/blob/v3/docs/guides/ServerRendering.md#async-routes
match({ history, routes }, (error, redirectLocation, renderProps) => {
  ReactDOM.render((
    <Provider store={store}>
      <DeviceProvider device={device}>
        <Router {...renderProps} onUpdate={scrollAndFireTracking}/>
      </DeviceProvider>
    </Provider>
  ), document.getElementById('root'))
})

/* global __DEVTOOLS__ */
if (__DEVTOOLS__ && !window.__REDUX_DEVTOOLS_EXTENSION__) {
  match({ history, routes  }, (error, redirectLocation, renderProps) => {
    const DevTools = require('./containers/DevTools').default
    ReactDOM.render((
      <Provider store={store}>
        <DeviceProvider device={device}>

            <Router {...renderProps}/>
            <DevTools />

        </DeviceProvider>
      </Provider>
    ), document.getElementById('root'))
  })
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2016 Kagilum SAS.
 *
 * This file is part of iceScrum.
 *
 * iceScrum is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License.
 *
 * iceScrum is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with iceScrum.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Authors:
 *
 * Vincent Barrier (vbarrier@kagilum.com)
 * Nicolas Noullet (nnoullet@kagilum.com)
 *
 */

registerAppController('chartCtrl', ['$scope', '$element', '$filter', 'Session', 'ProjectService', 'SprintService', 'ReleaseService', function($scope, $element, $filter, Session, ProjectService, SprintService, ReleaseService) {
    $scope.defaultOptions = {
        chart: {
            height: 350
        },
        title: {
            enable: true
        }
    };
    $scope.chartLoaders = {
        project: function(chartName, item) {
            return ProjectService.openChart(item ? item : Session.getProject(), chartName);
        },
        release: function(chartName, item) {
            return ReleaseService.openChart(item, chartName);
        },
        sprint: function(chartName, item) {
            return SprintService.openChart(item, $scope.currentProject ? $scope.currentProject : Session.getProject(), chartName);
        }
    };
    $scope.chartOptions = {
        project: {
            default: {
                chart: {
                    type: 'lineChart',
                    x: function(entry, index) { return index; },
                    y: function(entry) { return entry[0]; },
                    xAxis: {
                        tickFormat: function(entry) {
                            return $scope.labelsX[entry];
                        }
                    }
                }
            },
            flowCumulative: {
                chart: {
                    type: 'stackedAreaChart'
                }
            },
            burndown: {
                chart: {
                    type: 'multiBarChart',
                    stacked: true
                }
            },
            velocity: {
                chart: {
                    type: 'multiBarChart',
                    stacked: true
                }
            },
            parkingLot: {
                chart: {
                    type: 'multiBarHorizontalChart',
                    x: function(entry) { return entry[0]; },
                    y: function(entry) { return entry[1]; },
                    showValues: true,
                    xAxis: {
                        tickFormat: function(entry) {
                            return entry;
                        }
                    }
                }
            }
        },
        release: {
            default: {},
            parkingLot: {
                chart: {
                    type: 'multiBarHorizontalChart',
                    x: function(entry) { return entry[0]; },
                    y: function(entry) { return entry[1]; },
                    showValues: true,
                    xAxis: {
                        tickFormat: function(entry) {
                            return entry;
                        }
                    }
                }
            },
            burndown: {
                chart: {
                    type: 'multiBarChart',
                    x: function(entry, index) { return index; },
                    y: function(entry) { return entry[0]; },
                    stacked: true,
                    xAxis: {
                        tickFormat: function(entry) {
                            return $scope.labelsX[entry];
                        }
                    }
                }
            }
        },
        sprint: {
            default: {
                chart: {
                    type: 'lineChart',
                    x: function(entry) { return entry[0]; },
                    y: function(entry) { return entry[1]; },
                    xScale: d3.time.scale.utc(),
                    xAxis: {
                        tickFormat: $filter('dayShorter')
                    }
                }
            }
        }
    };
    $scope.openChart = function(itemType, chartName, item) {
        $scope.cleanData();
        $scope.options = _.merge({}, $scope.defaultOptions, $scope.chartOptions[itemType]['default'], $scope.chartOptions[itemType][chartName] ? $scope.chartOptions[itemType][chartName] : {});
        $scope.chartLoaders[itemType](chartName, item).then(function(chart) {
            $scope.data = chart.data;
            $scope.options = _.merge($scope.options, chart.options);
            if (chart.labelsX) {
                $scope.labelsX = chart.labelsX;
            }
            if (chart.labelsY) {
                $scope.labelsY = chart.labelsY;
            }
        });
    };
    $scope.saveChart = function() {
        var title = $element.find('.title.h4');
        saveChartAsPng($element.find('svg')[0], {}, title[0], function(imageBase64) {
            // Server side "attachment" content type is needed because the a.download HTML5 feature is not supported in crappy browsers (safari & co).
            jQuery.download($scope.serverUrl + '/saveImage', {'image': imageBase64, 'title': title.text()});
        });
    };
    $scope.cleanData = function() {
        $scope.data = [];
        $scope.labelsX = [];
        $scope.labelsY = [];
        $scope.options = {};
    };
    // Init
    $scope.cleanData();
}]);

controllers.controller('chartWidgetCtrl', ['$scope', 'WidgetService', 'FormService', 'ProjectService', function($scope, WidgetService, FormService, ProjectService) {
    var widget = $scope.widget; // $scope.widget is inherited
    $scope.refreshProjects = function(term) {
        ProjectService.listByUser({term: term, paginate: true}).then(function(projectsAndCount) {
            $scope.projects = projectsAndCount.projects;
            if (!term && widget.settings && widget.settings.project && !_.find($scope.projects, {id: widget.settings.project.id})) {
                $scope.projects.unshift(widget.settings.project);
            }
        });
    };
    $scope.refreshCharts = function() {
        if (!$scope.charts.length) {
            FormService.httpGet('charts/project').then(function(charts) {
                $scope.charts = charts;
            });
        }
    };
    $scope.widgetReady = function(widget) {
        return widget.settings && widget.settings.project && widget.settings.chart ? true : false;
    };
    $scope.getTitle = function() {
        return $scope.widgetReady(widget) ? widget.settings.project.name + ' - ' + widget.settings.chart.group + ' - ' + widget.settings.chart.name : '';
    };
    $scope.projectChanged = function() {
        if (!widget.settings) {
            widget.settings = {};
        }
        widget.settings.project = _.pick($scope.holder.project, ['id', 'name']);
    };
    $scope.chartChanged = function() {
        widget.settings.chart = _.pick($scope.holder.chart, ['id', 'name', 'type', 'group']);
    };
    // Init
    $scope.holder = {};
    $scope.charts = [];
    $scope.projects = [];
    $scope.$watch('widget.settings.project', function(newProject) {
        $scope.holder.project = newProject;
    });
    $scope.$watch('widget.settings.chart', function(newChart) {
        $scope.holder.chart = newChart;
    })
}]);

controllers.controller('chartWidgetChartCtrl', ['$scope', '$element', '$controller', 'ReleaseService', 'SprintService', function($scope, $element, $controller, ReleaseService, SprintService) {
    $controller('chartCtrl', {$scope: $scope, $element: $element});
    $scope.currentProject = $scope.widget.settings.project; // Required to provide a contexte to chart
    switch ($scope.widget.settings.chart.type) {
        case 'project':
            $scope.openChart('project', $scope.widget.settings.chart.id, $scope.currentProject);
            break;
        case 'release':
            ReleaseService.getCurrentOrNextRelease($scope.currentProject).then(function(release) {
                if (release && release.id) {
                    $scope.openChart('release', $scope.widget.settings.chart.id, release);
                }
            });
            break;
        case 'sprint':
            SprintService.getCurrentOrLastSprint($scope.currentProject).then(function(sprint) {
                if (sprint && sprint.id) {
                    $scope.openChart('sprint', $scope.widget.settings.chart.id, sprint);
                }
            });
            break;
    }
}]);<commit_msg>Smoother migration from previous chart widget to new<commit_after>/*
 * Copyright (c) 2016 Kagilum SAS.
 *
 * This file is part of iceScrum.
 *
 * iceScrum is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License.
 *
 * iceScrum is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with iceScrum.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Authors:
 *
 * Vincent Barrier (vbarrier@kagilum.com)
 * Nicolas Noullet (nnoullet@kagilum.com)
 *
 */

registerAppController('chartCtrl', ['$scope', '$element', '$filter', 'Session', 'ProjectService', 'SprintService', 'ReleaseService', function($scope, $element, $filter, Session, ProjectService, SprintService, ReleaseService) {
    $scope.defaultOptions = {
        chart: {
            height: 350
        },
        title: {
            enable: true
        }
    };
    $scope.chartLoaders = {
        project: function(chartName, item) {
            return ProjectService.openChart(item ? item : Session.getProject(), chartName);
        },
        release: function(chartName, item) {
            return ReleaseService.openChart(item, chartName);
        },
        sprint: function(chartName, item) {
            return SprintService.openChart(item, $scope.currentProject ? $scope.currentProject : Session.getProject(), chartName);
        }
    };
    $scope.chartOptions = {
        project: {
            default: {
                chart: {
                    type: 'lineChart',
                    x: function(entry, index) { return index; },
                    y: function(entry) { return entry[0]; },
                    xAxis: {
                        tickFormat: function(entry) {
                            return $scope.labelsX[entry];
                        }
                    }
                }
            },
            flowCumulative: {
                chart: {
                    type: 'stackedAreaChart'
                }
            },
            burndown: {
                chart: {
                    type: 'multiBarChart',
                    stacked: true
                }
            },
            velocity: {
                chart: {
                    type: 'multiBarChart',
                    stacked: true
                }
            },
            parkingLot: {
                chart: {
                    type: 'multiBarHorizontalChart',
                    x: function(entry) { return entry[0]; },
                    y: function(entry) { return entry[1]; },
                    showValues: true,
                    xAxis: {
                        tickFormat: function(entry) {
                            return entry;
                        }
                    }
                }
            }
        },
        release: {
            default: {},
            parkingLot: {
                chart: {
                    type: 'multiBarHorizontalChart',
                    x: function(entry) { return entry[0]; },
                    y: function(entry) { return entry[1]; },
                    showValues: true,
                    xAxis: {
                        tickFormat: function(entry) {
                            return entry;
                        }
                    }
                }
            },
            burndown: {
                chart: {
                    type: 'multiBarChart',
                    x: function(entry, index) { return index; },
                    y: function(entry) { return entry[0]; },
                    stacked: true,
                    xAxis: {
                        tickFormat: function(entry) {
                            return $scope.labelsX[entry];
                        }
                    }
                }
            }
        },
        sprint: {
            default: {
                chart: {
                    type: 'lineChart',
                    x: function(entry) { return entry[0]; },
                    y: function(entry) { return entry[1]; },
                    xScale: d3.time.scale.utc(),
                    xAxis: {
                        tickFormat: $filter('dayShorter')
                    }
                }
            }
        }
    };
    $scope.openChart = function(itemType, chartName, item) {
        $scope.cleanData();
        $scope.options = _.merge({}, $scope.defaultOptions, $scope.chartOptions[itemType]['default'], $scope.chartOptions[itemType][chartName] ? $scope.chartOptions[itemType][chartName] : {});
        $scope.chartLoaders[itemType](chartName, item).then(function(chart) {
            $scope.data = chart.data;
            $scope.options = _.merge($scope.options, chart.options);
            if (chart.labelsX) {
                $scope.labelsX = chart.labelsX;
            }
            if (chart.labelsY) {
                $scope.labelsY = chart.labelsY;
            }
        });
    };
    $scope.saveChart = function() {
        var title = $element.find('.title.h4');
        saveChartAsPng($element.find('svg')[0], {}, title[0], function(imageBase64) {
            // Server side "attachment" content type is needed because the a.download HTML5 feature is not supported in crappy browsers (safari & co).
            jQuery.download($scope.serverUrl + '/saveImage', {'image': imageBase64, 'title': title.text()});
        });
    };
    $scope.cleanData = function() {
        $scope.data = [];
        $scope.labelsX = [];
        $scope.labelsY = [];
        $scope.options = {};
    };
    // Init
    $scope.cleanData();
}]);

controllers.controller('chartWidgetCtrl', ['$scope', 'WidgetService', 'FormService', 'ProjectService', function($scope, WidgetService, FormService, ProjectService) {
    var widget = $scope.widget; // $scope.widget is inherited
    $scope.refreshProjects = function(term) {
        ProjectService.listByUser({term: term, paginate: true}).then(function(projectsAndCount) {
            $scope.projects = projectsAndCount.projects;
            if (!term && widget.settings && widget.settings.project && !_.find($scope.projects, {id: widget.settings.project.id})) {
                $scope.projects.unshift(widget.settings.project);
            }
        });
    };
    $scope.refreshCharts = function() {
        if (!$scope.charts.length) {
            FormService.httpGet('charts/project').then(function(charts) {
                $scope.charts = charts;
            });
        }
    };
    $scope.widgetReady = function(widget) {
        return widget.settings && widget.settings.project && widget.settings.chart ? true : false;
    };
    $scope.getTitle = function() {
        return $scope.widgetReady(widget) ? widget.settings.project.name + ' - ' + (widget.settings.chart.group ? widget.settings.chart.group + ' ' : '') + widget.settings.chart.name : '';
    };
    $scope.projectChanged = function() {
        if (!widget.settings) {
            widget.settings = {};
        }
        widget.settings.project = _.pick($scope.holder.project, ['id', 'name']);
    };
    $scope.chartChanged = function() {
        widget.settings.chart = _.pick($scope.holder.chart, ['id', 'name', 'type', 'group']);
    };
    // Init
    $scope.holder = {};
    $scope.charts = [];
    $scope.projects = [];
    $scope.$watch('widget.settings.project', function(newProject) {
        $scope.holder.project = newProject;
    });
    $scope.$watch('widget.settings.chart', function(newChart) {
        $scope.holder.chart = newChart;
    })
}]);

controllers.controller('chartWidgetChartCtrl', ['$scope', '$element', '$controller', 'ReleaseService', 'SprintService', function($scope, $element, $controller, ReleaseService, SprintService) {
    $controller('chartCtrl', {$scope: $scope, $element: $element});
    $scope.currentProject = $scope.widget.settings.project; // Required to provide a contexte to chart
    switch ($scope.widget.settings.chart.type) {
        case 'release':
            ReleaseService.getCurrentOrNextRelease($scope.currentProject).then(function(release) {
                if (release && release.id) {
                    $scope.openChart('release', $scope.widget.settings.chart.id, release);
                }
            });
            break;
        case 'sprint':
            SprintService.getCurrentOrLastSprint($scope.currentProject).then(function(sprint) {
                if (sprint && sprint.id) {
                    $scope.openChart('sprint', $scope.widget.settings.chart.id, sprint);
                }
            });
            break;
        default:
            $scope.openChart('project', $scope.widget.settings.chart.id, $scope.currentProject);
            break;
    }
}]);<|endoftext|>


<commit_before>//= require /bower_components/d3/d3.min.js
//= require_self

"use strict";

var OpenSpeedMonitor = OpenSpeedMonitor || {};
OpenSpeedMonitor.ChartComponents = OpenSpeedMonitor.ChartComponents || {};

OpenSpeedMonitor.ChartComponents.ChartHeader = (function () {
    var textData = "";
    var width = 500;
    var height = OpenSpeedMonitor.ChartComponents.ChartHeader.Height;
    var transitionDuration = 500;

    var setData = function (data) {
        textData = data.text || textData;
        width = data.width || width;
    };

    var render = function (svg) {
      var text = svg.selectAll(".header-text").data([textData], function (d) { return d; });
      text.exit()
          .transition()
          .duration(transitionDuration)
          .style("opacity", 0)
          .remove();
      text.enter()
          .append("text")
          .classed("header-text", true)
          .attr("text-anchor", "middle")
          .attr("dominant-baseline", "middle")
          .text(function (d) {
              return d;
          })
          .style("opacity", 0);
      text
          .transition()
          .duration(transitionDuration)
          .style("opacity", 1)
          .attr("x", width/2)
          .attr("y", height/2);
    };

    return {
        render: render,
        setData: setData
    };
});
OpenSpeedMonitor.ChartComponents.ChartHeader.Height = 40;

<commit_msg>chartHeader: Align text at bottom of component<commit_after>//= require /bower_components/d3/d3.min.js
//= require_self

"use strict";

var OpenSpeedMonitor = OpenSpeedMonitor || {};
OpenSpeedMonitor.ChartComponents = OpenSpeedMonitor.ChartComponents || {};

OpenSpeedMonitor.ChartComponents.ChartHeader = (function () {
    var textData = "";
    var width = 500;
    var height = OpenSpeedMonitor.ChartComponents.ChartHeader.Height;
    var transitionDuration = 500;

    var setData = function (data) {
        textData = data.text || textData;
        width = data.width || width;
    };

    var render = function (svg) {
      var text = svg.selectAll(".header-text").data([textData], function (d) { return d; });
      text.exit()
          .transition()
          .duration(transitionDuration)
          .style("opacity", 0)
          .remove();
      text.enter()
          .append("text")
          .classed("header-text", true)
          .attr("text-anchor", "middle")
          .attr("dominant-baseline", "alphabetic")
          .text(function (d) {
              return d;
          })
          .style("opacity", 0);
      text
          .transition()
          .duration(transitionDuration)
          .style("opacity", 1)
          .attr("x", width/2)
          .attr("y", height);
    };

    return {
        render: render,
        setData: setData
    };
});
OpenSpeedMonitor.ChartComponents.ChartHeader.Height = 40;

<|endoftext|>


<commit_before>// ERPNext - web based ERP (http://erpnext.com)
// Copyright (C) 2012 Web Notes Technologies Pvt Ltd
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

wn.pages['general-ledger'].onload = function(wrapper) {
	wn.ui.make_app_page({
		parent: wrapper,
		title: 'General Ledger',
		single_column: true
	});

	erpnext.general_ledger = new erpnext.GeneralLedger(wrapper);

}

erpnext.GeneralLedger = wn.views.GridReport.extend({
	init: function(wrapper) {
		this._super({
			title: "General Ledger",
			page: wrapper,
			parent: $(wrapper).find('.layout-main'),
			appframe: wrapper.appframe,
			doctypes: ["Company", "Account", "GL Entry", "Cost Center"],
		});
	},
	setup_columns: function() {
		this.columns = [
			{id: "posting_date", name: "Posting Date", field: "posting_date", width: 100,
				formatter: this.date_formatter},
			{id: "account", name: "Account", field: "account", width: 240,
				link_formatter: {
					filter_input: "account",
					open_btn: true,
					doctype: "'Account'"
				}},
			{id: "against_accont", name: "Against Account", field: "against_account",
				width: 240, hidden: this.is_default("account")},

			{id: "debit", name: "Debit", field: "debit", width: 100,
				formatter: this.currency_formatter},
			{id: "credit", name: "Credit", field: "credit", width: 100,
				formatter: this.currency_formatter},
			{id: "voucher_type", name: "Voucher Type", field: "voucher_type", width: 120},
			{id: "voucher_no", name: "Voucher No", field: "voucher_no", width: 160,
				link_formatter: {
					filter_input: "voucher_no",
					open_btn: true,
					doctype: "dataContext.voucher_type"
				}},
			{id: "remarks", name: "Remarks", field: "remarks", width: 200,
				formatter: this.text_formatter},

		];
	},
	filters: [
		{fieldtype:"Select", label: "Company", link:"Company", default_value: "Select Company...",
			filter: function(val, item, opts) {
				return item.company == val || val == opts.default_value;
			}},
		{fieldtype:"Select", label: "Account", link:"Account",
			default_value: "Select Account...", chosen: true,
			filter: function(val, item, opts, me) {
				if(val == opts.default_value) {
					return true;
				} else {
					// true if GL Entry belongs to selected
					// account ledger or group
					return me.is_child_account(val, item.account);
				}
			}},
		{fieldtype:"Data", label: "Voucher No",
			filter: function(val, item, opts) {
				if(!val) return true;
				return (item.voucher_no && item.voucher_no.indexOf(val)!=-1);
			}},
		{fieldtype:"Date", label: "From Date", filter: function(val, item) {
			return dateutil.str_to_obj(val) <= dateutil.str_to_obj(item.posting_date);
		}},
		{fieldtype:"Label", label: "To"},
		{fieldtype:"Date", label: "To Date", filter: function(val, item) {
			return dateutil.str_to_obj(val) >= dateutil.str_to_obj(item.posting_date);
		}},
		{fieldtype:"Button", label: "Refresh", icon:"icon-refresh icon-white", cssClass:"btn-info"},
		{fieldtype:"Button", label: "Reset Filters"}
	],
	setup_filters: function() {
		this._super();
		var me = this;

		// filter accounts options by company
		var accounts_by_company = this.make_accounts_by_company();
		this.filter_inputs.company && this.filter_inputs.company.change(function() {
			var $filter = me.filter_inputs.account;
			var company = $(this).val();
			var default_company = me.filter_inputs.company.get(0).opts.default_value;
			var default_account = $filter.get(0).opts.default_value;
			var new_options = [default_account].concat(
				$.map(wn.report_dump.data["Account"], function(ac) {
					return (company===default_company ||
						accounts_by_company[company].indexOf(ac.name)!=-1) ?
						ac.name : null;
				}));
			var old_account = me.filter_inputs.account.val();

			$filter.empty().add_options(new_options);

			if((old_account != default_account) && new_options.indexOf(old_account)!=-1) {
				$filter.val(old_account);
			}

			// chosen
			if(me.filter_inputs.company.get(0).opts.chosen) {
				$filter.trigger("liszt:updated");
			}

			me.filter_inputs.refresh.click();
		});

		this.filter_inputs.account && this.filter_inputs.account.change(function() {
			me.filter_inputs.refresh.click();
		});

	},
	init_filter_values: function() {
		this._super();
		this.filter_inputs.company.change();
	},
	apply_filters_from_route: function() {
		this._super();
		this.filter_inputs.company.change();
	},
	make_accounts_by_company: function() {
		var accounts_by_company = {};
		var me = this;
		$.each(wn.report_dump.data["Account"], function(i, ac) {
			if(!accounts_by_company[ac.company]) accounts_by_company[ac.company] = [];
			accounts_by_company[ac.company].push(ac.name);
		});
		return accounts_by_company;
	},
	is_child_account: function(account, item_account) {
		account = this.account_by_name[account];
		item_account = this.account_by_name[item_account];

		return ((item_account.lft >= account.lft) && (item_account.rgt <= account.rgt));
	},
	prepare_data: function() {
		// add Opening, Closing, Totals rows
		// if filtered by account and / or voucher
		var data = wn.report_dump.data["GL Entry"];
		var out = [];

		if(!this.account_by_name) {
			this.account_by_name = this.make_name_map(wn.report_dump.data["Account"]);
			this.make_voucher_acconuts_map();
		}

		var me = this;

		var from_date = dateutil.str_to_obj(this.from_date);
		var to_date = dateutil.str_to_obj(this.to_date);

		if(to_date < from_date) {
			msgprint("From Date must be before To Date");
			return;
		}

		var opening = {
			account: "Opening", debit: 0.0, credit: 0.0,
				id:"_opening", _show: true, _style: "font-weight: bold"
		}
		var totals = {
			account: "Totals", debit: 0.0, credit: 0.0,
				id:"_totals", _show: true, _style: "font-weight: bold"
		}

		$.each(data, function(i, item) {
			if((me.is_default("company") ? true : me.apply_filter(item, "company")) &&
				(!me.is_default("account") ? me.is_child_account(me.account, item.account)
				: true) && (me.voucher_no ? item.voucher_no==me.voucher_no : true)) {
				var date = dateutil.str_to_obj(item.posting_date);

				if(date < from_date || item.is_opening=="Yes") {
					opening.debit += item.debit;
					opening.credit += item.credit;
				} else if(date <= to_date) {
					totals.debit += item.debit;
					totals.credit += item.credit;
				}

				if(me.account) {
					item.against_account = me.voucher_accounts[item.voucher_type + ":"
						+ item.voucher_no][(item.debit > 0 ? "credits" : "debits")].join(", ");
				}

				if(me.apply_filters(item) && item.is_opening=="No") {
					out.push(item);
				}
			}
		})

		var closing = {
			account: "Closing (Opening + Totals)", debit: opening.debit + totals.debit,
				credit: opening.credit + totals.credit,
				id:"_closing", _show: true, _style: "font-weight: bold"
		}

		if(!me.is_default("account")) {
			me.appframe.set_title("General Ledger: " + me.account);

			if(me.account_by_name[me.account].debit_or_credit == "Debit") {
				opening.debit -= opening.credit; opening.credit = 0;
				closing.debit -= closing.credit; closing.credit = 0;
			} else {
				opening.credit -= opening.debit; opening.debit = 0;
				closing.credit -= closing.debit; closing.debit = 0;
			}
			var out = [opening].concat(out).concat([totals, closing]);
		} else {
			me.appframe.set_title("General Ledger");
			var out = out.concat([totals]);
		}

		this.data = out;
	},

	make_voucher_acconuts_map: function() {
		this.voucher_accounts = {};
		var data = wn.report_dump.data["GL Entry"];
		for(var i=0, j=data.length; i<j; i++) {
			var gl = data[i];

			if(!this.voucher_accounts[gl.voucher_type + ":" + gl.voucher_no])
				this.voucher_accounts[gl.voucher_type + ":" + gl.voucher_no] = {
					debits: [],
					credits: []
				}

			var va = this.voucher_accounts[gl.voucher_type + ":" + gl.voucher_no];
			if(gl.debit > 0) {
				va.debits.push(gl.account);
			} else {
				va.credits.push(gl.account);
			}
		}
	},

	get_plot_data: function() {
		var data = [];
		var me = this;
		if(me.is_default("account") || me.voucher_no) return false;
		var debit_or_credit = me.account_by_name[me.account].debit_or_credit;
		var balance = debit_or_credit=="Debit" ? me.data[0].debit : me.data[0].credit;
		data.push({
			label: me.account,
			data: [[dateutil.str_to_obj(me.from_date).getTime(), balance]]
				.concat($.map(me.data, function(col, idx) {
					if (col.posting_date) {
						var diff = (debit_or_credit == "Debit" ? 1 : -1) * (flt(col.debit) - flt(col.credit));
						balance += diff;
						return [[dateutil.str_to_obj(col.posting_date).getTime(), balance - diff],
								[dateutil.str_to_obj(col.posting_date).getTime(), balance]]
					}
					return null;
				})).concat([
					// closing
					[dateutil.str_to_obj(me.to_date).getTime(), balance]
				]),
			points: {show: true},
			lines: {show: true, fill: true},
		});
		return data;
	},
	get_plot_options: function() {
		return {
			grid: { hoverable: true, clickable: true },
			xaxis: { mode: "time",
				min: dateutil.str_to_obj(this.from_date).getTime(),
				max: dateutil.str_to_obj(this.to_date).getTime() }
		}
	},
});<commit_msg>commented out chosen code -- unable to adjust the margin/position correctly<commit_after>// ERPNext - web based ERP (http://erpnext.com)
// Copyright (C) 2012 Web Notes Technologies Pvt Ltd
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

wn.pages['general-ledger'].onload = function(wrapper) {
	wn.ui.make_app_page({
		parent: wrapper,
		title: 'General Ledger',
		single_column: true
	});

	erpnext.general_ledger = new erpnext.GeneralLedger(wrapper);

}

erpnext.GeneralLedger = wn.views.GridReport.extend({
	init: function(wrapper) {
		this._super({
			title: "General Ledger",
			page: wrapper,
			parent: $(wrapper).find('.layout-main'),
			appframe: wrapper.appframe,
			doctypes: ["Company", "Account", "GL Entry", "Cost Center"],
		});
	},
	setup_columns: function() {
		this.columns = [
			{id: "posting_date", name: "Posting Date", field: "posting_date", width: 100,
				formatter: this.date_formatter},
			{id: "account", name: "Account", field: "account", width: 240,
				link_formatter: {
					filter_input: "account",
					open_btn: true,
					doctype: "'Account'"
				}},
			{id: "against_accont", name: "Against Account", field: "against_account",
				width: 240, hidden: this.is_default("account")},

			{id: "debit", name: "Debit", field: "debit", width: 100,
				formatter: this.currency_formatter},
			{id: "credit", name: "Credit", field: "credit", width: 100,
				formatter: this.currency_formatter},
			{id: "voucher_type", name: "Voucher Type", field: "voucher_type", width: 120},
			{id: "voucher_no", name: "Voucher No", field: "voucher_no", width: 160,
				link_formatter: {
					filter_input: "voucher_no",
					open_btn: true,
					doctype: "dataContext.voucher_type"
				}},
			{id: "remarks", name: "Remarks", field: "remarks", width: 200,
				formatter: this.text_formatter},

		];
	},
	filters: [
		{fieldtype:"Select", label: "Company", link:"Company", default_value: "Select Company...",
			filter: function(val, item, opts) {
				return item.company == val || val == opts.default_value;
			}},
		{fieldtype:"Select", label: "Account", link:"Account",
			default_value: "Select Account...", chosen: true,
			filter: function(val, item, opts, me) {
				if(val == opts.default_value) {
					return true;
				} else {
					// true if GL Entry belongs to selected
					// account ledger or group
					return me.is_child_account(val, item.account);
				}
			}},
		{fieldtype:"Data", label: "Voucher No",
			filter: function(val, item, opts) {
				if(!val) return true;
				return (item.voucher_no && item.voucher_no.indexOf(val)!=-1);
			}},
		{fieldtype:"Date", label: "From Date", filter: function(val, item) {
			return dateutil.str_to_obj(val) <= dateutil.str_to_obj(item.posting_date);
		}},
		{fieldtype:"Label", label: "To"},
		{fieldtype:"Date", label: "To Date", filter: function(val, item) {
			return dateutil.str_to_obj(val) >= dateutil.str_to_obj(item.posting_date);
		}},
		{fieldtype:"Button", label: "Refresh", icon:"icon-refresh icon-white", cssClass:"btn-info"},
		{fieldtype:"Button", label: "Reset Filters"}
	],
	setup_filters: function() {
		this._super();
		var me = this;

		// filter accounts options by company
		var accounts_by_company = this.make_accounts_by_company();
		this.filter_inputs.company && this.filter_inputs.company.change(function() {
			var $filter = me.filter_inputs.account;
			var company = $(this).val();
			var default_company = me.filter_inputs.company.get(0).opts.default_value;
			var default_account = $filter.get(0).opts.default_value;
			var new_options = [default_account].concat(
				$.map(wn.report_dump.data["Account"], function(ac) {
					return (company===default_company ||
						accounts_by_company[company].indexOf(ac.name)!=-1) ?
						ac.name : null;
				}));
			var old_account = me.filter_inputs.account.val();

			$filter.empty().add_options(new_options);

			if((old_account != default_account) && new_options.indexOf(old_account)!=-1) {
				$filter.val(old_account);
			}

			// chosen
			// if(me.filter_inputs.company.get(0).opts.chosen) {
			// 	$filter.trigger("liszt:updated");
			// }

			me.filter_inputs.refresh.click();
		});

		this.filter_inputs.account && this.filter_inputs.account.change(function() {
			me.filter_inputs.refresh.click();
		});

	},
	init_filter_values: function() {
		this._super();
		this.filter_inputs.company.change();
	},
	apply_filters_from_route: function() {
		this._super();
		this.filter_inputs.company.change();
	},
	make_accounts_by_company: function() {
		var accounts_by_company = {};
		var me = this;
		$.each(wn.report_dump.data["Account"], function(i, ac) {
			if(!accounts_by_company[ac.company]) accounts_by_company[ac.company] = [];
			accounts_by_company[ac.company].push(ac.name);
		});
		return accounts_by_company;
	},
	is_child_account: function(account, item_account) {
		account = this.account_by_name[account];
		item_account = this.account_by_name[item_account];

		return ((item_account.lft >= account.lft) && (item_account.rgt <= account.rgt));
	},
	prepare_data: function() {
		// add Opening, Closing, Totals rows
		// if filtered by account and / or voucher
		var data = wn.report_dump.data["GL Entry"];
		var out = [];

		if(!this.account_by_name) {
			this.account_by_name = this.make_name_map(wn.report_dump.data["Account"]);
			this.make_voucher_acconuts_map();
		}

		var me = this;

		var from_date = dateutil.str_to_obj(this.from_date);
		var to_date = dateutil.str_to_obj(this.to_date);

		if(to_date < from_date) {
			msgprint("From Date must be before To Date");
			return;
		}

		var opening = {
			account: "Opening", debit: 0.0, credit: 0.0,
				id:"_opening", _show: true, _style: "font-weight: bold"
		}
		var totals = {
			account: "Totals", debit: 0.0, credit: 0.0,
				id:"_totals", _show: true, _style: "font-weight: bold"
		}

		$.each(data, function(i, item) {
			if((me.is_default("company") ? true : me.apply_filter(item, "company")) &&
				(!me.is_default("account") ? me.is_child_account(me.account, item.account)
				: true) && (me.voucher_no ? item.voucher_no==me.voucher_no : true)) {
				var date = dateutil.str_to_obj(item.posting_date);

				if(date < from_date || item.is_opening=="Yes") {
					opening.debit += item.debit;
					opening.credit += item.credit;
				} else if(date <= to_date) {
					totals.debit += item.debit;
					totals.credit += item.credit;
				}

				if(me.account) {
					item.against_account = me.voucher_accounts[item.voucher_type + ":"
						+ item.voucher_no][(item.debit > 0 ? "credits" : "debits")].join(", ");
				}

				if(me.apply_filters(item) && item.is_opening=="No") {
					out.push(item);
				}
			}
		})

		var closing = {
			account: "Closing (Opening + Totals)", debit: opening.debit + totals.debit,
				credit: opening.credit + totals.credit,
				id:"_closing", _show: true, _style: "font-weight: bold"
		}

		if(!me.is_default("account")) {
			me.appframe.set_title("General Ledger: " + me.account);

			if(me.account_by_name[me.account].debit_or_credit == "Debit") {
				opening.debit -= opening.credit; opening.credit = 0;
				closing.debit -= closing.credit; closing.credit = 0;
			} else {
				opening.credit -= opening.debit; opening.debit = 0;
				closing.credit -= closing.debit; closing.debit = 0;
			}
			var out = [opening].concat(out).concat([totals, closing]);
		} else {
			me.appframe.set_title("General Ledger");
			var out = out.concat([totals]);
		}

		this.data = out;
	},

	make_voucher_acconuts_map: function() {
		this.voucher_accounts = {};
		var data = wn.report_dump.data["GL Entry"];
		for(var i=0, j=data.length; i<j; i++) {
			var gl = data[i];

			if(!this.voucher_accounts[gl.voucher_type + ":" + gl.voucher_no])
				this.voucher_accounts[gl.voucher_type + ":" + gl.voucher_no] = {
					debits: [],
					credits: []
				}

			var va = this.voucher_accounts[gl.voucher_type + ":" + gl.voucher_no];
			if(gl.debit > 0) {
				va.debits.push(gl.account);
			} else {
				va.credits.push(gl.account);
			}
		}
	},

	get_plot_data: function() {
		var data = [];
		var me = this;
		if(me.is_default("account") || me.voucher_no) return false;
		var debit_or_credit = me.account_by_name[me.account].debit_or_credit;
		var balance = debit_or_credit=="Debit" ? me.data[0].debit : me.data[0].credit;
		data.push({
			label: me.account,
			data: [[dateutil.str_to_obj(me.from_date).getTime(), balance]]
				.concat($.map(me.data, function(col, idx) {
					if (col.posting_date) {
						var diff = (debit_or_credit == "Debit" ? 1 : -1) * (flt(col.debit) - flt(col.credit));
						balance += diff;
						return [[dateutil.str_to_obj(col.posting_date).getTime(), balance - diff],
								[dateutil.str_to_obj(col.posting_date).getTime(), balance]]
					}
					return null;
				})).concat([
					// closing
					[dateutil.str_to_obj(me.to_date).getTime(), balance]
				]),
			points: {show: true},
			lines: {show: true, fill: true},
		});
		return data;
	},
	get_plot_options: function() {
		return {
			grid: { hoverable: true, clickable: true },
			xaxis: { mode: "time",
				min: dateutil.str_to_obj(this.from_date).getTime(),
				max: dateutil.str_to_obj(this.to_date).getTime() }
		}
	},
});<|endoftext|>


<commit_before>//     oblo-util.js 0.6.4

//     (c) 2014-2011 Martijn M. Schrage, Oblomomov Systems
//     Oblo-util may be freely distributed under the MIT license.
//     For all details and documentation:
//     https://github.com/oblosys/oblo-util

(function(util){ // Cannot have '-' in name, so use 'util' rather than the verbose 'oblo_util'

  // Notes: basic modules, no active importing, mainly experiment for using npm also on client
  // needs to be defined before we call it.
  // NOTE: on client, use last elt of path for object ref, goes wrong with -'s in name.., so need to specify it in that case
  if (typeof window != 'undefined') // on client, NOTE: we have to manually include the required module scripts in the HTML
    window.require = function(moduleName, clientModuleObject) {
      return window[clientModuleObject ? clientModuleObject : moduleName.split('/').pop()];
    };

  var _ = require('underscore', '_'); // underscore calls itself '_' on client

  util.debug = true; // set this to false on deployment

  // Call console.log with all parameters, but only when util.debug == true
  util.log = function() {
    if (util.debug && typeof console != 'undefined')
      var log = Function.prototype.bind.call(console.log, console);
      log.apply(null, Array.prototype.slice.call(arguments));
  };

  util.error = function() {
    if (typeof console != 'undefined')
      var error = Function.prototype.bind.call(console.error, console);
      error.apply(null, Array.prototype.slice.call(arguments));
  };

  // Constrain x to the interval [min .. max]
  util.clip = function(min, max, x) {
    return Math.max(min, Math.min(x, max));
  };

  util.square = function(x) {
    return x*x;
  };

  // NOTE: replicated objects are only cloned on top-level
  util.replicate = function(n,x) {
    var xs = [];
    for (var i=0; i<n; i++)
      xs.push(_.clone(x));
    return xs;
  };

  // pad str with leading c's for a result string of length l (c is assumed to be a character)
  // NOTE: str is not clipped, so result may get longer than l
  util.pad = function(c, l, str) {
    var paddingLength = Math.max(0, l-(''+str).length);
    return util.replicate(paddingLength,c).join('')+str;
  };

  // pad integer with leading 0's when necessary
  util.padZero = function(l, n) {
    return util.pad('0', l, n);
  };

  util.addslashes = function( str ) {
    return (str + '').replace(/[\\"']/g, '\\$&').replace(/\u0000/g, '\\0');
  }

  // optional arg indentStr is to prefix every generated line with indentation
  // optional arg maxDepth is to prevent hanging on circular objects
  util.showJSON = function(json,indentStr,maxDepth) {
    indentStr = indentStr || '';
    maxDepth = typeof maxDepth == 'undefined' ? 20 : maxDepth;
    var str = '';

    if (typeof json == 'undefined') {
      str += 'undefined';
    } else if (json == null) {
      str += 'null';
    } else if (typeof json == 'string') {
      str += '\''+util.addslashes(json)+'\'';
    } else if (typeof json != 'object') {
      str += json;
    } else if (maxDepth<=0) {
      str += Array.isArray(json) ? '[...]' : '{...}';
    } else if (Array.isArray(json)) {
      if (json.length ==0 )
        str += '[]';
      else {
        for (var i = 0; i<json.length; i++)
          str += (i==0 ? '[ ' : indentStr + ', ') + util.showJSON(json[i],indentStr+'  ', maxDepth-1)+'\n';
        str += indentStr + ']';
      }
    } else if (typeof json == 'object') {
      var keys = Object.keys(json); // TODO: use underscore version for safety
      if (keys.length ==0 )
        str += '{}';
      else {
        for (var i = 0; i<keys.length; i++)
          str += (i==0 ? '{ ' : indentStr + ', ') + keys[i] + ':' +
          (typeof json[keys[i]] == 'object' && json[keys[i]] != null ? '\n' + indentStr + '    ' : ' ') + // for object children start new line
          util.showJSON(json[keys[i]], indentStr+'    ', maxDepth-1) + '\n';
        str += indentStr + '}';
      }
    } else {
      console.error('util.showJSON: internal error, unhandled type: \'' + typeof json + '\'');
    }
    return str;
  };

  util.showTime = function(date) {
    return util.padZero(2, date.getHours()) + ':' + util.padZero(2, date.getMinutes()) + ':' + util.padZero(2, date.getSeconds());
  };

  util.showDate = function(date) {
    return util.padZero(2, date.getDate()) + '-' + util.padZero(2, date.getMonth()+1) + '-' + util.padZero(4, date.getFullYear());
  };

  util.readDate = function(dateStr) {
    var parts = dateStr.split('-');
    if (parts.length == 3)
      return new Date(parts[2], parts[1]-1, parts[0]);
    else
      throw 'Exception: Incorrect date: "'+dateStr+'"';
  };

  /* Set boolean DOM attribute for jQuery object $elt according to HTML standard.
   * (absence denotes false, attrName=AttrName denotes true) */
  util.setAttr = function($elt, attrName, isSet) {
    if (isSet)
      $elt.attr(attrName, attrName);
    else
      $elt.removeAttr(attrName);
  };

})(typeof exports == 'undefined' ? this.util={} : exports); // pass exports if we're on the server, otherwise, create object util
<commit_msg>Bump copyright year to 2015<commit_after>//     oblo-util.js 0.6.4

//     (c) 2015-2011 Martijn M. Schrage, Oblomomov Systems
//     Oblo-util may be freely distributed under the MIT license.
//     For all details and documentation:
//     https://github.com/oblosys/oblo-util

(function(util){ // Cannot have '-' in name, so use 'util' rather than the verbose 'oblo_util'

  // Notes: basic modules, no active importing, mainly experiment for using npm also on client
  // needs to be defined before we call it.
  // NOTE: on client, use last elt of path for object ref, goes wrong with -'s in name.., so need to specify it in that case
  if (typeof window != 'undefined') // on client, NOTE: we have to manually include the required module scripts in the HTML
    window.require = function(moduleName, clientModuleObject) {
      return window[clientModuleObject ? clientModuleObject : moduleName.split('/').pop()];
    };

  var _ = require('underscore', '_'); // underscore calls itself '_' on client

  util.debug = true; // set this to false on deployment

  // Call console.log with all parameters, but only when util.debug == true
  util.log = function() {
    if (util.debug && typeof console != 'undefined')
      var log = Function.prototype.bind.call(console.log, console);
      log.apply(null, Array.prototype.slice.call(arguments));
  };

  util.error = function() {
    if (typeof console != 'undefined')
      var error = Function.prototype.bind.call(console.error, console);
      error.apply(null, Array.prototype.slice.call(arguments));
  };

  // Constrain x to the interval [min .. max]
  util.clip = function(min, max, x) {
    return Math.max(min, Math.min(x, max));
  };

  util.square = function(x) {
    return x*x;
  };

  // NOTE: replicated objects are only cloned on top-level
  util.replicate = function(n,x) {
    var xs = [];
    for (var i=0; i<n; i++)
      xs.push(_.clone(x));
    return xs;
  };

  // pad str with leading c's for a result string of length l (c is assumed to be a character)
  // NOTE: str is not clipped, so result may get longer than l
  util.pad = function(c, l, str) {
    var paddingLength = Math.max(0, l-(''+str).length);
    return util.replicate(paddingLength,c).join('')+str;
  };

  // pad integer with leading 0's when necessary
  util.padZero = function(l, n) {
    return util.pad('0', l, n);
  };

  util.addslashes = function( str ) {
    return (str + '').replace(/[\\"']/g, '\\$&').replace(/\u0000/g, '\\0');
  }

  // optional arg indentStr is to prefix every generated line with indentation
  // optional arg maxDepth is to prevent hanging on circular objects
  util.showJSON = function(json,indentStr,maxDepth) {
    indentStr = indentStr || '';
    maxDepth = typeof maxDepth == 'undefined' ? 20 : maxDepth;
    var str = '';

    if (typeof json == 'undefined') {
      str += 'undefined';
    } else if (json == null) {
      str += 'null';
    } else if (typeof json == 'string') {
      str += '\''+util.addslashes(json)+'\'';
    } else if (typeof json != 'object') {
      str += json;
    } else if (maxDepth<=0) {
      str += Array.isArray(json) ? '[...]' : '{...}';
    } else if (Array.isArray(json)) {
      if (json.length ==0 )
        str += '[]';
      else {
        for (var i = 0; i<json.length; i++)
          str += (i==0 ? '[ ' : indentStr + ', ') + util.showJSON(json[i],indentStr+'  ', maxDepth-1)+'\n';
        str += indentStr + ']';
      }
    } else if (typeof json == 'object') {
      var keys = Object.keys(json); // TODO: use underscore version for safety
      if (keys.length ==0 )
        str += '{}';
      else {
        for (var i = 0; i<keys.length; i++)
          str += (i==0 ? '{ ' : indentStr + ', ') + keys[i] + ':' +
          (typeof json[keys[i]] == 'object' && json[keys[i]] != null ? '\n' + indentStr + '    ' : ' ') + // for object children start new line
          util.showJSON(json[keys[i]], indentStr+'    ', maxDepth-1) + '\n';
        str += indentStr + '}';
      }
    } else {
      console.error('util.showJSON: internal error, unhandled type: \'' + typeof json + '\'');
    }
    return str;
  };

  util.showTime = function(date) {
    return util.padZero(2, date.getHours()) + ':' + util.padZero(2, date.getMinutes()) + ':' + util.padZero(2, date.getSeconds());
  };

  util.showDate = function(date) {
    return util.padZero(2, date.getDate()) + '-' + util.padZero(2, date.getMonth()+1) + '-' + util.padZero(4, date.getFullYear());
  };

  util.readDate = function(dateStr) {
    var parts = dateStr.split('-');
    if (parts.length == 3)
      return new Date(parts[2], parts[1]-1, parts[0]);
    else
      throw 'Exception: Incorrect date: "'+dateStr+'"';
  };

  /* Set boolean DOM attribute for jQuery object $elt according to HTML standard.
   * (absence denotes false, attrName=AttrName denotes true) */
  util.setAttr = function($elt, attrName, isSet) {
    if (isSet)
      $elt.attr(attrName, attrName);
    else
      $elt.removeAttr(attrName);
  };

})(typeof exports == 'undefined' ? this.util={} : exports); // pass exports if we're on the server, otherwise, create object util
<|endoftext|>


<commit_before>"use strict";

var OpenSpeedMonitor = OpenSpeedMonitor || {};
OpenSpeedMonitor.MeasurementSetupWizard = OpenSpeedMonitor.MeasurementSetupWizard || {};

OpenSpeedMonitor.MeasurementSetupWizard.CreateJobCard = (function () {

    var predefinedCronSelectBox = $("#selectExecutionSchedule");
    var cronStringInputField = $("#executionSchedule");
    var cronInputValid = true;
    var jobNameInput = $("#inputJobName");
    var existingJobNames = [];
    var inputsValid = false;
    var jobDiv = $("#createJob");
    var defaultJobName = "";
    var jobNameHelpBlock = $("#jobNameHelpBlock");
    var executionScheduleFormGroup = $("#executionScheduleFormGroup");
    var cronInputHelpBlock = $("#cronInputHelpBlock")

    var init = function () {
        // set change listeners
        predefinedCronSelectBox.change(updateCronStringFromPredefined);
        cronStringInputField.keyup(validateCronExpression);
        jobNameInput.change(function() { validateInputs(); });
        jobNameInput.keyup(function() { validateInputs(); });

        // init value
        var initValue = cronStringInputField.val()
        if (initValue) {
            // check if init value is a predefined cron string
            if (isPredefinedCronString(initValue)) {
                predefinedCronSelectBox.val(initValue);
                predefinedCronSelectBox.trigger("chosen:updated");
            } else {
                predefinedCronSelectBox.val("");
                cronStringInputField.val(initValue);
            }
        } else {
            // set default value.
            predefinedCronSelectBox.val(predefinedCronSelectBox.find("option:eq(1)").val());
            updateCronStringFromPredefined();
        }

        getExistingJobNames();
    }

    var isPredefinedCronString = function (cronString) {
        return predefinedCronSelectBox.find("option").is(function (index, elem) {
            return $(elem).val() === cronString;
        });
    }

    var updateCronStringFromPredefined = function () {
        var selectedValue = predefinedCronSelectBox.val();
        cronStringInputField.prop("readonly", !!selectedValue);
        if (!!selectedValue) {
            cronStringInputField.val(selectedValue);
        }
        validateCronExpression();
    }

    var validateJobNameInput = function () {
        var currentJobName = jobNameInput.val();
        var isDuplicateName = isExistingJobName(currentJobName);

        $("#jobNameFormGroup").toggleClass("has-error", !currentJobName);
        jobNameHelpBlock.toggleClass("hidden", !isDuplicateName);

        return currentJobName && !isDuplicateName;
    }

    var isExistingJobName = function (jobName) {
        return existingJobNames.indexOf(jobName) >= 0;
    }

    var validateInputs = function (isInitialCheck) {
        inputsValid = cronInputValid && validateJobNameInput();

        $('#createJobTab').toggleClass("failureText", !inputsValid && !isInitialCheck);

        informListeners();
    }

    var validateCronExpression = function () {
        $.ajax({
            url: OpenSpeedMonitor.urls.cronExpressionNextExecution,
            data: { cronExpression: cronStringInputField.val()},
            dataType: "text",
            type: 'GET',
            success: function (data) {
                processCronExpressionValidation(true, prettyCron.toString(cronStringInputField.val()));
            },
            error: function (e, status) {
                if (status === "error") {
                    processCronExpressionValidation(false, e.responseText);
                } else {
                    console.error(e);
                }
            }
        });
    }

    var processCronExpressionValidation = function (isValid, helpText) {
        cronInputValid = isValid;
        executionScheduleFormGroup.toggleClass("has-error", !isValid);
        cronInputHelpBlock.text(helpText);
        validateInputs();
    }

    var getExistingJobNames = function () {
        var url = OpenSpeedMonitor.urls.getJobNames;

        $.ajax({
            url: url,
            type: 'GET',
            dataType: "json",
            success: function (data) {
                existingJobNames = data;
            },
            error: function (e) {
                throw e;
            },
            traditional: true // grails compatible parameter array encoding
        });
    }

    var informListeners = function () {
        var event = new Event('changed')
        jobDiv.get(0).dispatchEvent(event);
    }

    var isValid = function () {
        return inputsValid;
    }

    var setDefaultJobName = function (newDefault) {
        var oldDefault = defaultJobName;
        defaultJobName = newDefault;
        if (jobNameInput.val() === oldDefault) {
            jobNameInput.val(defaultJobName);
            validateJobNameInput();
        }
    }

    init();
    return {
        isValid: isValid,
        setDefaultJobName: setDefaultJobName,
        validate: validateInputs
    }
})();
OpenSpeedMonitor.MeasurementSetupWizard.CreateJobCard.validate(true);
<commit_msg>Improved first validation of createJob tab<commit_after>"use strict";

var OpenSpeedMonitor = OpenSpeedMonitor || {};
OpenSpeedMonitor.MeasurementSetupWizard = OpenSpeedMonitor.MeasurementSetupWizard || {};

OpenSpeedMonitor.MeasurementSetupWizard.CreateJobCard = (function () {

    var predefinedCronSelectBox = $("#selectExecutionSchedule");
    var cronStringInputField = $("#executionSchedule");
    var cronInputValid = true;
    var jobNameInput = $("#inputJobName");
    var existingJobNames = [];
    var inputsValid = false;
    var jobDiv = $("#createJob");
    var defaultJobName = "";
    var jobNameHelpBlock = $("#jobNameHelpBlock");
    var executionScheduleFormGroup = $("#executionScheduleFormGroup");
    var cronInputHelpBlock = $("#cronInputHelpBlock");
    var createJobNavPill = $('#createJobTab');

    var init = function () {
        // set change listeners
        predefinedCronSelectBox.change(updateCronStringFromPredefined);
        cronStringInputField.keyup(validateCronExpression);
        jobNameInput.change(function() { validateInputs(); });
        jobNameInput.keyup(function() { validateInputs(); });

        // init value
        var initValue = cronStringInputField.val()
        if (initValue) {
            // check if init value is a predefined cron string
            if (isPredefinedCronString(initValue)) {
                predefinedCronSelectBox.val(initValue);
                predefinedCronSelectBox.trigger("chosen:updated");
            } else {
                predefinedCronSelectBox.val("");
                cronStringInputField.val(initValue);
            }
        } else {
            // set default value.
            predefinedCronSelectBox.val(predefinedCronSelectBox.find("option:eq(1)").val());
            updateCronStringFromPredefined();
        }

        getExistingJobNames();
    }

    var isPredefinedCronString = function (cronString) {
        return predefinedCronSelectBox.find("option").is(function (index, elem) {
            return $(elem).val() === cronString;
        });
    }

    var updateCronStringFromPredefined = function () {
        var selectedValue = predefinedCronSelectBox.val();
        cronStringInputField.prop("readonly", !!selectedValue);
        if (!!selectedValue) {
            cronStringInputField.val(selectedValue);
        }
        validateCronExpression();
    }

    var validateJobNameInput = function () {
        var currentJobName = jobNameInput.val();
        var isDuplicateName = isExistingJobName(currentJobName);

        $("#jobNameFormGroup").toggleClass("has-error", !currentJobName);
        jobNameHelpBlock.toggleClass("hidden", !isDuplicateName);

        return currentJobName && !isDuplicateName;
    }

    var isExistingJobName = function (jobName) {
        return existingJobNames.indexOf(jobName) >= 0;
    }

    var validateInputs = function () {
        inputsValid = cronInputValid && validateJobNameInput();
        var cardWasActive = createJobNavPill.parent().hasClass("wasActive");

        createJobNavPill.toggleClass("failureText", !inputsValid && cardWasActive);

        informListeners();
    }

    var validateCronExpression = function () {
        $.ajax({
            url: OpenSpeedMonitor.urls.cronExpressionNextExecution,
            data: { cronExpression: cronStringInputField.val()},
            dataType: "text",
            type: 'GET',
            success: function (data) {
                processCronExpressionValidation(true, prettyCron.toString(cronStringInputField.val()));
            },
            error: function (e, status) {
                if (status === "error") {
                    processCronExpressionValidation(false, e.responseText);
                } else {
                    console.error(e);
                }
            }
        });
    }

    var processCronExpressionValidation = function (isValid, helpText) {
        cronInputValid = isValid;
        executionScheduleFormGroup.toggleClass("has-error", !isValid);
        cronInputHelpBlock.text(helpText);
        validateInputs();
    }

    var getExistingJobNames = function () {
        var url = OpenSpeedMonitor.urls.getJobNames;

        $.ajax({
            url: url,
            type: 'GET',
            dataType: "json",
            success: function (data) {
                existingJobNames = data;
            },
            error: function (e) {
                throw e;
            },
            traditional: true // grails compatible parameter array encoding
        });
    }

    var informListeners = function () {
        var event = new Event('changed')
        jobDiv.get(0).dispatchEvent(event);
    }

    var isValid = function () {
        return inputsValid;
    }

    var setDefaultJobName = function (newDefault) {
        var oldDefault = defaultJobName;
        defaultJobName = newDefault;
        if (jobNameInput.val() === oldDefault) {
            jobNameInput.val(defaultJobName);
            validateInputs();
        }
    }

    init();
    return {
        isValid: isValid,
        setDefaultJobName: setDefaultJobName,
        validateCronExpression: validateCronExpression
    }
})();
OpenSpeedMonitor.MeasurementSetupWizard.CreateJobCard.validateCronExpression();
<|endoftext|>


<commit_before>"use strict";

$(function() {
    $('').css({ left: 78, top: 12 })
                                  .appendTo('#logo');
    $('').css({ left: 87, top: 16 })
                                  .appendTo('#logo');
    $('').css({ left: 105, top: 16 })
                                  .appendTo('#logo');
    $('').css({ left: 121, top: 12 })
                                  .appendTo('#logo');
    $(document).mousemove(function(event) {
        $('#logo img').each(function() {
            var dx = event.pageX - $(this).offset().left - $(this).width() / 2,
                dy = event.pageY - $(this).offset().top - $(this).height() / 2,
                transform = 'rotate(' + Math.atan2(dx, -dy) + 'rad)';
            $(this).css({ transform: transform,
                          '-moz-transform': transform,
                          '-webkit-transform': transform,
                          '-ms-transform': transform,
                          '-o-transform': transform });
        });
    });

    $('#whatis a').click(function() {
        $('#info').slideToggle(0)
                  .css('height', $('#info').height())
                  .slideToggle(0)
                  .slideToggle();
        return false;
    });
    $('#logout button').click(function() {
        localStorage.removeItem('tgtSession');
        window.location.reload(); // XXX
    });

    $('#login').submit(function(e) {
        // Even if we throw an exception, don't submit the form.
        e.preventDefault();

        $('#alert').slideUp(100);
        var username = $('#username')[0].value,
            password = $('#password')[0].value,
            fail = false;
        if(!username) {
            $('#username + .error').fadeIn();
            fail = true;
        } else {
            $('#username + .error').fadeOut();
        }
        if(!password) {
            $('#password + .error').fadeIn();
            fail = true;
        } else {
            $('#password + .error').fadeOut();
        }
        if(fail)
            return false;

        $('#password')[0].value = '';
        var text = $('#submit').text();
        $('#submit').attr('disabled', 'disabled').text('.');
        var interval = setInterval(function() {
            $('#submit').text(($('#submit').text() + '.').replace('.....', '.'));
        }, 500);
        var resetForm = function() {
            clearInterval(interval);
            $('#submit').attr('disabled', null).text(text);
        };
        Q.fcall(function() {
            var principal = KDC.Principal.fromString(username);
            return KDC.getTGTSession(principal, password);
        }).then(function(tgtSession) {
            log(tgtSession);
            // Save in local storage.
            localStorage.setItem('tgtSession', JSON.stringify(tgtSession));

            resetForm();
            $('#login').fadeOut();
            $('#authed').fadeIn();
            // FIXME: Property stringifying of principals
            $('#principal').text(tgtSession.cname.nameString.join('/') + '@' + tgtSession.crealm);
        }, function(error) {
            var string;
            if (error instanceof kcrypto.DecryptionError) {
                string = 'Incorrect password!';
            } else if (error instanceof KDC.Error) {
                if (error.code == krb.KDC_ERR_C_PRINCIPAL_UNKNOWN)
                    string = 'User does not exist!';
                else if (error.code == krb.KDC_ERR_PREAUTH_FAILED ||
                         error.code == krb.KRB_AP_ERR_BAD_INTEGRITY)
                    string = 'Incorrect password!';
                else
                    string = error.message;
            } else {
                string = String(error);
            }
            $('#alert-title').text('Error logging in:');
            $('#alert-text').text(string);
            $('#alert').slideDown(100);
            resetForm();
        }).done();
        return false;
    });

    // Check if we're already logged in.
    if (localStorage.getItem('tgtSession')) {
        var tgtSession = KDC.Session.fromDict(
            JSON.parse(localStorage.getItem('tgtSession')));
        // TODO: check tgtSession.isExpired
        $('#login').hide();
        $('#authed').show();
        // FIXME: Property stringifying of principals
        $('#principal').text(tgtSession.cname.nameString.join('/') + '@' + tgtSession.crealm);
    }
});
<commit_msg>Use KDC.Principal serialization functions<commit_after>"use strict";

$(function() {
    $('').css({ left: 78, top: 12 })
                                  .appendTo('#logo');
    $('').css({ left: 87, top: 16 })
                                  .appendTo('#logo');
    $('').css({ left: 105, top: 16 })
                                  .appendTo('#logo');
    $('').css({ left: 121, top: 12 })
                                  .appendTo('#logo');
    $(document).mousemove(function(event) {
        $('#logo img').each(function() {
            var dx = event.pageX - $(this).offset().left - $(this).width() / 2,
                dy = event.pageY - $(this).offset().top - $(this).height() / 2,
                transform = 'rotate(' + Math.atan2(dx, -dy) + 'rad)';
            $(this).css({ transform: transform,
                          '-moz-transform': transform,
                          '-webkit-transform': transform,
                          '-ms-transform': transform,
                          '-o-transform': transform });
        });
    });

    $('#whatis a').click(function() {
        $('#info').slideToggle(0)
                  .css('height', $('#info').height())
                  .slideToggle(0)
                  .slideToggle();
        return false;
    });
    $('#logout button').click(function() {
        localStorage.removeItem('tgtSession');
        window.location.reload(); // XXX
    });

    $('#login').submit(function(e) {
        // Even if we throw an exception, don't submit the form.
        e.preventDefault();

        $('#alert').slideUp(100);
        var username = $('#username')[0].value,
            password = $('#password')[0].value,
            fail = false;
        if(!username) {
            $('#username + .error').fadeIn();
            fail = true;
        } else {
            $('#username + .error').fadeOut();
        }
        if(!password) {
            $('#password + .error').fadeIn();
            fail = true;
        } else {
            $('#password + .error').fadeOut();
        }
        if(fail)
            return false;

        $('#password')[0].value = '';
        var text = $('#submit').text();
        $('#submit').attr('disabled', 'disabled').text('.');
        var interval = setInterval(function() {
            $('#submit').text(($('#submit').text() + '.').replace('.....', '.'));
        }, 500);
        var resetForm = function() {
            clearInterval(interval);
            $('#submit').attr('disabled', null).text(text);
        };
        var principal = KDC.Principal.fromString(username);
        KDC.getTGTSession(principal, password).then(function(tgtSession) {
            log(tgtSession);
            // Save in local storage.
            localStorage.setItem('tgtSession', JSON.stringify(tgtSession));

            resetForm();
            $('#login').fadeOut();
            $('#authed').fadeIn();
            $('#principal').text(principal.toString());
        }, function(error) {
            var string;
            if (error instanceof kcrypto.DecryptionError) {
                string = 'Incorrect password!';
            } else if (error instanceof KDC.Error) {
                if (error.code == krb.KDC_ERR_C_PRINCIPAL_UNKNOWN)
                    string = 'User does not exist!';
                else if (error.code == krb.KDC_ERR_PREAUTH_FAILED ||
                         error.code == krb.KRB_AP_ERR_BAD_INTEGRITY)
                    string = 'Incorrect password!';
                else
                    string = error.message;
            } else {
                string = String(error);
            }
            $('#alert-title').text('Error logging in:');
            $('#alert-text').text(string);
            $('#alert').slideDown(100);
            resetForm();
        }).done();
        return false;
    });

    // Check if we're already logged in.
    if (localStorage.getItem('tgtSession')) {
        var tgtSession = KDC.Session.fromDict(
            JSON.parse(localStorage.getItem('tgtSession')));
        // TODO: check tgtSession.isExpired
        $('#login').hide();
        $('#authed').show();
        $('#principal').text(new KDC.Principal(tgtSession.cname,
                                               tgtSession.crealm).toString());
    }
});
<|endoftext|>