<commit_before>var moment = require("alloy/moment"),
    _initted = false,
    _toolbar,
    _data,
    _picker,
    _properties = {};

if (arguments[0]) {
    var args = arguments[0];

    if (args.id) {
        exports.id = args.id;
        delete args.id;
    }

    delete args.__parentSymbol;
    delete args.__itemTemplate;
    delete args['$model'];

    applyProperties(arguments[0]);
} else {
    var args = {};
}

/**
 * Setup method for the widget its look & feel
 *
 * @param properties
 */
function applyProperties(properties) {
    var _apply = {};
    properties = properties || {};
    _.extend(_properties, properties);

    if (!_initted) {
        _initted = true;

        if (OS_IOS && _properties.toolbar) {
            _properties.__parent = $;
            _toolbar = Widget.createController('toolbar', _properties);
        }

        if (_toolbar) {
            $.widget.add(_toolbar.toolbar);
            $.widget.addEventListener('pickerCloseClick', hide);
        }

        if (_properties.type && _properties.type == 'PICKER_TYPE_DATE') {
            $.picker.setType(Ti.UI.PICKER_TYPE_DATE);

            if (!_properties.dateFormat) {
                _properties.dateFormat = 'DD-MM-YYYY';
            }

            _apply = _.pick(_properties, 'minDate', 'maxDate', 'value');
            if (_.size(_apply)) {
                $.picker.applyProperties(_apply);
            }
        }
    } else {
        if (OS_IOS && _toolbar) {
            _toolbar.applyProperties(_properties);
        }

        _apply = _.pick(_properties, 'minDate', 'maxDate', 'value');
        if (_.size(_apply)) {
            $.picker.applyProperties(_apply);
        }
    }
}

/**
 * Setup the data collection to be used in the PICKER_TYPE_PLAIN
 * This method is ignored when using PICKER_TYPE_DATE
 *
 * @param data
 */
function setDataCollection(data, selectedIndex) {
    if (isDate()) {
        Ti.API.info('Set data collection cannot be used in combination with dates');
        return;
    }

    _data = data;
    selectedIndex = selectedIndex || 0;

    if (OS_IOS) {
        var opts = [];

        _data.map(function(model) {
            opts.push(Ti.UI.createPickerRow({id: model.get('id'), title: model.get('title')}));
        });

        $.picker.add(opts);
        $.picker.setSelectedRow(0, selectedIndex);
    } else if (OS_ANDROID) {
        var opts = {
            options: _data.pluck('title'),
            selectedIndex: selectedIndex
        };

        $.picker.hide();
        _picker = Ti.UI.createOptionDialog(opts);
        _picker.addEventListener('click', triggerUpdate);
    }
}

/**
 * Show picker, on iOS in the bottom and Android as dialog
 */
function show() {
    if (OS_IOS) {
        $.widget.animate(Ti.UI.createAnimation({
            bottom: 0,
            duration: 300
        }));
    } else {
        if (isDate()) {
            $.picker.showDatePickerDialog({
                callback: function(e) {
                    triggerUpdate(e);
                }});
        } else {
            _picker.show();
        }
    }
}

/**
 * Hide the picker by moving below bottom, and trigger update for callback
 */
function hide() {
    $.widget.animate(Ti.UI.createAnimation({
        bottom: '-'+ $.widget.getHeight(),
        duration: 300
    }));

    triggerUpdate();
}

/**
 * Check if the current constructed picker is of type PICKER_TYPE_DATE
 *
 * @returns {boolean}
 */
function isDate() {
    return ($.picker.getType() == Ti.UI.PICKER_TYPE_DATE);
}

/**
 *
 * @param event
 */
function triggerUpdate(event) {
    var value;
    if (OS_IOS) {
        if (isDate()) {
            value = moment($.picker.getValue()).format(_properties.dateFormat)
        } else {
            value = _data.get($.picker.getSelectedRow(0).id);
        }

    } else if (OS_ANDROID) {
        if (isDate()) {
            value = moment(event.value).format(_properties.dateFormat);
        } else {
            value = _data.at(_picker.getSelectedIndex());
        }
    }
    $.trigger('change', {
        type: "change",
        source: $,
        model: value
    });
}

function cleanup() {
    if (OS_IOS && _properties.toolbar) {
        $.widget.removeEventListener('pickerCloseClick', hide);
    }
}

/*** EXPORTS ***/
exports.applyProperties = applyProperties;
exports.show = show;
exports.hide = hide;
exports.cleanup = cleanup;

exports.setDataCollection = setDataCollection;
Object.defineProperties($, {
    "_data": {
        set: setDataCollection
    }
});

// EVENTS
exports.addEventListener = $.on;
exports.removeEventListener = $.off;
exports.fireEvent = $.trigger;
<commit_msg>Update widget.js<commit_after>var moment = require("alloy/moment"),
    _initted = false,
    _toolbar,
    _data,
    _picker,
    _properties = {};

if (arguments[0]) {
    var args = arguments[0];

    if (args.id) {
        exports.id = args.id;
        delete args.id;
    }

    delete args.__parentSymbol;
    delete args.__itemTemplate;
    delete args['$model'];

    applyProperties(arguments[0]);
} else {
    var args = {};
}

/**
 * Setup method for the widget its look & feel
 *
 * @param properties
 */
function applyProperties(properties) {
    var _apply = {};
    properties = properties || {};
    _.extend(_properties, properties);

    if (!_initted) {
        _initted = true;

        if (OS_IOS && _properties.toolbar) {
            _properties.__parent = $;
            _toolbar = Widget.createController('toolbar', _properties);
        }

        if (_toolbar) {
            $.widget.add(_toolbar.toolbar);
            $.widget.addEventListener('pickerCloseClick', hide);
        }

        if (_properties.type && _properties.type == 'PICKER_TYPE_DATE') {
            $.picker.setType(Ti.UI.PICKER_TYPE_DATE);

            if (!_properties.dateFormat) {
                _properties.dateFormat = 'DD-MM-YYYY';
            }

            _apply = _.pick(_properties, 'minDate', 'maxDate', 'value');
            if (_.size(_apply)) {
                $.picker.applyProperties(_apply);
            }
        }
    } else {
        if (OS_IOS && _toolbar) {
            _toolbar.applyProperties(_properties);
        }

        _apply = _.pick(_properties, 'minDate', 'maxDate', 'value');
        if (_.size(_apply)) {
            $.picker.applyProperties(_apply);
        }
    }
}

/**
 * Setup the data collection to be used in the PICKER_TYPE_PLAIN
 * This method is ignored when using PICKER_TYPE_DATE
 *
 * @param data
 */
function setDataCollection(data, selectedIndex) {
    if (isDate()) {
        Ti.API.info('Set data collection cannot be used in combination with dates');
        return;
    }

    _data = data;
    selectedIndex = selectedIndex || 0;

    if (OS_IOS) {
        var opts = [];

        _data.map(function(model) {
            opts.push(Ti.UI.createPickerRow({id: model.get('id'), title: model.get('title')}));
        });

        $.picker.add(opts);
        $.picker.setSelectedRow(0, selectedIndex);
    } else if (OS_ANDROID) {
        var opts = {
            options: _data.pluck('title'),
            selectedIndex: selectedIndex
        };

        $.picker.hide();
        _picker = Ti.UI.createOptionDialog(opts);
        _picker.addEventListener('click', triggerUpdate);
    }
}

/**
 * Show picker, on iOS in the bottom and Android as dialog
 */
function show() {
    if (OS_IOS) {
        $.widget.animate(Ti.UI.createAnimation({
            bottom: 0,
            duration: 300
        }));
    } else {
        if (isDate()) {
            $.picker.showDatePickerDialog({
                callback: function(e) {
                    triggerUpdate(e);
                }});
        } else {
            _picker.show();
        }
    }
}

/**
 * Hide the picker by moving below bottom, and trigger update for callback
 */
function hide() {
    $.widget.animate(Ti.UI.createAnimation({
        bottom: '-'+ $.widget.getHeight(),
        duration: 300
    }));

    triggerUpdate();
    $.trigger('close', {
        type: "close",
        source: $
    });
}

/**
 * Check if the current constructed picker is of type PICKER_TYPE_DATE
 *
 * @returns {boolean}
 */
function isDate() {
    return ($.picker.getType() == Ti.UI.PICKER_TYPE_DATE);
}

/**
 *
 * @param event
 */
function triggerUpdate(event) {
    var value;
    if (OS_IOS) {
        if (isDate()) {
            value = moment($.picker.getValue()).format(_properties.dateFormat)
        } else {
            value = _data.get($.picker.getSelectedRow(0).id);
        }

    } else if (OS_ANDROID) {
        if (isDate()) {
            value = moment(event.value).format(_properties.dateFormat);
        } else {
            value = _data.at(_picker.getSelectedIndex());
        }
    }
    $.trigger('change', {
        type: "change",
        source: $,
        model: value
    });
}

function cleanup() {
    if (OS_IOS && _properties.toolbar) {
        $.widget.removeEventListener('pickerCloseClick', hide);
    }
}

/*** EXPORTS ***/
exports.applyProperties = applyProperties;
exports.show = show;
exports.hide = hide;
exports.cleanup = cleanup;

exports.setDataCollection = setDataCollection;
Object.defineProperties($, {
    "_data": {
        set: setDataCollection
    }
});

// EVENTS
exports.addEventListener = $.on;
exports.removeEventListener = $.off;
exports.fireEvent = $.trigger;
<|endoftext|>


<commit_before>/**
 * @fileOverview
 * api that invoked by js bundle code
 *
 * - define(name, factory): define a new composed component type
 * - bootstrap(type, config, data): require a certain type &
 *         render with (optional) data
 *
 * deprecated:
 * - register(type, options): register a new composed component type
 * - render(type, data): render by a certain type with (optional) data
 * - require(type)(data): require a type then render with data
 */

import semver from 'semver'
import * as _ from '../util'
import * as config from '../config'
import * as perf from '../perf'
import Vm from '../vm'
import * as downgrade from './downgrade'

const WEEX_COMPONENT_REG = /^\@weex-component\//
const WEEX_MODULE_REG = /^\@weex-module\//
const NORMAL_MODULE_REG = /^\.{1,2}\//
const JS_SURFIX_REG = /\.js$/

const isWeexComponent = name => !!name.match(WEEX_COMPONENT_REG)
const isWeexModule = name => !!name.match(WEEX_MODULE_REG)
const isNormalModule = name => !!name.match(NORMAL_MODULE_REG)
const isNpmModule = name => !isWeexComponent(name) &&
                              !isWeexModule(name) &&
                              !isNormalModule(name)

function removeWeexPrefix(str) {
  return str.replace(WEEX_COMPONENT_REG, '')
          .replace(WEEX_MODULE_REG, '')
}

function removeJSSurfix(str) {
  return str.replace(JS_SURFIX_REG, '')
}

let commonModules = {}

export function clearCommonModules() {
  commonModules = {}
}

// define(name, factory) for primary usage
// or
// define(name, deps, factory) for compatibility
// Notice: DO NOT use function define() {},
// it will cause error after builded by webpack
export var define = function (name, deps, factory) {
  perf.start('define', name)

  if (_.typof(deps) === 'function') {
    factory = deps
    deps = []
  }

  let _require = (name) => {
    let cleanName

    if (isWeexComponent(name)) {
      cleanName = removeWeexPrefix(name)
      return this.requireComponent(cleanName)
    }
    if (isWeexModule(name)) {
      cleanName = removeWeexPrefix(name)
      return this.requireModule(cleanName)
    }
    if (isNormalModule(name)) {
      cleanName = removeJSSurfix(name)
      return commonModules[name]
    }
    if (isNpmModule(name)) {
      cleanName = removeJSSurfix(name)
      return commonModules[name]
    }
  }
  let _module = {exports: {}}

  let cleanName
  if (isWeexComponent(name)) {
    cleanName = removeWeexPrefix(name)

    factory(_require, _module.exports, _module)

    this.registerComponent(cleanName, _module.exports)
  } else if (isWeexModule(name)) {
    cleanName = removeWeexPrefix(name)

    factory(_require, _module.exports, _module)

    Vm.registerModules({
      [cleanName]: _module.exports
    })
  } else if (isNormalModule(name)) {
    cleanName = removeJSSurfix(name)

    factory(_require, _module.exports, _module)

    commonModules[cleanName] = _module.exports
  } else if (isNpmModule(name)) {
    cleanName = removeJSSurfix(name)

    factory(_require, _module.exports, _module)

    let exports = _module.exports
    if (exports.template ||
        exports.style ||
        exports.methods) {
      // downgrade to old define method (define('componentName', factory))
      // the exports contain one key of template, style or methods
      // but it has risk!!!
      this.registerComponent(cleanName, exports)
    } else {
      commonModules[cleanName] = _module.exports
    }
  }

  perf.end('define', name)
}

export function bootstrap(name, config, data) {
  let cleanName

  if (isWeexComponent(name)) {
    cleanName = removeWeexPrefix(name)
  } else if (isNpmModule(name)) {
    cleanName = removeJSSurfix(name)
    // check if define by old 'define' method
    if (!this.customComponentMap[cleanName]) {
      return new Error(`It's not a component: ${name}`)
    }
  } else {
    return new Error(`Wrong component name: ${name}`)
  }

  config = _.isPlainObject(config) ? config : {}

  if (typeof config.transformerVersion === 'string' &&
    typeof global.needTransformerVersion === 'string' &&
    !semver.satisfies(config.transformerVersion,
      global.needTransformerVersion)) {
    return new Error(`JS Bundle version: ${config.transformerVersion} ` +
      `not compatible with ${global.needTransformerVersion}`)
  }

  let _checkDowngrade = downgrade.check(config.downgrade, this.options)
  if (_checkDowngrade.isDowngrade) {
    this.callTasks([{
      module: 'instanceWrap',
      method: 'error',
      args: [
        _checkDowngrade.errorType,
        _checkDowngrade.code,
        _checkDowngrade.errorMessage
      ]
    }])
    return new Error(`Downgrade: ${config.downgrade}`)
  }

  perf.start('create vm', cleanName)

  this.vm = new Vm(cleanName, {_app: this}, null, data, {
    'hook:ready': () => {
      perf.end('create vm', cleanName)
    }
  })
}

/**
 * @deprecated
 */
export function register(type, options) {
  perf.start('register', type)
  this.registerComponent(type, options)
  perf.end('register', type)
}

/**
 * @deprecated
 */
export function render(type, data) {
  return this.bootstrap(type, {}, data)
}

/**
 * @deprecated
 */
export function require(type) {
  return (data) => {
    return this.bootstrap(type, {}, data)
  }
}
<commit_msg>[bugfix] downgrade<commit_after>/**
 * @fileOverview
 * api that invoked by js bundle code
 *
 * - define(name, factory): define a new composed component type
 * - bootstrap(type, config, data): require a certain type &
 *         render with (optional) data
 *
 * deprecated:
 * - register(type, options): register a new composed component type
 * - render(type, data): render by a certain type with (optional) data
 * - require(type)(data): require a type then render with data
 */

import semver from 'semver'
import * as _ from '../util'
import * as config from '../config'
import * as perf from '../perf'
import Vm from '../vm'
import * as downgrade from './downgrade'

const WEEX_COMPONENT_REG = /^\@weex-component\//
const WEEX_MODULE_REG = /^\@weex-module\//
const NORMAL_MODULE_REG = /^\.{1,2}\//
const JS_SURFIX_REG = /\.js$/

const isWeexComponent = name => !!name.match(WEEX_COMPONENT_REG)
const isWeexModule = name => !!name.match(WEEX_MODULE_REG)
const isNormalModule = name => !!name.match(NORMAL_MODULE_REG)
const isNpmModule = name => !isWeexComponent(name) &&
                              !isWeexModule(name) &&
                              !isNormalModule(name)

function removeWeexPrefix(str) {
  return str.replace(WEEX_COMPONENT_REG, '')
          .replace(WEEX_MODULE_REG, '')
}

function removeJSSurfix(str) {
  return str.replace(JS_SURFIX_REG, '')
}

let commonModules = {}

export function clearCommonModules() {
  commonModules = {}
}

// define(name, factory) for primary usage
// or
// define(name, deps, factory) for compatibility
// Notice: DO NOT use function define() {},
// it will cause error after builded by webpack
export var define = function (name, deps, factory) {
  perf.start('define', name)

  if (_.typof(deps) === 'function') {
    factory = deps
    deps = []
  }

  let _require = (name) => {
    let cleanName

    if (isWeexComponent(name)) {
      cleanName = removeWeexPrefix(name)
      return this.requireComponent(cleanName)
    }
    if (isWeexModule(name)) {
      cleanName = removeWeexPrefix(name)
      return this.requireModule(cleanName)
    }
    if (isNormalModule(name)) {
      cleanName = removeJSSurfix(name)
      return commonModules[name]
    }
    if (isNpmModule(name)) {
      cleanName = removeJSSurfix(name)
      return commonModules[name]
    }
  }
  let _module = {exports: {}}

  let cleanName
  if (isWeexComponent(name)) {
    cleanName = removeWeexPrefix(name)

    factory(_require, _module.exports, _module)

    this.registerComponent(cleanName, _module.exports)
  } else if (isWeexModule(name)) {
    cleanName = removeWeexPrefix(name)

    factory(_require, _module.exports, _module)

    Vm.registerModules({
      [cleanName]: _module.exports
    })
  } else if (isNormalModule(name)) {
    cleanName = removeJSSurfix(name)

    factory(_require, _module.exports, _module)

    commonModules[cleanName] = _module.exports
  } else if (isNpmModule(name)) {
    cleanName = removeJSSurfix(name)

    factory(_require, _module.exports, _module)

    let exports = _module.exports
    if (exports.template ||
        exports.style ||
        exports.methods) {
      // downgrade to old define method (define('componentName', factory))
      // the exports contain one key of template, style or methods
      // but it has risk!!!
      this.registerComponent(cleanName, exports)
    } else {
      commonModules[cleanName] = _module.exports
    }
  }

  perf.end('define', name)
}

export function bootstrap(name, config, data) {
  let cleanName

  if (isWeexComponent(name)) {
    cleanName = removeWeexPrefix(name)
  } else if (isNpmModule(name)) {
    cleanName = removeJSSurfix(name)
    // check if define by old 'define' method
    if (!this.customComponentMap[cleanName]) {
      return new Error(`It's not a component: ${name}`)
    }
  } else {
    return new Error(`Wrong component name: ${name}`)
  }

  config = _.isPlainObject(config) ? config : {}

  if (typeof config.transformerVersion === 'string' &&
    typeof global.needTransformerVersion === 'string' &&
    !semver.satisfies(config.transformerVersion,
      global.needTransformerVersion)) {
    return new Error(`JS Bundle version: ${config.transformerVersion} ` +
      `not compatible with ${global.needTransformerVersion}`)
  }

  let _checkDowngrade = downgrade.check(config.downgrade)
  if (_checkDowngrade.isDowngrade) {
    this.callTasks([{
      module: 'instanceWrap',
      method: 'error',
      args: [
        _checkDowngrade.errorType,
        _checkDowngrade.code,
        _checkDowngrade.errorMessage
      ]
    }])
    return new Error(`Downgrade: ${config.downgrade}`)
  }

  perf.start('create vm', cleanName)

  this.vm = new Vm(cleanName, {_app: this}, null, data, {
    'hook:ready': () => {
      perf.end('create vm', cleanName)
    }
  })
}

/**
 * @deprecated
 */
export function register(type, options) {
  perf.start('register', type)
  this.registerComponent(type, options)
  perf.end('register', type)
}

/**
 * @deprecated
 */
export function render(type, data) {
  return this.bootstrap(type, {}, data)
}

/**
 * @deprecated
 */
export function require(type) {
  return (data) => {
    return this.bootstrap(type, {}, data)
  }
}
<|endoftext|>


<commit_before>var pg = require('pg'),
    mongoose = require('mongoose'),
    _ = require('underscore'),
    async = require('async'),
    winston = require('winston'),
    config = require('../server/settings'),
    shortid = require('short-mongo-id'),
    User = require('../server/models').User,
    Group = require('../server/models').Group,
    ForumPost = require('../server/models/forum').ForumPost;

mongoose.connect('mongodb://localhost/nidarholm');
var client = new pg.Client(config.convert.pg);

var log = new (winston.Logger)({
    transports: [
        new (winston.transports.Console)({level: process.env.DEBUG ? 'debug' : 'info'})
    ]
});

client.connect(function(err) {
    if(err) {
        return console.error('could not connect to postgres', err);
    }
    client.query('SELECT * from news_story where parent_id is null order by id', function(err, result) {
        if(err) {
            return console.error('error running query', err);
        }

        async.each(result.rows, function (post, callback) {
            if (!post.title) {
                callback();
            } else {
                var new_post = {
                    title: post.title,
                    created: post.created,
                    modified: post.updated,
                    creator: 'nidarholm.' + post.user_id,
                    original_slug: post.slug,
                    tags: ['nyheter'],
                    mdtext: post.content
                };
                if (!post.group_id) {
                    _.extend(new_post, {permissions: {public: true, groups: [], users: []}});
                    ForumPost.findOneAndUpdate({original_id: post.id+10000}, new_post, function (err, newpost) {
                        log.debug("toppinnlegg: ", post.id);

                        if (!newpost) {
                            _.extend(new_post, {_id: shortid(), original_id: post.id+10000});
                            ForumPost.create(new_post, function (err, newpost) {
                                callback(err);
                            });
                        }
                        else {
                            if (err) {
                                console.error(err, post, newpost);
                            }

                            callback(err);
                        }
                    });
                } else {
                    Group.findOne({old_id: post.group_id}, function (err, group) {
                        _.extend(new_post, {permissions: {public: false, groups: [group.id], users: []}});
                        ForumPost.findOneAndUpdate({original_id: post.id+10000}, new_post, function (err, newpost) {
                            log.debug("toppinnlegg: ", post.id);
                            if (!newpost) {
                                _.extend(new_post, {_id: shortid(), original_id: post.id+10000});
                                ForumPost.create(new_post, function (err, newpost) {
                                    callback(err);
                                });
                            }
                            else {
                                if (err) {
                                    console.error(err, post, newpost);
                                }

                                callback(err);
                            }
                        });
                    });
                }
            }
        }, function (err) {
            if (err) {
                log.error(err);
            }

            client.end();
            mongoose.connection.close();
        });
    });
});
<commit_msg>Wip: Not working<commit_after>var pg = require('pg'),
    mongoose = require('mongoose'),
    _ = require('underscore'),
    async = require('async'),
    winston = require('winston'),
    config = require('../server/settings'),
    shortid = require('short-mongo-id'),
    User = require('../server/models').User,
    Group = require('../server/models').Group,
    File = require('../server/models/files').File,
    ForumPost = require('../server/models/forum').ForumPost;

mongoose.connect('mongodb://localhost/nidarholm');
var client = new pg.Client(config.convert.pg);

var log = new (winston.Logger)({
    transports: [
        new (winston.transports.Console)({level: process.env.DEBUG ? 'debug' : 'info'})
    ]
});

var replacer = function (match, description, path) {
    console.log(match);
    var old_id = path.split("/").shift();
    File.findOne({old_id: old_id}, function (err, file) {
        if (err) {
            throw err;
        }
        if (file) {
            if (!description) {
                description = file.filename;
            }
            var newstring = "[![" + description + "](/files/n/" + file.hash + "/" + file.filename + ")](/files/" + file._id + ")";
            console.log(newstring);
            return newstring;
        }
        else {
            console.log("replaced by nothing");
            return "replaced by nothing";
        }
    });
};

var convert_temporary_markdown_syntax = function (string) {
    var newstring = string.replace(/\!\[(.*?)\]\[(\d+(?:\/\d+)?)\]/g, replacer);
    if (newstring.match(/\!\[/)) {
        console.log(newstring);
    }
    if (newstring.match("replaced by nothing")) {
        console.log("we have replaced");
    }
    return newstring;
};

client.connect(function(err) {
    if(err) {
        return console.error('could not connect to postgres', err);
    }
    client.query('SELECT * from news_story where parent_id is null order by id', function(err, result) {
        if(err) {
            return console.error('error running query', err);
        }

        async.each(result.rows, function (post, callback) {
            if (!post.title) {
                callback();
            } else {
                var new_post = {
                    title: post.title,
                    created: post.created,
                    modified: post.updated,
                    creator: 'nidarholm.' + post.user_id,
                    original_slug: post.slug,
                    tags: ['nyheter'],
                    mdtext: convert_temporary_markdown_syntax(post.content)
                };
                if (!post.group_id) {
                    _.extend(new_post, {permissions: {public: true, groups: [], users: []}});
                    ForumPost.findOneAndUpdate({original_id: post.id+10000}, new_post, function (err, newpost) {
                        log.debug("toppinnlegg: ", post.id);

                        if (!newpost) {
                            _.extend(new_post, {_id: shortid(), original_id: post.id+10000});
                            ForumPost.create(new_post, function (err, newpost) {
                                callback(err);
                            });
                        }
                        else {
                            if (err) {
                                console.error(err, post, newpost);
                            }

                            callback(err);
                        }
                    });
                } else {
                    Group.findOne({old_id: post.group_id}, function (err, group) {
                        _.extend(new_post, {permissions: {public: false, groups: [group.id], users: []}});
                        ForumPost.findOneAndUpdate({original_id: post.id+10000}, new_post, function (err, newpost) {
                            log.debug("toppinnlegg: ", post.id);
                            if (!newpost) {
                                _.extend(new_post, {_id: shortid(), original_id: post.id+10000});
                                ForumPost.create(new_post, function (err, newpost) {
                                    callback(err);
                                });
                            }
                            else {
                                if (err) {
                                    console.error(err, post, newpost);
                                }

                                callback(err);
                            }
                        });
                    });
                }
            }
        }, function (err) {
            if (err) {
                log.error(err);
            }

            client.end();
            mongoose.connection.close();
        });
    });
});
<|endoftext|>


<commit_before>import React from "react"
import { connect } from "react-redux"
import { Route } from 'react-router'
import { ConnectedRouter } from 'react-router-redux'
import InfoKyber from "../../components/InfoKyber"
import { Exchange } from "../../containers/Exchange"
import { Transfer } from "../../containers/Transfer"
import { Header, Rate } from "../../containers/Header"
import { ImportAccount } from "../ImportAccount"

import { Footer } from "../Layout"

import { Processing, ExchangeHistory, TransactionList } from "../../containers/CommonElements/"
import constanst from "../../services/constants"
// import { createNewConnection } from "../../services/ethereum/connection"

import history from "../../history"
import { clearSession, changeLanguage } from "../../actions/globalActions"
import { openInfoModal } from "../../actions/utilActions"
import { setConnection, createNewConnectionInstance } from "../../actions/connectionActions"
import { default as _ } from 'underscore';
import { LayoutView } from "../../components/Layout"
import { getTranslate } from 'react-localize-redux'

import Language from "../../../../lang"

@connect((store) => {
  return {
    ethereumNode: store.connection.ethereum,
    currentBlock: store.global.currentBlock,
    connected: store.global.connected,
    showBalance: store.global.showBalance,
    utils: store.utils,
    account: store.account,
    translate: getTranslate(store.locale),
    locale: store.locale
    // currentLanguage: getActiveLanguage(store.locale).code
  }
})

export default class Layout extends React.Component {
  constructor() {
    super();
    this.idleTime = 0;
    this.timeoutEndSession = constanst.IDLE_TIME_OUT / 10;    // x10 seconds
    this.idleMode = false;
    this.intervalIdle = null;
  }
  componentWillMount() {
    document.onload = this.resetTimmer;
    document.onmousemove = this.resetTimmer;
    document.onmousedown = this.resetTimmer; // touchscreen presses
    document.ontouchstart = this.resetTimmer;
    document.onclick = this.resetTimmer;     // touchpad clicks
    document.onscroll = this.resetTimmer;    // scrolling with arrow keys
    document.onkeypress = this.resetTimmer;

    this.intervalIdle = setInterval(this.checkTimmer.bind(this), 10000)

    this.props.dispatch(createNewConnectionInstance())
    // createNewConnection()
  }

  checkTimmer() {
    if (!this.props.account.account) return;
    if (this.props.utils.infoModal && this.props.utils.infoModal.open) return;
    if (this.idleTime >= this.timeoutEndSession) {
      let timeOut = constanst.IDLE_TIME_OUT/60
      let titleModal = this.props.translate('error.time_out') || 'Time out'
      let contentModal = this.props.translate('error.clear_data_timeout', {time: timeOut}) || `We've cleared all your data because your session is timed out ${timeOut} minutes`
      this.props.dispatch(openInfoModal(titleModal, contentModal));
      this.endSession();
    } else {
      this.idleTime++;
    }
  }

  resetTimmer = _.throttle(this.doResetTimer.bind(this), 5000)

  doResetTimer() {
    this.idleTime = 0;
  }

  endSession() {
    this.props.dispatch(clearSession());
  }

  setActiveLanguage = (language) => {
    this.props.dispatch(changeLanguage(this.props.ethereumNode, language, this.props.locale))
  }

  render() {
    var exchangeHistory = this.props.showBalance?<TransactionList />:""
    var footer = <Footer />
    var rate = <Rate />
    return (
      <LayoutView
        history={history}
        Header={Header}
        ImportAccount={ImportAccount}
        Exchange={Exchange}
        Transfer={Transfer}
        exchangeHistory={exchangeHistory}
        supportedLanguages={Language.supportLanguage}
        setActiveLanguage={this.setActiveLanguage}
        rate={rate}
        footer = {footer}
      />
    )
  }
}
<commit_msg>fix txs list<commit_after>import React from "react"
import { connect } from "react-redux"
import { Route } from 'react-router'
import { ConnectedRouter } from 'react-router-redux'
import InfoKyber from "../../components/InfoKyber"
import { Exchange } from "../../containers/Exchange"
import { Transfer } from "../../containers/Transfer"
import { Header, Rate } from "../../containers/Header"
import { ImportAccount } from "../ImportAccount"

import { Footer } from "../Layout"

import { Processing, ExchangeHistory, TransactionList } from "../../containers/CommonElements/"
import constanst from "../../services/constants"
// import { createNewConnection } from "../../services/ethereum/connection"

import history from "../../history"
import { clearSession, changeLanguage } from "../../actions/globalActions"
import { openInfoModal } from "../../actions/utilActions"
import { setConnection, createNewConnectionInstance } from "../../actions/connectionActions"
import { default as _ } from 'underscore';
import { LayoutView } from "../../components/Layout"
import { getTranslate } from 'react-localize-redux'

import Language from "../../../../lang"

@connect((store) => {
  return {
    ethereumNode: store.connection.ethereum,
    currentBlock: store.global.currentBlock,
    connected: store.global.connected,
    showBalance: store.global.showBalance,
    utils: store.utils,
    account: store.account,
    translate: getTranslate(store.locale),
    locale: store.locale
    // currentLanguage: getActiveLanguage(store.locale).code
  }
})

export default class Layout extends React.Component {
  constructor() {
    super();
    this.idleTime = 0;
    this.timeoutEndSession = constanst.IDLE_TIME_OUT / 10;    // x10 seconds
    this.idleMode = false;
    this.intervalIdle = null;
  }
  componentWillMount() {
    document.onload = this.resetTimmer;
    document.onmousemove = this.resetTimmer;
    document.onmousedown = this.resetTimmer; // touchscreen presses
    document.ontouchstart = this.resetTimmer;
    document.onclick = this.resetTimmer;     // touchpad clicks
    document.onscroll = this.resetTimmer;    // scrolling with arrow keys
    document.onkeypress = this.resetTimmer;

    this.intervalIdle = setInterval(this.checkTimmer.bind(this), 10000)

    this.props.dispatch(createNewConnectionInstance())
    // createNewConnection()
  }

  checkTimmer() {
    if (!this.props.account.account) return;
    if (this.props.utils.infoModal && this.props.utils.infoModal.open) return;
    if (this.idleTime >= this.timeoutEndSession) {
      let timeOut = constanst.IDLE_TIME_OUT/60
      let titleModal = this.props.translate('error.time_out') || 'Time out'
      let contentModal = this.props.translate('error.clear_data_timeout', {time: timeOut}) || `We've cleared all your data because your session is timed out ${timeOut} minutes`
      this.props.dispatch(openInfoModal(titleModal, contentModal));
      this.endSession();
    } else {
      this.idleTime++;
    }
  }

  resetTimmer = _.throttle(this.doResetTimer.bind(this), 5000)

  doResetTimer() {
    this.idleTime = 0;
  }

  endSession() {
    this.props.dispatch(clearSession());
  }

  setActiveLanguage = (language) => {
    this.props.dispatch(changeLanguage(this.props.ethereumNode, language, this.props.locale))
  }

  render() {
    var exchangeHistory = <TransactionList />
    var footer = <Footer />
    var rate = <Rate />
    return (
      <LayoutView
        history={history}
        Header={Header}
        ImportAccount={ImportAccount}
        Exchange={Exchange}
        Transfer={Transfer}
        exchangeHistory={exchangeHistory}
        supportedLanguages={Language.supportLanguage}
        setActiveLanguage={this.setActiveLanguage}
        rate={rate}
        footer = {footer}
      />
    )
  }
}
<|endoftext|>


<commit_before>import classNames from 'classnames';
import {Confirm} from 'reactjs-components';
import mixin from 'reactjs-mixin';
import prettycron from 'prettycron';
/* eslint-disable no-unused-vars */
import React from 'react';
/* eslint-enable no-unused-vars */
import {routerShape} from 'react-router';

import {StoreMixin} from 'mesosphere-shared-reactjs';

import Icon from '../../components/Icon';
import JobConfiguration from './JobConfiguration';
import JobFormModal from '../../components/modals/JobFormModal';
import JobRunHistoryTable from './JobRunHistoryTable';
import JobsBreadcrumbs from '../../components/breadcrumbs/JobsBreadcrumbs';
import Loader from '../../components/Loader';
import MetronomeStore from '../../stores/MetronomeStore';
import Page from '../../components/Page';
import RequestErrorMsg from '../../components/RequestErrorMsg';
import StringUtil from '../../utils/StringUtil';
import TabsMixin from '../../mixins/TabsMixin';
import TimeAgo from '../../components/TimeAgo';
import TaskStates from '../../../../plugins/services/src/js/constants/TaskStates';

const METHODS_TO_BIND = [
  'closeDialog',
  'handleEditButtonClick',
  'handleRunNowButtonClick',
  'handleDisableScheduleButtonClick',
  'handleEnableScheduleButtonClick',
  'handleDestroyButtonClick',
  'onMetronomeStoreJobDeleteError',
  'onMetronomeStoreJobDeleteSuccess',
  'onMetronomeStoreJobDetailError',
  'onMetronomeStoreJobDetailChange'
];

const DIALOGS = {
  EDIT: 'edit',
  DESTROY: 'destroy'
};

class JobDetailPage extends mixin(StoreMixin, TabsMixin) {
  constructor() {
    super(...arguments);

    this.store_listeners = [{
      name: 'metronome',
      events: [
        'jobDeleteSuccess',
        'jobDeleteError',
        'jobDetailChange',
        'jobDetailError',
        'jobRunError',
        'jobRunSuccess',
        'jobScheduleUpdateError',
        'jobScheduleUpdateSuccess'
      ],
      suppressUpdate: false
    }];

    this.tabs_tabs = {
      runHistory: 'Run History',
      configuration: 'Configuration'
    };

    this.state = {
      currentTab: Object.keys(this.tabs_tabs).shift(),
      disabledDialog: null,
      jobActionDialog: null,
      errorMsg: null,
      errorCount: 0,
      isJobFormModalOpen: false,
      isLoading: true
    };

    METHODS_TO_BIND.forEach((method) => {
      this[method] = this[method].bind(this);
    });
  }

  componentDidMount() {
    super.componentDidMount(...arguments);
    MetronomeStore.monitorJobDetail(this.props.params.id);
  }

  componentWillUnmount() {
    super.componentWillUnmount(...arguments);
    MetronomeStore.stopJobDetailMonitor(this.props.params.id);
  }

  onMetronomeStoreJobDeleteError(id, {message:errorMsg}) {
    if (id !== this.props.params.id || errorMsg == null) {
      return;
    }

    this.setState({
      jobActionDialog: DIALOGS.DESTROY,
      disabledDialog: null,
      errorMsg
    });
  }

  onMetronomeStoreJobDeleteSuccess() {
    this.closeDialog();
    this.context.router.push('/jobs');
  }

  onMetronomeStoreJobDetailError() {
    this.setState({errorCount: this.state.errorCount + 1});
  }

  onMetronomeStoreJobDetailChange() {
    this.setState({errorCount: 0, isLoading: false});
  }

  handleEditButtonClick() {
    this.setState({jobActionDialog: DIALOGS.EDIT});
  }

  handleRunNowButtonClick() {
    const job = MetronomeStore.getJob(this.props.params.id);

    MetronomeStore.runJob(job.getId());
  }

  handleDisableScheduleButtonClick() {
    MetronomeStore.toggleSchedule(this.props.params.id, false);
  };

  handleEnableScheduleButtonClick() {
    MetronomeStore.toggleSchedule(this.props.params.id, true);
  };

  handleDestroyButtonClick() {
    this.setState({jobActionDialog: DIALOGS.DESTROY});
  };

  handleAcceptDestroyDialog(stopCurrentJobRuns = false) {
    this.setState({disabledDialog: DIALOGS.DESTROY}, () => {
      MetronomeStore.deleteJob(this.props.params.id, stopCurrentJobRuns);
    });
  }

  handleMoreDropdownSelection(selection) {
    if (selection.id === DIALOGS.SCHEDULE_DISABLE) {
      MetronomeStore.toggleSchedule(this.props.params.id, false);
      return;
    }

    if (selection.id === DIALOGS.SCHEDULE_ENABLE) {
      MetronomeStore.toggleSchedule(this.props.params.id, true);
      return;
    }

    this.setState({jobActionDialog: selection.id});
  }

  closeDialog() {
    this.setState({
      disabledDialog: null,
      errorMsg: null,
      jobActionDialog: null
    });
  }

  getDestroyConfirmDialog() {
    const {id} = this.props.params;
    const {disabledDialog, jobActionDialog, errorMsg} = this.state;
    let stopCurrentJobRuns = false;
    let actionButtonLabel = 'Destroy Job';
    let message = `Are you sure you want to destroy ${id}? ` +
      'This action is irreversible.';

    if (/stopCurrentJobRuns=true/.test(errorMsg)) {
      actionButtonLabel = 'Stop Current Runs and Destroy Job';
      stopCurrentJobRuns = true;
      message = `Couldn't destroy ${id} as there are currently active job ` +
        'runs. Do you want to stop all runs and destroy the job?';
    }

    let content = (

          Destroy Job

{message}

    );

    return (
      <Confirm children={content}
        disabled={disabledDialog === DIALOGS.DESTROY}
        open={jobActionDialog === DIALOGS.DESTROY}
        onClose={this.closeDialog}
        leftButtonText="Cancel"
        leftButtonCallback={this.closeDialog}
        rightButtonText={actionButtonLabel}
        rightButtonClassName="button button-danger"
        rightButtonCallback=
          {this.handleAcceptDestroyDialog.bind(this, stopCurrentJobRuns)} />
    );
  }

  getErrorScreen() {
    return (

        <RequestErrorMsg />

    );
  }

  getLoadingScreen() {
    return (
      <Page>
        <Page.Header breadcrumbs={<JobsBreadcrumbs/>} />
        <Loader />
      </Page>
    );
  }

  getNavigationTabs() {
    return (

        {this.tabs_getUnroutedTabs()}

    );
  }

  getPrettySchedule(job) {
    const schedules = job.getSchedules();
    if (schedules == null || schedules.length === 0) {
      return null;
    }

    const schedule = schedules[0];
    if (schedule.enabled) {
      return prettycron.toString(schedule.cron);
    }
  }

  getJobStatus(job) {
    let longestRunningTask = null;
    const longestRunningActiveRun = job.getActiveRuns()
      .getLongestRunningActiveRun();

    if (longestRunningActiveRun != null) {
      longestRunningTask = longestRunningActiveRun.getTasks()
        .getLongestRunningTask();
    }

    if (longestRunningTask == null) {
      return null;
    }

    const status = TaskStates[longestRunningTask.getStatus()];
    return status.displayName;
  }

  getSubTitle(job) {
    const nodes = [];
    const scheduleText = this.getPrettySchedule(job);
    let longestRunningTask = null;
    const longestRunningActiveRun = job.getActiveRuns()
      .getLongestRunningActiveRun();

    if (longestRunningActiveRun != null) {
      longestRunningTask = longestRunningActiveRun.getTasks()
        .getLongestRunningTask();
    }

    if (longestRunningTask == null && scheduleText == null) {
      return null;
    }

    if (scheduleText != null) {
      nodes.push(

          <Icon
            className="icon-margin-right"
            key="schedule-icon"
            color="grey"
            id="repeat"
            size="mini" />
          Scheduled {StringUtil.lowercase(scheduleText)}

      );
    }

    if (longestRunningTask != null) {
      const dateCompleted = longestRunningTask.getDateCompleted();

      const status = TaskStates[longestRunningTask.getStatus()];
      let statusClasses = classNames('job-details-header-status', {
        'text-success': status.stateTypes.includes('success')
        && !status.stateTypes.includes('failure'),
        'text-danger': status.stateTypes.includes('failure')
      });

      let timePrefix = null;
      let shouldSuppressRelativeTime = dateCompleted == null;

      if (shouldSuppressRelativeTime) {
        timePrefix = 'for ';
      }

      nodes.push(

          {status.displayName}
        ,

          <TimeAgo
            prefix={timePrefix}
            suppressSuffix={shouldSuppressRelativeTime}
            time={longestRunningActiveRun.getDateCreated()} />

      );
    }

    return nodes;
  }

  renderConfigurationTabView(job) {
    return <JobConfiguration job={job} />;
  }

  renderRunHistoryTabView(job) {
    return <JobRunHistoryTable job={job} />;
  }

  getActions() {
    const job = MetronomeStore.getJob(this.props.params.id);
    const [schedule] = job.getSchedules();

    const actions = [];

    actions.push({
      label: 'Edit',
      onItemSelect: this.handleEditButtonClick
    });

    actions.push({
      label: 'Run Now',
      onItemSelect: this.handleRunNowButtonClick
    });

    if (schedule != null && schedule.enabled) {
      actions.push({
        label: 'Disable Schedule',
        onItemSelect: this.handleDisableScheduleButtonClick
      });
    }

    if (schedule != null && !schedule.enabled) {
      actions.push({
        label: 'Enable Schedule',
        onItemSelect: this.handleEnableScheduleButtonClick
      });
    }

    actions.push({
      className: 'text-danger',
      label: 'Destroy',
      onItemSelect: this.handleDestroyButtonClick
    });

    return actions;
  }

  getTabs() {
    const activeTab = this.state.currentTab;

    return [
      {
        label: 'Run History',
        callback: () => { this.setState({currentTab: 'runHistory'}); },
        isActive: activeTab === 'runHistory'
      },
      {
        label: 'Configuration',
        callback: () => { this.setState({currentTab: 'configuration'}); },
        isActive: activeTab === 'configuration'
      }
    ];
  }

  render() {
    if (this.state.errorCount > 3) {
      return this.getErrorScreen();
    }

    if (this.state.isLoading) {
      return this.getLoadingScreen();
    }

    // TaskDetailView
    if (this.props.params.taskID) {
      return this.props.children;
    }

    let job = MetronomeStore.getJob(this.props.params.id);
    const jobStatus = this.getJobStatus(job);

    return (
      <Page>
        <Page.Header
          actions={this.getActions()}
          breadcrumbs={<JobsBreadcrumbs jobID={job.getId()} jobStatus={jobStatus} />}
          tabs={this.getTabs()} />
        {this.tabs_getTabView(job)}
        <JobFormModal isEdit={true}
          job={job}
          open={this.state.jobActionDialog === DIALOGS.EDIT}
          onClose={this.closeDialog} />
        {this.getDestroyConfirmDialog()}
      </Page>
    );
  }
}

JobDetailPage.contextTypes = {
  router: routerShape
};

module.exports = JobDetailPage;
<commit_msg>Add a new line before return<commit_after>import classNames from 'classnames';
import {Confirm} from 'reactjs-components';
import mixin from 'reactjs-mixin';
import prettycron from 'prettycron';
/* eslint-disable no-unused-vars */
import React from 'react';
/* eslint-enable no-unused-vars */
import {routerShape} from 'react-router';

import {StoreMixin} from 'mesosphere-shared-reactjs';

import Icon from '../../components/Icon';
import JobConfiguration from './JobConfiguration';
import JobFormModal from '../../components/modals/JobFormModal';
import JobRunHistoryTable from './JobRunHistoryTable';
import JobsBreadcrumbs from '../../components/breadcrumbs/JobsBreadcrumbs';
import Loader from '../../components/Loader';
import MetronomeStore from '../../stores/MetronomeStore';
import Page from '../../components/Page';
import RequestErrorMsg from '../../components/RequestErrorMsg';
import StringUtil from '../../utils/StringUtil';
import TabsMixin from '../../mixins/TabsMixin';
import TimeAgo from '../../components/TimeAgo';
import TaskStates from '../../../../plugins/services/src/js/constants/TaskStates';

const METHODS_TO_BIND = [
  'closeDialog',
  'handleEditButtonClick',
  'handleRunNowButtonClick',
  'handleDisableScheduleButtonClick',
  'handleEnableScheduleButtonClick',
  'handleDestroyButtonClick',
  'onMetronomeStoreJobDeleteError',
  'onMetronomeStoreJobDeleteSuccess',
  'onMetronomeStoreJobDetailError',
  'onMetronomeStoreJobDetailChange'
];

const DIALOGS = {
  EDIT: 'edit',
  DESTROY: 'destroy'
};

class JobDetailPage extends mixin(StoreMixin, TabsMixin) {
  constructor() {
    super(...arguments);

    this.store_listeners = [{
      name: 'metronome',
      events: [
        'jobDeleteSuccess',
        'jobDeleteError',
        'jobDetailChange',
        'jobDetailError',
        'jobRunError',
        'jobRunSuccess',
        'jobScheduleUpdateError',
        'jobScheduleUpdateSuccess'
      ],
      suppressUpdate: false
    }];

    this.tabs_tabs = {
      runHistory: 'Run History',
      configuration: 'Configuration'
    };

    this.state = {
      currentTab: Object.keys(this.tabs_tabs).shift(),
      disabledDialog: null,
      jobActionDialog: null,
      errorMsg: null,
      errorCount: 0,
      isJobFormModalOpen: false,
      isLoading: true
    };

    METHODS_TO_BIND.forEach((method) => {
      this[method] = this[method].bind(this);
    });
  }

  componentDidMount() {
    super.componentDidMount(...arguments);
    MetronomeStore.monitorJobDetail(this.props.params.id);
  }

  componentWillUnmount() {
    super.componentWillUnmount(...arguments);
    MetronomeStore.stopJobDetailMonitor(this.props.params.id);
  }

  onMetronomeStoreJobDeleteError(id, {message:errorMsg}) {
    if (id !== this.props.params.id || errorMsg == null) {
      return;
    }

    this.setState({
      jobActionDialog: DIALOGS.DESTROY,
      disabledDialog: null,
      errorMsg
    });
  }

  onMetronomeStoreJobDeleteSuccess() {
    this.closeDialog();
    this.context.router.push('/jobs');
  }

  onMetronomeStoreJobDetailError() {
    this.setState({errorCount: this.state.errorCount + 1});
  }

  onMetronomeStoreJobDetailChange() {
    this.setState({errorCount: 0, isLoading: false});
  }

  handleEditButtonClick() {
    this.setState({jobActionDialog: DIALOGS.EDIT});
  }

  handleRunNowButtonClick() {
    const job = MetronomeStore.getJob(this.props.params.id);

    MetronomeStore.runJob(job.getId());
  }

  handleDisableScheduleButtonClick() {
    MetronomeStore.toggleSchedule(this.props.params.id, false);
  };

  handleEnableScheduleButtonClick() {
    MetronomeStore.toggleSchedule(this.props.params.id, true);
  };

  handleDestroyButtonClick() {
    this.setState({jobActionDialog: DIALOGS.DESTROY});
  };

  handleAcceptDestroyDialog(stopCurrentJobRuns = false) {
    this.setState({disabledDialog: DIALOGS.DESTROY}, () => {
      MetronomeStore.deleteJob(this.props.params.id, stopCurrentJobRuns);
    });
  }

  handleMoreDropdownSelection(selection) {
    if (selection.id === DIALOGS.SCHEDULE_DISABLE) {
      MetronomeStore.toggleSchedule(this.props.params.id, false);
      return;
    }

    if (selection.id === DIALOGS.SCHEDULE_ENABLE) {
      MetronomeStore.toggleSchedule(this.props.params.id, true);
      return;
    }

    this.setState({jobActionDialog: selection.id});
  }

  closeDialog() {
    this.setState({
      disabledDialog: null,
      errorMsg: null,
      jobActionDialog: null
    });
  }

  getDestroyConfirmDialog() {
    const {id} = this.props.params;
    const {disabledDialog, jobActionDialog, errorMsg} = this.state;
    let stopCurrentJobRuns = false;
    let actionButtonLabel = 'Destroy Job';
    let message = `Are you sure you want to destroy ${id}? ` +
      'This action is irreversible.';

    if (/stopCurrentJobRuns=true/.test(errorMsg)) {
      actionButtonLabel = 'Stop Current Runs and Destroy Job';
      stopCurrentJobRuns = true;
      message = `Couldn't destroy ${id} as there are currently active job ` +
        'runs. Do you want to stop all runs and destroy the job?';
    }

    let content = (

          Destroy Job

{message}

    );

    return (
      <Confirm children={content}
        disabled={disabledDialog === DIALOGS.DESTROY}
        open={jobActionDialog === DIALOGS.DESTROY}
        onClose={this.closeDialog}
        leftButtonText="Cancel"
        leftButtonCallback={this.closeDialog}
        rightButtonText={actionButtonLabel}
        rightButtonClassName="button button-danger"
        rightButtonCallback=
          {this.handleAcceptDestroyDialog.bind(this, stopCurrentJobRuns)} />
    );
  }

  getErrorScreen() {
    return (

        <RequestErrorMsg />

    );
  }

  getLoadingScreen() {
    return (
      <Page>
        <Page.Header breadcrumbs={<JobsBreadcrumbs/>} />
        <Loader />
      </Page>
    );
  }

  getNavigationTabs() {
    return (

        {this.tabs_getUnroutedTabs()}

    );
  }

  getPrettySchedule(job) {
    const schedules = job.getSchedules();
    if (schedules == null || schedules.length === 0) {
      return null;
    }

    const schedule = schedules[0];
    if (schedule.enabled) {
      return prettycron.toString(schedule.cron);
    }
  }

  getJobStatus(job) {
    let longestRunningTask = null;
    const longestRunningActiveRun = job.getActiveRuns()
      .getLongestRunningActiveRun();

    if (longestRunningActiveRun != null) {
      longestRunningTask = longestRunningActiveRun.getTasks()
        .getLongestRunningTask();
    }

    if (longestRunningTask == null) {
      return null;
    }

    const status = TaskStates[longestRunningTask.getStatus()];

    return status.displayName;
  }

  getSubTitle(job) {
    const nodes = [];
    const scheduleText = this.getPrettySchedule(job);
    let longestRunningTask = null;
    const longestRunningActiveRun = job.getActiveRuns()
      .getLongestRunningActiveRun();

    if (longestRunningActiveRun != null) {
      longestRunningTask = longestRunningActiveRun.getTasks()
        .getLongestRunningTask();
    }

    if (longestRunningTask == null && scheduleText == null) {
      return null;
    }

    if (scheduleText != null) {
      nodes.push(

          <Icon
            className="icon-margin-right"
            key="schedule-icon"
            color="grey"
            id="repeat"
            size="mini" />
          Scheduled {StringUtil.lowercase(scheduleText)}

      );
    }

    if (longestRunningTask != null) {
      const dateCompleted = longestRunningTask.getDateCompleted();

      const status = TaskStates[longestRunningTask.getStatus()];
      let statusClasses = classNames('job-details-header-status', {
        'text-success': status.stateTypes.includes('success')
        && !status.stateTypes.includes('failure'),
        'text-danger': status.stateTypes.includes('failure')
      });

      let timePrefix = null;
      let shouldSuppressRelativeTime = dateCompleted == null;

      if (shouldSuppressRelativeTime) {
        timePrefix = 'for ';
      }

      nodes.push(

          {status.displayName}
        ,

          <TimeAgo
            prefix={timePrefix}
            suppressSuffix={shouldSuppressRelativeTime}
            time={longestRunningActiveRun.getDateCreated()} />

      );
    }

    return nodes;
  }

  renderConfigurationTabView(job) {
    return <JobConfiguration job={job} />;
  }

  renderRunHistoryTabView(job) {
    return <JobRunHistoryTable job={job} />;
  }

  getActions() {
    const job = MetronomeStore.getJob(this.props.params.id);
    const [schedule] = job.getSchedules();

    const actions = [];

    actions.push({
      label: 'Edit',
      onItemSelect: this.handleEditButtonClick
    });

    actions.push({
      label: 'Run Now',
      onItemSelect: this.handleRunNowButtonClick
    });

    if (schedule != null && schedule.enabled) {
      actions.push({
        label: 'Disable Schedule',
        onItemSelect: this.handleDisableScheduleButtonClick
      });
    }

    if (schedule != null && !schedule.enabled) {
      actions.push({
        label: 'Enable Schedule',
        onItemSelect: this.handleEnableScheduleButtonClick
      });
    }

    actions.push({
      className: 'text-danger',
      label: 'Destroy',
      onItemSelect: this.handleDestroyButtonClick
    });

    return actions;
  }

  getTabs() {
    const activeTab = this.state.currentTab;

    return [
      {
        label: 'Run History',
        callback: () => { this.setState({currentTab: 'runHistory'}); },
        isActive: activeTab === 'runHistory'
      },
      {
        label: 'Configuration',
        callback: () => { this.setState({currentTab: 'configuration'}); },
        isActive: activeTab === 'configuration'
      }
    ];
  }

  render() {
    if (this.state.errorCount > 3) {
      return this.getErrorScreen();
    }

    if (this.state.isLoading) {
      return this.getLoadingScreen();
    }

    // TaskDetailView
    if (this.props.params.taskID) {
      return this.props.children;
    }

    let job = MetronomeStore.getJob(this.props.params.id);
    const jobStatus = this.getJobStatus(job);

    return (
      <Page>
        <Page.Header
          actions={this.getActions()}
          breadcrumbs={<JobsBreadcrumbs jobID={job.getId()} jobStatus={jobStatus} />}
          tabs={this.getTabs()} />
        {this.tabs_getTabView(job)}
        <JobFormModal isEdit={true}
          job={job}
          open={this.state.jobActionDialog === DIALOGS.EDIT}
          onClose={this.closeDialog} />
        {this.getDestroyConfirmDialog()}
      </Page>
    );
  }
}

JobDetailPage.contextTypes = {
  router: routerShape
};

module.exports = JobDetailPage;
<|endoftext|>


<commit_before>/**
 * @fileoverview Raphael area chart renderer.
 * @author NHN Ent.
 *         FE Development Lab <dl_javascript@nhnent.com>
 */

'use strict';

var RaphaelLineBase = require('./raphaelLineTypeBase');
var raphaelRenderUtil = require('./raphaelRenderUtil');

var EMPHASIS_OPACITY = 1;
var DE_EMPHASIS_OPACITY = 0.3;
var LEFT_BAR_WIDTH = 10;
var ADDING_DATA_ANIMATION_DURATION = 300;

var concat = Array.prototype.concat;

var RaphaelAreaChart = tui.util.defineClass(RaphaelLineBase, /** @lends RaphaelAreaChart.prototype */ {
    /**
     * RaphaelAreaChart is graph renderer for area chart.
     * @constructs RaphaelAreaChart
     * @private
     * @private
     * @extends RaphaelLineTypeBase
     */
    init: function() {
        /**
         * selected legend index
         * @type {?number}
         */
        this.selectedLegendIndex = null;

        /**
         * type of chart
         * @type {string}
         */
        this.chartType = 'area';

        /**
         * Line width
         * @type {number}
         */
        this.lineWidth = 1;
    },

    /**
     * Render function of area chart.
     * @param {object} paper - raphael paper
     * @param {{groupPositions: Array.<Array>, dimension: object, theme: object, options: object}} data render data
     * @returns {object}
     */
    render: function(paper, data) {
        var dimension = data.dimension;
        var groupPositions = data.groupPositions;
        var theme = data.theme;
        var colors = theme.colors;
        var options = data.options;
        var opacity = options.showDot ? 1 : 0;
        var borderStyle = this.makeBorderStyle(theme.borderColor, opacity);
        var outDotStyle = this.makeOutDotStyle(opacity, borderStyle);
        var lineWidth = this.lineWidth = (tui.util.isNumber(options.pointWidth) ? options.pointWidth : this.lineWidth);

        this.paper = paper;
        this.theme = data.theme;
        this.isSpline = options.spline;
        this.dimension = dimension;
        this.position = data.position;

        this.zeroTop = data.zeroTop;
        this.hasRangeData = data.hasRangeData;

        paper.setStart();

        this.groupPaths = this._getAreaChartPath(groupPositions, null, options.connectNulls);
        this.groupAreas = this._renderAreas(paper, this.groupPaths, colors, lineWidth);
        this.tooltipLine = this._renderTooltipLine(paper, dimension.height);
        this.groupDots = this._renderDots(paper, groupPositions, colors, opacity);

        if (options.allowSelect) {
            this.selectionDot = this._makeSelectionDot(paper);
            this.selectionColor = theme.selectionColor;

            if (this.hasRangeData) {
                this.selectionStartDot = this._makeSelectionDot(paper);
            }
        }

        this.outDotStyle = outDotStyle;
        this.groupPositions = groupPositions;
        this.dotOpacity = opacity;

        this.pivotGroupDots = null;

        return paper.setFinish();
    },

    /**
     * Get path for area chart.
     * @param {Array.<Array.<{left: number, top: number, startTop: number}>>} groupPositions - positions
     * @param {boolean} [hasExtraPath] - whether has extra path or not
     * @param {boolean} [connectNulls] - boolean value connect nulls or not
     * @returns {*}
     * @private
     */
    _getAreaChartPath: function(groupPositions, hasExtraPath, connectNulls) {
        var path;

        if (this.isSpline) {
            path = this._makeSplineAreaChartPath(groupPositions, hasExtraPath);
        } else {
            path = this._makeAreaChartPath(groupPositions, hasExtraPath, connectNulls);
        }

        return path;
    },

    /**
     * Render area graphs.
     * @param {object} paper paper
     * @param {Array.<object>} groupPaths group paths
     * @param {Array.<string>} colors colors
     * @param {number} lineWidth line width
     * @returns {Array} raphael objects
     * @private
     */
    _renderAreas: function(paper, groupPaths, colors, lineWidth) {
        var groupAreas;

        colors = colors.slice(0, groupPaths.length);
        colors.reverse();
        groupPaths.reverse();

        groupAreas = tui.util.map(groupPaths, function(path, groupIndex) {
            var areaColor = colors[groupIndex] || 'transparent',
                lineColor = areaColor,
                polygons = {
                    area: raphaelRenderUtil.renderArea(paper, path.area.join(' '), {
                        fill: areaColor,
                        opacity: 0.5,
                        stroke: areaColor
                    }),
                    line: raphaelRenderUtil.renderLine(paper, path.line.join(' '), lineColor, lineWidth)
                };

            if (path.startLine) {
                polygons.startLine = raphaelRenderUtil.renderLine(paper, path.startLine.join(' '), lineColor, 1);
            }

            return polygons;
        });

        return groupAreas.reverse();
    },

    /**
     * Make height.
     * @param {number} top top
     * @param {number} startTop start top
     * @returns {number} height
     * @private
     */
    _makeHeight: function(top, startTop) {
        return Math.abs(top - startTop);
    },

    /**
     * Make areas path.
     * @param {Array.<{left: number, top: number, startTop: number}>} positions positions
     * @param {boolean} [hasExtraPath] - whether has extra path or not
     * @returns {Array.<string | number>} path
     * @private
     */
    _makeAreasPath: function(positions, hasExtraPath) {
        var path = [];
        var paths = [];
        var prevNull = false;
        var positionLength = positions.length;
        var targetIndex;
        var formerPath = [];
        var latterPath = [];

        tui.util.forEachArray(positions, function(position, index) {
            var moveOrLine;
            if (position) {
                if (prevNull) {
                    moveOrLine = 'M';
                    prevNull = false;
                } else {
                    moveOrLine = 'L';
                }

                formerPath.push([moveOrLine, position.left, position.top]);
                latterPath.unshift(['L', position.left, position.startTop]);
            } else {
                prevNull = true;
                latterPath.push(['z']);
            }

            if (!position || index === positionLength - 1) {
                paths.push(formerPath.concat(latterPath));
                formerPath = [];
                latterPath = [];
            }
        });

        tui.util.forEachArray(paths, function(partialPath) {
            path = path.concat(partialPath);
        });

        if (hasExtraPath !== false) {
            targetIndex = positions.length - 1;
            path.splice(targetIndex + 1, 0, path[targetIndex], path[targetIndex + 1]);
        }

        path = concat.apply([], path);
        path[0] = 'M';

        return path;
    },

    /**
     * Make path for area chart.
     * @param {Array.<Array.<{left: number, top: number, startTop: number}>>} groupPositions positions
     * @param {boolean} [hasExtraPath] - whether has extra path or not
     * @param {boolean} [connectNulls] - boolean value connect nulls or not
     * @returns {Array.<{area: Array.<string | number>, line: Array.<string | number>}>} path
     * @private
     */
    _makeAreaChartPath: function(groupPositions, hasExtraPath, connectNulls) {
        var self = this;

        return tui.util.map(groupPositions, function(positions) {
            var paths;

            paths = {
                area: self._makeAreasPath(positions, hasExtraPath),
                line: self._makeLinesPath(positions, null, connectNulls)
            };

            if (self.hasRangeData) {
                paths.startLine = self._makeLinesPath(positions, 'startTop');
            }

            return paths;
        });
    },

    /**
     * Make spline area bottom path.
     * @param {Array.<{left: number, top: number}>} positions positions
     * @returns {Array.<string | number>} spline area path
     * @private
     */
    _makeSplineAreaBottomPath: function(positions) {
        var self = this;

        return tui.util.map(positions, function(position) {
            return ['L', position.left, self.zeroTop];
        }).reverse();
    },

    /**
     * Make spline path for area chart.
     * @param {Array.<Array.<{left: number, top: number, startTop: number}>>} groupPositions positions
     * @param {boolean} [hasExtraPath] - whether has extra path or not
     * @returns {Array.<{area: Array.<string | number>, line: Array.<string | number>}>} path
     * @private
     */
    _makeSplineAreaChartPath: function(groupPositions, hasExtraPath) {
        var self = this;

        return tui.util.map(groupPositions, function(positions) {
            var linesPath = self._makeSplineLinesPath(positions);
            var areaPath = JSON.parse(JSON.stringify(linesPath));
            var areasBottomPath = self._makeSplineAreaBottomPath(positions);
            var lastPosition;

            if (hasExtraPath !== false) {
                lastPosition = positions[positions.length - 1];
                areaPath.push(['L', lastPosition.left, lastPosition.top]);
                areasBottomPath.unshift(['L', lastPosition.left, self.zeroTop]);
            }

            return {
                area: areaPath.concat(areasBottomPath),
                line: linesPath
            };
        });
    },

    /**
     * Resize graph of area chart.
     * @param {object} params parameters
     *      @param {{width: number, height:number}} params.dimension dimension
     *      @param {Array.<Array.<{left:number, top:number}>>} params.groupPositions group positions
     */
    resize: function(params) {
        var self = this,
            dimension = params.dimension,
            groupPositions = params.groupPositions;

        this.resizeClipRect(dimension);

        this.zeroTop = params.zeroTop;
        this.groupPositions = groupPositions;
        this.groupPaths = this._getAreaChartPath(groupPositions);
        this.paper.setSize(dimension.width, dimension.height);
        this.tooltipLine.attr({top: dimension.height});

        tui.util.forEachArray(this.groupPaths, function(path, groupIndex) {
            var area = self.groupAreas[groupIndex];
            area.area.attr({path: path.area.join(' ')});
            area.line.attr({path: path.line.join(' ')});

            if (area.startLine) {
                area.startLine.attr({path: path.startLine.join(' ')});
            }

            tui.util.forEachArray(self.groupDots[groupIndex], function(item, index) {
                var position = groupPositions[groupIndex][index];
                var startPositon;

                if (item.endDot) {
                    self._moveDot(item.endDot.dot, position);
                }
                if (item.startDot) {
                    startPositon = tui.util.extend({}, position);
                    startPositon.top = startPositon.startTop;
                    self._moveDot(item.startDot.dot, startPositon);
                }
            });
        });
    },

    /**
     * Select legend.
     * @param {?number} legendIndex legend index
     */
    selectLegend: function(legendIndex) {
        var self = this,
            noneSelected = tui.util.isNull(legendIndex);

        this.selectedLegendIndex = legendIndex;

        tui.util.forEachArray(this.groupAreas, function(area, groupIndex) {
            var opacity = (noneSelected || legendIndex === groupIndex) ? EMPHASIS_OPACITY : DE_EMPHASIS_OPACITY;

            area.area.attr({'fill-opacity': opacity});
            area.line.attr({'stroke-opacity': opacity});

            if (area.startLine) {
                area.startLine.attr({'stroke-opacity': opacity});
            }

            tui.util.forEachArray(self.groupDots[groupIndex], function(item) {
                if (self.dotOpacity) {
                    item.endDot.dot.attr({'fill-opacity': opacity});
                    if (item.startDot) {
                        item.startDot.dot.attr({'fill-opacity': opacity});
                    }
                }
            });
        });
    },

    /**
     * Animate for adding data.
     * @param {object} data - data for graph rendering
     * @param {number} tickSize - tick size
     * @param {Array.<Array.<object>>} groupPositions - group positions
     * @param {boolean} [shiftingOption] - shifting option
     * @param {number} zeroTop - position top value for zero point
     */
    animateForAddingData: function(data, tickSize, groupPositions, shiftingOption, zeroTop) {
        var self = this;
        var additionalIndex = 0;
        var groupPaths;

        if (!groupPositions.length) {
            return;
        }

        this.zeroTop = zeroTop;

        groupPaths = this._getAreaChartPath(groupPositions, false);

        if (shiftingOption) {
            this.leftBar.animate({
                width: tickSize + LEFT_BAR_WIDTH
            }, ADDING_DATA_ANIMATION_DURATION);
            additionalIndex = 1;
        }

        tui.util.forEachArray(this.groupAreas, function(area, groupIndex) {
            var dots = self.groupDots[groupIndex];
            var groupPosition = groupPositions[groupIndex];
            var pathMap = groupPaths[groupIndex];

            if (shiftingOption) {
                self._removeFirstDot(dots);
            }

            tui.util.forEachArray(dots, function(item, index) {
                var position = groupPosition[index + additionalIndex];

                self._animateByPosition(item.endDot.dot, position);

                if (item.startDot) {
                    self._animateByPosition(item.startDot.dot, {
                        left: position.left,
                        top: position.startTop
                    });
                }
            });

            self._animateByPath(area.area, pathMap.area);
            self._animateByPath(area.line, pathMap.line);

            if (area.startLine) {
                self._animateByPath(area.startLine, pathMap.startLine);
            }
        });
    },

    renderSeriesLabel: function(paper, groupPositions, groupLabels, labelTheme) {
        var attributes = {
            'font-size': labelTheme.fontSize,
            'font-family': labelTheme.fontFamily,
            'font-weight': labelTheme.fontWeight,
            fill: labelTheme.color,
            'text-anchor': 'middle',
            opacity: 0
        };
        var set = paper.set();

        tui.util.forEach(groupLabels, function(categoryLabel, categoryIndex) {
            tui.util.forEach(categoryLabel, function(label, seriesIndex) {
                var position = groupPositions[categoryIndex][seriesIndex];
                var endLabel = raphaelRenderUtil.renderText(paper, position.end, label.end, attributes);
                var startLabel;

                set.push(endLabel);

                endLabel.node.style.userSelect = 'none';
                endLabel.node.style.cursor = 'default';
                endLabel.node.setAttribute('filter', 'url(#glow)');

                if (position.start) {
                    startLabel = raphaelRenderUtil.renderText(paper, position.start, label.start, attributes);

                    startLabel.node.style.userSelect = 'none';
                    startLabel.node.style.cursor = 'default';

                    set.push(startLabel);
                }
            });
        });

        return set;
    }
});

module.exports = RaphaelAreaChart;
<commit_msg>fix: AreaChart dynamic data shifting issue<commit_after>/**
 * @fileoverview Raphael area chart renderer.
 * @author NHN Ent.
 *         FE Development Lab <dl_javascript@nhnent.com>
 */

'use strict';

var RaphaelLineBase = require('./raphaelLineTypeBase');
var raphaelRenderUtil = require('./raphaelRenderUtil');

var EMPHASIS_OPACITY = 1;
var DE_EMPHASIS_OPACITY = 0.3;
var LEFT_BAR_WIDTH = 10;
var ADDING_DATA_ANIMATION_DURATION = 300;

var concat = Array.prototype.concat;

var RaphaelAreaChart = tui.util.defineClass(RaphaelLineBase, /** @lends RaphaelAreaChart.prototype */ {
    /**
     * RaphaelAreaChart is graph renderer for area chart.
     * @constructs RaphaelAreaChart
     * @private
     * @private
     * @extends RaphaelLineTypeBase
     */
    init: function() {
        /**
         * selected legend index
         * @type {?number}
         */
        this.selectedLegendIndex = null;

        /**
         * type of chart
         * @type {string}
         */
        this.chartType = 'area';

        /**
         * Line width
         * @type {number}
         */
        this.lineWidth = 1;
    },

    /**
     * Render function of area chart.
     * @param {object} paper - raphael paper
     * @param {{groupPositions: Array.<Array>, dimension: object, theme: object, options: object}} data render data
     * @returns {object}
     */
    render: function(paper, data) {
        var dimension = data.dimension;
        var groupPositions = data.groupPositions;
        var theme = data.theme;
        var colors = theme.colors;
        var options = data.options;
        var opacity = options.showDot ? 1 : 0;
        var borderStyle = this.makeBorderStyle(theme.borderColor, opacity);
        var outDotStyle = this.makeOutDotStyle(opacity, borderStyle);
        var lineWidth = this.lineWidth = (tui.util.isNumber(options.pointWidth) ? options.pointWidth : this.lineWidth);

        this.paper = paper;
        this.theme = data.theme;
        this.isSpline = options.spline;
        this.dimension = dimension;
        this.position = data.position;

        this.zeroTop = data.zeroTop;
        this.hasRangeData = data.hasRangeData;

        paper.setStart();

        this.groupPaths = this._getAreaChartPath(groupPositions, null, options.connectNulls);
        this.groupAreas = this._renderAreas(paper, this.groupPaths, colors, lineWidth);
        this.tooltipLine = this._renderTooltipLine(paper, dimension.height);
        this.groupDots = this._renderDots(paper, groupPositions, colors, opacity);

        if (options.allowSelect) {
            this.selectionDot = this._makeSelectionDot(paper);
            this.selectionColor = theme.selectionColor;

            if (this.hasRangeData) {
                this.selectionStartDot = this._makeSelectionDot(paper);
            }
        }

        this.outDotStyle = outDotStyle;
        this.groupPositions = groupPositions;
        this.dotOpacity = opacity;

        this.pivotGroupDots = null;

        return paper.setFinish();
    },

    /**
     * Get path for area chart.
     * @param {Array.<Array.<{left: number, top: number, startTop: number}>>} groupPositions - positions
     * @param {boolean} [hasExtraPath] - whether has extra path or not
     * @param {boolean} [connectNulls] - boolean value connect nulls or not
     * @returns {*}
     * @private
     */
    _getAreaChartPath: function(groupPositions, hasExtraPath, connectNulls) {
        var path;

        if (this.isSpline) {
            path = this._makeSplineAreaChartPath(groupPositions, hasExtraPath);
        } else {
            path = this._makeAreaChartPath(groupPositions, hasExtraPath, connectNulls);
        }

        return path;
    },

    /**
     * Render area graphs.
     * @param {object} paper paper
     * @param {Array.<object>} groupPaths group paths
     * @param {Array.<string>} colors colors
     * @param {number} lineWidth line width
     * @returns {Array} raphael objects
     * @private
     */
    _renderAreas: function(paper, groupPaths, colors, lineWidth) {
        var groupAreas;

        colors = colors.slice(0, groupPaths.length);
        colors.reverse();
        groupPaths.reverse();

        groupAreas = tui.util.map(groupPaths, function(path, groupIndex) {
            var areaColor = colors[groupIndex] || 'transparent',
                lineColor = areaColor,
                polygons = {
                    area: raphaelRenderUtil.renderArea(paper, path.area.join(' '), {
                        fill: areaColor,
                        opacity: 0.5,
                        stroke: areaColor
                    }),
                    line: raphaelRenderUtil.renderLine(paper, path.line.join(' '), lineColor, lineWidth)
                };

            if (path.startLine) {
                polygons.startLine = raphaelRenderUtil.renderLine(paper, path.startLine.join(' '), lineColor, 1);
            }

            return polygons;
        });

        return groupAreas.reverse();
    },

    /**
     * Make height.
     * @param {number} top top
     * @param {number} startTop start top
     * @returns {number} height
     * @private
     */
    _makeHeight: function(top, startTop) {
        return Math.abs(top - startTop);
    },

    /**
     * Make areas path.
     * @param {Array.<{left: number, top: number, startTop: number}>} positions positions
     * @param {boolean} [hasExtraPath] - whether has extra path or not
     * @returns {Array.<string | number>} path
     * @private
     */
    _makeAreasPath: function(positions, hasExtraPath) {
        var path = [];
        var paths = [];
        var prevNull = false;
        var positionLength = positions.length;
        var targetIndex;
        var formerPath = [];
        var latterPath = [];

        tui.util.forEachArray(positions, function(position, index) {
            var moveOrLine;
            if (position) {
                if (prevNull) {
                    moveOrLine = 'M';
                    prevNull = false;
                } else {
                    moveOrLine = 'L';
                }

                formerPath.push([moveOrLine, position.left, position.top]);
                latterPath.unshift(['L', position.left, position.startTop]);
            } else {
                prevNull = true;
                latterPath.push(['z']);
            }

            if (!position || index === positionLength - 1) {
                paths.push(formerPath.concat(latterPath));
                formerPath = [];
                latterPath = [];
            }
        });

        tui.util.forEachArray(paths, function(partialPath) {
            path = path.concat(partialPath);
        });

        if (hasExtraPath !== false) {
            targetIndex = positions.length - 1;
            path.splice(targetIndex + 1, 0, path[targetIndex], path[targetIndex + 1]);
        }

        path = concat.apply([], path);
        path[0] = 'M';

        return path;
    },

    /**
     * Make path for area chart.
     * @param {Array.<Array.<{left: number, top: number, startTop: number}>>} groupPositions positions
     * @param {boolean} [hasExtraPath] - whether has extra path or not
     * @param {boolean} [connectNulls] - boolean value connect nulls or not
     * @returns {Array.<{area: Array.<string | number>, line: Array.<string | number>}>} path
     * @private
     */
    _makeAreaChartPath: function(groupPositions, hasExtraPath, connectNulls) {
        var self = this;

        return tui.util.map(groupPositions, function(positions) {
            var paths;

            paths = {
                area: self._makeAreasPath(positions, hasExtraPath),
                line: self._makeLinesPath(positions, null, connectNulls)
            };

            if (self.hasRangeData) {
                paths.startLine = self._makeLinesPath(positions, 'startTop');
            }

            return paths;
        });
    },

    /**
     * Make spline area bottom path.
     * @param {Array.<{left: number, top: number}>} positions positions
     * @returns {Array.<string | number>} spline area path
     * @private
     */
    _makeSplineAreaBottomPath: function(positions) {
        var self = this;

        return tui.util.map(positions, function(position) {
            return ['L', position.left, self.zeroTop];
        }).reverse();
    },

    /**
     * Make spline path for area chart.
     * @param {Array.<Array.<{left: number, top: number, startTop: number}>>} groupPositions positions
     * @param {boolean} [hasExtraPath] - whether has extra path or not
     * @returns {Array.<{area: Array.<string | number>, line: Array.<string | number>}>} path
     * @private
     */
    _makeSplineAreaChartPath: function(groupPositions, hasExtraPath) {
        var self = this;

        return tui.util.map(groupPositions, function(positions) {
            var linesPath = self._makeSplineLinesPath(positions);
            var areaPath = JSON.parse(JSON.stringify(linesPath));
            var areasBottomPath = self._makeSplineAreaBottomPath(positions);
            var lastPosition;

            if (hasExtraPath !== false) {
                lastPosition = positions[positions.length - 1];
                areaPath.push(['L', lastPosition.left, lastPosition.top]);
                areasBottomPath.unshift(['L', lastPosition.left, self.zeroTop]);
            }

            return {
                area: areaPath.concat(areasBottomPath),
                line: linesPath
            };
        });
    },

    /**
     * Resize graph of area chart.
     * @param {object} params parameters
     *      @param {{width: number, height:number}} params.dimension dimension
     *      @param {Array.<Array.<{left:number, top:number}>>} params.groupPositions group positions
     */
    resize: function(params) {
        var self = this,
            dimension = params.dimension,
            groupPositions = params.groupPositions;

        this.resizeClipRect(dimension);

        this.zeroTop = params.zeroTop;
        this.groupPositions = groupPositions;
        this.groupPaths = this._getAreaChartPath(groupPositions);
        this.paper.setSize(dimension.width, dimension.height);
        this.tooltipLine.attr({top: dimension.height});

        tui.util.forEachArray(this.groupPaths, function(path, groupIndex) {
            var area = self.groupAreas[groupIndex];
            area.area.attr({path: path.area.join(' ')});
            area.line.attr({path: path.line.join(' ')});

            if (area.startLine) {
                area.startLine.attr({path: path.startLine.join(' ')});
            }

            tui.util.forEachArray(self.groupDots[groupIndex], function(item, index) {
                var position = groupPositions[groupIndex][index];
                var startPositon;

                if (item.endDot) {
                    self._moveDot(item.endDot.dot, position);
                }
                if (item.startDot) {
                    startPositon = tui.util.extend({}, position);
                    startPositon.top = startPositon.startTop;
                    self._moveDot(item.startDot.dot, startPositon);
                }
            });
        });
    },

    /**
     * Select legend.
     * @param {?number} legendIndex legend index
     */
    selectLegend: function(legendIndex) {
        var self = this,
            noneSelected = tui.util.isNull(legendIndex);

        this.selectedLegendIndex = legendIndex;

        tui.util.forEachArray(this.groupAreas, function(area, groupIndex) {
            var opacity = (noneSelected || legendIndex === groupIndex) ? EMPHASIS_OPACITY : DE_EMPHASIS_OPACITY;

            area.area.attr({'fill-opacity': opacity});
            area.line.attr({'stroke-opacity': opacity});

            if (area.startLine) {
                area.startLine.attr({'stroke-opacity': opacity});
            }

            tui.util.forEachArray(self.groupDots[groupIndex], function(item) {
                if (self.dotOpacity) {
                    item.endDot.dot.attr({'fill-opacity': opacity});
                    if (item.startDot) {
                        item.startDot.dot.attr({'fill-opacity': opacity});
                    }
                }
            });
        });
    },

    /**
     * Animate for adding data.
     * @param {object} data - data for graph rendering
     * @param {number} tickSize - tick size
     * @param {Array.<Array.<object>>} groupPositions - group positions
     * @param {boolean} [shiftingOption] - shifting option
     * @param {number} zeroTop - position top value for zero point
     */
    animateForAddingData: function(data, tickSize, groupPositions, shiftingOption, zeroTop) {
        var self = this;
        var groupPaths = this._getAreaChartPath(groupPositions, false);
        var additionalIndex = 0;

        if (!groupPositions.length) {
            return;
        }

        if (shiftingOption) {
            additionalIndex = 1;
        }

        this.zeroTop = zeroTop;

        tui.util.forEachArray(this.groupAreas, function(area, groupIndex) {
            var dots = self.groupDots[groupIndex];
            var groupPosition = groupPositions[groupIndex];
            var pathMap = groupPaths[groupIndex];

            if (shiftingOption) {
                self._removeFirstDot(dots);
            }

            tui.util.forEachArray(dots, function(item, index) {
                var position = groupPosition[index + additionalIndex];
                self._animateByPosition(item.endDot.dot, position, tickSize);

                if (item.startDot) {
                    self._animateByPosition(item.startDot.dot, {
                        left: position.left,
                        top: position.startTop
                    }, tickSize);
                }
            });

            self._animateByPath(area.area, pathMap.area, tickSize);
            self._animateByPath(area.line, pathMap.line, tickSize);

            if (area.startLine) {
                self._animateByPath(area.startLine, pathMap.startLine, tickSize);
            }
        });
    },

    renderSeriesLabel: function(paper, groupPositions, groupLabels, labelTheme) {
        var attributes = {
            'font-size': labelTheme.fontSize,
            'font-family': labelTheme.fontFamily,
            'font-weight': labelTheme.fontWeight,
            fill: labelTheme.color,
            'text-anchor': 'middle',
            opacity: 0
        };
        var set = paper.set();

        tui.util.forEach(groupLabels, function(categoryLabel, categoryIndex) {
            tui.util.forEach(categoryLabel, function(label, seriesIndex) {
                var position = groupPositions[categoryIndex][seriesIndex];
                var endLabel = raphaelRenderUtil.renderText(paper, position.end, label.end, attributes);
                var startLabel;

                set.push(endLabel);

                endLabel.node.style.userSelect = 'none';
                endLabel.node.style.cursor = 'default';
                endLabel.node.setAttribute('filter', 'url(#glow)');

                if (position.start) {
                    startLabel = raphaelRenderUtil.renderText(paper, position.start, label.start, attributes);

                    startLabel.node.style.userSelect = 'none';
                    startLabel.node.style.cursor = 'default';

                    set.push(startLabel);
                }
            });
        });

        return set;
    }
});

module.exports = RaphaelAreaChart;
<|endoftext|>


<commit_before>function redrawControl(control)
{
    $.nette.ajax({
        method: 'GET',
        traditional: true,
        url: redrawControlUrl + '&control=' + control
    });
}

function redrawRow(control, rowId)
{
    $.nette.ajax({
        method: 'GET',
        traditional: true,
        url: redrawRowUrl + '&control=' + control + '&rowId=' + rowId
    });
}

function debounce(func, wait, immediate) {
    var timeout;
    return function () {
        var context = this, args = arguments;
        var later = function () {
            timeout = null;
            if (!immediate) func.apply(context, args);
        };
        var callNow = immediate && !timeout;
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
        if (callNow) func.apply(context, args);
    };
}

function refreshPlugins(context)
{
    $(context).find('.iframePopup').magnificPopup({type: 'iframe'});
    $(context).find('.ajaxPopup').magnificPopup({type: 'ajax'});
}

$(document).ready(function ()
{
    $.nette.ext('snippets').after(function (el)
    {
        refreshPlugins(el);
    });
    $.nette.ext('flash', {
        complete: flashFadeOut
    });
    $.nette.init();

    refreshPlugins(document.body);
});
<commit_msg>Update common.js<commit_after>function redrawControl(control)
{
    $.nette.ajax({
        method: 'GET',
        traditional: true,
        url: redrawControlUrl + '&control=' + control
    });
}

function redrawRow(control, rowId)
{
    $.nette.ajax({
        method: 'GET',
        traditional: true,
        url: redrawRowUrl + '&control=' + control + '&rowId=' + rowId
    });
}

function debounce(func, wait, immediate) {
    var timeout;
    return function () {
        var context = this, args = arguments;
        var later = function () {
            timeout = null;
            if (!immediate) func.apply(context, args);
        };
        var callNow = immediate && !timeout;
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
        if (callNow) func.apply(context, args);
    };
}

function refreshPlugins(context)
{
    $(context).find('.iframePopup').magnificPopup({type: 'iframe'});
    $(context).find('.ajaxPopup').magnificPopup({type: 'ajax'});
}

$(document).ready(function ()
{
    $.nette.ext('snippets').after(function (el)
    {
        refreshPlugins(el);
    });
    $.nette.init();

    refreshPlugins(document.body);
});
<|endoftext|>