<commit_before>const _ = require('lodash/fp')

const namespaces = {
  ADVANCED: 'advanced',
  WALLETS: 'wallets',
  OPERATOR_INFO: 'operatorInfo',
  NOTIFICATIONS: 'notifications',
  LOCALE: 'locale',
  COMMISSIONS: 'commissions',
  RECEIPT: 'receipt',
  COIN_ATM_RADAR: 'coinAtmRadar',
  TERMS_CONDITIONS: 'termsConditions',
  CASH_OUT: 'cashOut',
  CASH_IN: 'cashIn',
  COMPLIANCE: 'compliance'
}

const stripl = _.curry((q, str) => _.startsWith(q, str) ? str.slice(q.length) : str)
const filter = namespace => _.pickBy((value, key) => _.startsWith(`${namespace}_`)(key))
const strip = key => _.mapKeys(stripl(`${key}_`))

const fromNamespace = _.curry((key, config) => _.compose(strip(key), filter(key))(config))
const toNamespace = _.curry((ns, config) => _.mapKeys(key => `${ns}_${key}`, config))

const getCommissions = (cryptoCode, deviceId, config) => {
  const commissions = fromNamespace(namespaces.COMMISSIONS)(config)
  const overrides = commissions.overrides

  if (_.isEmpty(overrides)) return _.omit('overrides', commissions)

  const specificFilter = it => it.machine === deviceId && _.includes(cryptoCode)(it.cryptoCurrencies)
  const specificAllCoinsFilter = it => it.machine === deviceId && _.includes('ALL_COINS')(it.cryptoCurrencies)
  const allMachinesFilter = it => it.machine === 'ALL_MACHINES' && _.includes(cryptoCode)(it.cryptoCurrencies)

  const specificOverrides = _.filter(specificFilter)(overrides)
  const specificAllCoinsOverrides = _.filter(specificAllCoinsFilter)(overrides)
  const allMachinesOverrides = _.filter(allMachinesFilter)(overrides)

  const priorityOrderOverrides = [
    commissions,
    ...allMachinesOverrides,
    ...specificAllCoinsOverrides,
    ...specificOverrides
  ]

  return _.omit('overrides', _.assignAll(priorityOrderOverrides))
}

const getLocale = (deviceId, it) => {
  const locale = fromNamespace(namespaces.LOCALE)(it)
  const filter = _.matches({ machine: deviceId })
  return _.omit('overrides', _.assignAll([locale, ..._.filter(filter)(locale.overrides)]))
}

const getGlobalLocale = it => getLocale(null, it)

const getWalletSettings = (key, it) => {
  const filter = _.matches({ cryptoCurrency: key })

  const getAdvancedSettings = it => {
    const advancedSettings = fromNamespace(namespaces.ADVANCED)(it)
    return _.omit(['overrides', 'cryptoCurrency', 'id'], _.assignAll([advancedSettings, ..._.filter(filter)(advancedSettings.overrides)]))
  }
  const walletsSettings = fromNamespace(namespaces.WALLETS)(it)
  return _.assign(fromNamespace(key)(walletsSettings), getAdvancedSettings(walletsSettings))
}
const getCashOut = (key, it) => _.compose(fromNamespace(key), fromNamespace(namespaces.CASH_OUT))(it)
const getGlobalCashOut = fromNamespace(namespaces.CASH_OUT)
const getOperatorInfo = fromNamespace(namespaces.OPERATOR_INFO)
const getCoinAtmRadar = fromNamespace(namespaces.COIN_ATM_RADAR)
const getTermsConditions = fromNamespace(namespaces.TERMS_CONDITIONS)
const getReceipt = fromNamespace(namespaces.RECEIPT)
const getCompliance = fromNamespace(namespaces.COMPLIANCE)

const getAllCryptoCurrencies = (config) => {
  const locale = fromNamespace(namespaces.LOCALE)(config)
  const cryptos = locale.cryptoCurrencies
  const overridesCryptos = _.map(_.get('cryptoCurrencies'))(locale.overrides)
  return _.uniq(_.flatten([cryptos, ...overridesCryptos]))
}

const getNotifications = (cryptoCurrency, machine, config) => {
  const notifications = fromNamespace(namespaces.NOTIFICATIONS)(config)

  const smsSettings = fromNamespace('sms', notifications)
  const emailSettings = fromNamespace('email', notifications)
  const notificationCenterSettings = fromNamespace('notificationCenter', notifications)

  const notifNoOverrides = _.omit(['cryptoBalanceOverrides', 'fiatBalanceOverrides'], notifications)

  const findByCryptoCurrency = _.find(_.matches({ cryptoCurrency }))
  const findByMachine = _.find(_.matches({ machine }))

  const cryptoFields = ['cryptoHighBalance', 'cryptoLowBalance', 'highBalance', 'lowBalance']
  const fiatFields = ['fillingPercentageCassette1', 'fillingPercentageCassette2', 'fillingPercentageCassette3', 'fillingPercentageCassette4']

  const getCryptoSettings = _.compose(_.pick(cryptoFields), _.defaultTo(notifications), findByCryptoCurrency)
  const cryptoSettings = getCryptoSettings(notifications.cryptoBalanceOverrides)

  if (cryptoSettings.highBalance) {
    cryptoSettings['cryptoHighBalance'] = cryptoSettings.highBalance
    delete cryptoSettings.highBalance
  }

  if (cryptoSettings.lowBalance) {
    cryptoSettings['cryptoLowBalance'] = cryptoSettings.lowBalance
    delete cryptoSettings.lowBalance
  }

  const getFiatSettings = _.compose(_.pick(fiatFields), _.defaultTo(notifications), findByMachine)
  const fiatSettings = getFiatSettings(notifications.fiatBalanceOverrides)
  return { ...notifNoOverrides, sms: smsSettings, email: emailSettings, ...cryptoSettings, ...fiatSettings, notificationCenter: notificationCenterSettings }
}

const getGlobalNotifications = config => getNotifications(null, null, config)

const getTriggers = _.get('triggers')

/* `customInfoRequests` is the result of a call to `getCustomInfoRequests` */
const getTriggersAutomation = (customInfoRequests, config) => {
  return customInfoRequests
    .then(infoRequests => {
      const defaultAutomation = _.get('triggersConfig_automation')(config)
      const requirements = {
        sanctions: defaultAutomation,
        idCardPhoto: defaultAutomation,
        idCardData: defaultAutomation,
        facephoto: defaultAutomation,
        usSsn: defaultAutomation
      }

      _.forEach(it => {
        requirements[it.id] = defaultAutomation
      }, infoRequests)

      const overrides = _.get('triggersConfig_overrides')(config)

      const requirementsOverrides = _.reduce((acc, override) => {
        return _.assign(acc, { [override.requirement]: override.automation })
      }, {}, overrides)

      return _.assign(requirements, requirementsOverrides)
    })
}

const splitGetFirst = _.compose(_.head, _.split('_'))

const getCryptosFromWalletNamespace =
  _.flowRight(_.without('advanced'), _.uniq, _.map(splitGetFirst), _.keys, fromNamespace('wallets'))

const getCashInSettings = config => fromNamespace(namespaces.CASH_IN)(config)

const getCryptoUnits = (crypto, config) =>
  getWalletSettings(crypto, config).cryptoUnits ?? 'full'

const setTermsConditions = toNamespace(namespaces.TERMS_CONDITIONS)

module.exports = {
  getWalletSettings,
  getCashInSettings,
  getOperatorInfo,
  getNotifications,
  getGlobalNotifications,
  getLocale,
  getGlobalLocale,
  getCommissions,
  getReceipt,
  getCompliance,
  getCoinAtmRadar,
  getTermsConditions,
  getAllCryptoCurrencies,
  getTriggers,
  getTriggersAutomation,
  getGlobalCashOut,
  getCashOut,
  getCryptosFromWalletNamespace,
  getCryptoUnits,
  setTermsConditions,
}
<commit_msg>chore: use function alias<commit_after>const _ = require('lodash/fp')

const namespaces = {
  ADVANCED: 'advanced',
  WALLETS: 'wallets',
  OPERATOR_INFO: 'operatorInfo',
  NOTIFICATIONS: 'notifications',
  LOCALE: 'locale',
  COMMISSIONS: 'commissions',
  RECEIPT: 'receipt',
  COIN_ATM_RADAR: 'coinAtmRadar',
  TERMS_CONDITIONS: 'termsConditions',
  CASH_OUT: 'cashOut',
  CASH_IN: 'cashIn',
  COMPLIANCE: 'compliance'
}

const stripl = _.curry((q, str) => _.startsWith(q, str) ? str.slice(q.length) : str)
const filter = namespace => _.pickBy((value, key) => _.startsWith(`${namespace}_`)(key))
const strip = key => _.mapKeys(stripl(`${key}_`))

const fromNamespace = _.curry((key, config) => _.compose(strip(key), filter(key))(config))
const toNamespace = _.curry((ns, config) => _.mapKeys(key => `${ns}_${key}`, config))

const getCommissions = (cryptoCode, deviceId, config) => {
  const commissions = fromNamespace(namespaces.COMMISSIONS)(config)
  const overrides = commissions.overrides

  if (_.isEmpty(overrides)) return _.omit('overrides', commissions)

  const specificFilter = it => it.machine === deviceId && _.includes(cryptoCode)(it.cryptoCurrencies)
  const specificAllCoinsFilter = it => it.machine === deviceId && _.includes('ALL_COINS')(it.cryptoCurrencies)
  const allMachinesFilter = it => it.machine === 'ALL_MACHINES' && _.includes(cryptoCode)(it.cryptoCurrencies)

  const specificOverrides = _.filter(specificFilter)(overrides)
  const specificAllCoinsOverrides = _.filter(specificAllCoinsFilter)(overrides)
  const allMachinesOverrides = _.filter(allMachinesFilter)(overrides)

  const priorityOrderOverrides = [
    commissions,
    ...allMachinesOverrides,
    ...specificAllCoinsOverrides,
    ...specificOverrides
  ]

  return _.omit('overrides', _.assignAll(priorityOrderOverrides))
}

const getLocale = (deviceId, it) => {
  const locale = fromNamespace(namespaces.LOCALE)(it)
  const filter = _.matches({ machine: deviceId })
  return _.omit('overrides', _.assignAll([locale, ..._.filter(filter)(locale.overrides)]))
}

const getGlobalLocale = it => getLocale(null, it)

const getWalletSettings = (key, it) => {
  const filter = _.matches({ cryptoCurrency: key })

  const getAdvancedSettings = it => {
    const advancedSettings = fromNamespace(namespaces.ADVANCED)(it)
    return _.omit(['overrides', 'cryptoCurrency', 'id'], _.assignAll([advancedSettings, ..._.filter(filter)(advancedSettings.overrides)]))
  }
  const walletsSettings = fromNamespace(namespaces.WALLETS)(it)
  return _.assign(fromNamespace(key)(walletsSettings), getAdvancedSettings(walletsSettings))
}
const getCashOut = (key, it) => _.compose(fromNamespace(key), fromNamespace(namespaces.CASH_OUT))(it)
const getGlobalCashOut = fromNamespace(namespaces.CASH_OUT)
const getOperatorInfo = fromNamespace(namespaces.OPERATOR_INFO)
const getCoinAtmRadar = fromNamespace(namespaces.COIN_ATM_RADAR)
const getTermsConditions = fromNamespace(namespaces.TERMS_CONDITIONS)
const getReceipt = fromNamespace(namespaces.RECEIPT)
const getCompliance = fromNamespace(namespaces.COMPLIANCE)

const getAllCryptoCurrencies = (config) => {
  const locale = fromNamespace(namespaces.LOCALE)(config)
  const cryptos = locale.cryptoCurrencies
  const overridesCryptos = _.map(_.get('cryptoCurrencies'))(locale.overrides)
  return _.uniq(_.flatten([cryptos, ...overridesCryptos]))
}

const getNotifications = (cryptoCurrency, machine, config) => {
  const notifications = fromNamespace(namespaces.NOTIFICATIONS)(config)

  const smsSettings = fromNamespace('sms', notifications)
  const emailSettings = fromNamespace('email', notifications)
  const notificationCenterSettings = fromNamespace('notificationCenter', notifications)

  const notifNoOverrides = _.omit(['cryptoBalanceOverrides', 'fiatBalanceOverrides'], notifications)

  const findByCryptoCurrency = _.find(_.matches({ cryptoCurrency }))
  const findByMachine = _.find(_.matches({ machine }))

  const cryptoFields = ['cryptoHighBalance', 'cryptoLowBalance', 'highBalance', 'lowBalance']
  const fiatFields = ['fillingPercentageCassette1', 'fillingPercentageCassette2', 'fillingPercentageCassette3', 'fillingPercentageCassette4']

  const getCryptoSettings = _.compose(_.pick(cryptoFields), _.defaultTo(notifications), findByCryptoCurrency)
  const cryptoSettings = getCryptoSettings(notifications.cryptoBalanceOverrides)

  if (cryptoSettings.highBalance) {
    cryptoSettings['cryptoHighBalance'] = cryptoSettings.highBalance
    delete cryptoSettings.highBalance
  }

  if (cryptoSettings.lowBalance) {
    cryptoSettings['cryptoLowBalance'] = cryptoSettings.lowBalance
    delete cryptoSettings.lowBalance
  }

  const getFiatSettings = _.compose(_.pick(fiatFields), _.defaultTo(notifications), findByMachine)
  const fiatSettings = getFiatSettings(notifications.fiatBalanceOverrides)
  return { ...notifNoOverrides, sms: smsSettings, email: emailSettings, ...cryptoSettings, ...fiatSettings, notificationCenter: notificationCenterSettings }
}

const getGlobalNotifications = config => getNotifications(null, null, config)

const getTriggers = _.get('triggers')

/* `customInfoRequests` is the result of a call to `getCustomInfoRequests` */
const getTriggersAutomation = (customInfoRequests, config) => {
  return customInfoRequests
    .then(infoRequests => {
      const defaultAutomation = _.get('triggersConfig_automation')(config)
      const requirements = {
        sanctions: defaultAutomation,
        idCardPhoto: defaultAutomation,
        idCardData: defaultAutomation,
        facephoto: defaultAutomation,
        usSsn: defaultAutomation
      }

      _.forEach(it => {
        requirements[it.id] = defaultAutomation
      }, infoRequests)

      const overrides = _.get('triggersConfig_overrides')(config)

      const requirementsOverrides = _.reduce((acc, override) => {
        return _.assign(acc, { [override.requirement]: override.automation })
      }, {}, overrides)

      return _.assign(requirements, requirementsOverrides)
    })
}

const splitGetFirst = _.compose(_.head, _.split('_'))

const getCryptosFromWalletNamespace =
  _.compose(_.without('advanced'), _.uniq, _.map(splitGetFirst), _.keys, fromNamespace('wallets'))

const getCashInSettings = config => fromNamespace(namespaces.CASH_IN)(config)

const getCryptoUnits = (crypto, config) =>
  getWalletSettings(crypto, config).cryptoUnits ?? 'full'

const setTermsConditions = toNamespace(namespaces.TERMS_CONDITIONS)

module.exports = {
  getWalletSettings,
  getCashInSettings,
  getOperatorInfo,
  getNotifications,
  getGlobalNotifications,
  getLocale,
  getGlobalLocale,
  getCommissions,
  getReceipt,
  getCompliance,
  getCoinAtmRadar,
  getTermsConditions,
  getAllCryptoCurrencies,
  getTriggers,
  getTriggersAutomation,
  getGlobalCashOut,
  getCashOut,
  getCryptosFromWalletNamespace,
  getCryptoUnits,
  setTermsConditions,
}
<|endoftext|>


<commit_before>Module("block.ui.shape", function (m) {

	var refreshTimeout;

    Class("PropertiesPanel", {
        isa: block.ui.Shape,
        has: {
            _shape: {
                is: "rw"
            }
        },
        methods: {

            // Warning ugly:
            // ele must be an input or select
            // ele.id must me a method name or a methodName-firstPara
            callProp: function (ele, shape, value) {

                var $ele = $(ele);

                var id    = ele.id
                 var parts = id.substr(4).split("-");
                 var prop  = parts[0];
                 var optionalPara = parts[1];
                 var paras = [];
                 if(optionalPara) {
                     paras.push(optionalPara)
                 }
                 if(arguments.length > 2) {
                     var val = "" + value;

                     if($ele.attr("addPx")) {
                         val += "px"
                     }
                     paras.push(val)
                 }
                 var does = $ele.attr('jooseDoes');
                 if(shape.meta.can(prop) && (!does || shape.meta.does(shape.meta.classNameToClassObject(does))) ) {
                     ele.disabled = false;
                     var val = shape[prop].apply(shape, paras);
                     if(val != null) {
                         if($ele.attr("addPx")) {
                             val = val.replace(/px/, "")
                         }
                         return val
                     } else {
                         return ""
                     }
                 } else {
                     ele.disabled = true;
                     return "n/a"
                 }
            },

            place: function () {
                var me = this;

                this.$  = $("#properties");

                this.redraw()

                this.$.find("#shapeProperties input,#shapeProperties select").each(function () {

                    var input = $(this);

                    input.change(function () {
                        var shape = me.getShape();
                        if(shape) {
                            me.callProp(this, shape, $(this).val())
                            document.manager.setDirty(true)
                            document.sync.saveState()
                        }
                    })
                })
            },

            show: function () {
                $('#shapeProperties').show()
                $('#documentProperties').hide()
                this.redraw()
            },

            hide: function () {
                $('#shapeProperties').hide()
                $('#documentProperties').show()
                this.redraw()
            },

            setShape: function (newEle) {
                this._shape = newEle
                this.refresh(newEle);
                this.show()
            },

            refresh: function (shape) {

            	if(refreshTimeout) {
            		clearTimeout(refreshTimeout)
            	}

                var me = this;

                refreshTimeout = setTimeout(function () {
                	if(shape === me.getShape()) {
                	    $('#shapeType').html(shape.type())
                	    me.$.find("#shapeProperties input, #shapeProperties select").each(function () {
                	        $(this).val(me.callProp(this, shape))
                	    })
                	    $.colorPicker.refreshSamples()
               	 	}
                }, 0)
            },

            redraw: function () {
            	var height = this.$.height();
                this.$.css("top",""+($(window).height() - height - 20) + "px"); // 10 is padding
                this.$.css("width", ""+($(window).width() - 150)  + "px"); // FIXME get rid of constants
            }
        }
    })
})<commit_msg>Fix change handling and issue a change event if an input field is tainted and the shape losses focus.<commit_after>Module("block.ui.shape", function (m) {

    var refreshTimeout;

    Class("PropertiesPanel", {
        isa: block.ui.Shape,
        has: {
            _shape: {
                is: "rw"
            },

            _openEdit: { // stores an edit action that gets executed if there wasnt an event before a change of shape
                is: "rw"
            }
        },
        methods: {

            // Warning ugly:
            // ele must be an input or select
            // ele.id must me a method name or a methodName-firstPara
            callProp: function (ele, shape, value) {

                var $ele = $(ele);

                var id    = ele.id
                 var parts = id.substr(4).split("-");
                 var prop  = parts[0];
                 var optionalPara = parts[1];
                 var paras = [];
                 if(optionalPara) {
                     paras.push(optionalPara)
                 }
                 if(arguments.length > 2) {
                     var val = "" + value;

                     if($ele.attr("addPx")) {
                         val += "px"
                     }
                     paras.push(val)
                 }
                 var does = $ele.attr('jooseDoes');
                 if(shape.meta.can(prop) && (!does || shape.meta.does(shape.meta.classNameToClassObject(does))) ) {
                     ele.disabled = false;
                     var val = shape[prop].apply(shape, paras);
                     if(val != null) {
                         if($ele.attr("addPx")) {
                             val = val.replace(/px/, "")
                         }
                         return val
                     } else {
                         return ""
                     }
                 } else {
                     ele.disabled = true;
                     return "n/a"
                 }
            },

            handleChange: function (input, shape) {
                var me = this;
                if(shape) {
                    me.setOpenEdit(null);
                    document.undo.addUpdateStep(shape)
                    me.callProp(input, shape, $(input).val())
                    shape.touch()
                }
            },

            place: function () {
                var me = this;

                this.$  = $("#properties");

                this.redraw()

                // Update property on change of input field or select box
                this.$.find("#shapeProperties input,#shapeProperties select").each(function () {
                    $(this).change(function () {
                        me.handleChange(this, me.getShape())
                    })
                })

                // if we have a keypress event on an input, we will interpret this as a change if
                // there is no onchange event, but we change shapes
                this.$.find("#shapeProperties input").each(function () {
                    $(this).keypress(function () {

                        var input = this;
                        var shape = me.getShape()

                        me.setOpenEdit(function () {
                            me.handleChange(input, shape)
                        })
                    })
                })
            },

            show: function () {
                $('#shapeProperties').show()
                $('#documentProperties').hide()
                this.redraw()
            },

            hide: function () {
                this.executeOpenEdit()
                $('#shapeProperties').hide()
                $('#documentProperties').show()
                this.redraw()
            },

            executeOpenEdit: function () {
                var edit = this.getOpenEdit();
                if(edit) {
                    edit()
                    this.setOpenEdit(null)
                }
            },

            setShape: function (newEle) {
                this.executeOpenEdit()
                this._shape = newEle
                this.refresh(newEle);
                this.show()
            },

            refresh: function (shape) {

                if(refreshTimeout) {
                    clearTimeout(refreshTimeout)
                }

                var me = this;

                // fill in values from newly assigned shape
                refreshTimeout = setTimeout(function () {
                    if(shape === me.getShape()) {
                        $('#shapeType').html(shape.type())
                        me.$.find("#shapeProperties input, #shapeProperties select").each(function () {
                            $(this).val(me.callProp(this, shape))
                        })
                        $.colorPicker.refreshSamples()
                        }
                }, 0)
            },

            redraw: function () {
                var height = this.$.height();
                this.$.css("top",""+($(window).height() - height - 20) + "px"); // 10 is padding
                this.$.css("width", ""+($(window).width() - 150)  + "px"); // FIXME get rid of constants
            }
        }
    })
})<|endoftext|>


<commit_before>var blacklist = require('blacklist');
var classnames = require('classnames');
var React = require('react');

function hasChildrenWithVerticalFill(children) {
	var result = false;

	React.Children.forEach(children, (c) => {
		if (result) return; // early-exit
		if (!c) return;
		if (!c.type) return

		result = !!c.type.shouldFillVerticalSpace;
	});

	return result;
}

var Container = React.createClass({
	propTypes: {
		align: React.PropTypes.oneOf(['end', 'center', 'start']),
		direction: React.PropTypes.oneOf(['column', 'row']),
		justify: React.PropTypes.oneOfType([
			React.PropTypes.bool,
			React.PropTypes.oneOf(['end', 'center', 'start'])
		]),
		grow: React.PropTypes.bool,
		fill: React.PropTypes.bool
	},
	componentDidMount () {
		if (this.props.scrollable && this.props.scrollable.mount) {
			this.props.scrollable.mount(this);
		}
	},
	componentWillUnmount () {
		if (this.props.scrollable && this.props.scrollable.unmount) {
			this.props.scrollable.unmount(this);
		}
	},
	render () {
		var direction = this.props.direction;
		if (!direction) {
			if (hasChildrenWithVerticalFill(this.props.children)) {
				direction = 'column';
			}
		}

		var fill = this.props.fill;
		if (direction === 'column' || this.props.scrollable) {
			fill = true;
		}

		var align = this.props.align;
		if (direction === 'column' && align === 'top') align = 'start';
		if (direction === 'column' && align === 'bottom') align = 'end';
		if (direction === 'row' && align === 'left') align = 'start';
		if (direction === 'row' && align === 'right') align = 'end';

		var className = classnames(this.props.className, {
			'Container--fill': fill,
			'Container--direction-column': direction === 'column',
			'Container--direction-row': direction === 'row',
			'Container--align-center': align === 'center',
			'Container--align-start': align === 'start',
			'Container--align-end': align === 'end',
			'Container--justify-center': this.props.justify === 'center',
			'Container--justify-start': this.props.justify === 'start',
			'Container--justify-end': this.props.justify === 'end',
			'Container--justified': this.props.justify === true,
			'Container--scrollable': this.props.scrollable
		});

		var props = blacklist(this.props, 'className', 'direction', 'fill', 'justify', 'scrollable');

		return (

				{this.props.children}

		);
	}
});

function initScrollable() {
	var pos;
	var scrollable = {
		reset () {
			pos = { left: 0, top: 0 };
		},
		mount (element) {
			var node = React.findDOMNode(element);
			node.scrollLeft = pos.left;
			node.scrollTop = pos.top;
		},
		unmount (element) {
			var node = React.findDOMNode(element);
			pos.left = node.scrollLeft;
			pos.top = node.scrollTop;
		}
	};
	scrollable.reset();
	return scrollable;
}

Container.initScrollable = initScrollable;

export default Container;
<commit_msg>Adding propType for scrollable & sorting propTypes<commit_after>var blacklist = require('blacklist');
var classnames = require('classnames');
var React = require('react');

function hasChildrenWithVerticalFill(children) {
	var result = false;

	React.Children.forEach(children, (c) => {
		if (result) return; // early-exit
		if (!c) return;
		if (!c.type) return

		result = !!c.type.shouldFillVerticalSpace;
	});

	return result;
}

var Container = React.createClass({
	propTypes: {
		align: React.PropTypes.oneOf(['end', 'center', 'start']),
		direction: React.PropTypes.oneOf(['column', 'row']),
		fill: React.PropTypes.bool,
		grow: React.PropTypes.bool,
		justify: React.PropTypes.oneOfType([
			React.PropTypes.bool,
			React.PropTypes.oneOf(['end', 'center', 'start'])
		]),
		scrollable: React.PropTypes.oneOfType([
			React.PropTypes.bool,
			React.PropTypes.object
		])
	},
	componentDidMount () {
		if (this.props.scrollable && this.props.scrollable.mount) {
			this.props.scrollable.mount(this);
		}
	},
	componentWillUnmount () {
		if (this.props.scrollable && this.props.scrollable.unmount) {
			this.props.scrollable.unmount(this);
		}
	},
	render () {
		var direction = this.props.direction;
		if (!direction) {
			if (hasChildrenWithVerticalFill(this.props.children)) {
				direction = 'column';
			}
		}

		var fill = this.props.fill;
		if (direction === 'column' || this.props.scrollable) {
			fill = true;
		}

		var align = this.props.align;
		if (direction === 'column' && align === 'top') align = 'start';
		if (direction === 'column' && align === 'bottom') align = 'end';
		if (direction === 'row' && align === 'left') align = 'start';
		if (direction === 'row' && align === 'right') align = 'end';

		var className = classnames(this.props.className, {
			'Container--fill': fill,
			'Container--direction-column': direction === 'column',
			'Container--direction-row': direction === 'row',
			'Container--align-center': align === 'center',
			'Container--align-start': align === 'start',
			'Container--align-end': align === 'end',
			'Container--justify-center': this.props.justify === 'center',
			'Container--justify-start': this.props.justify === 'start',
			'Container--justify-end': this.props.justify === 'end',
			'Container--justified': this.props.justify === true,
			'Container--scrollable': this.props.scrollable
		});

		var props = blacklist(this.props, 'className', 'direction', 'fill', 'justify', 'scrollable');

		return (

				{this.props.children}

		);
	}
});

function initScrollable() {
	var pos;
	var scrollable = {
		reset () {
			pos = { left: 0, top: 0 };
		},
		mount (element) {
			var node = React.findDOMNode(element);
			node.scrollLeft = pos.left;
			node.scrollTop = pos.top;
		},
		unmount (element) {
			var node = React.findDOMNode(element);
			pos.left = node.scrollLeft;
			pos.top = node.scrollTop;
		}
	};
	scrollable.reset();
	return scrollable;
}

Container.initScrollable = initScrollable;

export default Container;
<|endoftext|>


<commit_before>var ScudCloud = {
	overrideNotifications: function(){
		TS.ui.growls.no_notifications = false;
		TS.ui.growls.checkPermission = function() { return true; };
		TS.ui.growls.getPermissionLevel = function() { return 'granted'; };
		TS.ui.growls.show = function(j,f,o,p){ desktop.sendMessage(j,f); };
		TS.ui.banner.close();
	},
	overrideConnect: function(){
		TS.ms.connected_sig.add(function(){ScudCloud.connect(true);});
		TS.ms.disconnected_sig.add(function(){ScudCloud.connect(false);});
	},
	connect: function(b){
		desktop.enableMenus(b);
		if(b) desktop.populate(JSON.stringify({'channels': ScudCloud.listChannels(), 'teams': ScudCloud.listTeams(), 'icon': TS.model.team.icon.image_88}));
	},
    count: function(){
		var total=0;
		$('span.unread_highlight').not('.hidden').each(function(i){
			total+= new Number($(this).text().replace('+','')); }
		);
		return total;
    },
	createSnippet: function(){
		return TS.ui.snippet_dialog.start();
	},
    listChannels: function(){
		return TS.channels.getUnarchivedChannelsForUser();
	},
    listTeams: function(){
		var list = TS.getAllTeams();
		// Fix for current team displaying no icon
		list[0].team_icon = {"image_88":TS.model.team.icon.image_88};
		return list;
	},
    quicklist: function(){
		desktop.quicklist(ScudCloud.listChannels());
	},
	join: function(c){
		return TS.channels.join(c);
	},
	setClipboard: function(data){
		TS.client.ui.file_pasted_sig.dispatch(data, TS.model.shift_key_pressed);
	},
    preferences: function(){
		return TS.ui.prefs_dialog.start();
	},
    addTeam: function(){
		document.location = TS.boot_data.signin_url;
	},
	getCurrentTeam: function(){
		var list = TS.getAllTeams();
		if(list!=null) for(var i=0;list.length;i++){
			if(list[i].team_url==TS.boot_data.team_url){
				return list[i].id;
			}
		}
		return "";
	},
    logout: function(){
		document.location = TS.boot_data.logout_url;
	},
    help: function(){
		return TS.help_dialog.start();
	},
    isConnected: function(){
        return "undefined" != typeof TS && "undefined" != typeof TS.model && TS.model.ms_connected;
    }
};
if("undefined" != typeof TS){
	document.onpaste = function(e){desktop.pasted(false);};
	ScudCloud.overrideNotifications();
	ScudCloud.overrideConnect();
}
<commit_msg>Better JS<commit_after>var ScudCloud = {
    started: false,
	overrideNotifications: function(){
		TS.ui.growls.no_notifications = false;
		TS.ui.growls.checkPermission = function() { return true; };
		TS.ui.growls.getPermissionLevel = function() { return 'granted'; };
		TS.ui.growls.show = function(j,f,o,p){ desktop.sendMessage(j,f); };
		TS.ui.banner.close();
	},
	overrideConnect: function(){
		TS.ms.connected_sig.add(function(){ScudCloud.connect(true);});
		TS.ms.disconnected_sig.add(function(){ScudCloud.connect(false);});
	},
	overrideBanner: function(){
		ScudCloud.showBanner = TS.ui.banner.show;
		TS.ui.banner.show = function(){ ScudCloud.showBanner(); ScudCloud.overrideNotifications(); };
	},
	connect: function(b){
		desktop.enableMenus(b);
		if(b) desktop.populate(JSON.stringify({'channels': ScudCloud.listChannels(), 'teams': ScudCloud.listTeams(), 'icon': TS.model.team.icon.image_88}));
	},
    count: function(){
		var total=0;
		$('span.unread_highlight').not('.hidden').each(function(i){
			total+= new Number($(this).text().replace('+','')); }
		);
		return total;
    },
	createSnippet: function(){
		return TS.ui.snippet_dialog.start();
	},
    listChannels: function(){
		return TS.channels.getUnarchivedChannelsForUser();
	},
    listTeams: function(){
		var list = TS.getAllTeams();
		// Fix for current team displaying no icon
		list[0].team_icon = {"image_88":TS.model.team.icon.image_88};
		return list;
	},
    quicklist: function(){
		desktop.quicklist(ScudCloud.listChannels());
	},
	join: function(c){
		return TS.channels.join(c);
	},
	setClipboard: function(data){
		TS.client.ui.file_pasted_sig.dispatch(data, TS.model.shift_key_pressed);
	},
    preferences: function(){
		return TS.ui.prefs_dialog.start();
	},
    addTeam: function(){
		document.location = TS.boot_data.signin_url;
	},
	getCurrentTeam: function(){
		var list = TS.getAllTeams();
		if(list!=null) for(var i=0;list.length;i++){
			if(list[i].team_url==TS.boot_data.team_url){
				return list[i].id;
			}
		}
		return "";
	},
    logout: function(){
		document.location = TS.boot_data.logout_url;
	},
    help: function(){
		return TS.help_dialog.start();
	},
    isConnected: function(){
        return "undefined" != typeof TS && "undefined" != typeof TS.model && TS.model.ms_connected;
    }
};
if("undefined" != typeof TS && false == ScudCloud.started){
	document.onpaste = function(e){desktop.pasted(false);};
	ScudCloud.overrideConnect();
	ScudCloud.overrideBanner();
	ScudCloud.started = true;
}
<|endoftext|>


<commit_before>// TODO: there's probably a better way to import these...

isic.ENUMS = {};

isic.ENUMS.DEFAULT_INTERPRETATIONS = {
    'undefined': 'categorical',
    'null': 'categorical',
    boolean: 'categorical',
    integer: 'ordinal',
    number: 'ordinal',
    date: 'categorical',
    string: 'categorical',
    object: 'categorical'
};

isic.ENUMS.ATTRIBUTE_GENERALITY = [
    'object',
    'string',
    'number',
    'integer'
];

isic.ENUMS.FILTER_STATES = {
    NO_FILTERS: 0,
    FILTERED: 1,
    EXCLUDED: 2
};

isic.ENUMS.BIN_STATES = {
    INCLUDED: 0,
    EXCLUDED: 1,
    PARTIAL: 2
};

// TODO: It should be trivial to borrow code from Resonant Laboratory to
// autodetect this (requires an additional server endpoint)
isic.ENUMS.SCHEMA = {
    'folderId': {
        'coerceToType': 'objectid',
        'humanName': 'Dataset'
    },
    'meta.clinical.benign_malignant': {
        'coerceToType': 'string',
        'humanName': 'Benign / Malignant'
    },
    'meta.clinical.age': {
        'coerceToType': 'number',
        'interpretation': 'ordinal',
        'humanName': 'Age',
        'lowBound': 0,
        'highBound': 90,
        'numBins': 9
    },
    'meta.clinical.sex': {
        'coerceToType': 'string',
        'humanName': 'Sex'
    },
    'meta.clinical.clin_size_long_diam_mm': {
        'coerceToType': 'number',
        'interpretation': 'ordinal',
        'humanName': 'Clinical Size - Longest Diameter (mm)',
        'lowBound': 0,
        'highBound': 110,
        'numBins': 11
    },
    'meta.clinical.personal_hx_mm': {
        'coerceToType': 'string',
        'humanName': 'Personal History of Melanoma'
    },
    'meta.clinical.family_hx_mm': {
        'coerceToType': 'string',
        'humanName': 'Family History of Melanoma'
    }
};
<commit_msg>Display the "diagnosis_confirm_type" facet<commit_after>// TODO: there's probably a better way to import these...

isic.ENUMS = {};

isic.ENUMS.DEFAULT_INTERPRETATIONS = {
    'undefined': 'categorical',
    'null': 'categorical',
    boolean: 'categorical',
    integer: 'ordinal',
    number: 'ordinal',
    date: 'categorical',
    string: 'categorical',
    object: 'categorical'
};

isic.ENUMS.ATTRIBUTE_GENERALITY = [
    'object',
    'string',
    'number',
    'integer'
];

isic.ENUMS.FILTER_STATES = {
    NO_FILTERS: 0,
    FILTERED: 1,
    EXCLUDED: 2
};

isic.ENUMS.BIN_STATES = {
    INCLUDED: 0,
    EXCLUDED: 1,
    PARTIAL: 2
};

// TODO: It should be trivial to borrow code from Resonant Laboratory to
// autodetect this (requires an additional server endpoint)
isic.ENUMS.SCHEMA = {
    'folderId': {
        'coerceToType': 'objectid',
        'humanName': 'Dataset'
    },
    'meta.clinical.benign_malignant': {
        'coerceToType': 'string',
        'humanName': 'Benign or Malignant'
    },
    'meta.clinical.age': {
        'coerceToType': 'number',
        'interpretation': 'ordinal',
        'humanName': 'Age',
        'lowBound': 0,
        'highBound': 90,
        'numBins': 9
    },
    'meta.clinical.sex': {
        'coerceToType': 'string',
        'humanName': 'Sex'
    },
    'meta.clinical.diagnosis_confirm_type': {
        'coerceToType': 'string',
        'humanName': 'Type of Diagnosis'
    },
    'meta.clinical.clin_size_long_diam_mm': {
        'coerceToType': 'number',
        'interpretation': 'ordinal',
        'humanName': 'Clinical Size - Longest Diameter (mm)',
        'lowBound': 0,
        'highBound': 110,
        'numBins': 11
    },
    'meta.clinical.personal_hx_mm': {
        'coerceToType': 'string',
        'humanName': 'Personal History of Melanoma'
    },
    'meta.clinical.family_hx_mm': {
        'coerceToType': 'string',
        'humanName': 'Family History of Melanoma'
    }
};
<|endoftext|>


<commit_before>/* Inicialització en català per a l'extenció 'calendar' per jQuery. */
/* Writers: (joan.leon@gmail.com). */
jQuery(function($){
	$.datepicker.regional['ca'] = {
		closeText: 'Tancar',
		prevText: '<Ant',
		nextText: 'Seg>',
		currentText: 'Avui',
		monthNames: ['Gener','Febrer','Març','Abril','Maig','Juny',
		'Juliol','Agost','Setembre','Octubre','Novembre','Desembre'],
		monthNamesShort: ['Gen','Feb','Mar','Abr','Mai','Jun',
		'Jul','Ago','Set','Oct','Nov','Des'],
		dayNames: ['Diumenge','Dilluns','Dimarts','Dimecres','Dijous','Divendres','Dissabte'],
		dayNamesShort: ['Dug','Dln','Dmt','Dmc','Djs','Dvn','Dsb'],
		dayNamesMin: ['Dg','Dl','Dt','Dc','Dj','Dv','Ds'],
		weekHeader: 'Sm',
		dateFormat: 'dd/mm/yy',
		firstDay: 1,
		isRTL: false,
		showMonthAfterYear: false,
		yearSuffix: ''};
	$.datepicker.setDefaults($.datepicker.regional['ca']);
});<commit_msg>Datepicker: Updated catalan translation using globalize.js as a reference (https://github.com/jquery/globalize/blob/master/lib/cultures/globalize.culture.ca.js). Fixes #7894 Datepicker: Update Catalan Localization<commit_after>/* Inicialització en català per a l'extensió 'UI date picker' per jQuery. */
/* Writers: (joan.leon@gmail.com). */
jQuery(function($){
	$.datepicker.regional['ca'] = {
		closeText: 'Tanca',
		prevText: 'Anterior',
		nextText: 'Següent',
		currentText: 'Avui',
		monthNames: ['gener','febrer','març','abril','maig','juny',
		'juliol','agost','setembre','octubre','novembre','desembre'],
		monthNamesShort: ['gen','feb','març','abr','maig','juny',
		'jul','ag','set','oct','nov','des'],
		dayNames: ['diumenge','dilluns','dimarts','dimecres','dijous','divendres','dissabte'],
		dayNamesShort: ['dg','dl','dt','dc','dj','dv','ds'],
		dayNamesMin: ['dg','dl','dt','dc','dj','dv','ds'],
		weekHeader: 'Set',
		dateFormat: 'dd/mm/yy',
		firstDay: 1,
		isRTL: false,
		showMonthAfterYear: false,
		yearSuffix: ''};
	$.datepicker.setDefaults($.datepicker.regional['ca']);
});
<|endoftext|>


<commit_before>import React from 'react';
import TextField from 'material-ui/TextField';
import FlatButton from 'material-ui/FlatButton';

let center = {
    display: "flex",
    flexDirection: "column",
    flexWrap: "wrap",
    justifyContent: "center",
    alignItems: "center",
};

const emptyError = "Please, enter sportsman name";

class UI extends React.Component {
    constructor() {
        super();

        this.state = {
            firstName: "",
            secondName: "",
            emptyFirstNameError: null,
            emptySecondNameError: null,
        };
    }

    render() {
        return (

 Comparison

                <TextField floatingLabelText="First name"
                           style={{ marginRight: "10px" }}
                           errorText={this.state.emptyFirstNameError}
                           onChange={this.handleFirstNameChange.bind(this)
                           />

                <TextField floatingLabelText="Second name",
                           errorText={this.state.emptySecondNameError}
                           onChange={this.handleSecondNameChange.bind(this)
                           />

                <FlatButton label="Compare"
                            style={center}
                            onClick={this.validation.bind(this)}/>

        );
    }

    handleFirstNameChange = (event) => {
        this.setState({
            firstName: event.target.value,
        });
    };

    handleSecondNameChange = (event) => {
        this.setState({
            secondName: event.target.value,
        });
    };

    validation = () => {
        if (this.state.firstName === "") {
            this.setState({
                emptyFirstNameError: emptyError
            });

            return;
        }

        this.setState({
            emptyFirstNameError: null
        });

        if (this.state.secondName === "") {
            this.setState({
                emptySecondNameError: emptyError
            });

            return;
        }

        this.setState({
            emptySecondNameError: null
        });

        console.log(this.state.firstName + " " + this.state.secondName);
    };
}

export default UI;<commit_msg>created header of the comparison<commit_after>import React from 'react';
import TextField from 'material-ui/TextField';
import FlatButton from 'material-ui/FlatButton';
import Paper from 'material-ui/Paper';

let centerRow = {
    display: "flex",
    flexDirection: "row",
    flexWrap: "wrap",
    justifyContent: "center",
    alignItems: "center",
};

let centerComponents = {
    display: "flex",
    flexDirection: "column",
    flexWrap: "wrap",
    justifyContent: "center",
    alignItems: "center",
};

const emptyError = "Please, enter sportsman name";

class UI extends React.Component {
    constructor() {
        super();

        this.state = {
            firstName: "",
            secondName: "",
            emptyFirstNameError: null,
            emptySecondNameError: null,
        };
    }

    // TODO : react style
    // TODO : file with form and handling
    render() {
        return (

 Comparison

                <Paper zDepth={2}>

		                <TextField floatingLabelText="First name"
		                           style={{ marginRight: "10px",
		                           			marginLeft: "10px" }}
		                           errorText={this.state.emptyFirstNameError}
		                           onChange={this.handleFirstNameChange.bind(this)}
		                           />

		                <TextField floatingLabelText="Second name"
		                		   style={{ marginRight: "10px" }}
		                           errorText={this.state.emptySecondNameError}
		                           onChange={this.handleSecondNameChange.bind(this)}
		                           />

		                <FlatButton label="Compare"
		                			style={{ marginBottom: "10px" }}
		                            onClick={this.validation.bind(this)}/>

                </Paper>

        );
    }

    handleFirstNameChange = (event) => {
        this.setState({
            firstName: event.target.value,
        });
    };

    handleSecondNameChange = (event) => {
        this.setState({
            secondName: event.target.value,
        });
    };

    validation = () => {
        if (this.state.firstName === "") {
            this.setState({
                emptyFirstNameError: emptyError
            });

            return;
        }

        this.setState({
            emptyFirstNameError: null
        });

        if (this.state.secondName === "") {
            this.setState({
                emptySecondNameError: emptyError
            });

            return;
        }

        this.setState({
            emptySecondNameError: null
        });

        console.log(this.state.firstName + " " + this.state.secondName);
    };
}

export default UI;<|endoftext|>


<commit_before>export default {
  lang: 'el',
  label: {
    clear: 'Καθαρισμός',
    ok: 'Εντάξει',
    cancel: 'Ακύρωση',
    close: 'Κλείσιμο',
    set: 'Ορισμός',
    select: 'Επιλογή',
    reset: 'Επαναφορά',
    remove: 'Αφαίρεση',
    update: 'Αναβάθμιση',
    create: 'Δημιουργία',
    search: 'Αναζήτηση',
    filter: 'Φίλτρο',
    refresh: 'Ανανέωση'
  },
  date: {
    days: 'Κυριακή_Δευτέρα_Τρίτη_Τετάρτη_Πέμπτη_Παρασκευή_Σάββατο'.split('_'),
    daysShort: 'Κυρ_Δευ_Τρι_Τετ_Πεμ_Παρ_Σαβ'.split('_'),
    months: 'Ιανουάριος_Φεβρουάριος_Μάρτιος_Απρίλιος_Μάιος_Ιούνιος_Ιούλιος_Αύγουστος_Σεπτέμβριος_Οκτώβριος_Νοέμβριος_Δεκέμβριος'.split('_'),
    monthsShort: 'Ιαν_Φεβ_Μαρ_Απρ_Μαϊ_Ιουν_Ιουλ_Αυγ_Σεπ_Οκτ_Νοε_Δεκ'.split('_'),
    firstDayOfWeek: 1, // 0-6, 0 - Sunday, 1 Monday, ...
    format24h: true
  },
  pullToRefresh: {
    pull: 'Τράβηξε κάτω για ανανέωση',
    release: 'Άφησε για ανανέωση',
    refresh: 'Ανανέωση...'
  },
  table: {
    noData: 'Χωρίς δεδομένα',
    noResults: 'Δεν βρέθηκαν αποτελέσματα',
    loading: 'Φόρτωση...',
    selectedRecords: function (rows) {
      return rows === 1
        ? '1 επιλεγμένη εγγραφή.'
        : (rows === 0 ? 'Καμμία' : rows) + ' επιλεγμένες εγγραφές.'
    },
    recordsPerPage: 'Εγγραφές ανα σελίδα:',
    allRows: 'Όλες',
    pagination: function (start, end, total) {
      return start + '-' + end + ' από ' + total
    },
    columns: 'Στήλες'
  },
  editor: {
    url: 'Διεύθυνση URL', // Needs Translation
    bold: 'Έντονα',
    italic: 'Πλάγια',
    strikethrough: 'Διακριτή διαγραφή',
    underline: 'Υπογράμμιση',
    unorderedList: 'Αταξινόμητη λίστα',
    orderedList: 'Ταξινομημένη λίστα',
    subscript: 'Δείκτης',
    superscript: 'Εκθέτης',
    hyperlink: 'Υπερσύνδεσμος',
    toggleFullscreen: 'Εναλλαγή μεγιστοποίησης οθόνης',
    quote: 'Παράθεση',
    left: 'Αριστερή στοίχιση',
    center: 'Κεντρική στοίχιση',
    right: 'Δεξιά στοίχιση',
    justify: 'Πλήρης στοίχιση',
    print: 'Εκτύπωση',
    outdent: 'Μείωση εσοχής',
    indent: 'Αύξηση εσοχής',
    removeFormat: 'Απαλοιφή μορφοποίησης',
    formatting: 'Μορφοποίηση',
    fontSize: 'Μέγεθος γραμματοσειράς',
    align: 'Στοίχιση',
    hr: 'Εισαγωγή οριζόντιας γραμμής',
    undo: 'Αναίρεση',
    redo: 'Επανάληψη',
    header1: 'Επικεφαλίδα 1',
    header2: 'Επικεφαλίδα 2',
    header3: 'Επικεφαλίδα 3',
    header4: 'Επικεφαλίδα 4',
    header5: 'Επικεφαλίδα 5',
    header6: 'Επικεφαλίδα 6',
    paragraph: 'Παράγραφος',
    code: 'Κώδικας',
    size1: 'Πολύ μικρό',
    size2: 'Μικρό',
    size3: 'Κανονικό',
    size4: 'Μεσαίο',
    size5: 'Μεγάλο',
    size6: 'Πολύ μεγάλο',
    size7: 'Μέγιστο',
    defaultFont: 'Προκαθορισμένη gραμματοσειρά'
  },
  tree: {
    noNodes: 'Μη διαθέσιμοι κόμβοι',
    noResults: 'Δεν βρέθηκαν αποτελέσματα'
  }
}
<commit_msg>fix: Greek translation letter updated (#2355)<commit_after>export default {
  lang: 'el',
  label: {
    clear: 'Καθαρισμός',
    ok: 'Εντάξει',
    cancel: 'Ακύρωση',
    close: 'Κλείσιμο',
    set: 'Ορισμός',
    select: 'Επιλογή',
    reset: 'Επαναφορά',
    remove: 'Αφαίρεση',
    update: 'Αναβάθμιση',
    create: 'Δημιουργία',
    search: 'Αναζήτηση',
    filter: 'Φίλτρο',
    refresh: 'Ανανέωση'
  },
  date: {
    days: 'Κυριακή_Δευτέρα_Τρίτη_Τετάρτη_Πέμπτη_Παρασκευή_Σάββατο'.split('_'),
    daysShort: 'Κυρ_Δευ_Τρι_Τετ_Πεμ_Παρ_Σαβ'.split('_'),
    months: 'Ιανουάριος_Φεβρουάριος_Μάρτιος_Απρίλιος_Μάιος_Ιούνιος_Ιούλιος_Αύγουστος_Σεπτέμβριος_Οκτώβριος_Νοέμβριος_Δεκέμβριος'.split('_'),
    monthsShort: 'Ιαν_Φεβ_Μαρ_Απρ_Μαϊ_Ιουν_Ιουλ_Αυγ_Σεπ_Οκτ_Νοε_Δεκ'.split('_'),
    firstDayOfWeek: 1, // 0-6, 0 - Sunday, 1 Monday, ...
    format24h: true
  },
  pullToRefresh: {
    pull: 'Τράβηξε κάτω για ανανέωση',
    release: 'Άφησε για ανανέωση',
    refresh: 'Ανανέωση...'
  },
  table: {
    noData: 'Χωρίς δεδομένα',
    noResults: 'Δεν βρέθηκαν αποτελέσματα',
    loading: 'Φόρτωση...',
    selectedRecords: function (rows) {
      return rows === 1
        ? '1 επιλεγμένη εγγραφή.'
        : (rows === 0 ? 'Καμμία' : rows) + ' επιλεγμένες εγγραφές.'
    },
    recordsPerPage: 'Εγγραφές ανα σελίδα:',
    allRows: 'Όλες',
    pagination: function (start, end, total) {
      return start + '-' + end + ' από ' + total
    },
    columns: 'Στήλες'
  },
  editor: {
    url: 'Διεύθυνση URL', // Needs Translation
    bold: 'Έντονα',
    italic: 'Πλάγια',
    strikethrough: 'Διακριτή διαγραφή',
    underline: 'Υπογράμμιση',
    unorderedList: 'Αταξινόμητη λίστα',
    orderedList: 'Ταξινομημένη λίστα',
    subscript: 'Δείκτης',
    superscript: 'Εκθέτης',
    hyperlink: 'Υπερσύνδεσμος',
    toggleFullscreen: 'Εναλλαγή μεγιστοποίησης οθόνης',
    quote: 'Παράθεση',
    left: 'Αριστερή στοίχιση',
    center: 'Κεντρική στοίχιση',
    right: 'Δεξιά στοίχιση',
    justify: 'Πλήρης στοίχιση',
    print: 'Εκτύπωση',
    outdent: 'Μείωση εσοχής',
    indent: 'Αύξηση εσοχής',
    removeFormat: 'Απαλοιφή μορφοποίησης',
    formatting: 'Μορφοποίηση',
    fontSize: 'Μέγεθος γραμματοσειράς',
    align: 'Στοίχιση',
    hr: 'Εισαγωγή οριζόντιας γραμμής',
    undo: 'Αναίρεση',
    redo: 'Επανάληψη',
    header1: 'Επικεφαλίδα 1',
    header2: 'Επικεφαλίδα 2',
    header3: 'Επικεφαλίδα 3',
    header4: 'Επικεφαλίδα 4',
    header5: 'Επικεφαλίδα 5',
    header6: 'Επικεφαλίδα 6',
    paragraph: 'Παράγραφος',
    code: 'Κώδικας',
    size1: 'Πολύ μικρό',
    size2: 'Μικρό',
    size3: 'Κανονικό',
    size4: 'Μεσαίο',
    size5: 'Μεγάλο',
    size6: 'Πολύ μεγάλο',
    size7: 'Μέγιστο',
    defaultFont: 'Προκαθορισμένη γραμματοσειρά'
  },
  tree: {
    noNodes: 'Μη διαθέσιμοι κόμβοι',
    noResults: 'Δεν βρέθηκαν αποτελέσματα'
  }
}
<|endoftext|>


<commit_before>'use strict';

var Node = require('../node');

var TYPE = 'closest';

var PARAMS = {
    source: Node.PARAM.NODE(Node.GEOMETRY.ANY),
    target: Node.PARAM.NODE(Node.GEOMETRY.ANY),
    responses: Node.PARAM.NULLABLE(Node.PARAM.NUMBER(), 1),
    category: Node.PARAM.NULLABLE(Node.PARAM.STRING())
};

var Closest = Node.create(TYPE, PARAMS, {cache: true, version: 1});

module.exports = Closest;

var closestTemplate = Node.template([
    'WITH',
    '    source as({{=it.squery}}),',
    '    target as({{=it.tquery}})',
    'SELECT',
    '    t.*,',
    '    source.cartodb_id as source_cartodb_id,',
    '    {{? it.responses > 1}} t.ranking as closest_rank,{{?}}',
    '    ST_Distance(geography(t.the_geom), geography(source.the_geom)) as closest_dist',
    'FROM source',
    'CROSS JOIN LATERAL (',
    '    SELECT * FROM (',
    '        SELECT *,',
    '            row_number() over(',
    '                {{? it.category !== null}}PARTITION BY {{=it.category}}{{?}}',
    '                ORDER BY source.the_geom <-> the_geom',
    '            ) AS ranking',
    '        FROM target',
    '    ) AS ranked',
    '    WHERE ranking <= {{=it.responses}}',
    ') AS t'
].join('\n'));

Closest.prototype.sql = function(){
    return closestTemplate({
        squery: this.source.getQuery(),
        tquery: this.target.getQuery(),
        responses: this.responses,
        category: this.category
    });
};
<commit_msg>fix dupped cartodb_id and giving back the source geom when autocrossing nodes<commit_after>'use strict';

var Node = require('../node');

var TYPE = 'closest';

var PARAMS = {
    source: Node.PARAM.NODE(Node.GEOMETRY.ANY),
    target: Node.PARAM.NODE(Node.GEOMETRY.ANY),
    responses: Node.PARAM.NULLABLE(Node.PARAM.NUMBER(), 1),
    category: Node.PARAM.NULLABLE(Node.PARAM.STRING())
};

var Closest = Node.create(TYPE, PARAMS, {
    cache: true,
    version: 1
});

module.exports = Closest;

var closestTemplate = Node.template([
    'WITH',
    '    source as({{=it.squery}}),',
    '    target as({{=it.tquery}})',
    'SELECT',
    '    row_number() over() as cartodb_id,',
    '    {{=it.tcolumns}},',
    '    t.cartodb_id as target_cartodb_id,',
    '    source.cartodb_id as source_cartodb_id,',
    '    {{? it.responses > 1}} t.ranking as closest_rank,{{?}}',
    '    ST_Distance(geography(t.the_geom), geography(source.the_geom)) as closest_dist',
    'FROM source',
    'CROSS JOIN LATERAL (',
    '    SELECT * FROM (',
    '        SELECT *,',
    '            row_number() over(',
    '                {{? it.category !== null}}PARTITION BY {{=it.category}}{{?}}',
    '                ORDER BY source.the_geom <-> the_geom',
    '            ) AS ranking',
    '        FROM target',
    '    ) AS ranked',
    '    WHERE ranking <= {{=it.responses}}',
    '    AND not ST_equals(the_geom, source.the_geom)',
    ') AS t'
].join('\n'));

Closest.prototype.sql = function () {
    var tcols =
        return closestTemplate({
            squery: this.source.getQuery(),
            tquery: this.target.getQuery(),
            tcolumns: this.target.getColumns().filter(function (column1) {
                return column1 !== ‘cartodb_id’;
            }).map(function (column2) {
                return 't.' + column2;
            }).join(', '),
            responses: this.responses,
            category: this.category
        });
};
<|endoftext|>


<commit_before>/**
 * Posts
 *
 * for PostsController
 */
var Posts = {};

/**
 * functions to execute when document is ready
 *
 * only for PagesController
 *
 * @return void
 */
Posts.documentReady = function() {
    Posts.search();
}

/**
 * Submits form for searching Pages
 *
 * @return void
 */
Posts.search = function() {

    $('#PostAdminIndexForm, #PostAdminFilterForm').submit(function() {
        var q='';

        //query string
        if($('#PostQ').val() != '') {
            q=$('#PostQ').val();
        }
        var loadUrl = Hurad.basePath + 'admin/posts/index';
        if (q != '') {
            loadUrl +='/q:'+q;
        }

        window.location = loadUrl;
        return false;
    });
}

/**
 * document ready
 *
 * @return void
 */
$(document).ready(function() {
    if (Hurad.params.controller == 'posts') {
        Posts.documentReady();
    }
});
<commit_msg>Change form id.<commit_after>/**
 * Posts
 *
 * for PostsController
 */
var Posts = {};

/**
 * functions to execute when document is ready
 *
 * only for PagesController
 *
 * @return void
 */
Posts.documentReady = function() {
    Posts.search();
}

/**
 * Submits form for searching Pages
 *
 * @return void
 */
Posts.search = function() {

    $('#AdminSearchForm').submit(function() {
        var q='';

        //query string
        if($('#PostQ').val() != '') {
            q=$('#PostQ').val();
        }
        var loadUrl = Hurad.basePath + 'admin/posts/index';
        if (q != '') {
            loadUrl +='/q:'+q;
        }

        window.location = loadUrl;
        return false;
    });
}

/**
 * document ready
 *
 * @return void
 */
$(document).ready(function() {
    if (Hurad.params.controller == 'posts') {
        Posts.documentReady();
    }
});
<|endoftext|>


<commit_before>'use strict';

var Node = require('../node');

var TYPE = 'closest';

var PARAMS = {
    source: Node.PARAM.NODE(Node.GEOMETRY.ANY),
    target: Node.PARAM.NODE(Node.GEOMETRY.ANY),
    responses: Node.PARAM.NULLABLE(Node.PARAM.NUMBER(), 1)
};

var Closest = Node.create(TYPE, PARAMS, {cache: true, version: 1});

module.exports = Closest;

var closestTemplate = Node.template([
    'WITH',
    ' source as({{=it.squery}}),',
    ' target as({{=it.tquery}})',
    'SELECT',
    ' s.*,',
    ' t.cartodb_id as closest_id,',
    ' ST_Distance(geography(t.the_geom),',
    ' geography(s.the_geom)) as closest_dist',
    'FROM',
    '(',
        'SELECT DISTINCT ON (the_geom) *',
        ' FROM source',
    ') AS s',
    'CROSS JOIN LATERAL',
    '(',
        'SELECT cartodb_id, the_geom',
        ' FROM target',
        ' ORDER BY s.the_geom <-> the_geom',
        ' LIMIT {{=it.responses}}',
    ') AS t'
].join('\n');

Closest.prototype.sql = function(){
    return closestTemplate({
        squery: this.source.getQuery(),
        tquery: this.target.getQuery(),
        responses: this.responses
    });
};
<commit_msg>Add multiple results option<commit_after>'use strict';

var Node = require('../node');

var TYPE = 'closest';

var PARAMS = {
    source: Node.PARAM.NODE(Node.GEOMETRY.ANY),
    target: Node.PARAM.NODE(Node.GEOMETRY.ANY),
    responses: Node.PARAM.NULLABLE(Node.PARAM.NUMBER(), 1)
};

var Closest = Node.create(TYPE, PARAMS, {cache: true, version: 1});

module.exports = Closest;

var closestTemplate = Node.template([
    'WITH',
    ' source as({{=it.squery}}),',
    ' target as({{=it.tquery}})',
    'SELECT',
    ' s.*,',
    ' t.cartodb_id as closest_id,',
    ' ST_Distance(geography(t.the_geom),',
    ' geography(s.the_geom)) as closest_dist',
    'FROM',
    '(',
        'SELECT DISTINCT ON (the_geom) *',
        ' FROM source',
    ') AS s',
    'CROSS JOIN LATERAL',
    '(',
        'SELECT cartodb_id, the_geom',
        ' FROM target',
        ' ORDER BY s.the_geom <-> the_geom',
        ' LIMIT {{=it.responses}}',
    ') AS t'
].join('\n'));

Closest.prototype.sql = function(){
    return closestTemplate({
        squery: this.source.getQuery(),
        tquery: this.target.getQuery(),
        responses: this.responses
    });
};
<|endoftext|>


<commit_before>/* eslint-disable no-console */

const maxIdLength = 16;
const validIdPattern = /^[0-9a-z]+$/;
const indentErrMsg = ' '.repeat(9);

/**
 * Write incorrectly formatted curriculum ids in paths, course, and lessons
 * to the console.log.
 *
 * @param {String[]} invalidIds - Array of erroneous ids
 * @param {string} errMessage - Custom error message describing the situation
 * @returns {[]} - empty array
 */
const logInvalidIds = (invalidIds, errMessage) => {
  invalidIds.forEach((id) => {
    console.log(`${indentErrMsg}${errMessage} for ${id}`);
  });
  return [];
};

/**
 * Write curriculum ids in paths, course, and lessons which have invalid
 * relationship connections to the console.log.
 *
 * @param {String} fromElementNm - Name of the curriculum element containing the reference to the id
 * @param {String} toElementNm - Name of the curriculum element that defines the id
 * @param {String[]} invalidIds - Array of erroneous ids
 * @returns {[]} - empty array
 */
const logInvalidRelations = (fromElementNm, toElementNm, invalidIds) => {
  invalidIds.forEach((id) => {
    console.log(`${indentErrMsg}${fromElementNm} id ${id[0]} contains unknown ${toElementNm} id ${id[1]}`);
  });
  return [];
};

/**
 * Validate the composition of a path, course, lesson identifier
 *
 * @param {Object} jsonData - JSON object containing the data elements. This
 * must be formatted as {"<id>": {...id: "<id>"...}...}
 * @returns {String[]} invalidIds - Array of invalid id's. Those containing
 * something other than lowercase letters and digits.
 */
const validateIdComposition = jsonData => Object.keys(jsonData).reduce((invalidIds, itemId) => {
  if (!itemId.match(validIdPattern)) {
    invalidIds.push(itemId);
  }
  return invalidIds;
}, []);

/**
 * Verify that the key of JSON element matches the value of the 'id'
 * attribute inside the element block.
 *
 * @param {Object} jsonData - JSON object containing the data elements. This
 * must be formatted as {"<id>": {...id: "<id>"...}...}.
 * @returns {String[]} invalidIds - Array of invalid id's. Those that don't
 * match the key of the element block.
 */
const validateIdMatch = jsonData => Object.keys(jsonData).reduce((invalidIds, itemId) => {
  if (itemId !== jsonData[itemId].id) {
    invalidIds.push(itemId);
  }
  return invalidIds;
}, []);

/**
 * Validate the length of a path, course, lesson identifier
 *
 * @param {Object} jsonData - JSON object containing the data elements. This
 * must be formatted as {"<id>": {...id: "<id>"...}...}
 * @returns {String[]} invalidIds - Array of id's exceeding 16 characters
 */
const validateIdLength = jsonData => Object.keys(jsonData).reduce((invalidIds, itemId) => {
  if (itemId.length > maxIdLength) {
    invalidIds.push(itemId);
  }
  return invalidIds;
}, []);

/**
 * Polyfill to insulate the app from the fact that Object.values is an
 * experimental feature not found in all browsers.
 *
 * @param {Object} x - The object values are to be extracted from.
 * @returns {Array} - An array of object values
 */
Object.values = x =>
  Object.keys(x).reduce((y, z) => y.push(x[z]) && y, []);

/**
 * Validate a relationship between two data elements.
 *
 * @param {String} childAttrNm - Attribute name in the child JSON object
 * @param {Object} childJSON - JSON object containing the child data elements.
 * This must be formatted as {"<id>": {...id: "<id>"...}...}
 * @param {String} parentAttrNm - Attribute name in the child JSON object
 * @param {Object} parentJSON - JSON object containing the parent data elements.
 * This must be formatted as {"<id>": {...id: "<id>"...}...}
 * @returns {String[]} invalidIds - Array of id's exceeding 16 characters
 */
const validateRelationship = (childAttrNm, childJSON, parentAttrNm, parentJSON) =>
    Object.values(childJSON).reduce((invalidIds, childElement) => {
      childElement[childAttrNm].forEach((itemId) => {
        if (parentJSON[itemId] === undefined) {
          invalidIds.push([childElement.id, itemId]);
        }
      });
      return invalidIds;
    }, []);

export { logInvalidIds, logInvalidRelations,
  validateIdComposition, validateIdLength, validateIdMatch, validateRelationship };
<commit_msg>Add attribution to Object.values function and refactor to use .map<commit_after>/* eslint-disable no-console */

const maxIdLength = 16;
const validIdPattern = /^[0-9a-z]+$/;
const indentErrMsg = ' '.repeat(9);

/**
 * Write incorrectly formatted curriculum ids in paths, course, and lessons
 * to the console.log.
 *
 * @param {String[]} invalidIds - Array of erroneous ids
 * @param {string} errMessage - Custom error message describing the situation
 * @returns {[]} - empty array
 */
const logInvalidIds = (invalidIds, errMessage) => {
  invalidIds.forEach((id) => {
    console.log(`${indentErrMsg}${errMessage} for ${id}`);
  });
  return [];
};

/**
 * Write curriculum ids in paths, course, and lessons which have invalid
 * relationship connections to the console.log.
 *
 * @param {String} fromElementNm - Name of the curriculum element containing the reference to the id
 * @param {String} toElementNm - Name of the curriculum element that defines the id
 * @param {String[]} invalidIds - Array of erroneous ids
 * @returns {[]} - empty array
 */
const logInvalidRelations = (fromElementNm, toElementNm, invalidIds) => {
  invalidIds.forEach((id) => {
    console.log(`${indentErrMsg}${fromElementNm} id ${id[0]} contains unknown ${toElementNm} id ${id[1]}`);
  });
  return [];
};

/**
 * Validate the composition of a path, course, lesson identifier
 *
 * @param {Object} jsonData - JSON object containing the data elements. This
 * must be formatted as {"<id>": {...id: "<id>"...}...}
 * @returns {String[]} invalidIds - Array of invalid id's. Those containing
 * something other than lowercase letters and digits.
 */
const validateIdComposition = jsonData => Object.keys(jsonData).reduce((invalidIds, itemId) => {
  if (!itemId.match(validIdPattern)) {
    invalidIds.push(itemId);
  }
  return invalidIds;
}, []);

/**
 * Verify that the key of JSON element matches the value of the 'id'
 * attribute inside the element block.
 *
 * @param {Object} jsonData - JSON object containing the data elements. This
 * must be formatted as {"<id>": {...id: "<id>"...}...}.
 * @returns {String[]} invalidIds - Array of invalid id's. Those that don't
 * match the key of the element block.
 */
const validateIdMatch = jsonData => Object.keys(jsonData).reduce((invalidIds, itemId) => {
  if (itemId !== jsonData[itemId].id) {
    invalidIds.push(itemId);
  }
  return invalidIds;
}, []);

/**
 * Validate the length of a path, course, lesson identifier
 *
 * @param {Object} jsonData - JSON object containing the data elements. This
 * must be formatted as {"<id>": {...id: "<id>"...}...}
 * @returns {String[]} invalidIds - Array of id's exceeding 16 characters
 */
const validateIdLength = jsonData => Object.keys(jsonData).reduce((invalidIds, itemId) => {
  if (itemId.length > maxIdLength) {
    invalidIds.push(itemId);
  }
  return invalidIds;
}, []);

/**
 * Polyfill to insulate the app from the fact that Object.values is an
 * experimental feature not found in all browsers. This solution was
 * copied from https://stackoverflow.com/questions/35090153/babel-support-for-object-entries
 *
 * @param {Object} x - The object values are to be extracted from.
 * @returns {Array} - An array of object values
 */
Object.values = anObject =>
  Object.keys(anObject).map(key => anObject[key]);

/**
 * Validate a relationship between two data elements.
 *
 * @param {String} childAttrNm - Attribute name in the child JSON object
 * @param {Object} childJSON - JSON object containing the child data elements.
 * This must be formatted as {"<id>": {...id: "<id>"...}...}
 * @param {String} parentAttrNm - Attribute name in the child JSON object
 * @param {Object} parentJSON - JSON object containing the parent data elements.
 * This must be formatted as {"<id>": {...id: "<id>"...}...}
 * @returns {String[]} invalidIds - Array of id's exceeding 16 characters
 */
const validateRelationship = (childAttrNm, childJSON, parentAttrNm, parentJSON) =>
    Object.values(childJSON).reduce((invalidIds, childElement) => {
      childElement[childAttrNm].forEach((itemId) => {
        if (parentJSON[itemId] === undefined) {
          invalidIds.push([childElement.id, itemId]);
        }
      });
      return invalidIds;
    }, []);

export { logInvalidIds, logInvalidRelations,
  validateIdComposition, validateIdLength, validateIdMatch, validateRelationship };
<|endoftext|>


<commit_before>appricot = {};

appricot.run = function() {
    if (window.location.protocol != 'https:') {
        window.location.href = 'https://appricot.me';
        return;
    }
    var app = new appricot.App();
    app.render(document.getElementById('root'));
};

appricot.login = function() {
    window.location.href = [
        "https://alpha.app.net/oauth/authenticate?",
        "client_id=","PkMGurQpTzGLmcyzK65sj4JXpkzVwUtE",
        "&response_type=token",
        "&redirect_uri=","https://appricot.me/",
        "&scope=stream write_post",
    ].join('');
};

appricot.App = Class.$extend({
    rootNode: null,
    authenticated: false,

    __init__: function() {
        if (window.location.hash.match('#access_token') || window.localStorage['ACCESS_TOKEN']) {
            if (window.location.hash.match('#access_token')) {
                appricot.ACCESS_TOKEN = window.location.hash.split("=")[1];
                window.localStorage['ACCESS_TOKEN'] = appricot.ACCESS_TOKEN;
            } else {
                appricot.ACCESS_TOKEN = window.localStorage['ACCESS_TOKEN'];
            }
            window.location.href = '#';
            this.authenticated = true;
        } else {
            appricot.login();
        }
    },

    render: function(node) {
        this.rootNode = node;

        if (this.authenticated) {
            this.renderUI();
        }
    },

    renderUI: function() {
        var userStream = new appricot.UserStream();
        var globalStream = new appricot.GlobalStream();
        var mentionStream = new appricot.MentionStream();

        var pageContainer = document.createElement('div');
        bonzo(pageContainer).addClass('row');

        var toolbar = document.createElement('div');
        bonzo(toolbar).addClass('span1 toolbar');

        var mainPage = document.createElement('div');
        bonzo(mainPage).addClass('span11');

        var streams = document.createElement('div');
        bonzo(streams).addClass('row');

        bonzo(mainPage).append(streams);

        var refresh = document.createElement('button');
        bonzo(refresh)
            .addClass('btn')
            .html("");
        bean.add(refresh, 'click', _.bind(this.handleRefreshButton, this, userStream));
        bean.add(refresh, 'click', _.bind(this.handleRefreshButton, this, globalStream));
        bean.add(refresh, 'click', _.bind(this.handleRefreshButton, this, mentionStream));
        bonzo(toolbar).append(refresh);

        bonzo(streams).append(userStream.render());
        bonzo(streams).append(mentionStream.render());
        bonzo(streams).append(globalStream.render());
        bonzo(userStream.render()).addClass('stream1');
        bonzo(mentionStream.render()).addClass('stream2');
        bonzo(globalStream.render()).addClass('stream3');

        bonzo(pageContainer)
            .append(toolbar)
            .append(mainPage);

        bonzo(this.rootNode).append(pageContainer);
        userStream.load();
        mentionStream.load();
        globalStream.load();
    },

    handleRefreshButton: function(stream) {
        _gaq.push(['_trackEvent', 'Streams', 'Refresh Button Click', '']);
        stream.loadMoreNewer();
    }
});

appricot.PostBox = Class.$extend({
    node: null,

    __init__: function() {

    },

    render: function() {
        if (!this.node) {
            this.node = document.createElement('div');
        }

        return this.node;
    }
});

appricot.Stream = Class.$extend({
    cache: null,
    isFetching: false,
    topOfFirstLoad: 0,
    postNode: null,
    firstLoad: true,
    currentTopPostId: 0,

    __init__: function(endpoint) {
        this.endpoint = endpoint;
        this.cache = [];
    },

    load: function() {
        this.cache = [];
        if (this.firstLoad) {
            this.firstLoad = false;
            this.loadPositionFromServer();
            return;
        }
        // var lastPos = window.localStorage['stream_pos_' + this.type];
        if (this.currentTopPostId) {
            this.loadTopStreamAfterNextFetch = true;
            this.loadData({
                before_id: parseInt(this.currentTopPostId, 10) + 1
            });
        } else {
            this.loadData();
        }
    },

    loadPositionFromServer: function() {
        reqwest({
            url: 'https://appricot.me/go/get_position',
            type: 'json',
            data: {
                'access_token': appricot.ACCESS_TOKEN,
                'stream_id': this.type
            },
            success: _.bind(this.handlePositionLoad, this)
        });
    },

    savePositionToServer: _.debounce(function(pos) {
        reqwest({
            url: 'https://appricot.me/go/set_position',
            type: 'json',
            data: {
                'access_token': appricot.ACCESS_TOKEN,
                'stream_id': this.type,
                'position': pos
            }
        });
    }, 10000),

    handlePositionLoad: function(data) {
        if (data["code"] == 401) {
            appricot.login();
            return;
        }

        this.currentTopPostId = data['position'];
        if (this.currentTopPostId) {
            this.currentTopPostId = parseInt(this.currentTopPostId, 10);
        }

        this.load();
    },

    loadData: function(params) {
        this.isFetching = true;

        params = params || {};

        reqwest({
            url: this.endpoint,
            type: 'json',
            data: _.extend({
                'access_token': appricot.ACCESS_TOKEN,
                'count': 100
            }, params),
            success: _.bind(this.handleLoad, this),
            error: _.bind(function(err) {
                if (err.status == 401) {
                    appricot.login();
                }
            }, this)
        });
    },

    render: function() {
        if (!this.node) {
            this.node = document.createElement('div');
            bonzo(this.node).addClass('span6 stream_container');

            this.statusBar = document.createElement('div');
            bonzo(this.statusBar).addClass('row-fluid statusbar');
            bonzo(this.node).append(this.statusBar);

            this.postNode = document.createElement('div');
            bonzo(this.postNode).addClass('stream_post_container');
            bonzo(this.node).append(this.postNode);
            bean.add(this.postNode, 'scroll', _.bind(this.handleScroll, this));
        }

        return this.node;
    },

    updateStatus: function(count) {
        bonzo(this.statusBar).html(
            Mustache.render("{{count}} new posts", {
                count: count
            })
        );
    },

    handleScroll: function(e) {
        if (this.lockScroll) {
            return;
        }

        var count = 0;
        if (this.cache.length > 0) {
            var scrollTop = bonzo(this.postNode).scrollTop();
            var topPost = _.find(this.cache, function(item) {
                if(item.render().offsetTop >= scrollTop) {
                    return true;
                }
                count++;
            }, this);

            if (this.currentTopPostId != topPost.id) {
                // window.localStorage['stream_pos_' + this.type] = topPost.id;
                this.savePositionToServer(topPost.id);
                this.currentTopPostId = topPost.id;
            }
            this.updateStatus(count);
        }

        var wrappedNode = bonzo(this.postNode);
        if (wrappedNode.scrollTop() >= this.postNode.scrollHeight - wrappedNode.offset().height - 10) {
            this.loadMorePrevious();
        }
    },

    handleLoad: function(data) {
        var fetchMoreBefore = null;
        var oldTopPost = null;
        var topOfCache = null;

        var isFreshCache = (this.cache.length == 0);

        if (data.length == 0) {
            console.log("NO DATA!? OMG");
            return;
        }

        // Create post wrapper objects for all the new items.
        data = _.map(data, function(item) {
            return new appricot.Post(item);
        });

        if (isFreshCache) {
            this.topOfFirstLoad = _.first(data).id;
        } else {
            topOfCache = _.first(this.cache);
            // new data is "newer" than the existing cache data.
            console.log(_.last(data).id, this.topOfFirstLoad);
            if (this.topOfFirstLoad && _.last(data).id <= this.topOfFirstLoad) {
                this.topOfFirstLoad = 0;
            }
            if (_.last(data).id > _.first(this.cache).id) {
                this.topOfFirstLoad = _.first(this.cache).id;
            }

            // the post which is on top at present (before we add in the new dataset).
            oldTopPost = _.first(this.cache);
        }

        this.cache = _.union(this.cache, data);

        var idMap = _.groupBy(this.cache, 'id');
        this.cache = _.map(idMap, function(value, key, list) {
            if (value.length == 1) {
                return value[0];
            } else {
                var rendered = _.find(value, function(post) {
                    if (bonzo(post.render()).parent().length > 0) {
                        return true;
                    }
                }, this);

                if (rendered) {
                    return rendered;
                } else {
                    return value[0];
                }
            }
        }, this);

        this.cache = _.sortBy(this.cache, function(item) { return item.id; }); // this will break for large numbers...
        // this.cache = _.uniq(this.cache, true, function(item) { return item.id; });
        this.cache.reverse();

        var oldScrollHeight = this.postNode.scrollHeight;
        this.lockScroll = true;
        var shouldAdjustPosition = false;

        _.each(this.cache, function(element, index, list) {
            if (bonzo(element.render()).parent().length == 0) {
                if (index == 0) {
                    bonzo(this.postNode).prepend(element.render());
                } else {
                    bonzo(element.render()).insertAfter(list[index - 1].render());
                }
            }
        }, this);

        // Was this element above the current viewed top post?
        if (this.currentTopPostId && _.first(data).id > this.currentTopPostId) {
            shouldAdjustPosition = true;
        }

        if (!isFreshCache && shouldAdjustPosition) {
            var diffScrollHeight = this.postNode.scrollHeight - oldScrollHeight;
            bonzo(this.postNode).scrollTop(bonzo(this.postNode).scrollTop() + diffScrollHeight);
        }

        this.lockScroll = false;

        this.isFetching = false;

        if (this.topOfFirstLoad) {
            this.loadData({
                since_id: this.topOfFirstLoad - 1,
                before_id: (_.last(data).id > this.topOfFirstLoad ? _.last(data).id : null)
            });
            return;
        }

        if (fetchMoreBefore) {
            this.loadMoreNewer(fetchMoreBefore);
        }
    },

    loadMorePrevious: function() {
        if (this.isFetching) {
            return;
        }

        this.loadData({before_id: _.last(this.cache).id});
    },

    loadMoreNewer: function(before_id) {
        if (this.isFetching) {
            return;
        }

        this.loadData({
            since_id: parseInt(_.first(this.cache).id) - 1,
            before_id: before_id || null
        });
    }
});

appricot.UserStream = appricot.Stream.$extend({
    type: 'userstream',

    __init__: function() {
        this.$super('https://alpha-api.app.net/stream/0/posts/stream');
    }
});

appricot.GlobalStream = appricot.Stream.$extend({
    type: 'globalstream',

    __init__: function() {
        this.$super('https://alpha-api.app.net/stream/0/posts/stream/global');
    },

    load: function() {
        this.cache = [];

        this.loadData();
    }
});

appricot.MentionStream = appricot.Stream.$extend({
    type: 'mentionstream',

    __init__: function() {
        this.$super('https://alpha-api.app.net/stream/0/users/me/mentions');
    }
});

appricot.Post = Class.$extend({
    post: null,
    node: null,
    id: 0,

    __init__: function(post) {
        this.post = post;
        this.id = parseInt(this.post.id, 10);
    },

    render: function() {
        if (!this.node) {
            this.node = document.createElement('div');

            var content = this.post.text;
            var mentions = this.post.entities.mentions;
            var hashtags = this.post.entities.hashtags;
            var links = this.post.entities.links;

            var entities = [];

            _.each(mentions, function(elem, index, list) {
                entities.push({
                    pos: elem.pos,
                    len: elem.len,
                    html: Mustache.render("@{{username}}", {
                        username: elem.name
                    })
                });
            }, this);

            _.each(hashtags, function(elem, index, list) {
                entities.push({
                    pos: elem.pos,
                    len: elem.len,
                    html: Mustache.render("#{{tag}}", {
                        tag: elem.name
                    })
                });
            }, this);

            _.each(links, function(elem, index, list) {
                entities.push({
                    pos: elem.pos,
                    len: elem.len,
                    html: Mustache.render("{{text}}", {
                        url: elem.url,
                        text: elem.text
                    })
                });
            }, this);

            // Sort entities
            entities = _.sortBy(entities, 'pos');
            entities.reverse();

            // Apply them.
            _.each(entities, function(elem, index, list) {
                content = content.substring(0, elem.pos) + elem.html + content.substring(elem.pos + elem.len);
            }, this);

            var date = new Date(this.post.created_at);
            bonzo(this.node)
                .addClass('post row-fluid')
                .html(Mustache.render("

{{post.user.username}}

{{date}}

{{&content}}

", {
                    post: this.post,
                    content: content,
                    date: date.toDateString() + " " + date.toLocaleTimeString()
                }));
        }

        return this.node;
    }
});
<commit_msg>Improved newline support.<commit_after>appricot = {};

appricot.run = function() {
    if (window.location.protocol != 'https:') {
        window.location.href = 'https://appricot.me';
        return;
    }
    var app = new appricot.App();
    app.render(document.getElementById('root'));
};

appricot.login = function() {
    window.location.href = [
        "https://alpha.app.net/oauth/authenticate?",
        "client_id=","PkMGurQpTzGLmcyzK65sj4JXpkzVwUtE",
        "&response_type=token",
        "&redirect_uri=","https://appricot.me/",
        "&scope=stream write_post",
    ].join('');
};

appricot.App = Class.$extend({
    rootNode: null,
    authenticated: false,

    __init__: function() {
        if (window.location.hash.match('#access_token') || window.localStorage['ACCESS_TOKEN']) {
            if (window.location.hash.match('#access_token')) {
                appricot.ACCESS_TOKEN = window.location.hash.split("=")[1];
                window.localStorage['ACCESS_TOKEN'] = appricot.ACCESS_TOKEN;
            } else {
                appricot.ACCESS_TOKEN = window.localStorage['ACCESS_TOKEN'];
            }
            window.location.href = '#';
            this.authenticated = true;
        } else {
            appricot.login();
        }
    },

    render: function(node) {
        this.rootNode = node;

        if (this.authenticated) {
            this.renderUI();
        }
    },

    renderUI: function() {
        var userStream = new appricot.UserStream();
        var globalStream = new appricot.GlobalStream();
        var mentionStream = new appricot.MentionStream();

        var pageContainer = document.createElement('div');
        bonzo(pageContainer).addClass('row');

        var toolbar = document.createElement('div');
        bonzo(toolbar).addClass('span1 toolbar');

        var mainPage = document.createElement('div');
        bonzo(mainPage).addClass('span11');

        var streams = document.createElement('div');
        bonzo(streams).addClass('row');

        bonzo(mainPage).append(streams);

        var refresh = document.createElement('button');
        bonzo(refresh)
            .addClass('btn')
            .html("");
        bean.add(refresh, 'click', _.bind(this.handleRefreshButton, this, userStream));
        bean.add(refresh, 'click', _.bind(this.handleRefreshButton, this, globalStream));
        bean.add(refresh, 'click', _.bind(this.handleRefreshButton, this, mentionStream));
        bonzo(toolbar).append(refresh);

        bonzo(streams).append(userStream.render());
        bonzo(streams).append(mentionStream.render());
        bonzo(streams).append(globalStream.render());
        bonzo(userStream.render()).addClass('stream1');
        bonzo(mentionStream.render()).addClass('stream2');
        bonzo(globalStream.render()).addClass('stream3');

        bonzo(pageContainer)
            .append(toolbar)
            .append(mainPage);

        bonzo(this.rootNode).append(pageContainer);
        userStream.load();
        mentionStream.load();
        globalStream.load();
    },

    handleRefreshButton: function(stream) {
        _gaq.push(['_trackEvent', 'Streams', 'Refresh Button Click', '']);
        stream.loadMoreNewer();
    }
});

appricot.PostBox = Class.$extend({
    node: null,

    __init__: function() {

    },

    render: function() {
        if (!this.node) {
            this.node = document.createElement('div');
        }

        return this.node;
    }
});

appricot.Stream = Class.$extend({
    cache: null,
    isFetching: false,
    topOfFirstLoad: 0,
    postNode: null,
    firstLoad: true,
    currentTopPostId: 0,

    __init__: function(endpoint) {
        this.endpoint = endpoint;
        this.cache = [];
    },

    load: function() {
        this.cache = [];
        if (this.firstLoad) {
            this.firstLoad = false;
            this.loadPositionFromServer();
            return;
        }
        // var lastPos = window.localStorage['stream_pos_' + this.type];
        if (this.currentTopPostId) {
            this.loadTopStreamAfterNextFetch = true;
            this.loadData({
                before_id: parseInt(this.currentTopPostId, 10) + 1
            });
        } else {
            this.loadData();
        }
    },

    loadPositionFromServer: function() {
        reqwest({
            url: 'https://appricot.me/go/get_position',
            type: 'json',
            data: {
                'access_token': appricot.ACCESS_TOKEN,
                'stream_id': this.type
            },
            success: _.bind(this.handlePositionLoad, this)
        });
    },

    savePositionToServer: _.debounce(function(pos) {
        reqwest({
            url: 'https://appricot.me/go/set_position',
            type: 'json',
            data: {
                'access_token': appricot.ACCESS_TOKEN,
                'stream_id': this.type,
                'position': pos
            }
        });
    }, 10000),

    handlePositionLoad: function(data) {
        if (data["code"] == 401) {
            appricot.login();
            return;
        }

        this.currentTopPostId = data['position'];
        if (this.currentTopPostId) {
            this.currentTopPostId = parseInt(this.currentTopPostId, 10);
        }

        this.load();
    },

    loadData: function(params) {
        this.isFetching = true;

        params = params || {};

        reqwest({
            url: this.endpoint,
            type: 'json',
            data: _.extend({
                'access_token': appricot.ACCESS_TOKEN,
                'count': 100
            }, params),
            success: _.bind(this.handleLoad, this),
            error: _.bind(function(err) {
                if (err.status == 401) {
                    appricot.login();
                }
            }, this)
        });
    },

    render: function() {
        if (!this.node) {
            this.node = document.createElement('div');
            bonzo(this.node).addClass('span6 stream_container');

            this.statusBar = document.createElement('div');
            bonzo(this.statusBar).addClass('row-fluid statusbar');
            bonzo(this.node).append(this.statusBar);

            this.postNode = document.createElement('div');
            bonzo(this.postNode).addClass('stream_post_container');
            bonzo(this.node).append(this.postNode);
            bean.add(this.postNode, 'scroll', _.bind(this.handleScroll, this));
        }

        return this.node;
    },

    updateStatus: function(count) {
        bonzo(this.statusBar).html(
            Mustache.render("{{count}} new posts", {
                count: count
            })
        );
    },

    handleScroll: function(e) {
        if (this.lockScroll) {
            return;
        }

        var count = 0;
        if (this.cache.length > 0) {
            var scrollTop = bonzo(this.postNode).scrollTop();
            var topPost = _.find(this.cache, function(item) {
                if(item.render().offsetTop >= scrollTop) {
                    return true;
                }
                count++;
            }, this);

            if (this.currentTopPostId != topPost.id) {
                // window.localStorage['stream_pos_' + this.type] = topPost.id;
                this.savePositionToServer(topPost.id);
                this.currentTopPostId = topPost.id;
            }
            this.updateStatus(count);
        }

        var wrappedNode = bonzo(this.postNode);
        if (wrappedNode.scrollTop() >= this.postNode.scrollHeight - wrappedNode.offset().height - 10) {
            this.loadMorePrevious();
        }
    },

    handleLoad: function(data) {
        var fetchMoreBefore = null;
        var oldTopPost = null;
        var topOfCache = null;

        var isFreshCache = (this.cache.length == 0);

        if (data.length == 0) {
            console.log("NO DATA!? OMG");
            return;
        }

        // Create post wrapper objects for all the new items.
        data = _.map(data, function(item) {
            return new appricot.Post(item);
        });

        if (isFreshCache) {
            this.topOfFirstLoad = _.first(data).id;
        } else {
            topOfCache = _.first(this.cache);
            // new data is "newer" than the existing cache data.
            console.log(_.last(data).id, this.topOfFirstLoad);
            if (this.topOfFirstLoad && _.last(data).id <= this.topOfFirstLoad) {
                this.topOfFirstLoad = 0;
            }
            if (_.last(data).id > _.first(this.cache).id) {
                this.topOfFirstLoad = _.first(this.cache).id;
            }

            // the post which is on top at present (before we add in the new dataset).
            oldTopPost = _.first(this.cache);
        }

        this.cache = _.union(this.cache, data);

        var idMap = _.groupBy(this.cache, 'id');
        this.cache = _.map(idMap, function(value, key, list) {
            if (value.length == 1) {
                return value[0];
            } else {
                var rendered = _.find(value, function(post) {
                    if (bonzo(post.render()).parent().length > 0) {
                        return true;
                    }
                }, this);

                if (rendered) {
                    return rendered;
                } else {
                    return value[0];
                }
            }
        }, this);

        this.cache = _.sortBy(this.cache, function(item) { return item.id; }); // this will break for large numbers...
        // this.cache = _.uniq(this.cache, true, function(item) { return item.id; });
        this.cache.reverse();

        var oldScrollHeight = this.postNode.scrollHeight;
        this.lockScroll = true;
        var shouldAdjustPosition = false;

        _.each(this.cache, function(element, index, list) {
            if (bonzo(element.render()).parent().length == 0) {
                if (index == 0) {
                    bonzo(this.postNode).prepend(element.render());
                } else {
                    bonzo(element.render()).insertAfter(list[index - 1].render());
                }
            }
        }, this);

        // Was this element above the current viewed top post?
        if (this.currentTopPostId && _.first(data).id > this.currentTopPostId) {
            shouldAdjustPosition = true;
        }

        if (!isFreshCache && shouldAdjustPosition) {
            var diffScrollHeight = this.postNode.scrollHeight - oldScrollHeight;
            bonzo(this.postNode).scrollTop(bonzo(this.postNode).scrollTop() + diffScrollHeight);
        }

        this.lockScroll = false;

        this.isFetching = false;

        if (this.topOfFirstLoad) {
            this.loadData({
                since_id: this.topOfFirstLoad - 1,
                before_id: (_.last(data).id > this.topOfFirstLoad ? _.last(data).id : null)
            });
            return;
        }

        if (fetchMoreBefore) {
            this.loadMoreNewer(fetchMoreBefore);
        }
    },

    loadMorePrevious: function() {
        if (this.isFetching) {
            return;
        }

        this.loadData({before_id: _.last(this.cache).id});
    },

    loadMoreNewer: function(before_id) {
        if (this.isFetching) {
            return;
        }

        this.loadData({
            since_id: parseInt(_.first(this.cache).id) - 1,
            before_id: before_id || null
        });
    }
});

appricot.UserStream = appricot.Stream.$extend({
    type: 'userstream',

    __init__: function() {
        this.$super('https://alpha-api.app.net/stream/0/posts/stream');
    }
});

appricot.GlobalStream = appricot.Stream.$extend({
    type: 'globalstream',

    __init__: function() {
        this.$super('https://alpha-api.app.net/stream/0/posts/stream/global');
    },

    load: function() {
        this.cache = [];

        this.loadData();
    }
});

appricot.MentionStream = appricot.Stream.$extend({
    type: 'mentionstream',

    __init__: function() {
        this.$super('https://alpha-api.app.net/stream/0/users/me/mentions');
    }
});

appricot.Post = Class.$extend({
    post: null,
    node: null,
    id: 0,

    __init__: function(post) {
        this.post = post;
        this.id = parseInt(this.post.id, 10);
    },

    render: function() {
        if (!this.node) {
            this.node = document.createElement('div');

            var content = this.post.text;
            var mentions = this.post.entities.mentions;
            var hashtags = this.post.entities.hashtags;
            var links = this.post.entities.links;

            var entities = [];

            _.each(mentions, function(elem, index, list) {
                entities.push({
                    pos: elem.pos,
                    len: elem.len,
                    html: Mustache.render("@{{username}}", {
                        username: elem.name
                    })
                });
            }, this);

            _.each(hashtags, function(elem, index, list) {
                entities.push({
                    pos: elem.pos,
                    len: elem.len,
                    html: Mustache.render("#{{tag}}", {
                        tag: elem.name
                    })
                });
            }, this);

            _.each(links, function(elem, index, list) {
                entities.push({
                    pos: elem.pos,
                    len: elem.len,
                    html: Mustache.render("{{text}}", {
                        url: elem.url,
                        text: elem.text
                    })
                });
            }, this);

            // Sort entities
            entities = _.sortBy(entities, 'pos');
            entities.reverse();

            // Apply them.
            _.each(entities, function(elem, index, list) {
                content = content.substring(0, elem.pos) + elem.html + content.substring(elem.pos + elem.len);
            }, this);

            var date = new Date(this.post.created_at);
            bonzo(this.node)
                .addClass('post row-fluid')
                .html(Mustache.render("

{{post.user.username}}

{{date}}

{{&content}}

", {
                    post: this.post,
                    content: content.replace("\n", "
"),
                    date: date.toDateString() + " " + date.toLocaleTimeString()
                }));
        }

        return this.node;
    }
});
<|endoftext|>


<commit_before>import React, { useState } from 'react';
import PropTypes from 'prop-types';
import TextBox from '../textbox';
import I18nHelper from '../../../utils/helpers/i18n';

const Decimal = (props) => {
  const [decimalValue, setDecimalValue] = useState('0.00');

  const testValue = (value) => {
    const { precision } = props;
    const format = I18nHelper.format();
    const delimiter = `\\${format.delimiter}`;
    const seperator = `\\${format.separator}`;

    const regex = new RegExp(`^[\\d${delimiter}]*[${seperator}{1}]?\\d{0,${precision}}?$`);
    const isGoodDecimal = regex.test(value);

    return isGoodDecimal;
  }

  const handleChange = (evt) => {
    const target = evt.target;
    const { value, selectionEnd } = evt.target;
    const testString = testValue(value);

    if (testString) {
      setDecimalValue(value);
      props.onChange({ target: { value: value } })
      setTimeout(() => {
        target.setSelectionRange(selectionEnd, selectionEnd)
      });
    }
  }

  const handleBlur = () => {
    const addCommasRegex = /(\d)(?=(\d{3})+(?!\d))/g;
    const parts = decimalValue.split('.');
    const integer = parts[0];

    let newInteger = integer.replace(/,/g, '');
    newInteger = newInteger.replace(addCommasRegex, '$1,');
    let array = [newInteger];

    if (parts[1]) {
      array.push('.', parts[1]);
    }
    setDecimalValue(array.join(''));
  }

  return (
    <TextBox
      {...props}
      onChange={ handleChange }
      onBlur={ handleBlur }
      value={ decimalValue }
    />
  );
};

Decimal.propTypes = {
  /**
   * The default value alignment on the input
   */
  align: PropTypes.string,
  /**
   * The decimal precision of the value in the input
   */
  precision: PropTypes.number,
  /**
   * The width of the input as a percentage
   */
  inputWidth: PropTypes.number,
  /**
   * The value of the input
   */
  value: PropTypes.string
}

Decimal.defaultProps = {
  align: 'left',
  precision: 2,
  inputWidth: 100
};

export default Decimal;
<commit_msg>Updates Decimal if Precision Prop Changes<commit_after>import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import TextBox from '../textbox';
import I18nHelper from '../../../utils/helpers/i18n';

const Decimal = (props) => {
  const [decimalValue, setDecimalValue] = useState('0.00');

  useEffect(() => {
    // Update decimalValue if precision prop changes
    const { precision } = props;
    const parts = decimalValue.split('.');
    let newDecimal = parts[1];
    const decimalLength = parts[1].length;
    let diff;

    if (precision > decimalLength) { // Precision increased
      diff = precision - decimalLength;
      for (let i = 0; i < diff; i++) {
        newDecimal = newDecimal + '0';
      }
    } else if (precision < decimalLength) { // Precision decreased
      diff = decimalLength - precision;
      newDecimal = Math.round(newDecimal / (10 * diff));
    }

    setDecimalValue([parts[0], '.', newDecimal].join(''));
  }, [props.precision]);

  const testValue = (value) => {
    const { precision } = props;
    const format = I18nHelper.format();
    const delimiter = `\\${format.delimiter}`;
    const seperator = `\\${format.separator}`;

    const regex = new RegExp(`^[\\d${delimiter}]*[${seperator}{1}]?\\d{0,${precision}}?$`);
    const isGoodDecimal = regex.test(value);

    return isGoodDecimal;
  }

  const handleChange = (evt) => {
    const target = evt.target;
    const { value, selectionEnd } = evt.target;
    const testString = testValue(value);

    if (testString) {
      setDecimalValue(value);
      props.onChange({ target: { value: value } })
      setTimeout(() => {
        target.setSelectionRange(selectionEnd, selectionEnd)
      });
    }
  }

  const handleBlur = () => {
    const addCommasRegex = /(\d)(?=(\d{3})+(?!\d))/g;
    const parts = decimalValue.split('.');
    const integer = parts[0];

    let newInteger = integer.replace(/,/g, '');
    newInteger = newInteger.replace(addCommasRegex, '$1,');
    let array = [newInteger];

    if (parts[1]) {
      array.push('.', parts[1]);
    }
    setDecimalValue(array.join(''));
  }

  console.log(props)
  return (
    <TextBox
      {...props}
      onChange={ handleChange }
      onBlur={ handleBlur }
      value={ decimalValue }
    />
  );
};

Decimal.propTypes = {
  /**
   * The default value alignment on the input
   */
  align: PropTypes.string,
  /**
   * The decimal precision of the value in the input
   */
  precision: PropTypes.number,
  /**
   * The width of the input as a percentage
   */
  inputWidth: PropTypes.number,
  /**
   * The value of the input
   */
  value: PropTypes.string
}

Decimal.defaultProps = {
  align: 'left',
  precision: 2,
  inputWidth: 100
};

export default Decimal;
<|endoftext|>