<commit_before>/*
 * nonFormValidate jQuery Plugin v1.0.0.0b
 * Licensed under the MIT license.
 * Copyright 2012 G.Burak Demirezen
 */ (function ($) {
    $.fn.nonFormValidate = function (options) {
        var defaults = {
            form: false,
            error: true,
			multierrortext : true ,
            errorText: {
                required: 'Bu Alan Boş Geçilemez',
                email: 'Hatalı Email Adresi',
                number: 'Bu Alana Yanlızca Sayı Girilebilir',
                letter: 'Bu Alana Yanlızca Metin Girilebilir',
                letterornumber: 'Bu Alana Yanlızca Metin ve Sayı Girilebilir',
                decimal: 'Bu Alana Yanlızca Sayı veya Rasyonel Sayı Girilebilir',
                url: 'Bu Alana Yanlızca Url Girilebilir',
                dateTR: 'Bu Alana Yanlızca Tarih Girilebilir "GG/AA/YYYY , GG-AA-YYYY"',
                phoneTR: 'Bu Alana Yanlızca Telefon Girilebilir "0(530) 000 00 00, 0(530) 000-00-00"',
                min: 'En Az {count} Karakter Olmalıdır',
                max: 'En Fazla {count} Karakter Olmalıdır',
				equals: 'Şifreniz Birbiriyle Uyuşmuyor',
				checkbox: 'Bu Alanı İşaretlemek Zorunludur',
				radio: 'Bu Alanı işaretlemek Zorunludur radio',
				list: 'Bir Seçim Yapmalısınız'
            }
        }, settings = $.extend(defaults, options);

        var $validate = "validate",
            $class = '.nValidate',
            $dom = this,
            $validatePattern = null,
            $firstValidate = 0,
            $errorClass = 'span.error',
            $minmax = 0,
            $minMaxText = '',
			$password = '',
			$focusOut = false,
			$type,
			$choseControl = false,
			$choseGroup = '',
			$choseValidateGroup = false;

        $.nonControl = function () {
            $firstValidate = 0;
            $($dom).children($errorClass).remove();
            $($dom).children($class).each(function () {
                $.nonScan(this, this.className);
            });
        };

        $.nonScan = function ($this, $class, $out) {
			if(typeof $out != 'undefined')
				$focusOut = true;

            var $pattern = new RegExp('v\\[(.*)\\]', 'g'),
                $array = $pattern.exec($class),
                $size,
                $sizePattern,
                $multi = [];
            if ($array != null) {
                if ($array.length > 0) {
                    $multi = $array[1].split(' ');
                    for (i in $multi) {
                        $sizePattern = new RegExp('^[min\\[|max\\[|password\\[|equals\\[|checkbox\\[|radio\\[]+([0-9]+)\\]$', 'g');
                        $size = $sizePattern.exec($multi[i]);
                        if ($size != null) {
                            if ($size.length > 0) {
                                $minmax = parseInt($size[1]);
                                $multi[i] = $size[0].replace(/[^min|^max|^password|^equals|^checkbox|^radio]/g, '');
                            }
                        };
						if($multi[i] == 'checkbox' || $multi[i] == 'radio'){
							if($choseValidateGroup == false){
								if($choseGroup != $.groupClear($this))
									$.nonTrigger($this, $multi[i]);
							}else{
								$.chooseControl($this);
								if($choseGroup == $.groupClear($this)){
									$.nonTrigger($this, $multi[i]);
								}
							}
						}else{
							$.nonTrigger($this, $multi[i]);
						}
                    } //for
                }
            } else {
                console.error('insert "v[required]" type of validation Elements');
            }
        };

		$.addValidateClass = function ($this, $text) {
			console.log($this);
            $firstValidate++;
            $($this).addClass($validate);
            if (settings.error){
				if($($this).next('span.error').length < 1) {
					$($this).after('' + $text + '');
				}else if(settings.multierrortext){
					if(!$focusOut)
						$($this).next('span.error').append(document.createTextNode(' ' + $text));
					else
						$($this).next('span.error').text($text);
				}
			}
            if ($firstValidate == 1) {
                $('html,body').animate({
                    scrollTop: $($this).offset().top - 20
                }, 1000);
            }
			$focusOut = false;
        };

		$.chooseControl = function(dom){
			$choseGroup = $.groupClear(dom);
			$choseControl = false;

			$($dom).children($class).each(function () {
                $type = $(this).attr('type');
				//console.log($(this).attr('type'))
				if($type == 'checkbox' || $type == 'radio'){
					if($choseGroup == $.groupClear(this)){
						if($(this).is(':checked') == true){
							$choseControl = true;
						}
					}
				}
            });
			return $choseControl;
		};

		$($class).live('change', function () {
			if($dom != null){
				if($(this).attr('type') == 'checkbox' || $(this).attr('type') == 'radio'){
					$firstValidate = 0;
					$choseValidateGroup = true;
					$.nonScan(this,this.className);
				}
			}
			$choseValidateGroup = false;
        });

        $.start = function () {
            if (!settings.form) {
                if ($dom != null) {
                    $.nonControl();
                }
            } else {
                console.log('form true');
            }
        };

		$.groupClear = function(dom){
			var pattern = /v\[.*\]/;
			return pattern.exec(dom.className).toString();
		};

		$.groupValidateClear = function(dom){
			var $validateGroup = $.groupClear(dom);
			$($dom).children($class).each(function () {
                $type = $(this).attr('type');
				if($type == 'checkbox' || $type == 'radio'){
					if($validateGroup == $.groupClear(this)){
						$(this).removeClass('vadidate');
						$(this).next('span.error').remove();
					}
				}
            });
		};

		$.removeValidate = function(dom){
			$(dom).removeClass('validate');
		};

		$($class).live('focusout', function () {
			if($dom != null){
				if($(this).attr('type') != 'checkbox' && $(this).attr('type') != 'radio'){
					$firstValidate = 0;
					$.nonScan(this,this.className,true);
					if(!$(this).hasClass('validate'))
						$(this).next('span.error').remove();
				}
			}
        });

		$.nonTrigger = function ($this, $class) {
            $minMaxText = '';
            switch ($class) {
            case 'email':
                validations.email($this.value) == false ? $.addValidateClass($this, settings.errorText.email) : $.removeValidate($this);
                break;
            case 'required':
                validations.required($this.value) == false ? $.addValidateClass($this, settings.errorText.required) : $.removeValidate($this);
                break;
            case 'number':
                validations.number($this.value) == false ? $.addValidateClass($this, settings.errorText.number) : $.removeValidate($this);
                break;
            case 'letter':
                validations.letter($this.value) == false ? $.addValidateClass($this, settings.errorText.letter) : $.removeValidate($this);
                break;
            case 'letterornumber':
                validations.letterornumber($this.value) == false ? $.addValidateClass($this, settings.errorText.letterornumber) : $.removeValidate($this);
                break;
            case 'decimal':
                validations.decimal($this.value) == false || $this.value == '' ? $.addValidateClass($this, settings.errorText.decimal) : $.removeValidate($this);
                break;
            case 'url':
                validations.url($this.value) == false ? $.addValidateClass($this, settings.errorText.url) : $.removeValidate($this);
                break;
            case 'dateTR':
                validations.dateTR($this.value) == false ? $.addValidateClass($this, settings.errorText.dateTR) : $.removeValidate($this);
                break;
            case 'phoneTR':
                validations.phoneTR($this.value) == false ? $.addValidateClass($this, settings.errorText.phoneTR) : $.removeValidate($this);
                break;
            case 'min':
                $minMaxText = settings.errorText.min.replace(/\{count\}/g, $minmax);
                validations.min($this.value) == false ? $.addValidateClass($this, $minMaxText) : $.removeValidate($this);
                break;
            case 'max':
                $minMaxText = settings.errorText.max.replace(/\{count\}/g, $minmax);
                validations.max($this.value) == false ? $.addValidateClass($this, $minMaxText) : $.removeValidate($this);
                break;
			case 'password':
            	$password = $this.value
                break;
			case 'equals':
            	validations.equals($this.value) == false ? $.addValidateClass($this, settings.errorText.equals) : $.removeValidate($this);
                break;
			case 'checkbox':
				if(validations.checkbox($this) == false){//--------------------------------------
					if(!$choseValidateGroup)
						$.addValidateClass($this, settings.errorText.checkbox);
					else{
						var ptr = new RegExp("nValidate v\\[.*\\]");
						var ali = ptr.exec($this.className)
						//ali = ali.replace(/^(\s)/g,'.')
						console.log(ali);
						//$.addValidateClass($($this.className), settings.errorText.checkbox);
					}
				}else{
					$.groupValidateClear($this);
				}
                break;
			case 'radio':
				validations.radio($this) == false ? $.addValidateClass($this, settings.errorText.radio) : $.removeValidate($this);
                break;
            }
        };

        var validations = {
            required: function (val) {
                return val == '' ? false : true;
            },
            email: function (val) {
                pattern = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/;
                return pattern.test(val);
            },
            number: function (val) {
                pattern = /^[0-9]+$/;
                return pattern.test(val);
            },
            letter: function (val) {
                pattern = /^[a-zA-Z]+$/;
                return pattern.test(val);
            },
            letterornumber: function (val) {
                pattern = /^[0-9a-zA-Z]+$/;
                return pattern.test(val);
            },
            decimal: function (val) {
                pattern = /^[\-\+]?(([0-9]+)([\.,]([0-9]+))?|([\.,]([0-9]+))?)$/;
                return pattern.test(val);
            },
            url: function (val) {
                pattern = /(http|https|ftp):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?/;
                return pattern.test(val);
            },
            dateTR: function (val) {
                pattern = /^(0?[1-9]|[12][0-9]|3[01])[\/\-](0?[1-9]|1[012])[\/\-]\d{4}$/;
                return pattern.test(val);
            },
            phoneTR: function (val) {
                pattern = /0[\(|\s][0-9]{3}\)?[-\s\/][0-9]{3}[-\s\/][0-9]{2}[-\s\/][0-9]{2}/;
                return pattern.test(val);
            },
            min: function (val) {
                return val.length < $minmax || val.length == 0 ? false : true;
            },
            max: function (val) {
                return val.length > $minmax || val.length == 0 ? false : true;
            },
			equals: function (val) {
                return val != $password ? false : true;
            },
			checkbox: function(dom){
				return $.chooseControl(dom);
			},
			radio: function(dom){
				return $.chooseControl(dom);
			},
			list: function(dom){

			}
        };

        //trigger pluging
        $.start();
    };
})(jQuery);<commit_msg>new version<commit_after>/*
 * nonFormValidate jQuery Plugin v1.0.0.0b
 * Licensed under the MIT license.
 * Copyright 2012 G.Burak Demirezen
 */ (function ($) {
    $.fn.nonFormValidate = function (options) {
        var defaults = {
            form: false,
            error: true,
			multierrortext : true ,
            errorText: {
                required: 'Bu Alan Boş Geçilemez',
                email: 'Hatalı Email Adresi',
                number: 'Bu Alana Yanlızca Sayı Girilebilir',
                letter: 'Bu Alana Yanlızca Metin Girilebilir',
                letterornumber: 'Bu Alana Yanlızca Metin ve Sayı Girilebilir',
                decimal: 'Bu Alana Yanlızca Sayı veya Rasyonel Sayı Girilebilir',
                url: 'Bu Alana Yanlızca Url Girilebilir',
                dateTR: 'Bu Alana Yanlızca Tarih Girilebilir "GG/AA/YYYY , GG-AA-YYYY"',
                phoneTR: 'Bu Alana Yanlızca Telefon Girilebilir "0(530) 000 00 00, 0(530) 000-00-00"',
                min: 'En Az {count} Karakter Olmalıdır',
                max: 'En Fazla {count} Karakter Olmalıdır',
				equals: 'Şifreniz Birbiriyle Uyuşmuyor',
				checkbox: 'Bu Alanı İşaretlemek Zorunludur',
				radio: 'Bu Alanı işaretlemek Zorunludur radio',
				list: 'Bir Seçim Yapmalısınız'
            }
        }, settings = $.extend(defaults, options);

        var $validate = "validate",
            $class = '.nValidate',
            $dom = this,
            $validatePattern = null,
            $firstValidate = 0,
            $errorClass = 'span.error',
            $minmax = 0,
            $minMaxText = '',
			$password = '',
			$focusOut = false,
			$type,
			$choseControl = false,
			$choseGroup = '',
			$choseValidateGroup = false,
			$removeClassName = 'validate radio checkbox equals password max min phoneTR dateTR url decimal letterornumber letter number required email';

        $.nonControl = function () {
            $firstValidate = 0;
            $($dom).children($errorClass).remove();
            $($dom).children($class).each(function () {
                $.nonScan(this, this.className);
            });
        };

        $.nonScan = function ($this, $class, $out) {
			if(typeof $out != 'undefined')
				$focusOut = true;

            var $pattern = new RegExp('v\\[(.*)\\]', 'g'),
                $array = $pattern.exec($class),
                $size,
                $sizePattern,
                $multi = [];
            if ($array != null) {
                if ($array.length > 0) {
                    $multi = $array[1].split(' ');
                    for (i in $multi) {
                        $sizePattern = new RegExp('^[min\\[|max\\[|password\\[|equals\\[|checkbox\\[|radio\\[]+([0-9]+)\\]$', 'g');
                        $size = $sizePattern.exec($multi[i]);
                        if ($size != null) {
                            if ($size.length > 0) {
                                $minmax = parseInt($size[1]);
                                $multi[i] = $size[0].replace(/[^min|^max|^password|^equals|^checkbox|^radio]/g, '');
                            }
                        };
						if($multi[i] == 'checkbox' || $multi[i] == 'radio'){
							if($choseValidateGroup == false){
								if($choseGroup != $.groupClear($this))
									$.nonTrigger($this, $multi[i]);
							}else{
								$.chooseControl($this);
								if($choseGroup == $.groupClear($this)){
									$.nonTrigger($this, $multi[i]);
								}
							}
						}else{
							$.nonTrigger($this, $multi[i]);
						}
                    } //for
                }
            } else {
                console.error('insert "v[required]" type of validation Elements');
            }
        };

		$.addValidateClass = function ($this, $text, $types) {
            $firstValidate++;
            $($this).addClass($validate+' '+$types);
            if (settings.error){
				if($($this).next('span.error').length < 1) {
					$($this).after('' + $text + '');
				}else if(settings.multierrortext){
					if(!$focusOut)
						$($this).next('span.error').append(document.createTextNode(' ' + $text));
					else
						$($this).next('span.error').text($text);
				}
			}
            if ($firstValidate == 1) {
                $('html,body').animate({
                    scrollTop: $($this).offset().top - 20
                }, 1000);
            }
			$focusOut = false;
        };

		$.chooseControl = function(dom){
			$choseGroup = $.groupClear(dom);
			$choseControl = false;

			$($dom).children($class).each(function () {
                $type = $(this).attr('type');
				if($type == 'checkbox' || $type == 'radio'){
					if($choseGroup == $.groupClear(this)){
						if($(this).is(':checked') == true){
							$choseControl = true;
						}
					}
				}
            });
			return $choseControl;
		};

		$($class).live('change', function () {
			if($dom != null){
				if($(this).attr('type') == 'checkbox' || $(this).attr('type') == 'radio'){
					$firstValidate = 0;
					$choseValidateGroup = true;
					$.nonScan(this,this.className);
				}
			}
			$choseValidateGroup = false;
        });

        $.start = function () {
            if (!settings.form) {
                if ($dom != null) {
                    $.nonControl();
                }
            } else {
                console.log('form true');
            }
        };

		$.groupClear = function(dom){
			var pattern = /v\[.*\]/;
			return pattern.exec(dom.className).toString();
		};

		$.groupValidateClear = function(dom){
			var $validateGroup = $.groupClear(dom);
			$($dom).children($class).each(function () {
                $type = $(this).attr('type');
				if($type == 'checkbox' || $type == 'radio'){
					if($validateGroup == $.groupClear(this)){
						$(this).removeClass($removeClassName);
						$(this).next('span.error').remove();
					}
				}
            });
		};

		$.removeValidate = function(dom){
			$(dom).removeClass($removeClassName);
		};

		$($class).live('focusout', function () {
			if($dom != null){
				if($(this).attr('type') != 'checkbox' && $(this).attr('type') != 'radio'){
					$firstValidate = 0;
					$.nonScan(this,this.className,true);
					if(!$(this).hasClass('validate'))
						$(this).next('span.error').remove();
				}
			}
        });

		$.nonTrigger = function ($this, $class) {
            $minMaxText = '';
            switch ($class) {
            case 'email':
                validations.email($this.value) == false ? $.addValidateClass($this, settings.errorText.email, $class) : $.removeValidate($this);
                break;
            case 'required':
                validations.required($this.value) == false ? $.addValidateClass($this, settings.errorText.required, $class) : $.removeValidate($this);
                break;
            case 'number':
                validations.number($this.value) == false ? $.addValidateClass($this, settings.errorText.number, $class) : $.removeValidate($this);
                break;
            case 'letter':
                validations.letter($this.value) == false ? $.addValidateClass($this, settings.errorText.letter, $class) : $.removeValidate($this);
                break;
            case 'letterornumber':
                validations.letterornumber($this.value) == false ? $.addValidateClass($this, settings.errorText.letterornumber, $class) : $.removeValidate($this);
                break;
            case 'decimal':
                validations.decimal($this.value) == false || $this.value == '' ? $.addValidateClass($this, settings.errorText.decimal, $class) : $.removeValidate($this);
                break;
            case 'url':
                validations.url($this.value) == false ? $.addValidateClass($this, settings.errorText.url, $class) : $.removeValidate($this);
                break;
            case 'dateTR':
                validations.dateTR($this.value) == false ? $.addValidateClass($this, settings.errorText.dateTR, $class) : $.removeValidate($this);
                break;
            case 'phoneTR':
                validations.phoneTR($this.value) == false ? $.addValidateClass($this, settings.errorText.phoneTR, $class) : $.removeValidate($this);
                break;
            case 'min':
                $minMaxText = settings.errorText.min.replace(/\{count\}/g, $minmax);
                validations.min($this.value) == false ? $.addValidateClass($this, $minMaxText, $class) : $.removeValidate($this);
                break;
            case 'max':
                $minMaxText = settings.errorText.max.replace(/\{count\}/g, $minmax);
                validations.max($this.value) == false ? $.addValidateClass($this, $minMaxText, $class) : $.removeValidate($this);
                break;
			case 'password':
            	$password = $this.value
                break;
			case 'equals':
            	validations.equals($this.value) == false ? $.addValidateClass($this, settings.errorText.equals, $class) : $.removeValidate($this);
                break;
			case 'checkbox':
				if(validations.checkbox($this) == false){
						$.addValidateClass($this, settings.errorText.checkbox, $class);
				}else{
					$.groupValidateClear($this);
				}
                break;
			case 'radio':
				if(validations.radio($this) == false){
						$.addValidateClass($this, settings.errorText.radio, $class);
				}else{
					$.groupValidateClear($this);
				}
                break;
            }
        };

        var validations = {
            required: function (val) {
                return val == '' ? false : true;
            },
            email: function (val) {
                pattern = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/;
                return pattern.test(val);
            },
            number: function (val) {
                pattern = /^[0-9]+$/;
                return pattern.test(val);
            },
            letter: function (val) {
                pattern = /^[a-zA-Z]+$/;
                return pattern.test(val);
            },
            letterornumber: function (val) {
                pattern = /^[0-9a-zA-Z]+$/;
                return pattern.test(val);
            },
            decimal: function (val) {
                pattern = /^[\-\+]?(([0-9]+)([\.,]([0-9]+))?|([\.,]([0-9]+))?)$/;
                return pattern.test(val);
            },
            url: function (val) {
                pattern = /(http|https|ftp):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?/;
                return pattern.test(val);
            },
            dateTR: function (val) {
                pattern = /^(0?[1-9]|[12][0-9]|3[01])[\/\-](0?[1-9]|1[012])[\/\-]\d{4}$/;
                return pattern.test(val);
            },
            phoneTR: function (val) {
                pattern = /0[\(|\s][0-9]{3}\)?[-\s\/][0-9]{3}[-\s\/][0-9]{2}[-\s\/][0-9]{2}/;
                return pattern.test(val);
            },
            min: function (val) {
                return val.length < $minmax || val.length == 0 ? false : true;
            },
            max: function (val) {
                return val.length > $minmax || val.length == 0 ? false : true;
            },
			equals: function (val) {
                return val != $password ? false : true;
            },
			checkbox: function(dom){
				return $.chooseControl(dom);
			},
			radio: function(dom){
				return $.chooseControl(dom);
			},
			list: function(dom){

			}
        };

        //trigger pluging
        $.start();
    };
})(jQuery);<|endoftext|>


<commit_before>const preact = require('preact')
const findDOMElement = require('@uppy/utils/lib/findDOMElement')

/**
 * Defer a frequent call to the microtask queue.
 */
function debounce (fn) {
  let calling = null
  let latestArgs = null
  return (...args) => {
    latestArgs = args
    if (!calling) {
      calling = Promise.resolve().then(() => {
        calling = null
        // At this point `args` may be different from the most
        // recent state, if multiple calls happened since this task
        // was queued. So we use the `latestArgs`, which definitely
        // is the most recent call.
        return fn(...latestArgs)
      })
    }
    return calling
  }
}

/**
 * Boilerplate that all Plugins share - and should not be used
 * directly. It also shows which methods final plugins should implement/override,
 * this deciding on structure.
 *
 * @param {object} main Uppy core object
 * @param {object} object with plugin options
 * @returns {Array|string} files or success/fail message
 */
module.exports = class Plugin {
  constructor (uppy, opts) {
    this.uppy = uppy
    this.opts = opts || {}

    this.update = this.update.bind(this)
    this.mount = this.mount.bind(this)
    this.install = this.install.bind(this)
    this.uninstall = this.uninstall.bind(this)
  }

  getPluginState () {
    const { plugins } = this.uppy.getState()
    return plugins[this.id] || {}
  }

  setPluginState (update) {
    const { plugins } = this.uppy.getState()

    this.uppy.setState({
      plugins: {
        ...plugins,
        [this.id]: {
          ...plugins[this.id],
          ...update
        }
      }
    })
  }

  setOptions (newOpts) {
    this.opts = { ...this.opts, ...newOpts }
    this.setPluginState() // so that UI re-renders with new options
  }

  update (state) {
    if (typeof this.el === 'undefined') {
      return
    }

    if (this._updateUI) {
      this._updateUI(state)
    }
  }

  // Called after every state update, after everything's mounted. Debounced.
  afterUpdate () {

  }

  /**
   * Called when plugin is mounted, whether in DOM or into another plugin.
   * Needed because sometimes plugins are mounted separately/after `install`,
   * so this.el and this.parent might not be available in `install`.
   * This is the case with @uppy/react plugins, for example.
   */
  onMount () {

  }

  /**
   * Check if supplied `target` is a DOM element or an `object`.
   * If it’s an object — target is a plugin, and we search `plugins`
   * for a plugin with same name and return its target.
   *
   * @param {string|object} target
   *
   */
  mount (target, plugin) {
    const callerPluginName = plugin.id

    const targetElement = findDOMElement(target)

    if (targetElement) {
      this.isTargetDOMEl = true

      // API for plugins that require a synchronous rerender.
      this.rerender = (state) => {
        // plugin could be removed, but this.rerender is debounced below,
        // so it could still be called even after uppy.removePlugin or uppy.close
        // hence the check
        if (!this.uppy.getPlugin(this.id)) return
        this.el = preact.render(this.render(state), targetElement, this.el)
        this.afterUpdate()
      }
      this._updateUI = debounce(this.rerender)

      this.uppy.log(`Installing ${callerPluginName} to a DOM element '${target}'`)

      // clear everything inside the target container
      if (this.opts.replaceTargetContent) {
        targetElement.innerHTML = ''
      }

      this.el = preact.render(this.render(this.uppy.getState()), targetElement)

      this.onMount()
      return this.el
    }

    let targetPlugin
    if (typeof target === 'object' && target instanceof Plugin) {
      // Targeting a plugin *instance*
      targetPlugin = target
    } else if (typeof target === 'function') {
      // Targeting a plugin type
      const Target = target
      // Find the target plugin instance.
      this.uppy.iteratePlugins((plugin) => {
        if (plugin instanceof Target) {
          targetPlugin = plugin
          return false
        }
      })
    }

    if (targetPlugin) {
      this.uppy.log(`Installing ${callerPluginName} to ${targetPlugin.id}`)
      this.parent = targetPlugin
      this.el = targetPlugin.addTarget(plugin)

      this.onMount()
      return this.el
    }

    this.uppy.log(`Not installing ${callerPluginName}`)
    throw new Error(`Invalid target option given to ${callerPluginName}. Please make sure that the element
      exists on the page, or that the plugin you are targeting has been installed. Check that the <script> tag initializing Uppy
      comes at the bottom of the page, before the closing </body> tag (see https://github.com/transloadit/uppy/issues/1042).`)
  }

  render (state) {
    throw (new Error('Extend the render method to add your plugin to a DOM element'))
  }

  addTarget (plugin) {
    throw (new Error('Extend the addTarget method to add your plugin to another plugin\'s target'))
  }

  unmount () {
    if (this.isTargetDOMEl && this.el && this.el.parentNode) {
      this.el.parentNode.removeChild(this.el)
    }
  }

  install () {

  }

  uninstall () {
    this.unmount()
  }
}
<commit_msg>core: add some more suggestions to the incorrect `target` warning (#2242)<commit_after>const preact = require('preact')
const findDOMElement = require('@uppy/utils/lib/findDOMElement')

/**
 * Defer a frequent call to the microtask queue.
 */
function debounce (fn) {
  let calling = null
  let latestArgs = null
  return (...args) => {
    latestArgs = args
    if (!calling) {
      calling = Promise.resolve().then(() => {
        calling = null
        // At this point `args` may be different from the most
        // recent state, if multiple calls happened since this task
        // was queued. So we use the `latestArgs`, which definitely
        // is the most recent call.
        return fn(...latestArgs)
      })
    }
    return calling
  }
}

/**
 * Boilerplate that all Plugins share - and should not be used
 * directly. It also shows which methods final plugins should implement/override,
 * this deciding on structure.
 *
 * @param {object} main Uppy core object
 * @param {object} object with plugin options
 * @returns {Array|string} files or success/fail message
 */
module.exports = class Plugin {
  constructor (uppy, opts) {
    this.uppy = uppy
    this.opts = opts || {}

    this.update = this.update.bind(this)
    this.mount = this.mount.bind(this)
    this.install = this.install.bind(this)
    this.uninstall = this.uninstall.bind(this)
  }

  getPluginState () {
    const { plugins } = this.uppy.getState()
    return plugins[this.id] || {}
  }

  setPluginState (update) {
    const { plugins } = this.uppy.getState()

    this.uppy.setState({
      plugins: {
        ...plugins,
        [this.id]: {
          ...plugins[this.id],
          ...update
        }
      }
    })
  }

  setOptions (newOpts) {
    this.opts = { ...this.opts, ...newOpts }
    this.setPluginState() // so that UI re-renders with new options
  }

  update (state) {
    if (typeof this.el === 'undefined') {
      return
    }

    if (this._updateUI) {
      this._updateUI(state)
    }
  }

  // Called after every state update, after everything's mounted. Debounced.
  afterUpdate () {

  }

  /**
   * Called when plugin is mounted, whether in DOM or into another plugin.
   * Needed because sometimes plugins are mounted separately/after `install`,
   * so this.el and this.parent might not be available in `install`.
   * This is the case with @uppy/react plugins, for example.
   */
  onMount () {

  }

  /**
   * Check if supplied `target` is a DOM element or an `object`.
   * If it’s an object — target is a plugin, and we search `plugins`
   * for a plugin with same name and return its target.
   *
   * @param {string|object} target
   *
   */
  mount (target, plugin) {
    const callerPluginName = plugin.id

    const targetElement = findDOMElement(target)

    if (targetElement) {
      this.isTargetDOMEl = true

      // API for plugins that require a synchronous rerender.
      this.rerender = (state) => {
        // plugin could be removed, but this.rerender is debounced below,
        // so it could still be called even after uppy.removePlugin or uppy.close
        // hence the check
        if (!this.uppy.getPlugin(this.id)) return
        this.el = preact.render(this.render(state), targetElement, this.el)
        this.afterUpdate()
      }
      this._updateUI = debounce(this.rerender)

      this.uppy.log(`Installing ${callerPluginName} to a DOM element '${target}'`)

      // clear everything inside the target container
      if (this.opts.replaceTargetContent) {
        targetElement.innerHTML = ''
      }

      this.el = preact.render(this.render(this.uppy.getState()), targetElement)

      this.onMount()
      return this.el
    }

    let targetPlugin
    if (typeof target === 'object' && target instanceof Plugin) {
      // Targeting a plugin *instance*
      targetPlugin = target
    } else if (typeof target === 'function') {
      // Targeting a plugin type
      const Target = target
      // Find the target plugin instance.
      this.uppy.iteratePlugins((plugin) => {
        if (plugin instanceof Target) {
          targetPlugin = plugin
          return false
        }
      })
    }

    if (targetPlugin) {
      this.uppy.log(`Installing ${callerPluginName} to ${targetPlugin.id}`)
      this.parent = targetPlugin
      this.el = targetPlugin.addTarget(plugin)

      this.onMount()
      return this.el
    }

    this.uppy.log(`Not installing ${callerPluginName}`)

    let message = `Invalid target option given to ${callerPluginName}.`
    if (typeof target === 'function') {
      message += ' The given target is not a Plugin class. ' +
        'Please check that you\'re not specifying a React Component instead of a plugin. ' +
        'If you are using @uppy/* packages directly, make sure you have only 1 version of @uppy/core installed: ' +
        'run `npm ls @uppy/core` on the command line and verify that all the versions match and are deduped correctly.'
    } else {
      message += 'If you meant to target an HTML element, please make sure that the element exists. ' +
        'Check that the <script> tag initializing Uppy is right before the closing </body> tag at the end of the page. ' +
        '(see https://github.com/transloadit/uppy/issues/1042)\n\n' +
        'If you meant to target a plugin, please confirm that your `import` statements or `require` calls are correct.'
    }
    throw new Error(message)
  }

  render (state) {
    throw (new Error('Extend the render method to add your plugin to a DOM element'))
  }

  addTarget (plugin) {
    throw (new Error('Extend the addTarget method to add your plugin to another plugin\'s target'))
  }

  unmount () {
    if (this.isTargetDOMEl && this.el && this.el.parentNode) {
      this.el.parentNode.removeChild(this.el)
    }
  }

  install () {

  }

  uninstall () {
    this.unmount()
  }
}
<|endoftext|>


<commit_before>import Inferno   from 'inferno'
import Component from 'inferno-component'
import styled    from 'styled-components'
import { bind }  from 'decko'

export const Checkbox = styled.div`
  width: 16px;
  height: 16px;
  border-radius: 2px;
  box-sizing: border-box;
  border: 2px solid ${props => props.checked ? 'teal' : '#9e9e9e'};
  cursor: pointer;
  background-color: ${props => props.checked ? 'teal' : 'none'};
  transition: background-color 300ms cubic-bezier(0.4, 0.0, 0.2, 1),
    border-color 150ms linear;
  outline: none;
  position: relative;
  &::before, &::after {
		content: '';
		background: #fff;
		height: 16px;
		width: 16px;
		position: absolute;
    top: -2px;
		left: -2px;
    opacity: ${props => props.checked ? '1' : '0'};
		transform: translate(4px, 6px) rotate(44.91deg) scale(.1,.1);
		transform-origin: 0 0;
		transition: transform 300ms cubic-bezier(0.4, 0.0, 0.2, 1),
      opacity 500ms cubic-bezier(0.4, 0.0, 0.2, 1);
	}
  &::after {
    transform: translate(4px, 6.5px) rotate(44.91deg) ${props => props.checked ? 'scale(.3411,.1)' : 'scale(.1, .1)'}
	}
  &::before {
    transform: translate(6px, 10.5px) rotate(-45deg) ${props => props.checked ? 'scale(.5612,.1)' : 'scale(.1, .1)'}
  }
`
<commit_msg>:art: Added the 'size' property<commit_after>import Inferno   from 'inferno'
import Component from 'inferno-component'
import styled    from 'styled-components'
import { bind }  from 'decko'

export const Checkbox = styled.div`
  width: ${props => props.size || 18}px;
  height: ${props => props.size || 18}px;
  border-radius: 2px;
  box-sizing: border-box;
  border: 2px solid ${props => props.checked ? 'teal' : '#9e9e9e'};
  cursor: pointer;
  background-color: ${props => props.checked ? 'teal' : 'none'};
  transition: background-color 300ms cubic-bezier(0.4, 0.0, 0.2, 1),
    border-color 200ms linear;
  outline: none;
  position: relative;

  &::before,
  &::after {
		content: '';
		background: #fff;
		height: ${props => props.size || 18}px;
		width: ${props => props.size || 18}px;
		position: absolute;
    top: -2px;
		left: -2px;
    opacity: ${props => props.checked ? '1' : '0'};
		transform-origin: 0 0;
		transition: transform 200ms cubic-bezier(0.4, 0.0, 0.2, 1),
      opacity 500ms cubic-bezier(0.4, 0.0, 0.2, 1);
	}

  &::after {
    transform: translate(${props => (props.size / 3.6) || 5}px, ${props => (props.size / 2.3) || 7.8}px)
      rotate(44.91deg)
      ${props => props.checked ? 'scale(.32,.1)' : 'scale(.1, .1)'}
	}

  &::before {
    transform: translate(${props => (props.size / 2.66) || 6.7}px, ${props => (props.size / 1.5) || 12}px)
      rotate(-45deg)
      ${props => props.checked ? 'scale(.5612,.1)' : 'scale(.1, .1)'}
  }
`
<|endoftext|>


<commit_before>import walkRoutes from './utils/walkRoutes';
import pathnameAddon from './addons/pathname';
import Response from './response';

function createConfig(history, routes, options = {}) {
  const {
    addons = [],
    middleware = [],
    cache = false
  } = options;

  const finalAddons = addons.concat(pathnameAddon);

  let uris = [];
  const globals = {};
  const subscribers = [];

  let currentResponse;
  let lastUpdate;

  const setup = routes => {
    const registerFunctions = [];
    for (let key in globals) {
      delete globals[key];
    }

    finalAddons.forEach(addonFactory => {
      const addon = addonFactory();
      globals[addon.name] = addon.get;
      registerFunctions.push(addon);
    });

    uris = walkRoutes(routes, registerFunctions, {});
  };

  const respond = (key) => {
    const resp = new Response(key, history.location);
    uris.some(uri => uri.match(history.location.pathname, resp));
    return resp;
  };

  const runURILoadFunctions = resp => {
    if (!resp.uri) {
      resp.setStatus(404);
      return Promise.resolve(resp);
    }
    const { preload, load } = resp.uri;
    return Promise.all([
      preload ? preload() : null,
      load ? load(resp) : null
    ]).then(
      () => {
        resp.call();
        return resp;
      },
      err => {
        // not sure what to do here yet
        return Promise.reject(err);
      }
    );
  };

  const setCurrentResponse = (location) => {
    let { key } = location;
    // hash history quick fix
    if (key == null) {
      key = Math.random().toString(36).slice(2, 8);
    }
    currentResponse = key;
    return key;
  }

  const prepareResponse = () => {
    const responseKey = setCurrentResponse(history.location);

    if (cache) {
      const resp = cache.get(history.location)
      if (resp != null) {
        return Promise.resolve(resp);
      }
    }

    const response = respond(responseKey);
    return runURILoadFunctions(response).then(resp => {
      const respObject = middleware.length
        ? middleware.reduce((obj, curr) => curr(obj), resp.asObject())
        : resp.asObject();
      // save this for quick ref
      if (cache) {
        cache.set(resp);
      }
      lastUpdate = respObject;
      return respObject;
    });
  };

  const subscribe = fn => {
    if (typeof fn !== 'function') {
      throw new Error('The argument passed to subscribe must be a function');
    }

    if (lastUpdate) {
      fn(lastUpdate);
    }

    const newLength = subscribers.push(fn);
    return () => {
      subscribers[newLength - 1] = null;
    };
  };

  const emit = response => {
    // don't emit old responses
    if (response.location.key !== currentResponse) {
      return;
    }
    subscribers.forEach(fn => {
      if (fn != null) {
        fn(response);
      }
    });
  };

  const ready = () =>
    (lastUpdate ? Promise.resolve(lastUpdate) : prepareResponse());

  // now that everything is defined, actually do the setup
  setup(routes);
  const unlisten = history.listen(() => {
    prepareResponse().then(resp => {
      emit(resp);
    });
  });

  return {
    ready,
    refresh: setup,
    subscribe,
    addons: globals,
    history
  };
}

export default createConfig;
<commit_msg>response.key not response.location.key<commit_after>import walkRoutes from './utils/walkRoutes';
import pathnameAddon from './addons/pathname';
import Response from './response';

function createConfig(history, routes, options = {}) {
  const {
    addons = [],
    middleware = [],
    cache = false
  } = options;

  const finalAddons = addons.concat(pathnameAddon);

  let uris = [];
  const globals = {};
  const subscribers = [];

  let currentResponse;
  let lastUpdate;

  const setup = routes => {
    const registerFunctions = [];
    for (let key in globals) {
      delete globals[key];
    }

    finalAddons.forEach(addonFactory => {
      const addon = addonFactory();
      globals[addon.name] = addon.get;
      registerFunctions.push(addon);
    });

    uris = walkRoutes(routes, registerFunctions, {});
  };

  const respond = (key) => {
    const resp = new Response(key, history.location);
    uris.some(uri => uri.match(history.location.pathname, resp));
    return resp;
  };

  const runURILoadFunctions = resp => {
    if (!resp.uri) {
      resp.setStatus(404);
      return Promise.resolve(resp);
    }
    const { preload, load } = resp.uri;
    return Promise.all([
      preload ? preload() : null,
      load ? load(resp) : null
    ]).then(
      () => {
        resp.call();
        return resp;
      },
      err => {
        // not sure what to do here yet
        return Promise.reject(err);
      }
    );
  };

  const setCurrentResponse = (location) => {
    let { key } = location;
    // hash history quick fix
    if (key == null) {
      key = Math.random().toString(36).slice(2, 8);
    }
    currentResponse = key;
    return key;
  }

  const prepareResponse = () => {
    const responseKey = setCurrentResponse(history.location);

    if (cache) {
      const resp = cache.get(history.location)
      if (resp != null) {
        return Promise.resolve(resp);
      }
    }

    const response = respond(responseKey);
    return runURILoadFunctions(response).then(resp => {
      const respObject = middleware.length
        ? middleware.reduce((obj, curr) => curr(obj), resp.asObject())
        : resp.asObject();
      // save this for quick ref
      if (cache) {
        cache.set(resp);
      }
      lastUpdate = respObject;
      return respObject;
    });
  };

  const subscribe = fn => {
    if (typeof fn !== 'function') {
      throw new Error('The argument passed to subscribe must be a function');
    }

    if (lastUpdate) {
      fn(lastUpdate);
    }

    const newLength = subscribers.push(fn);
    return () => {
      subscribers[newLength - 1] = null;
    };
  };

  const emit = response => {
    // don't emit old responses
    if (response.key !== currentResponse) {
      return;
    }
    subscribers.forEach(fn => {
      if (fn != null) {
        fn(response);
      }
    });
  };

  const ready = () =>
    (lastUpdate ? Promise.resolve(lastUpdate) : prepareResponse());

  // now that everything is defined, actually do the setup
  setup(routes);
  const unlisten = history.listen(() => {
    prepareResponse().then(resp => {
      emit(resp);
    });
  });

  return {
    ready,
    refresh: setup,
    subscribe,
    addons: globals,
    history
  };
}

export default createConfig;
<|endoftext|>


<commit_before>/*
    Date format with slash "/" (also "-" and ".") between numbers
    - Tuesday 11/3/2015
    - 11/3/2015
    - 11/3
    - Terça 11 do 3
    - 11 do 3
*/
var moment = require('moment');
var Parser = require('../parser').Parser;
var ParsedResult = require('../../result').ParsedResult;
var util = require('../../utils/PT-BR');

var PATTERN = new RegExp('(\\W|^)' +
    '(?:' +
        '(?:n[oa]\\s*?)?' +
        '\\b((?:dom(?:ingo)?|seg(?:unda)?|ter(?:er[cç]a)?|qua(?:rta)?|qui(?:nta?)?|sex(?:ta)?|s[áa]b(?:ado)?)(?:-feira)?)\\b' +
        '\\s*\\,?\\s*' +
    ')?' +
    '([0-3]{0,1}[0-9]{1})(?:[\\/\\.\\-]|\\s*do\\s*)([0-3]{0,1}[0-9]{1})' +
    '(?:' +
        '[\\/\\.\\-]|\\s*de\\s*' +
        '([0-9]{4}\s*\,?\s*|[0-9]{2}\s*\,?\s*)' +
    ')?' +
    '(\\W|$)', 'i');

var DAYS_OFFSET = util.WEEKDAY_OFFSET;

var OPENNING_GROUP = 1;
var ENDING_GROUP = 6;

var WEEKDAY_GROUP = 2;
var DAY_GROUP = 3;
var MONTH_GROUP = 4;
var YEAR_GROUP = 5;

exports.Parser = function PTBRSlashDateFormatParser(argument) {
    Parser.apply(this, arguments);

    this.pattern = function () { return PATTERN; };
    this.extract = function(text, ref, match, opt){

        if(match[OPENNING_GROUP] == '/' || match[ENDING_GROUP] == '/') {
            // Long skip, if there is some overlapping like:
            // XX[/YY/ZZ]
            // [XX/YY/]ZZ
            match.index += match[0].length
            return;
        }

        var index = match.index + match[OPENNING_GROUP].length;
        var text = match[0].substr(match[OPENNING_GROUP].length, match[0].length - match[ENDING_GROUP].length);

        var result = new ParsedResult({
            text: text,
            index: index,
            ref: ref,
        });

        if(text.match(/^\d\.\d$/)) return;
        if(text.match(/^\d\.\d{1,2}\.\d{1,2}$/)) return;

        // dd/MM -> OK
        // dd-MM -> OK
        // dd do MM -> OK
        // dd.MM -> NG
        if(!match[YEAR_GROUP] && match[0].indexOf('.') > 0) return;

        var date = null;
        var year = match[YEAR_GROUP] || moment(ref).year() + '';
        var month = match[MONTH_GROUP];
        var day   = match[DAY_GROUP];

        month = parseInt(month);
        day  = parseInt(day);
        year = parseInt(year);

        if(month < 1 || month > 12) {
            if(month > 12) {
                // dd/mm/yyyy date format if day looks like a month, and month
                // looks like a day.
                if (day >= 1 && day <= 12 && month >= 13 && month <= 31) {
                    // unambiguous
                    var tday = month;
                    month = day;
                    day = tday;
                }
                else {
                    // both month and day are <= 12
                    return null;
                }
            }
        }
        if(day < 1 || day > 31) return null;

        if(year < 100){
            if (year > 50) {
                year = year + 1900;
            } else {
                year = year + 2000;
            }
        }

        result.start.assign('day', day);
        result.start.assign('month', month);
        result.start.assign('year', year);

        //Day of week
        if(match[WEEKDAY_GROUP]) {
            result.start.assign('weekday', DAYS_OFFSET[match[WEEKDAY_GROUP].toLowerCase()]);
        }

        result.tags['PTBRSlashDateFormatParser'] = true;
        return result;
    };
};
<commit_msg>Remove Tuesday abbreviation ("ter")<commit_after>/*
    Date format with slash "/" (also "-" and ".") between numbers
    - Tuesday 11/3/2015
    - 11/3/2015
    - 11/3
    - Terça 11 do 3
    - 11 do 3
*/
var moment = require('moment');
var Parser = require('../parser').Parser;
var ParsedResult = require('../../result').ParsedResult;
var util = require('../../utils/PT-BR');

// "Terça" ("Tuesday") don't have abbreviation to don't get confused with verb "ter" ("have")
var PATTERN = new RegExp('(\\W|^)' +
    '(?:' +
        '(?:n[oa]\\s*?)?' +
        '\\b((?:dom(?:ingo)?|seg(?:unda)?|ter[cç]a|qua(?:rta)?|qui(?:nta?)?|sex(?:ta)?|s[áa]b(?:ado)?)(?:-feira)?)\\b' +
        '\\s*\\,?\\s*' +
    ')?' +
    '([0-3]{0,1}[0-9]{1})(?:[\\/\\.\\-]|\\s*do\\s*)([0-3]{0,1}[0-9]{1})' +
    '(?:' +
        '[\\/\\.\\-]|\\s*de\\s*' +
        '([0-9]{4}\s*\,?\s*|[0-9]{2}\s*\,?\s*)' +
    ')?' +
    '(\\W|$)', 'i');

var DAYS_OFFSET = util.WEEKDAY_OFFSET;

var OPENNING_GROUP = 1;
var ENDING_GROUP = 6;

var WEEKDAY_GROUP = 2;
var DAY_GROUP = 3;
var MONTH_GROUP = 4;
var YEAR_GROUP = 5;

exports.Parser = function PTBRSlashDateFormatParser(argument) {
    Parser.apply(this, arguments);

    this.pattern = function () { return PATTERN; };
    this.extract = function(text, ref, match, opt){

        if(match[OPENNING_GROUP] == '/' || match[ENDING_GROUP] == '/') {
            // Long skip, if there is some overlapping like:
            // XX[/YY/ZZ]
            // [XX/YY/]ZZ
            match.index += match[0].length
            return;
        }

        var index = match.index + match[OPENNING_GROUP].length;
        var text = match[0].substr(match[OPENNING_GROUP].length, match[0].length - match[ENDING_GROUP].length);

        var result = new ParsedResult({
            text: text,
            index: index,
            ref: ref,
        });

        if(text.match(/^\d\.\d$/)) return;
        if(text.match(/^\d\.\d{1,2}\.\d{1,2}$/)) return;

        // dd/MM -> OK
        // dd-MM -> OK
        // dd do MM -> OK
        // dd.MM -> NG
        if(!match[YEAR_GROUP] && match[0].indexOf('.') > 0) return;

        var date = null;
        var year = match[YEAR_GROUP] || moment(ref).year() + '';
        var month = match[MONTH_GROUP];
        var day   = match[DAY_GROUP];

        month = parseInt(month);
        day  = parseInt(day);
        year = parseInt(year);

        if(month < 1 || month > 12) {
            if(month > 12) {
                // dd/mm/yyyy date format if day looks like a month, and month
                // looks like a day.
                if (day >= 1 && day <= 12 && month >= 13 && month <= 31) {
                    // unambiguous
                    var tday = month;
                    month = day;
                    day = tday;
                }
                else {
                    // both month and day are <= 12
                    return null;
                }
            }
        }
        if(day < 1 || day > 31) return null;

        if(year < 100){
            if (year > 50) {
                year = year + 1900;
            } else {
                year = year + 2000;
            }
        }

        result.start.assign('day', day);
        result.start.assign('month', month);
        result.start.assign('year', year);

        //Day of week
        if(match[WEEKDAY_GROUP]) {
            result.start.assign('weekday', DAYS_OFFSET[match[WEEKDAY_GROUP].toLowerCase()]);
        }

        result.tags['PTBRSlashDateFormatParser'] = true;
        return result;
    };
};
<|endoftext|>


<commit_before>((global) => {
  const TOKEN_TYPE_STRING = 'string';
  const TOKEN_TYPE_ARRAY = 'array';

  const validTokenKeys = [{
    key: 'author',
    type: 'string',
    param: 'username',
  },{
    key: 'assignee',
    type: 'string',
    param: 'username',
  },{
    key: 'milestone',
    type: 'string',
    param: 'title',
  },{
    key: 'label',
    type: 'array',
    param: 'name%5B%5D',
  },];

  class FilteredSearchManager {
    constructor() {
      this.bindEvents();
      this.loadSearchParamsFromURL();
      this.clearTokens();
    }

    bindEvents() {
      const input = document.querySelector('.filtered-search');

      input.addEventListener('input', this.tokenize.bind(this));
      input.addEventListener('keydown', this.checkForEnter.bind(this));
    }

    clearTokens() {
      this.tokens = [];
      this.searchToken = '';
    }

    loadSearchParamsFromURL() {
      const params = window.location.search.split('&');
      let inputValue = '';

      params.forEach((p) => {
        const split = p.split('=');
        const key = split[0];
        const value = split[1];

        const match = validTokenKeys.find((t) => {
          return key === `${t.key}_${t.param}`;
        });

        if (match) {
          const sanitizedKey = key.slice(0, key.indexOf('_'));
          inputValue += `${sanitizedKey}:${value} `;
        } else if (!match && key === 'search') {
          // Sanitize value as URL converts spaces into %20
          const sanitizedValue = value.replace('%20', ' ');
          inputValue += `${sanitizedValue} `;
        }
      });

      // Trim the last space value
      document.querySelector('.filtered-search').value = inputValue.trim();
    }

    tokenize(event) {
      // Re-calculate tokens
      this.clearTokens();

      // TODO: Current implementation does not support token values that have valid spaces in them
      // Example/ label:community contribution
      const input = event.target.value;
      const inputs = input.split(' ');
      let searchTerms = '';

      inputs.forEach((i) => {
        const colonIndex = i.indexOf(':');

        // Check if text is a token
        if (colonIndex !== -1) {
          const tokenKey = i.slice(0, colonIndex).toLowerCase();
          const tokenValue = i.slice(colonIndex + 1);

          const match = validTokenKeys.filter((v) => {
            return v.key === tokenKey;
          })[0];

          if (match && tokenValue.length > 0) {
            this.tokens.push({
              key: match.key,
              value: tokenValue,
            });
          }
        } else {
          searchTerms += i + ' ';
        }
      }, this);

      this.searchToken = searchTerms.trim();
      this.printTokens();
    }

    printTokens() {
      console.log('tokens:')
      this.tokens.forEach((token) => {
        console.log(token);
      })
      console.log('search: ' + this.searchToken);
    }

    checkForEnter(event) {
      if (event.key === 'Enter') {
        event.stopPropagation();
        event.preventDefault();
        this.search();
      }
    }

    search() {
      console.log('search');
      let path = '?scope=all&state=opened&utf8=✓';

      this.tokens.forEach((token) => {
        const param = validTokenKeys.find((t) => {
          return t.key === token.key;
        }).param;

        path += `&${token.key}_${param}=${token.value}`;
      });

      if (this.searchToken) {
        path += '&search=' + this.searchToken;
      }

      window.location = path;
    }
  }

  global.FilteredSearchManager = FilteredSearchManager;
})(window.gl || (window.gl = {}));
<commit_msg>Fixed bug where search terms with colons were not searchable<commit_after>((global) => {
  const TOKEN_TYPE_STRING = 'string';
  const TOKEN_TYPE_ARRAY = 'array';

  const validTokenKeys = [{
    key: 'author',
    type: 'string',
    param: 'username',
  },{
    key: 'assignee',
    type: 'string',
    param: 'username',
  },{
    key: 'milestone',
    type: 'string',
    param: 'title',
  },{
    key: 'label',
    type: 'array',
    param: 'name%5B%5D',
  },];

  class FilteredSearchManager {
    constructor() {
      this.bindEvents();
      this.loadSearchParamsFromURL();
      this.clearTokens();
    }

    bindEvents() {
      const input = document.querySelector('.filtered-search');

      input.addEventListener('input', this.tokenize.bind(this));
      input.addEventListener('keydown', this.checkForEnter.bind(this));
    }

    clearTokens() {
      this.tokens = [];
      this.searchToken = '';
    }

    loadSearchParamsFromURL() {
      const params = window.location.search.split('&');
      let inputValue = '';

      params.forEach((p) => {
        const split = p.split('=');
        const key = split[0];
        const value = split[1];

        const match = validTokenKeys.find((t) => {
          return key === `${t.key}_${t.param}`;
        });

        if (match) {
          const sanitizedKey = key.slice(0, key.indexOf('_'));
          inputValue += `${sanitizedKey}:${value} `;
        } else if (!match && key === 'search') {
          // Sanitize value as URL converts spaces into %20
          const sanitizedValue = value.replace('%20', ' ');
          inputValue += `${sanitizedValue} `;
        }
      });

      // Trim the last space value
      document.querySelector('.filtered-search').value = inputValue.trim();
    }

    tokenize(event) {
      // Re-calculate tokens
      this.clearTokens();

      // TODO: Current implementation does not support token values that have valid spaces in them
      // Example/ label:community contribution
      const input = event.target.value;
      const inputs = input.split(' ');
      let searchTerms = '';

      const addSearchTerm = function addSearchTerm(term) {
        searchTerms += term + ' ';
      }

      inputs.forEach((i) => {
        const colonIndex = i.indexOf(':');

        if (colonIndex !== -1) {
          const tokenKey = i.slice(0, colonIndex).toLowerCase();
          const tokenValue = i.slice(colonIndex + 1);

          const match = validTokenKeys.filter((v) => {
            return v.key === tokenKey;
          })[0];

          if (match && tokenValue.length > 0) {
            this.tokens.push({
              key: match.key,
              value: tokenValue,
            });
          } else {
            addSearchTerm(i);
          }
        } else {
          addSearchTerm(i);
        }
      }, this);

      this.searchToken = searchTerms.trim();
      this.printTokens();
    }

    printTokens() {
      console.log('tokens:')
      this.tokens.forEach((token) => {
        console.log(token);
      })
      console.log('search: ' + this.searchToken);
    }

    checkForEnter(event) {
      if (event.key === 'Enter') {
        event.stopPropagation();
        event.preventDefault();
        this.search();
      }
    }

    search() {
      console.log('search');
      let path = '?scope=all&state=opened&utf8=✓';

      this.tokens.forEach((token) => {
        const param = validTokenKeys.find((t) => {
          return t.key === token.key;
        }).param;

        path += `&${token.key}_${param}=${token.value}`;
      });

      if (this.searchToken) {
        path += '&search=' + this.searchToken;
      }

      window.location = path;
    }
  }

  global.FilteredSearchManager = FilteredSearchManager;
})(window.gl || (window.gl = {}));
<|endoftext|>


<commit_before>// Karma configuration
// Generated on Thu Dec 19 2013 05:42:28 GMT-0300 (CLST)
/*global module*/
'use strict';

var dkoboDirs = {
    projStatic: '../dkobo/static',
    sut: '../dkobo/koboform/static/js/sut',
    js: '../dkobo/koboform/static/js',
    staticTemplates: '../dkobo/koboform/static/templates'
};

module.exports = function(config) {
    config.set({

        // base path, that will be used to resolve files and exclude
        basePath: '',

        // frameworks to use
        frameworks: ['jasmine'],

        // list of files / patterns to load in the browser
        files: [
            dkoboDirs.projStatic + '/js/angular.js',
            dkoboDirs.projStatic + '/js/angular-*.js',
            dkoboDirs.projStatic + '/js/underscore.js',
            dkoboDirs.projStatic + '/js/jquery-1.10.2.js',
            dkoboDirs.projStatic + '/js/jquery-migrate-1.2.1.js',
            dkoboDirs.projStatic + '/js/jquery-ui-1.10.3.custom.js',
            dkoboDirs.projStatic + '/js/select2.min.js',
            dkoboDirs.projStatic + '/js/backbone.js',
            dkoboDirs.projStatic + '/js/Backbone.Validation.js',
            dkoboDirs.projStatic + '/js/jquery.poshytip.js',
            dkoboDirs.projStatic + '/js/jquery-editable-poshytip.js',
            dkoboDirs.sut + '/lib/init.js',
            dkoboDirs.sut + '/jasmine/jasmine.js',
            dkoboDirs.js + '/controllers/*.js',
            dkoboDirs.js + '/directives/*.js',
            dkoboDirs.js + '/factories/*.js',
            dkoboDirs.js + '/services/*.js',
            dkoboDirs.js + '/*.js',
            dkoboDirs.js + '/csv.coffee',
            dkoboDirs.js + '/xlform/*.coffee',
            dkoboDirs.js + '/xlform/validator.js',
            dkoboDirs.js + '/xlform/validator.backbone.adapters.js',
            dkoboDirs.js + '/xlform/XLF.skipLogicParser.js',
            dkoboDirs.staticTemplates + '/*.html',
            dkoboDirs.sut + '/lib/sinon.js',
            dkoboDirs.js + '/xlform/spec/spec.coffee',
            dkoboDirs.sut + '/tests/*.js',
        ],

        // list of files to exclude
        exclude: [
            '../xlform/*.backbone.*.js'
        ],

        // test results reporter to use
        // possible values: 'dots', 'progress', 'junit', 'growl', 'coverage'
        reporters: ['progress'],
        preprocessors: {
            '../*/*.js': ['coverage'],
            '../dkobo/koboform/static/templates/*.html': 'ng-html2js',
            '../**/*.coffee': 'coffee'
        },

        /// https://github.com/vojtajina/ng-directive-testing/commit/7b7a0b8f6b3698868daddc40828da39c3c6b6272#diff-766793014309586429b517112184567d
        /// https://github.com/karma-runner/karma-ng-html2js-preprocessor
        ngHtml2JsPreprocessor: {

            // or define a custom transform function
            cacheIdFromPath: function(filepath) {
                var matches = /^\/(.+\/)*(.+)\.(.+)$/.exec(filepath);

                return 'templates/' + matches[2] + '.' + matches[3];
            }
        },

        coffeePreprocessor: {
            // options passed to the coffee compiler
            options: {
                bare: true,
                sourceMap: false
            },
            // transforming the filenames
            transformPath: function(path) {
                return path.replace(/\.coffee$/, '.coffee-karma.js');
            }
        },
        // web server port
        port: 9876,

        // enable / disable colors in the output (reporters and logs)
        colors: true,

        // level of logging
        // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
        logLevel: config.LOG_INFO,

        // enable / disable watching file and executing tests whenever any file changes
        autoWatch: true,

        // Start these browsers, currently available:
        // - Chrome
        // - ChromeCanary
        // - Firefox
        // - Opera (has to be installed with `npm install karma-opera-launcher`)
        // - Safari (only Mac; has to be installed with `npm install karma-safari-launcher`)
        // - PhantomJS
        // - IE (only Windows; has to be installed with `npm install karma-ie-launcher`)
        browsers: ['Chrome'],

        // If browser does not capture in given timeout [ms], kill it
        captureTimeout: 60000,

        // Continuous Integration mode
        // if true, it capture browsers, run tests and exit
        singleRun: false
    });
};
<commit_msg>removing old karma-confs directory<commit_after><|endoftext|>


<commit_before>'use strict';

const getChannelURL = require('ember-source-channel-url');

module.exports = function() {
  return Promise.all([
    getChannelURL('release'),
    getChannelURL('beta'),
    getChannelURL('canary')
  ]).then((urls) => {
    return {
      scenarios: [
        {
          name: 'ember-lts-2.4',
          bower: {
            dependencies: {
              'ember': 'components/ember#lts-2-4'
            },
            resolutions: {
              'ember': 'lts-2-4'
            }
          },
          npm: {
            devDependencies: {
              'ember-source': null
            }
          }
        },
        {
          name: 'ember-lts-2.8',
          bower: {
            dependencies: {
              'ember': 'components/ember#lts-2-8'
            },
            resolutions: {
              'ember': 'lts-2-8'
            }
          },
          npm: {
            devDependencies: {
              'ember-source': null
            }
          }
        },
        {
          name: 'ember-lts-2.12',
          npm: {
            devDependencies: {
              'ember-source': '~2.12.0'
            }
          }
        },
        {
          name: 'ember-lts-2.16',
          env: {
            EMBER_OPTIONAL_FEATURES: JSON.stringify({ 'jquery-integration': true })
          },
          npm: {
            devDependencies: {
              '@ember/jquery': '^0.5.1',
              'ember-source': '~2.16.0'
            }
          }
        },
        {
          name: 'ember-lts-2.18',
          env: {
            EMBER_OPTIONAL_FEATURES: JSON.stringify({ 'jquery-integration': true })
          },
          npm: {
            devDependencies: {
              '@ember/jquery': '^0.5.1',
              'ember-source': '~2.18.0'
            }
          }
        },
        {
          name: 'ember-release',
          npm: {
            devDependencies: {
              'ember-source': urls[0]
            }
          }
        },
        {
          name: 'ember-beta',
          npm: {
            devDependencies: {
              'ember-source': urls[1]
            }
          }
        },
        {
          name: 'ember-canary',
          npm: {
            devDependencies: {
              'ember-source': urls[2]
            }
          }
        },
        {
          name: 'ember-default',
          npm: {
            devDependencies: {}
          }
        },
        {
          name: 'with-ember-test-helpers',
          bower: {
            dependencies: {
              'ember': 'components/ember#release'
            },
            resolutions: {
              'ember': 'release'
            }
          },
          npm: {
            devDependencies: {
              'ember-cli-qunit': '4.0.0'
            }
          }
        },
        {
          name: 'with-@ember/test-helpers',
          bower: {
            dependencies: {
              'ember': 'components/ember#release'
            },
            resolutions: {
              'ember': 'release'
            }
          },
          npm: {
            devDependencies: {
              'ember-cli-qunit': '4.3.0'
            }
          }
        },
        {
          name: 'node-tests',
          command: 'npm run nodetest',
          bower: {
            dependencies: {}
          }
        },
        {
          name: 'ember-default-with-jquery',
          env: {
            EMBER_OPTIONAL_FEATURES: JSON.stringify({
              'jquery-integration': true
            })
          },
          npm: {
            devDependencies: {
              '@ember/jquery': '^0.5.1'
            }
          }
        }
      ]
    };
  });
};
<commit_msg>Disable ember-source for more bower scenarios<commit_after>'use strict';

const getChannelURL = require('ember-source-channel-url');

module.exports = function() {
  return Promise.all([
    getChannelURL('release'),
    getChannelURL('beta'),
    getChannelURL('canary')
  ]).then((urls) => {
    return {
      scenarios: [
        {
          name: 'ember-lts-2.4',
          bower: {
            dependencies: {
              'ember': 'components/ember#lts-2-4'
            },
            resolutions: {
              'ember': 'lts-2-4'
            }
          },
          npm: {
            devDependencies: {
              'ember-source': null
            }
          }
        },
        {
          name: 'ember-lts-2.8',
          bower: {
            dependencies: {
              'ember': 'components/ember#lts-2-8'
            },
            resolutions: {
              'ember': 'lts-2-8'
            }
          },
          npm: {
            devDependencies: {
              'ember-source': null
            }
          }
        },
        {
          name: 'ember-lts-2.12',
          npm: {
            devDependencies: {
              'ember-source': '~2.12.0'
            }
          }
        },
        {
          name: 'ember-lts-2.16',
          env: {
            EMBER_OPTIONAL_FEATURES: JSON.stringify({ 'jquery-integration': true })
          },
          npm: {
            devDependencies: {
              '@ember/jquery': '^0.5.1',
              'ember-source': '~2.16.0'
            }
          }
        },
        {
          name: 'ember-lts-2.18',
          env: {
            EMBER_OPTIONAL_FEATURES: JSON.stringify({ 'jquery-integration': true })
          },
          npm: {
            devDependencies: {
              '@ember/jquery': '^0.5.1',
              'ember-source': '~2.18.0'
            }
          }
        },
        {
          name: 'ember-release',
          npm: {
            devDependencies: {
              'ember-source': urls[0]
            }
          }
        },
        {
          name: 'ember-beta',
          npm: {
            devDependencies: {
              'ember-source': urls[1]
            }
          }
        },
        {
          name: 'ember-canary',
          npm: {
            devDependencies: {
              'ember-source': urls[2]
            }
          }
        },
        {
          name: 'ember-default',
          npm: {
            devDependencies: {}
          }
        },
        {
          name: 'with-ember-test-helpers',
          bower: {
            dependencies: {
              'ember': 'components/ember#release'
            },
            resolutions: {
              'ember': 'release'
            }
          },
          npm: {
            devDependencies: {
              'ember-cli-qunit': '4.0.0',
              'ember-source': null
            }
          }
        },
        {
          name: 'with-@ember/test-helpers',
          bower: {
            dependencies: {
              'ember': 'components/ember#release'
            },
            resolutions: {
              'ember': 'release'
            }
          },
          npm: {
            devDependencies: {
              'ember-cli-qunit': '4.3.0',
              'ember-source': null
            }
          }
        },
        {
          name: 'node-tests',
          command: 'npm run nodetest',
          bower: {
            dependencies: {}
          }
        },
        {
          name: 'ember-default-with-jquery',
          env: {
            EMBER_OPTIONAL_FEATURES: JSON.stringify({
              'jquery-integration': true
            })
          },
          npm: {
            devDependencies: {
              '@ember/jquery': '^0.5.1'
            }
          }
        }
      ]
    };
  });
};
<|endoftext|>


<commit_before>'use strict';

const getChannelURL = require('ember-source-channel-url');

module.exports = async function() {
  return {
    scenarios: [
      {
        name: 'ember-lts-3.4',
        npm: {
          devDependencies: {
            'ember-source': '~3.4.0'
          }
        }
      },
      {
        name: 'ember-lts-3.8',
        npm: {
          devDependencies: {
            'ember-source': '~3.8.0'
          }
        }
      },
      {
        name: 'ember-release',
        npm: {
          devDependencies: {
            'ember-source': await getChannelURL('release')
          }
        }
      },
      {
        name: 'ember-beta',
        npm: {
          devDependencies: {
            'ember-source': await getChannelURL('beta')
          }
        }
      },
      {
        name: 'ember-canary',
        npm: {
          devDependencies: {
            'ember-source': await getChannelURL('canary')
          }
        }
      },
      // The default `.travis.yml` runs this scenario via `npm test`,
      // not via `ember try`. It's still included here so that running
      // `ember try:each` manually or from a customized CI config will run it
      // along with all the other scenarios.
      {
        name: 'ember-default',
        npm: {
          devDependencies: {}
        }
      },
      {
        name: 'ember-default-with-jquery',
        env: {
          EMBER_OPTIONAL_FEATURES: JSON.stringify({
            'jquery-integration': true
          })
        },
        npm: {
          devDependencies: {
            '@ember/jquery': '^0.5.1'
          }
        }
      }
    ]
  };
};
<commit_msg>Use yarn in ember-try<commit_after>'use strict';

const getChannelURL = require('ember-source-channel-url');

module.exports = async function() {
  return {
    useYarn: true,
    scenarios: [
      {
        name: 'ember-lts-3.4',
        npm: {
          devDependencies: {
            'ember-source': '~3.4.0'
          }
        }
      },
      {
        name: 'ember-lts-3.8',
        npm: {
          devDependencies: {
            'ember-source': '~3.8.0'
          }
        }
      },
      {
        name: 'ember-release',
        npm: {
          devDependencies: {
            'ember-source': await getChannelURL('release')
          }
        }
      },
      {
        name: 'ember-beta',
        npm: {
          devDependencies: {
            'ember-source': await getChannelURL('beta')
          }
        }
      },
      {
        name: 'ember-canary',
        npm: {
          devDependencies: {
            'ember-source': await getChannelURL('canary')
          }
        }
      },
      // The default `.travis.yml` runs this scenario via `npm test`,
      // not via `ember try`. It's still included here so that running
      // `ember try:each` manually or from a customized CI config will run it
      // along with all the other scenarios.
      {
        name: 'ember-default',
        npm: {
          devDependencies: {}
        }
      },
      {
        name: 'ember-default-with-jquery',
        env: {
          EMBER_OPTIONAL_FEATURES: JSON.stringify({
            'jquery-integration': true
          })
        },
        npm: {
          devDependencies: {
            '@ember/jquery': '^0.5.1'
          }
        }
      }
    ]
  };
};
<|endoftext|>


<commit_before>/* eslint-disable */
'use strict';

const getChannelURL = require('ember-source-channel-url');

module.exports = function() {
  return Promise.all([
    getChannelURL('release'),
    getChannelURL('beta'),
    getChannelURL('canary')
  ]).then((urls) => {
    return {
      scenarios: [
        {
          name: 'ember-lts-3.4',
          npm: {
            devDependencies: {
              'ember-source': '~3.4.0'
            }
          }
        },
        {
          name: 'ember-lts-3.8',
          npm: {
            devDependencies: {
              'ember-source': '~3.8.0'
            }
          }
        },
        {
          name: 'ember-lts-3.12',
          npm: {
            devDependencies: {
              'ember-source': '~3.12.0'
            }
          }
        },
        {
          name: 'ember-release',
          npm: {
            devDependencies: {
              'ember-source': urls[0]
            }
          }
        },
        {
          name: 'ember-beta',
          npm: {
            devDependencies: {
              'ember-source': urls[1]
            }
          }
        },
        {
          name: 'ember-canary',
          npm: {
            devDependencies: {
              'ember-source': urls[2]
            }
          }
        },
        {
          name: 'ember-default',
          npm: {
            devDependencies: {}
          }
        }
      ]
    };
  });
};
<commit_msg>fix builds<commit_after>/* eslint-disable */
'use strict';

const getChannelURL = require('ember-source-channel-url');

module.exports = function() {
  return Promise.all([
    getChannelURL('release'),
    getChannelURL('beta'),
    getChannelURL('canary')
  ]).then((urls) => {
    return {
      npmOptions: ['--legacy-peer-deps'],
      scenarios: [
        {
          name: 'ember-lts-3.4',
          npm: {
            devDependencies: {
              'ember-source': '~3.4.0'
            }
          }
        },
        {
          name: 'ember-lts-3.8',
          npm: {
            devDependencies: {
              'ember-source': '~3.8.0'
            }
          }
        },
        {
          name: 'ember-lts-3.12',
          npm: {
            devDependencies: {
              'ember-source': '~3.12.0'
            }
          }
        },
        {
          name: 'ember-release',
          npm: {
            devDependencies: {
              'ember-source': urls[0]
            }
          }
        },
        {
          name: 'ember-beta',
          npm: {
            devDependencies: {
              'ember-source': urls[1]
            }
          }
        },
        {
          name: 'ember-canary',
          npm: {
            devDependencies: {
              'ember-source': urls[2]
            }
          }
        },
        {
          name: 'ember-default',
          npm: {
            devDependencies: {}
          }
        }
      ]
    };
  });
};
<|endoftext|>


<commit_before>/* eslint-env node */
module.exports = {
  useYarn: true,
  scenarios: [
    {
      name: 'ember-1.13',
      dependencies: {
        'ember': '~1.13.13'
      }
    },
    {
      name: 'ember-lts-2.4',
      bower: {
        dependencies: {
          'ember': 'components/ember#lts-2-4'
        },
        resolutions: {
          'ember': 'lts-2-4'
        }
      },
      npm: {
        devDependencies: {
          'ember-source': null
        }
      }
    },
    {
      name: '2.6',
      dependencies: {
        'ember': '~2.6.0'
      }
    },
    {
      name: '2.7',
      dependencies: {
        'ember': '~2.7.0'
      }
    },
    {
      name: 'ember-lts-2.8',
      bower: {
        dependencies: {
          'ember': 'components/ember#lts-2-8'
        },
        resolutions: {
          'ember': 'lts-2-8'
        }
      },
      npm: {
        devDependencies: {
          'ember-source': null
        }
      }
    },
    {
      name: 'ember-lts-2.12',
      npm: {
        devDependencies: {
          'ember-source': '~2.12.0'
        }
      }
    },
    {
      name: 'ember-lts-2.16',
      npm: {
        devDependencies: {
          'ember-source': '~2.16.0'
        }
      }
    },
    {
      name: 'ember-release',
      bower: {
        dependencies: {
          'ember': 'components/ember#release'
        },
        resolutions: {
          'ember': 'release'
        }
      },
      npm: {
        devDependencies: {
          'ember-source': null
        }
      }
    },
    {
      name: 'ember-beta',
      bower: {
        dependencies: {
          'ember': 'components/ember#beta'
        },
        resolutions: {
          'ember': 'beta'
        }
      },
      npm: {
        devDependencies: {
          'ember-source': null
        }
      }
    },
    {
      name: 'ember-canary',
      bower: {
        dependencies: {
          'ember': 'components/ember#canary'
        },
        resolutions: {
          'ember': 'canary'
        }
      },
      npm: {
        devDependencies: {
          'ember-source': null
        }
      }
    },
    {
      name: 'ember-default',
      npm: {
        devDependencies: {}
      }
    },
    {
      name: 'fastboot-tests',
      command: 'ember fastboot:test',
      npm: {
        devDependencies: {}
      }
    }
  ]
};
<commit_msg>Copy ember-try scenarios from other repo<commit_after>/* eslint-env node */
module.exports = {
  useYarn: true,
  scenarios: [
    {
      name: 'ember-1.13',
      bower: {
        dependencies: {
          ember: '~1.13.0',
          'ember-cli-shims': '0.0.6',
          'ember-data': '~1.13.0',
        },
      },
      npm: {
        devDependencies: {
          'ember-cli-shims': null,
          'ember-data': '~1.13.0',
          'ember-source': null,
        },
      },
    },
    {
      name: 'ember-lts-2.4',
      bower: {
        dependencies: {
          'ember': 'components/ember#lts-2-4'
        },
        resolutions: {
          'ember': 'lts-2-4'
        }
      },
      npm: {
        devDependencies: {
          'ember-source': null
        }
      }
    },
    {
      name: '2.6',
      bower: {
        dependencies: {
          ember: '~2.6.0',
          'ember-cli-shims': null,
        },
      },
      npm: {
        devDependencies: {
          'ember-source': null,
        },
      },
    },
    {
      name: '2.7',
      bower: {
        dependencies: {
          ember: '~2.7.0',
          'ember-cli-shims': null,
        },
      },
      npm: {
        devDependencies: {
          'ember-source': null,
        },
      },
    },
    {
      name: 'ember-lts-2.8',
      bower: {
        dependencies: {
          'ember': 'components/ember#lts-2-8'
        },
        resolutions: {
          'ember': 'lts-2-8'
        }
      },
      npm: {
        devDependencies: {
          'ember-source': null
        }
      }
    },
    {
      name: 'ember-lts-2.12',
      npm: {
        devDependencies: {
          'ember-source': '~2.12.0'
        }
      }
    },
    {
      name: 'ember-lts-2.16',
      npm: {
        devDependencies: {
          'ember-source': '~2.16.0'
        }
      }
    },
    {
      name: 'ember-release',
      bower: {
        dependencies: {
          'ember': 'components/ember#release'
        },
        resolutions: {
          'ember': 'release'
        }
      },
      npm: {
        devDependencies: {
          'ember-source': null
        }
      }
    },
    {
      name: 'ember-beta',
      bower: {
        dependencies: {
          'ember': 'components/ember#beta'
        },
        resolutions: {
          'ember': 'beta'
        }
      },
      npm: {
        devDependencies: {
          'ember-source': null
        }
      }
    },
    {
      name: 'ember-canary',
      bower: {
        dependencies: {
          'ember': 'components/ember#canary'
        },
        resolutions: {
          'ember': 'canary'
        }
      },
      npm: {
        devDependencies: {
          'ember-source': null
        }
      }
    },
    {
      name: 'ember-default',
      npm: {
        devDependencies: {}
      }
    },
    {
      name: 'fastboot-tests',
      command: 'ember fastboot:test',
      npm: {
        devDependencies: {}
      }
    }
  ]
};
<|endoftext|>


<commit_before>/*
 * The aspiredb project
 *
 * Copyright (c) 2013 University of British Columbia
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
Ext.require([ 'ASPIREdb.store.SubjectStore',
				'ASPIREdb.ActiveProjectSettings' ]);

/**
 * Queries Subject values and loads them into a {@link Ext.grid.Panel}
 *
 */
Ext.define('ASPIREdb.view.subject.SubjectGrid', {
	extend : 'Ext.grid.Panel',
	alias : 'widget.subjectGrid',
	title : 'Subject',
	multiSelect : true,
	store : Ext.create('ASPIREdb.store.SubjectStore'),

	columns : [
			{
				text : "Subject Id",
				dataIndex : 'patientId',
				flex : 1
			},
			{
				text : "Labels",
				dataIndex : 'label',
				renderer : function(value) {
					var ret = "";
					for ( var i = 0; i < value.length; i++) {
						ret += "" + value[i].name
								+ " ";
					}
					return ret;
				},
				flex : 1
			}, ],

	tbar : [ {
		xtype : 'button',
		id : 'addLabelButton',
		text : '',
		tooltip : 'Add a new Label',
		icon : 'scripts/ASPIREdb/resources/images/icons/add.png',
	}, {
		xtype : 'button',
		id : 'removeLabelButton',
		text : '',
		tooltip : 'Remove labels from a Subject',
		icon : 'scripts/ASPIREdb/resources/images/icons/delete.png',
		listeners : {
			click : function() {
				alert("Clicked Remove Labels");
			}
		}
	}, {
		xtype : 'button',
		id : 'configLabelButton',
		text : '',
		tooltip : 'Configure Labels',
		icon : 'scripts/ASPIREdb/resources/images/icons/wrench.png',
		listeners : {
			click : function() {
				alert("Clicked Configure Labels");
			}
		}
	}, {
		xtype : 'tbfill'
	}, {
		xtype : 'button',
		text : '',
		tooltip : 'Download table contents as text',
		icon : 'scripts/ASPIREdb/resources/images/icons/disk.png',
		listeners : {
			click : function() {
				alert("Clicked Save");
			}
		}
	} ],

	/**
	 *
	 */
	initComponent : function() {

		this.callParent();

		var me = this;

		ASPIREdb.EVENT_BUS.on('filter_submit', function(filterConfigs) {
			QueryService.querySubjects(filterConfigs, {
				callback : function(pageLoad) {
					var subjectValueObjects = pageLoad.items;

					// TODO: fix me (define grid/store in initComponent)
					// me.items.removeAll();

					var data = [];
					for ( var i = 0; i < subjectValueObjects.length; i++) {
						var val = subjectValueObjects[i];
						var row = [ val.id, val.patientId, val.labels ];
						data.push(row);
					}
					me.store.loadData(data);

					var ids = [];
					for ( var i = 0; i < subjectValueObjects.length; i++) {
						var o = subjectValueObjects[i];
						ids.push(o.id);
					}
					ASPIREdb.EVENT_BUS.fireEvent('subjects_loaded', ids);

				}
			});
		});

		// add event handlers to buttons
		Ext.getCmp('addLabelButton').on('click', this.onMakeLabelClick);
	},

	/**
	 * Assigns a Label to a Subject
	 *
	 * @param event
	 */
	onMakeLabelClick : function(event) {

		var ids = [];
		var grid = this.findParentByType('grid');
		var selSubjects = grid.getSelectionModel().getSelection();
		for ( var i = 0; i < selSubjects.length; i++) {
			ids.push(selSubjects[i].get('id'));
		}

		// TODO replace with input from user
		var theLabel = new LabelValueObject();
		theLabel.name = 'aa';
		theLabel.colour = 'FFB6C1';

		// store in database
		SubjectService.addLabel(ids, theLabel);

		// update local store
		for ( var i = 0; i < selSubjects.length; i++) {
			var oldLabels = selSubjects[i].get('label');
			oldLabels.push(theLabel);
			selSubjects[i].set('label', oldLabels);
		}

		// refresh grid
		grid.store.sync();
		grid.getView().refresh();
	},

});
<commit_msg>Small code cleanup<commit_after>/*
 * The aspiredb project
 *
 * Copyright (c) 2013 University of British Columbia
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
Ext.require([ 'ASPIREdb.store.SubjectStore',
				'ASPIREdb.ActiveProjectSettings' ]);

/**
 * Queries Subject values and loads them into a {@link Ext.grid.Panel}
 *
 */
Ext.define('ASPIREdb.view.subject.SubjectGrid', {
	extend : 'Ext.grid.Panel',
	alias : 'widget.subjectGrid',
	title : 'Subject',
	multiSelect : true,
	store : Ext.create('ASPIREdb.store.SubjectStore'),

	columns : [
			{
				text : "Subject Id",
				dataIndex : 'patientId',
				flex : 1
			},
			{
				text : "Labels",
				dataIndex : 'label',
				renderer : function(value) {
					var ret = "";
					for ( var i = 0; i < value.length; i++) {
						ret += "" + value[i].name
								+ " ";
					}
					return ret;
				},
				flex : 1
			}, ],

	tbar : [ {
		xtype : 'button',
		id : 'addLabelButton',
		text : '',
		tooltip : 'Add a new Label',
		icon : 'scripts/ASPIREdb/resources/images/icons/add.png',
	}, {
		xtype : 'button',
		id : 'removeLabelButton',
		text : '',
		tooltip : 'Remove labels from a Subject',
		icon : 'scripts/ASPIREdb/resources/images/icons/delete.png',
		listeners : {
			click : function() {
				alert("Clicked Remove Labels");
			}
		}
	}, {
		xtype : 'button',
		id : 'configLabelButton',
		text : '',
		tooltip : 'Configure Labels',
		icon : 'scripts/ASPIREdb/resources/images/icons/wrench.png',
		listeners : {
			click : function() {
				alert("Clicked Configure Labels");
			}
		}
	}, {
		xtype : 'tbfill'
	}, {
		xtype : 'button',
		text : '',
		tooltip : 'Download table contents as text',
		icon : 'scripts/ASPIREdb/resources/images/icons/disk.png',
		listeners : {
			click : function() {
				alert("Clicked Save");
			}
		}
	} ],

	/**
	 *
	 */
	initComponent : function() {

		this.callParent();

		var me = this;

		ASPIREdb.EVENT_BUS.on('filter_submit', function(filterConfigs) {
			QueryService.querySubjects(filterConfigs, {
				callback : function(pageLoad) {
					var subjectValueObjects = pageLoad.items;

					// TODO: fix me (define grid/store in initComponent)
					// me.items.removeAll();

					var data = [];
					for ( var i = 0; i < subjectValueObjects.length; i++) {
						var val = subjectValueObjects[i];
						var row = [ val.id, val.patientId, val.labels ];
						data.push(row);
					}
					me.store.loadData(data);

					var ids = [];
					for ( var i = 0; i < subjectValueObjects.length; i++) {
						var o = subjectValueObjects[i];
						ids.push(o.id);
					}
					ASPIREdb.EVENT_BUS.fireEvent('subjects_loaded', ids);

				}
			});
		});

		// add event handlers to buttons
		Ext.getCmp('addLabelButton').on('click', this.onMakeLabelClick);
	},

	/**
	 * Assigns a Label to a Subject
	 *
	 * @param event
	 */
	onMakeLabelClick : function(event) {

		var ids = [];
		var grid = this.findParentByType('grid');
		var selSubjects = grid.getSelectionModel().getSelection();
		for ( var i = 0; i < selSubjects.length; i++) {
			ids.push(selSubjects[i].get('id'));
		}

		// TODO replace with input from user
		var theLabel = new LabelValueObject();
		theLabel.name = 'aa';
		theLabel.colour = 'FFB6C1';

		// store in database
		SubjectService.addLabel(ids, theLabel);

		// update local store
		for ( var i = 0; i < selSubjects.length; i++) {
			selSubjects[i].get('label').push(theLabel);
		}

		// refresh grid
		grid.store.sync();
		grid.getView().refresh();
	},

});
<|endoftext|>


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

/**
 * External dependencies
 */
import { render } from '@testing-library/react';
import Moveable from 'react-moveable';
import PropTypes from 'prop-types';
import React, { forwardRef } from 'react';

/**
 * Internal dependencies
 */
import { UnitsProvider } from '../../../../edit-story/units';
import withOverlay from '../../overlay/withOverlay';
import CanvasContext from '../context';
import Selection from '../selection';
import StoryContext from '../../../app/story/context';
import TransformProvider from '../../transform/transformProvider';

jest.mock('react-moveable', () => jest.fn(() => ({ children }) => children));

const pageSize = { width: 100, height: 100 };

const element1 = { id: '1', type: 'text' };
const element2 = { id: '2', type: 'text' };

const WrapperWithRef = ({ children }, ref) => (

    <TransformProvider>
      <UnitsProvider pageSize={pageSize}>{children}</UnitsProvider>
    </TransformProvider>

);
const Wrapper = withOverlay(forwardRef(WrapperWithRef));

WrapperWithRef.propTypes = {
  children: PropTypes.node,
};

describe('multiSelectionMovable', () => {
  let updateElementsById;
  let updateSelectedElements;
  let target1;
  let target2;
  let storyContext;
  let canvasContext;

  beforeEach(() => {
    updateElementsById = jest.fn();
    updateSelectedElements = jest.fn();
    target1 = document.createElement('div');
    target2 = document.createElement('div');

    storyContext = {
      state: { selectedElements: [element1, element2] },
      actions: { updateElementsById, updateSelectedElements },
    };
    canvasContext = {
      state: {
        pageSize,
        nodesById: {
          '1': target1,
          '2': target2,
        },
      },
    };
  });

  function arrange() {
    return render(
      <StoryContext.Provider value={storyContext}>
        <CanvasContext.Provider value={canvasContext}>
          <Selection />
        </CanvasContext.Provider>
      </StoryContext.Provider>,
      { wrapper: Wrapper }
    );
  }

  function performRotatation(rotateTo) {
    const moveable = Moveable.mock.calls[Moveable.mock.calls.length - 1][0];
    moveable.onRotateGroupStart({ events: [{ set: () => {} }] });
    moveable.onRotateGroup({
      events: [
        {
          target: target1,
          beforeRotate: rotateTo,
          drag: { beforeTranslate: [0, 0] },
        },
        {
          target: target2,
          beforeRotate: rotateTo,
          drag: { beforeTranslate: [0, 0] },
        },
      ],
    });
    moveable.onRotateGroupEnd({ targets: [target1, target2] });
  }

  const rotateCases = [
    ['normally', { rotateTo: 45, expectedRotationAngle: 45 }],
    ['through 360 degrees', { rotateTo: 370, expectedRotationAngle: 10 }],
    ['through negative', { rotateTo: -370, expectedRotationAngle: 350 }],
  ];

  it.each(rotateCases)(
    'should rotate %p',
    (_, { rotateTo, expectedRotationAngle }) => {
      arrange();
      performRotatation(rotateTo);

      const anyN = expect.any(Number);
      expect(updateElementsById).toHaveBeenCalledWith({
        elementIds: ['1'],
        properties: { rotationAngle: expectedRotationAngle, x: anyN, y: anyN },
      });
      expect(updateElementsById).toHaveBeenCalledWith({
        elementIds: ['2'],
        properties: { rotationAngle: expectedRotationAngle, x: anyN, y: anyN },
      });
    }
  );
});
<commit_msg>Update tests.<commit_after>/*
 * Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */
import { render } from '@testing-library/react';
import Moveable from 'react-moveable';
import PropTypes from 'prop-types';
import React, { forwardRef } from 'react';

/**
 * Internal dependencies
 */
import { UnitsProvider } from '../../../../edit-story/units';
import withOverlay from '../../overlay/withOverlay';
import CanvasContext from '../context';
import Selection from '../selection';
import StoryContext from '../../../app/story/context';
import TransformProvider from '../../transform/transformProvider';

jest.mock('react-moveable', () => jest.fn(() => ({ children }) => children));

const pageSize = { width: 100, height: 100 };

const element1 = { id: '1', type: 'text', x: 0, y: 0 };
const element2 = { id: '2', type: 'text', x: 1, y: 1 };

const WrapperWithRef = ({ children }, ref) => (

    <TransformProvider>
      <UnitsProvider pageSize={pageSize}>{children}</UnitsProvider>
    </TransformProvider>

);
const Wrapper = withOverlay(forwardRef(WrapperWithRef));

WrapperWithRef.propTypes = {
  children: PropTypes.node,
};

describe('multiSelectionMovable', () => {
  let updateElementsById;
  let updateSelectedElements;
  let target1;
  let target2;
  let storyContext;
  let canvasContext;

  beforeEach(() => {
    updateElementsById = jest.fn();
    updateSelectedElements = jest.fn();
    target1 = document.createElement('div');
    target2 = document.createElement('div');

    storyContext = {
      state: { selectedElements: [element1, element2] },
      actions: { updateElementsById, updateSelectedElements },
    };
    canvasContext = {
      state: {
        pageSize,
        nodesById: {
          '1': target1,
          '2': target2,
        },
      },
    };
  });

  function arrange() {
    return render(
      <StoryContext.Provider value={storyContext}>
        <CanvasContext.Provider value={canvasContext}>
          <Selection />
        </CanvasContext.Provider>
      </StoryContext.Provider>,
      { wrapper: Wrapper }
    );
  }

  function performRotatation(rotateTo) {
    const moveable = Moveable.mock.calls[Moveable.mock.calls.length - 1][0];
    moveable.onRotateGroupStart({ events: [{ set: () => {} }] });
    moveable.onRotateGroup({
      events: [
        {
          target: target1,
          beforeRotate: rotateTo,
          drag: { beforeTranslate: [0, 0] },
        },
        {
          target: target2,
          beforeRotate: rotateTo,
          drag: { beforeTranslate: [0, 0] },
        },
      ],
    });
    moveable.onRotateGroupEnd({ targets: [target1, target2] });
  }

  const rotateCases = [
    ['normally', { rotateTo: 45, expectedRotationAngle: 45 }],
    ['through 360 degrees', { rotateTo: 370, expectedRotationAngle: 10 }],
    ['through negative', { rotateTo: -370, expectedRotationAngle: 350 }],
  ];

  it.each(rotateCases)(
    'should rotate %p',
    (_, { rotateTo, expectedRotationAngle }) => {
      arrange();

      performRotatation(rotateTo);

      const func = updateElementsById.mock.calls[0][0].properties;
      expect(func(element1)).toStrictEqual({
        ...element1,
        rotationAngle: expectedRotationAngle,
      });
      expect(func(element2)).toStrictEqual({
        ...element2,
        rotationAngle: expectedRotationAngle,
      });
      expect(updateElementsById).toHaveBeenCalledTimes(1);
    }
  );
});
<|endoftext|>