<commit_before>(function(root) {

	var nwtHelperInstance = global.nwt.load().library('NWTHelperInstance', false);

	/**
	 * A panel instance represents a single panel
	 */
	function PanelInstance(content, config) {
		this.content = content;

		if( !config ) {
			config = {};
		}

		// Default any styles
		config.pos = config.pos || [0,0];
		config.width = config.width || (config.centered ? 400 : 'auto');

		this.config = config;
	}
	global.nwt.extend(PanelInstance, nwtHelperInstance);

	/**
	 * Renders the panel instnace
	 */
	PanelInstance.prototype.render = function() {

		var styles = [];

		styles.push('position:absolute;');
		styles.push('left:' + this.config.pos[0] + 'px;');
		styles.push('top:' + this.config.pos[1] + 'px;');
		styles.push('width:' + this.config.width + 'px;');

		var extraClass = "";
		if( this.config.centered ) {
			extraClass = ' nwt_panel_centered';
			styles.push('position:absolute;');
			styles.push('left:50%;');
			styles.push('top:50%;');
			styles.push('margin-left:-' + (this.config.width/2) + 'px;');
			styles.push('margin-top:-200px;');
		}

		var style = 'style="' + styles.join('') + '" ',

		title = '';

		if( this.content.definition && this.content.definition.pageTitle ) {
			title = this.content.definition.pageTitle;
		}

		var content = [
			'
',
				'
', title , '
',
				'
',
					this.content + '',
				'
',
				'

',
			'
'
		];

		return content.join('');
	};

	/**
	 * Panel helper class
	 * Creates panels on the page
	 * @constructor
	 */
	function PanelHelper() {
	};

	/**
	 * Returns a new panel object
	 */
	PanelHelper.prototype.render = function(content, config) {
		return new PanelInstance(content, config);
	};

	/**
	 * Returns a link which renders a panel loaded
	 * via ajax when clicked
	 * @param string Link title
	 * @param resource
	 */
	PanelHelper.prototype.ajax = function(linkContent, ajaxResource) {
		var htmlHelper = global.nwt.load().helper('Html');

		global.nwt.requireScript('widgets/Panel');

		if( !(ajaxResource instanceof String) ) {
			ajaxResource = ajaxResource.join('/');
		}

		return htmlHelper.link(linkContent, '#', {class: 'nwt_panel_ajax', 'data-resource' : ajaxResource });
	};

	root.PanelHelper = PanelHelper;
}(this));
<commit_msg>Add close link method<commit_after>(function(root) {

	var nwtHelperInstance = global.nwt.load().library('NWTHelperInstance', false);

	/**
	 * A panel instance represents a single panel
	 */
	function PanelInstance(content, config) {
		this.content = content;

		if( !config ) {
			config = {};
		}

		// Default any styles
		config.pos = config.pos || [0,0];
		config.width = config.width || (config.centered ? 400 : 'auto');

		this.config = config;
	}
	global.nwt.extend(PanelInstance, nwtHelperInstance);

	/**
	 * Renders the panel instnace
	 */
	PanelInstance.prototype.render = function() {

		var styles = [];

		styles.push('position:absolute;');
		styles.push('left:' + this.config.pos[0] + 'px;');
		styles.push('top:' + this.config.pos[1] + 'px;');
		styles.push('width:' + this.config.width + 'px;');

		var extraClass = "";
		if( this.config.centered ) {
			extraClass = ' nwt_panel_centered';
			styles.push('position:absolute;');
			styles.push('left:50%;');
			styles.push('top:50%;');
			styles.push('margin-left:-' + (this.config.width/2) + 'px;');
			styles.push('margin-top:-200px;');
		}

		var style = 'style="' + styles.join('') + '" ',

		title = '';

		if( this.content.definition && this.content.definition.pageTitle ) {
			title = this.content.definition.pageTitle;
		}

		var content = [
			'
',
				'
', title , '
',
				'
',
					this.content + '',
				'
',
				'

',
			'
'
		];

		return content.join('');
	};

	/**
	 * Panel helper class
	 * Creates panels on the page
	 * @constructor
	 */
	function PanelHelper() {
	};

	/**
	 * Returns a new panel object
	 */
	PanelHelper.prototype.render = function(content, config) {
		return new PanelInstance(content, config);
	};

	/**
	 * Renders a close link for the panel
	 */
	PanelHelper.prototype.closeLink = function(linkText) {
		linkText = linkText || 'Close';

		var Html = global.nwt.load().helper('Html');

		return Html.link(linkText, '#', {class: 'nwt_panel_closeParentPanel'});
	};

	/**
	 * Returns a link which renders a panel loaded
	 * via ajax when clicked
	 * @param string Link title
	 * @param resource
	 */
	PanelHelper.prototype.ajax = function(linkContent, ajaxResource) {
		var htmlHelper = global.nwt.load().helper('Html');

		global.nwt.requireScript('widgets/Panel');

		if( !(ajaxResource instanceof String) ) {
			ajaxResource = ajaxResource.join('/');
		}

		return htmlHelper.link(linkContent, '#', {class: 'nwt_panel_ajax', 'data-resource' : ajaxResource });
	};

	root.PanelHelper = PanelHelper;
}(this));
<|endoftext|>


<commit_before>// https://fgnass.github.com/spin.js
(function(document, undefined) {

/**
 * Copyright (c) 2011 Felix Gnass [fgnass at neteye dot de]
 * Licensed under the MIT license
 *
 * Unfortunately uglify.js doesn't provide an option to de-duplicate strings
 * or to use string-based property access. Hence we have to manually define
 * some string constants in order to keep file-size below our 3K limit, as
 * one of the design goals was to create a script that is smaller than an
 * animated GIF.
 */

  var width = 'width',
      length = 'length',
      radius = 'radius',
      lines = 'lines',
      trail = 'trail',
      color = 'color',
      opacity = 'opacity',
      speed = 'speed',
      shadow = 'shadow',
      style = 'style',
      height = 'height',
      left = 'left',
      top = 'top',
      px = 'px',
      childNodes = 'childNodes',
      firstChild = 'firstChild',
      parentNode = 'parentNode',
      position = 'position',
      relative = 'relative',
      absolute = 'absolute',
      animation = 'animation',
      transform = 'transform',
      Origin = 'Origin',
      coord = 'coord',
      black = '#000',
      styleSheets = style + 'Sheets',
      prefixes = "webkit0Moz0ms0O".split(0), /* Vendor prefixes, separated by zeros */
      animations = {}, /* Animation rules keyed by their name */
      useCssAnimations;

  /**
   *
   */
  function eachPair(args, it) {
    var end = ~~((args[length]-1)/2);
    for (var i = 1; i <= end; i++) {
      it(args[i*2-1], args[i*2]);
    }
  }

  /**
   * Utility function to create elements. If no tag name is given, a DIV is created.
   */
  function createEl(tag) {
    var el = document.createElement(tag || 'div');
    eachPair(arguments, function(prop, val) {
      el[prop] = val;
    });
    return el;
  }

  function ins(parent, child1, child2) {
    if(child2 && !child2[parentNode]) ins(parent, child2);
    parent.insertBefore(child1, child2||null);
    return parent;
  }

  /**
   * Insert a new stylesheet to hold the @keyframe or VML rules.
   */
  ins(document.documentElement[firstChild], createEl(style));
  var sheet = document[styleSheets][document[styleSheets][length] - 1];

  /**
   * Creates an opacity keyframe animation rule.
   */
  function addAnimation(to, end) {
    var name = [opacity, end, ~~(to*100)].join('-'),
        dest = '{' + opacity + ':' + to + '}',
        i;

    if (!animations[name]) {
      for (i=0; i<prefixes[length]; i++) {
        try {
          sheet.insertRule('@' +
            (prefixes[i] && '-'+prefixes[i].toLowerCase() +'-' || '') +
            'keyframes ' + name + '{0%{' + opacity + ':1}' +
            end + '%' + dest + 'to' + dest + '}', sheet.cssRules[length]);
        }
        catch (err) {
        }
      }
      animations[name] = 1;
    }
    return name;
  }

  /**
   * Tries various vendor prefixes and returns the first supported property.
   **/
  function vendor(el, prop) {
    var s = el[style],
        pp,
        i;

    if(s[prop] !== undefined) return prop;
    prop = prop.charAt(0).toUpperCase() + prop.slice(1);
    for(i=0; i<prefixes[length]; i++) {
      pp = prefixes[i]+prop;
      if(s[pp] !== undefined) return pp;
    }
  }

  /**
   * Sets multiple style properties at once.
   */
  function css(el) {
    eachPair(arguments, function(n, val) {
      el[style][vendor(el, n)||n] = val;
    });
    return el;
  }

  /**
   * Fills in default values. The values are passed as argument pairs rather
   * than as object in order to save some extra bytes.
   */
  function defaults(obj) {
    eachPair(arguments, function(prop, val) {
      if (obj[prop] === undefined) obj[prop] = val;
    });
    return obj;
  }

  /** The constructor */
  var Spinner = function Spinner(o) {
    this.el = this[lines](this.opts = defaults(o || {},
      lines, 12,
      trail, 100,
      length, 7,
      width, 5,
      radius, 10,
      color, black,
      opacity, 1/4,
      speed, 1));
  },
  proto = Spinner.prototype = {
    spin: function(target) {
      var self = this,
          el = self.el;

      if (target) {
        ins(target, css(el,
          left, ~~(target.offsetWidth/2) + px,
          top, ~~(target.offsetHeight/2) + px
        ), target[firstChild]);
      }
      self.on = 1;
      if (!useCssAnimations) {
        // No CSS animation support, use setTimeout() instead
        var o = self.opts,
            i = 0,
            f = 20/o[speed],
            ostep = (1-o[opacity])/(f*o[trail] / 100),
            astep = f/o[lines];

        (function anim() {
          i++;
          for (var s=o[lines]; s; s--) {
            var alpha = Math.max(1-(i+s*astep)%f * ostep, o[opacity]);
            self[opacity](el, o[lines]-s, alpha, o);
          }
          if (self.on) setTimeout(anim, 50);
        })();
      }
      return self;
    },
    stop: function() {
      var self = this,
          el = self.el;

      self.on = 0;
      if (el[parentNode]) el[parentNode].removeChild(el);
      return self;
    }
  };
  proto[lines] = function(o) {
    var el = css(createEl(), position, relative),
        animationName = addAnimation(o[opacity], o[trail]),
        i = 0,
        seg;

    function fill(color, shadow) {
      return css(createEl(),
        position, absolute,
        width, (o[length]+o[width]) + px,
        height, o[width] + px,
        'background', color,
        'boxShadow', shadow,
        transform + Origin, left,
        transform, 'rotate(' + ~~(360/o[lines]*i) + 'deg) translate(' + o[radius]+px +',0)',
        'borderRadius', '100em'
      );
    }
    for (; i < o[lines]; i++) {
      seg = css(createEl(),
        position, absolute,
        top, 1+~(o[width]/2) + px,
        transform, 'translate3d(0,0,0)',
        animation, animationName + ' ' + 1/o[speed] + 's linear infinite ' + (1/o[lines]/o[speed]*i - 1/o[speed]) + 's'
      );
      if (o[shadow]) ins(seg, css(fill(black, '0 0 4px ' + black), top, 2+px));
      ins(el, ins(seg, fill(o[color], '0 0 1px rgba(0,0,0,.1)')));
    }
    return el;
  };
  proto[opacity] = function(el, i, val) {
    el[childNodes][i][style][opacity] = val;
  };

  ///////////////////////////////////////////////////////////////////////////////
  // VML rendering for IE
  ///////////////////////////////////////////////////////////////////////////////

  var behavior = 'behavior',
      URL_VML = 'url(#default#VML)',
      tag = 'group0roundrect0fill0stroke'.split(0);

  /**
   * Check and init VML support
   */
  (function() {
    var s = css(createEl(tag[0]), behavior, URL_VML),
        i;

    if (!vendor(s, transform) && s.adj) {
      // VML support detected. Insert CSS rules for group, shape and stroke.
      for (i=0; i < tag[length]; i++) {
        sheet.addRule(tag[i], behavior + ':' + URL_VML);
      }
      proto[lines] = function() {
        var o = this.opts,
            r = o[length]+o[width],
            s = 2*r;

        function grp() {
          return css(createEl(tag[0], coord+'size', s +' '+s, coord+Origin, -r + ' ' + -r), width, s, height, s);
        }

        var g = grp(),
            margin = ~(o[length]+o[radius]+o[width])+px,
            i;

        function seg(i, dx, filter) {
          ins(g,
            ins(css(grp(), 'rotation', 360 / o[lines] * i + 'deg', left, ~~dx),
              ins(css(createEl(tag[1], 'arcsize', 1), width, r, height, o[width], left, o[radius], top, -o[width]/2, 'filter', filter),
                createEl(tag[2], color, o[color], opacity, o[opacity]),
                createEl(tag[3], opacity, 0) // transparent stroke to fix color bleeding upon opacity change
              )
            )
          );
        }

        if (o[shadow]) {
          for (i = 1; i <= o[lines]; i++) {
            seg(i, -2, 'progid:DXImage'+transform+'.Microsoft.Blur(pixel'+radius+'=2,make'+shadow+'=1,'+shadow+opacity+'=.3)');
          }
        }
        for (i = 1; i <= o[lines]; i++) {
          seg(i);
        }
        return ins(css(createEl(),
          'margin', margin + ' 0 0 ' + margin,
          position, relative
        ), g);
      };
      proto[opacity] = function(el, i, val, o) {
        o = o[shadow] && o[lines] || 0;
        el[firstChild][childNodes][i+o][firstChild][firstChild][opacity] = val;
      };
    }
    else {
      useCssAnimations = vendor(s, animation);
    }
  })();

  window.Spinner = Spinner;

})(document);
<commit_msg>Use getElementsByTagName() to look up head. Fixes #13<commit_after>// https://fgnass.github.com/spin.js
(function(document, undefined) {

/**
 * Copyright (c) 2011 Felix Gnass [fgnass at neteye dot de]
 * Licensed under the MIT license
 *
 * Unfortunately uglify.js doesn't provide an option to de-duplicate strings
 * or to use string-based property access. Hence we have to manually define
 * some string constants in order to keep file-size below our 3K limit, as
 * one of the design goals was to create a script that is smaller than an
 * animated GIF.
 */

  var width = 'width',
      length = 'length',
      radius = 'radius',
      lines = 'lines',
      trail = 'trail',
      color = 'color',
      opacity = 'opacity',
      speed = 'speed',
      shadow = 'shadow',
      style = 'style',
      height = 'height',
      left = 'left',
      top = 'top',
      px = 'px',
      childNodes = 'childNodes',
      firstChild = 'firstChild',
      parentNode = 'parentNode',
      position = 'position',
      relative = 'relative',
      absolute = 'absolute',
      animation = 'animation',
      transform = 'transform',
      Origin = 'Origin',
      coord = 'coord',
      black = '#000',
      styleSheets = style + 'Sheets',
      prefixes = "webkit0Moz0ms0O".split(0), /* Vendor prefixes, separated by zeros */
      animations = {}, /* Animation rules keyed by their name */
      useCssAnimations;

  /**
   *
   */
  function eachPair(args, it) {
    var end = ~~((args[length]-1)/2);
    for (var i = 1; i <= end; i++) {
      it(args[i*2-1], args[i*2]);
    }
  }

  /**
   * Utility function to create elements. If no tag name is given, a DIV is created.
   */
  function createEl(tag) {
    var el = document.createElement(tag || 'div');
    eachPair(arguments, function(prop, val) {
      el[prop] = val;
    });
    return el;
  }

  function ins(parent, child1, child2) {
    if(child2 && !child2[parentNode]) ins(parent, child2);
    parent.insertBefore(child1, child2||null);
    return parent;
  }

  /**
   * Insert a new stylesheet to hold the @keyframe or VML rules.
   */
  ins(document.getElementsByTagName('head')[0], createEl(style));
  var sheet = document[styleSheets][document[styleSheets][length] - 1];

  /**
   * Creates an opacity keyframe animation rule.
   */
  function addAnimation(to, end) {
    var name = [opacity, end, ~~(to*100)].join('-'),
        dest = '{' + opacity + ':' + to + '}',
        i;

    if (!animations[name]) {
      for (i=0; i<prefixes[length]; i++) {
        try {
          sheet.insertRule('@' +
            (prefixes[i] && '-'+prefixes[i].toLowerCase() +'-' || '') +
            'keyframes ' + name + '{0%{' + opacity + ':1}' +
            end + '%' + dest + 'to' + dest + '}', sheet.cssRules[length]);
        }
        catch (err) {
        }
      }
      animations[name] = 1;
    }
    return name;
  }

  /**
   * Tries various vendor prefixes and returns the first supported property.
   **/
  function vendor(el, prop) {
    var s = el[style],
        pp,
        i;

    if(s[prop] !== undefined) return prop;
    prop = prop.charAt(0).toUpperCase() + prop.slice(1);
    for(i=0; i<prefixes[length]; i++) {
      pp = prefixes[i]+prop;
      if(s[pp] !== undefined) return pp;
    }
  }

  /**
   * Sets multiple style properties at once.
   */
  function css(el) {
    eachPair(arguments, function(n, val) {
      el[style][vendor(el, n)||n] = val;
    });
    return el;
  }

  /**
   * Fills in default values. The values are passed as argument pairs rather
   * than as object in order to save some extra bytes.
   */
  function defaults(obj) {
    eachPair(arguments, function(prop, val) {
      if (obj[prop] === undefined) obj[prop] = val;
    });
    return obj;
  }

  /** The constructor */
  var Spinner = function Spinner(o) {
    this.el = this[lines](this.opts = defaults(o || {},
      lines, 12,
      trail, 100,
      length, 7,
      width, 5,
      radius, 10,
      color, black,
      opacity, 1/4,
      speed, 1));
  },
  proto = Spinner.prototype = {
    spin: function(target) {
      var self = this,
          el = self.el;

      if (target) {
        ins(target, css(el,
          left, ~~(target.offsetWidth/2) + px,
          top, ~~(target.offsetHeight/2) + px
        ), target[firstChild]);
      }
      self.on = 1;
      if (!useCssAnimations) {
        // No CSS animation support, use setTimeout() instead
        var o = self.opts,
            i = 0,
            f = 20/o[speed],
            ostep = (1-o[opacity])/(f*o[trail] / 100),
            astep = f/o[lines];

        (function anim() {
          i++;
          for (var s=o[lines]; s; s--) {
            var alpha = Math.max(1-(i+s*astep)%f * ostep, o[opacity]);
            self[opacity](el, o[lines]-s, alpha, o);
          }
          if (self.on) setTimeout(anim, 50);
        })();
      }
      return self;
    },
    stop: function() {
      var self = this,
          el = self.el;

      self.on = 0;
      if (el[parentNode]) el[parentNode].removeChild(el);
      return self;
    }
  };
  proto[lines] = function(o) {
    var el = css(createEl(), position, relative),
        animationName = addAnimation(o[opacity], o[trail]),
        i = 0,
        seg;

    function fill(color, shadow) {
      return css(createEl(),
        position, absolute,
        width, (o[length]+o[width]) + px,
        height, o[width] + px,
        'background', color,
        'boxShadow', shadow,
        transform + Origin, left,
        transform, 'rotate(' + ~~(360/o[lines]*i) + 'deg) translate(' + o[radius]+px +',0)',
        'borderRadius', '100em'
      );
    }
    for (; i < o[lines]; i++) {
      seg = css(createEl(),
        position, absolute,
        top, 1+~(o[width]/2) + px,
        transform, 'translate3d(0,0,0)',
        animation, animationName + ' ' + 1/o[speed] + 's linear infinite ' + (1/o[lines]/o[speed]*i - 1/o[speed]) + 's'
      );
      if (o[shadow]) ins(seg, css(fill(black, '0 0 4px ' + black), top, 2+px));
      ins(el, ins(seg, fill(o[color], '0 0 1px rgba(0,0,0,.1)')));
    }
    return el;
  };
  proto[opacity] = function(el, i, val) {
    el[childNodes][i][style][opacity] = val;
  };

  ///////////////////////////////////////////////////////////////////////////////
  // VML rendering for IE
  ///////////////////////////////////////////////////////////////////////////////

  var behavior = 'behavior',
      URL_VML = 'url(#default#VML)',
      tag = 'group0roundrect0fill0stroke'.split(0);

  /**
   * Check and init VML support
   */
  (function() {
    var s = css(createEl(tag[0]), behavior, URL_VML),
        i;

    if (!vendor(s, transform) && s.adj) {
      // VML support detected. Insert CSS rules for group, shape and stroke.
      for (i=0; i < tag[length]; i++) {
        sheet.addRule(tag[i], behavior + ':' + URL_VML);
      }
      proto[lines] = function() {
        var o = this.opts,
            r = o[length]+o[width],
            s = 2*r;

        function grp() {
          return css(createEl(tag[0], coord+'size', s +' '+s, coord+Origin, -r + ' ' + -r), width, s, height, s);
        }

        var g = grp(),
            margin = ~(o[length]+o[radius]+o[width])+px,
            i;

        function seg(i, dx, filter) {
          ins(g,
            ins(css(grp(), 'rotation', 360 / o[lines] * i + 'deg', left, ~~dx),
              ins(css(createEl(tag[1], 'arcsize', 1), width, r, height, o[width], left, o[radius], top, -o[width]/2, 'filter', filter),
                createEl(tag[2], color, o[color], opacity, o[opacity]),
                createEl(tag[3], opacity, 0) // transparent stroke to fix color bleeding upon opacity change
              )
            )
          );
        }

        if (o[shadow]) {
          for (i = 1; i <= o[lines]; i++) {
            seg(i, -2, 'progid:DXImage'+transform+'.Microsoft.Blur(pixel'+radius+'=2,make'+shadow+'=1,'+shadow+opacity+'=.3)');
          }
        }
        for (i = 1; i <= o[lines]; i++) {
          seg(i);
        }
        return ins(css(createEl(),
          'margin', margin + ' 0 0 ' + margin,
          position, relative
        ), g);
      };
      proto[opacity] = function(el, i, val, o) {
        o = o[shadow] && o[lines] || 0;
        el[firstChild][childNodes][i+o][firstChild][firstChild][opacity] = val;
      };
    }
    else {
      useCssAnimations = vendor(s, animation);
    }
  })();

  window.Spinner = Spinner;

})(document);
<|endoftext|>


<commit_before>'using strict';

var PargApp = function(canvas, args, baseurl) {
    this.canvas = canvas;
    this.args = args;
    this.baseurl = baseurl || 'parg/';
    this.nrequests = 0;
    this.requests = [];
    this.linked_module = null;

    // First, execute the user-defined main() function in its entirety:
    this.module = CreateParg({parg: this});

    // Now, make HTTP requests for all assets:
    this.request_assets();

    // After receiving responses from all HTTP requests, parg will
    // automatically call the user-defined init() function.
};

PargApp.prototype.asset_preload = function(id) {
    var url = this.baseurl + id;
    var xhr = new XMLHttpRequest();
    xhr.open('GET', url, true);
    xhr.responseType = 'arraybuffer';
    var onloadFunc = function() {
        if (xhr.response) {
            this.onasset(id, xhr.response)
        }
    }.bind(this);
    var errorFunc = function() {
        window.console.error('Unable to download ' + url);
    };
    xhr.onload = onloadFunc;
    xhr.onerror = errorFunc;
    this.requests[this.nrequests++] = xhr;
};

PargApp.prototype.request_assets = function() {
    for (var i = 0, len = this.requests.length; i < len; i++) {
        this.requests[i].send(null);
    }
};

PargApp.prototype.onasset = function(id, arraybuffer) {
    var ptr = this.module.Asset.alloc(id, arraybuffer.byteLength);
    var u8buffer = new Uint8Array(arraybuffer);
    this.module.HEAPU8.set(u8buffer, ptr);
    this.module.Asset.commit(id);
    if (--this.nrequests == 0) {
        this.start();
    }
};

PargApp.prototype.start = function() {

    var cevents = {
        PAR_EVENT_DOWN: 0,
        PAR_EVENT_UP: 1,
        PAR_EVENT_MOVE: 2
    };

    var dims = this.module.par_window_dims;
    var $canvas = $(this.canvas);
    var canvas = $canvas[0];
    $canvas.css({
        width: dims[0] + 'px',
        height: dims[1] + 'px'
    });
    canvas.width = dims[0] * window.devicePixelRatio;
    canvas.height = dims[1] * window.devicePixelRatio;

    var GLctx = this.module.createContext(canvas, 1, 1, {
        alpha: true,
        antialias: true
    })
    GLctx.clearColor(0.2, 0.4, 0.8, 1.0);
    GLctx.clear(GLctx.COLOR_BUFFER_BIT);
    $canvas.show();

    this.module.Window.init(this.args);

    var clientWidth = canvas.clientWidth;
    var clientHeight = canvas.clientHeight;
    var clientMaxY = clientHeight - 1;

    var onmousecore = function(event) {
        var box = canvas.getBoundingClientRect();
        var x = (event.clientX - box.left) / clientWidth;
        var y = (clientMaxY - event.clientY + box.top) / clientHeight;
        var etype = event.type;
        if (etype == "mousedown") {
            this.Window.input(cevents.PAR_EVENT_DOWN, x, y, 0);
        } else if (etype == "mouseup") {
            this.Window.input(cevents.PAR_EVENT_UP, x, y, 0);
        } else if (etype == "mousemove") {
            this.Window.input(cevents.PAR_EVENT_MOVE, x, y, 0);
        } else if (etype == "mousewheel") {
            event.preventDefault();
            var delta = event.wheelDelta / 10.0;
            this.Window.input(cevents.PAR_EVENT_MOVE, x, y, delta);
        } else if (etype == "DOMMouseScroll") {
            event.preventDefault();
            var delta = -event.detail / 2.0;
            this.Window.input(cevents.PAR_EVENT_MOVE, x, y, delta);
        }
    };

    var onmouse = onmousecore.bind(this.module);
    if (this.linked_module) {
        var fn1 = onmouse;
        var fn2 = onmousecore.bind(this.linked_module);
        onmouse = function(event) {
            fn1(event);
            fn2(event);
        };
    }

    canvas.addEventListener("mousedown", onmouse);
    canvas.addEventListener("mouseup", onmouse);
    canvas.addEventListener("mousemove", onmouse);
    canvas.addEventListener("mousewheel", onmouse);
    canvas.addEventListener("DOMMouseScroll", onmouse);

    var raf = function() {
        var milliseconds = window.performance.now();
        this.module.Window.tick(milliseconds / 1000.0);
        this.module.Window.draw();
        window.requestAnimationFrame(raf);
    }.bind(this);

    window.requestAnimationFrame(raf);
};
<commit_msg>lint cleanup<commit_after>'using strict';

var PargApp = function(canvas, args, baseurl) {
    this.canvas = canvas;
    this.args = args;
    this.baseurl = baseurl || 'parg/';
    this.nrequests = 0;
    this.requests = [];
    this.linked_module = null;

    // First, execute the user-defined main() function in its entirety:
    this.module = CreateParg({parg: this});

    // Now, make HTTP requests for all assets:
    this.request_assets();

    // After receiving responses from all HTTP requests, parg will
    // automatically call the user-defined init() function.
};

PargApp.prototype.asset_preload = function(id) {
    var url = this.baseurl + id;
    var xhr = new XMLHttpRequest();
    xhr.open('GET', url, true);
    xhr.responseType = 'arraybuffer';
    var onloadFunc = function() {
        if (xhr.response) {
            this.onasset(id, xhr.response);
        }
    }.bind(this);
    var errorFunc = function() {
        window.console.error('Unable to download ' + url);
    };
    xhr.onload = onloadFunc;
    xhr.onerror = errorFunc;
    this.requests[this.nrequests++] = xhr;
};

PargApp.prototype.request_assets = function() {
    for (var i = 0, len = this.requests.length; i < len; i++) {
        this.requests[i].send(null);
    }
};

PargApp.prototype.onasset = function(id, arraybuffer) {
    var ptr = this.module.Asset.alloc(id, arraybuffer.byteLength);
    var u8buffer = new Uint8Array(arraybuffer);
    this.module.HEAPU8.set(u8buffer, ptr);
    this.module.Asset.commit(id);
    if (--this.nrequests === 0) {
        this.start();
    }
};

PargApp.prototype.start = function() {

    var cevents = {
        PAR_EVENT_DOWN: 0,
        PAR_EVENT_UP: 1,
        PAR_EVENT_MOVE: 2
    };

    var dims = this.module.par_window_dims;
    var $canvas = $(this.canvas);
    var canvas = $canvas[0];
    $canvas.css({
        width: dims[0] + 'px',
        height: dims[1] + 'px'
    });
    canvas.width = dims[0] * window.devicePixelRatio;
    canvas.height = dims[1] * window.devicePixelRatio;

    var GLctx = this.module.createContext(canvas, 1, 1, {
        alpha: true,
        antialias: true
    });
    GLctx.clearColor(0.2, 0.4, 0.8, 1.0);
    GLctx.clear(GLctx.COLOR_BUFFER_BIT);
    $canvas.show();

    this.module.Window.init(this.args);

    var clientWidth = canvas.clientWidth;
    var clientHeight = canvas.clientHeight;
    var clientMaxY = clientHeight - 1;

    var onmousecore = function(event) {
        var box = canvas.getBoundingClientRect();
        var x = (event.clientX - box.left) / clientWidth;
        var y = (clientMaxY - event.clientY + box.top) / clientHeight;
        var etype = event.type;
        var delta;
        if (etype == "mousedown") {
            this.Window.input(cevents.PAR_EVENT_DOWN, x, y, 0);
        } else if (etype == "mouseup") {
            this.Window.input(cevents.PAR_EVENT_UP, x, y, 0);
        } else if (etype == "mousemove") {
            this.Window.input(cevents.PAR_EVENT_MOVE, x, y, 0);
        } else if (etype == "mousewheel") {
            event.preventDefault();
            delta = event.wheelDelta / 10.0;
            this.Window.input(cevents.PAR_EVENT_MOVE, x, y, delta);
        } else if (etype == "DOMMouseScroll") {
            event.preventDefault();
            delta = -event.detail / 2.0;
            this.Window.input(cevents.PAR_EVENT_MOVE, x, y, delta);
        }
    };

    var onmouse = onmousecore.bind(this.module);
    if (this.linked_module) {
        var fn1 = onmouse;
        var fn2 = onmousecore.bind(this.linked_module);
        onmouse = function(event) {
            fn1(event);
            fn2(event);
        };
    }

    canvas.addEventListener("mousedown", onmouse);
    canvas.addEventListener("mouseup", onmouse);
    canvas.addEventListener("mousemove", onmouse);
    canvas.addEventListener("mousewheel", onmouse);
    canvas.addEventListener("DOMMouseScroll", onmouse);

    var raf = function() {
        var milliseconds = window.performance.now();
        this.module.Window.tick(milliseconds / 1000.0);
        this.module.Window.draw();
        window.requestAnimationFrame(raf);
    }.bind(this);

    window.requestAnimationFrame(raf);
};
<|endoftext|>


<commit_before>'use strict';
var path = require('path');
var fs = require('fs');
var chalk = require('chalk');

exports.STATE_NEEDLE = '/* STATES-NEEDLE - DO NOT REMOVE THIS */';

// inspired by https://github.com/cgross/generator-cg-angular/blob/master/utils.js
exports.addToFile = function (filename, lineToAdd, beforeMarker)
{
    try {
        var fullPath = path.resolve(process.cwd(), filename);
        var fileSrc = fs.readFileSync(fullPath, 'utf8');

        var indexOf = fileSrc.indexOf(beforeMarker);
        var lineStart = fileSrc.substring(0, indexOf).lastIndexOf('\n') + 1;
        var indent = fileSrc.substring(lineStart, indexOf);
        fileSrc = fileSrc.substring(0, indexOf) + lineToAdd + '\n' + indent + fileSrc.substring(indexOf);

        fs.writeFileSync(fullPath, fileSrc);
    } catch (e) {
        throw e;
    }
};

exports.injectRoute = function (routesFile, name, url, tplUrl, ctrl, that)
{
    var ind = '    ';
    var template = tplUrl ? ',\n' + ind + ind + ind + ind + 'templateUrl: \'' + tplUrl + '\'' : '';
    ctrl = ctrl ? ',\n' + ind + ind + ind + ind + 'controller: \'' + ctrl + '\'' : '';
    var code = '' +
        '.state(AAAL_BASE_STATE + \'' + name + '\', {' +
        '\n' + ind + ind + ind + ind + 'url: \'' + url + '\'' +
        ctrl +
        template +
        '\n' + ind + ind + ind + '})';
    exports.addToFile(routesFile, code, exports.STATE_NEEDLE);

    that.log.writeln(chalk.green(' updating') + ' %s', path.basename(routesFile));
};

<commit_msg>finished object to string converter<commit_after>'use strict';
var path = require('path');
var fs = require('fs');
var chalk = require('chalk');

exports.STATE_NEEDLE = '/* STATES-NEEDLE - DO NOT REMOVE THIS */';

// inspired by https://github.com/cgross/generator-cg-angular/blob/master/utils.js
exports.addToFile = function (filename, lineToAdd, beforeMarker)
{
    try {
        var fullPath = path.resolve(process.cwd(), filename);
        var fileSrc = fs.readFileSync(fullPath, 'utf8');

        var indexOf = fileSrc.indexOf(beforeMarker);
        var lineStart = fileSrc.substring(0, indexOf).lastIndexOf('\n') + 1;
        var indent = fileSrc.substring(lineStart, indexOf);
        fileSrc = fileSrc.substring(0, indexOf) + lineToAdd + '\n' + indent + fileSrc.substring(indexOf);

        fs.writeFileSync(fullPath, fileSrc);
    } catch (e) {
        throw e;
    }
};

exports.injectRoute = function (routesFile, name, url, tplUrl, ctrl, that)
{
    var ind = '    ';
    var template = tplUrl ? ',\n' + ind + ind + ind + ind + 'templateUrl: \'' + tplUrl + '\'' : '';
    ctrl = ctrl ? ',\n' + ind + ind + ind + ind + 'controller: \'' + ctrl + '\'' : '';
    var code = '' +
        '.state(AAAL_BASE_STATE + \'' + name + '\', {' +
        '\n' + ind + ind + ind + ind + 'url: \'' + url + '\'' +
        ctrl +
        template +
        '\n' + ind + ind + ind + '})';
    exports.addToFile(routesFile, code, exports.STATE_NEEDLE);

    that.log.writeln(chalk.green(' updating') + ' %s', path.basename(routesFile));
};

exports.simpleObjectToString = simpleObjectToString;

function simpleObjectToString(obj, startIndent)
{
    var IND = '    ';

    function handleTypes(item, startIndent)
    {
        var str = '';
        if (typeof(item) === "boolean") {
            str += item ? 'true' : 'false';
        } else if (typeof item === 'number') {
            str += item;
        } else if (typeof item === 'string') {
            str += '\'' + item + '\'';
        } else if (item instanceof Array) {
            str += createArrayStr(item, startIndent + IND);
        } else if (typeof item === 'object') {
            str += createObjStr(item, startIndent + IND);
        }
        return str;
    }

    function createArrayStr(arr, startIndent)
    {
        var arrStr = '[';
        for (var i = 0; i < arr.length; i++) {
            var arrItem = arr[i];
            arrStr += '\n' + startIndent + IND;
            arrStr += handleTypes(arrItem, startIndent);

            if (i < arr.length - 1) {
                arrStr += ',';
            }
        }
        arrStr += '\n' + startIndent + ']';

        return arrStr;
    }

    function createObjectPropsStr(obj, key, startIndent, i)
    {
        var objPropsStr = '';
        var prop = obj[key];
        var objLength = Object.keys(obj).length - 1;

        objPropsStr += '\n' + startIndent + IND + '\'' + key + '\': ';
        objPropsStr += handleTypes(prop, startIndent);

        if (i < objLength) {
            objPropsStr += ',';
        }

        return objPropsStr;
    }

    function createObjStr(obj, startIndent)
    {
        var str = '';
        var i = 0;
        str += '{';
        for (var key in obj) {
            str += createObjectPropsStr(obj, key, startIndent, i);
            i++;
        }
        str += '\n' + startIndent + '}';
        return str;
    }

    if (obj instanceof Array) {
        return createArrayStr(obj, startIndent);
    } else {
        return createObjStr(obj, startIndent);
    }
}

<|endoftext|>


<commit_before><commit_msg>Added logging<commit_after><|endoftext|>


<commit_before>import React from 'react';
import { mount } from 'enzyme';
import { useTranslation } from '../src/useTranslation';

jest.unmock('../src/useTranslation');

const i18n = {
  language: 'en',
  languages: ['en'],
  services: {
    resourceStore: {
      data: {},
    },
    backendConnector: { backend: {} },
  },
  isInitialized: true,
  changeLanguage: () => {},
  getFixedT: () => message => message,
  hasResourceBundle: (lng, ns) => ns === 'ns1' || ns === 'ns2' || ns === 'ns3',
  loadNamespaces: () => {},
  on: () => {},
  options: {},
};

describe('useTranslation', () => {
  function TestComponent() {
    const [t] = useTranslation(['ns1', 'ns2', 'ns3'], { i18n });

    return <div>{t('keyOne')}</div>;
  }

  it('should render correct content if ready (having all ns)', () => {
    mount(<TestComponent />, {});
    // console.log(wrapper.debug());
    expect(i18n.reportNamespaces.getUsedNamespaces()).toEqual(['ns1', 'ns2', 'ns3']);
  });
});
<commit_msg>useTranslation.usedNamespaces.spec.js, 1 test<commit_after>import React from 'react';
import { renderHook } from '@testing-library/react-hooks';
import { useTranslation } from '../src/useTranslation';

jest.unmock('../src/useTranslation');

describe('useTranslation', () => {
  it('should render correct content if ready (having all ns)', () => {
    const i18n = {
      language: 'en',
      languages: ['en'],
      services: {
        resourceStore: {
          data: {},
        },
        backendConnector: { backend: {} },
      },
      isInitialized: true,
      changeLanguage: () => {},
      getFixedT: () => message => message,
      hasResourceBundle: (lng, ns) => ns === 'ns1' || ns === 'ns2' || ns === 'ns3',
      loadNamespaces: () => {},
      on: () => {},
      off: () => {},
      options: {},
    };
    renderHook(() => useTranslation(['ns1', 'ns2', 'ns3'], { i18n }));
    expect(i18n.reportNamespaces.getUsedNamespaces()).toEqual(['ns1', 'ns2', 'ns3']);
  });
});
<|endoftext|>


<commit_before>
frappe.provide('frappe.views');

frappe.ui.GroupBy = class {
	constructor(report_view) {
		this.report_view = report_view;
		this.page = report_view.page;
		this.doctype = report_view.doctype;
		this.setup_group_by_area();
	}

	setup_group_by_area() {
		this.make_group_by_button();
		let sql_aggregate_function = [
			{name:'count', label: 'Count'},
			{name:'sum', label: 'Sum'},
			{name:'avg', label:'Average'}
		];
		this.groupby_edit_area = $(frappe.render_template("group_by", {
			doctype: this.doctype,
			groupby_conditions: this.get_group_by_fields(),
			aggregate_function_conditions: sql_aggregate_function,
		}));

		this.groupby_select = this.groupby_edit_area.find('select.groupby');
		this.aggregate_function_select = this.groupby_edit_area.find('select.aggregate-function');
		this.aggregate_on_select = this.groupby_edit_area.find('select.aggregate-on');

		// set default to count
		this.aggregate_function_select.val("count");
		this.page.wrapper.find(".frappe-list").append(
			this.groupby_edit_area);

		//Set aggregate on options as numeric fields if function is sum or average
		this.aggregate_function_select.on('change', () => {
			this.show_hide_aggregate_on();
		});

		// try running on change
		this.groupby_select.on('change', () => this.apply_group_by_and_refresh());
		this.aggregate_function_select.on('change', () => this.apply_group_by_and_refresh());
		this.aggregate_on_select.on('change', () => this.apply_group_by_and_refresh());

		$('.set-groupby-and-run').on('click', () => {
			this.apply_group_by_and_refresh();
		});

		$('.remove-groupby').on('click', () => {
			this.remove_group_by();
		});
	}

	show_hide_aggregate_on() {

		for (let doctype in this.all_fields) {
			const doctype_fields = this.all_fields[doctype];
			doctype_fields.forEach(field => {
				let fn = this.aggregate_function_select.val();
				if(fn === 'sum' || fn === 'avg') {
					// pick numeric fields for sum / avg
					if(frappe.model.is_numeric_field(field.fieldtype)) {
						let option_text = doctype == this.doctype
						? field.label
						: `${field.label} (${doctype})`
						this.aggregate_on_select.append(
							$(`<option data-doctype="${doctype}"
								value="${field.fieldname}">>`,
								{ value : field.fieldname })
								.text(option_text));
					}
					this.aggregate_on_select.show();
				} else {
					// count, so no aggregate function
					this.aggregate_on_select.hide();
				}
			});
		}
	}

	get_settings() {
		if (this.group_by)  {
			return {
				group_by: this.group_by,
				aggregate_function: this.aggregate_function,
				aggregate_on: this.aggregate_on
			};
		} else {
			return null;
		}
	}

	apply_settings(settings) {

		// Extract fieldname from `tabdoctype`.`fieldname`
		let group_by_fieldname = settings.group_by.split('.')[1].replace(/`/g, '');

		this.groupby_select.val(group_by_fieldname);
		this.aggregate_function_select.val(settings.aggregate_function);
		this.show_hide_aggregate_on();
		this.aggregate_on_select.val(settings.aggregate_on);
		this.groupby_edit_area.show();

		this.apply_group_by();
	}

	make_group_by_button() {
		let group_by_button =  $(`

				<button class="btn btn-default btn-xs add-groupby text-muted">
						${__("Add Group")}
				</button>

`);
		this.page.wrapper.find(".sort-selector").before(group_by_button);
		group_by_button.click(() => this.groupby_edit_area.show());
	}

	apply_group_by() {
		this.group_by_doctype = this.groupby_select.find(':selected').attr('data-doctype');
		this.group_by_field = this.groupby_select.val();
		this.group_by = '`tab' + this.group_by_doctype + '`.`' + this.group_by_field + '`';
		this.aggregate_function = this.aggregate_function_select.val();

		if (this.aggregate_function === 'count') {
			this.aggregate_on = 'name';
			this.aggregate_on_doctype = null;
		} else {
			this.aggregate_on = this.aggregate_on_select.val();
			this.aggregate_on_doctype = this.aggregate_on_select.find(':selected').attr('data-doctype');
		}

		//All necessary fields must be set before applying group by
		if(!this.group_by) {
			this.page.wrapper.find('.groupby').focus();
			return;
		} else if(!this.aggregate_function) {
			this.page.wrapper.find('.aggregate-function').focus();
			return;
		} else if(!this.aggregate_on && this.aggregate_function!=='count') {
			this.page.wrapper.find('.aggregate-on').focus();
			return;
		}

		return true;

	}

	apply_group_by_and_refresh() {
		if (this.apply_group_by()) {
			this.report_view.refresh();
		}
	}

	set_args(args) {
		if (this.aggregate_function && this.group_by) {
			let aggregate_column, aggregate_on_field;
			if (this.aggregate_function === 'count') {
				aggregate_column = 'count(`tab'+ this.doctype + '`.`name`)';
			} else {
				aggregate_column =
					`${this.aggregate_function}(\`tab${this.aggregate_on_doctype}\`.\`${this.aggregate_on}\`)`;
				aggregate_on_field = '`tab' + this.aggregate_on_doctype + '`.`' + this.aggregate_on + '`';
			}

			this.report_view.group_by = this.group_by;
			this.report_view.sort_by = '_aggregate_column';
			this.report_view.sort_order = 'desc';

			// save orignial fields
			if(!this.report_view.fields.map(f => f[0]).includes('_aggregate_column')) {
				this.original_fields = this.report_view.fields.map(f => f);
			}

			this.report_view.fields = [
				[this.group_by_field, this.group_by_doctype]
			];

			// rebuild fields for group by
			args.fields = this.report_view.get_fields();

			// add aggregate column in both query args and report views
			this.report_view.fields.push(['_aggregate_column', this.aggregate_on_doctype || this.doctype]);
			args.fields.push(aggregate_column + ' as _aggregate_column');

			if (aggregate_on_field) {
				args.fields.push(aggregate_on_field);
			}

			// setup columns in datatable
			this.report_view.setup_columns();

			Object.assign(args, {
				with_comment_count: false,
				group_by: this.report_view.group_by || null,
				order_by: '_aggregate_column desc'
			});
		}

	}

	get_group_by_docfield() {
		// called from build_column
		let docfield;
		if (this.aggregate_function === 'count') {
			docfield = {
				fieldtype: 'Int',
				label: __('Count'),
				parent: this.doctype,
				width: 120
			};
		} else {
			// get properties of "aggregate_on", for example Net Total
			docfield = Object.assign({}, frappe.meta.docfield_map[this.aggregate_on_doctype][this.aggregate_on]);
			if (this.aggregate_function === 'sum') {
				docfield.label = __('Sum of {0}', [docfield.label]);
			} else {
				docfield.label = __('Average of {0}', [docfield.label]);
			}
		}
		docfield.fieldname = '_aggregate_column';

		return docfield;
	}

	remove_group_by() {
		this.groupby_edit_area.hide();

		this.order_by = '';
		this.group_by = null;
		this.aggregate_function = null;
		this.aggregate_on = null;
		$(".groupby").val("");
		$(".aggregate-function").val("count");
		$(".aggregate-on").empty().val("").hide();

		// restore original fields
		if (this.original_fields) {
			this.report_view.fields = this.original_fields;
		} else {
			this.report_view.set_default_fields();
		}
		this.report_view.setup_columns();
		this.original_fields = null;
		this.report_view.refresh();
	}

	get_group_by_fields() {
		this.group_by_fields = {};
		this.all_fields = {};

		let fields = this.report_view.meta.fields.filter(f => ["Select", "Link", "Data", "Int"].includes(f.fieldtype));
		this.group_by_fields[this.doctype] = fields;
		this.all_fields[this.doctype] = this.report_view.meta.fields;

		const standard_fields_filter = df =>
			!in_list(frappe.model.no_value_type, df.fieldtype) && !df.report_hide;

		const table_fields = frappe.meta.get_table_fields(this.doctype)
			.filter(df => !df.hidden);

		table_fields.forEach(df => {
			const cdt = df.options;
			const child_table_fields = frappe.meta.get_docfields(cdt).filter(standard_fields_filter);
			this.group_by_fields[cdt] = child_table_fields;
			this.all_fields[cdt] = child_table_fields;
		});
		return this.group_by_fields;
	}

};
<commit_msg>fix: codacy<commit_after>
frappe.provide('frappe.views');

frappe.ui.GroupBy = class {
	constructor(report_view) {
		this.report_view = report_view;
		this.page = report_view.page;
		this.doctype = report_view.doctype;
		this.setup_group_by_area();
	}

	setup_group_by_area() {
		this.make_group_by_button();
		let sql_aggregate_function = [
			{name:'count', label: 'Count'},
			{name:'sum', label: 'Sum'},
			{name:'avg', label:'Average'}
		];
		this.groupby_edit_area = $(frappe.render_template("group_by", {
			doctype: this.doctype,
			groupby_conditions: this.get_group_by_fields(),
			aggregate_function_conditions: sql_aggregate_function,
		}));

		this.groupby_select = this.groupby_edit_area.find('select.groupby');
		this.aggregate_function_select = this.groupby_edit_area.find('select.aggregate-function');
		this.aggregate_on_select = this.groupby_edit_area.find('select.aggregate-on');

		// set default to count
		this.aggregate_function_select.val("count");
		this.page.wrapper.find(".frappe-list").append(
			this.groupby_edit_area);

		//Set aggregate on options as numeric fields if function is sum or average
		this.aggregate_function_select.on('change', () => {
			this.show_hide_aggregate_on();
		});

		// try running on change
		this.groupby_select.on('change', () => this.apply_group_by_and_refresh());
		this.aggregate_function_select.on('change', () => this.apply_group_by_and_refresh());
		this.aggregate_on_select.on('change', () => this.apply_group_by_and_refresh());

		$('.set-groupby-and-run').on('click', () => {
			this.apply_group_by_and_refresh();
		});

		$('.remove-groupby').on('click', () => {
			this.remove_group_by();
		});
	}

	show_hide_aggregate_on() {

		for (let doctype in this.all_fields) {
			const doctype_fields = this.all_fields[doctype];
			doctype_fields.forEach(field => {
				let fn = this.aggregate_function_select.val();
				if(fn === 'sum' || fn === 'avg') {
					// pick numeric fields for sum / avg
					if(frappe.model.is_numeric_field(field.fieldtype)) {
						let option_text = doctype == this.doctype
							? field.label
							: `${field.label} (${doctype})`;
						this.aggregate_on_select.append(
							$(`<option data-doctype="${doctype}"
							value="${field.fieldname}">>`,
							{ value: field.fieldname }).text(option_text));
					}
					this.aggregate_on_select.show();
				} else {
					// count, so no aggregate function
					this.aggregate_on_select.hide();
				}
			});
		}
	}

	get_settings() {
		if (this.group_by)  {
			return {
				group_by: this.group_by,
				aggregate_function: this.aggregate_function,
				aggregate_on: this.aggregate_on
			};
		} else {
			return null;
		}
	}

	apply_settings(settings) {

		// Extract fieldname from `tabdoctype`.`fieldname`
		let group_by_fieldname = settings.group_by.split('.')[1].replace(/`/g, '');

		this.groupby_select.val(group_by_fieldname);
		this.aggregate_function_select.val(settings.aggregate_function);
		this.show_hide_aggregate_on();
		this.aggregate_on_select.val(settings.aggregate_on);
		this.groupby_edit_area.show();

		this.apply_group_by();
	}

	make_group_by_button() {
		let group_by_button =  $(`

				<button class="btn btn-default btn-xs add-groupby text-muted">
						${__("Add Group")}
				</button>

`);
		this.page.wrapper.find(".sort-selector").before(group_by_button);
		group_by_button.click(() => this.groupby_edit_area.show());
	}

	apply_group_by() {
		this.group_by_doctype = this.groupby_select.find(':selected').attr('data-doctype');
		this.group_by_field = this.groupby_select.val();
		this.group_by = '`tab' + this.group_by_doctype + '`.`' + this.group_by_field + '`';
		this.aggregate_function = this.aggregate_function_select.val();

		if (this.aggregate_function === 'count') {
			this.aggregate_on = 'name';
			this.aggregate_on_doctype = null;
		} else {
			this.aggregate_on = this.aggregate_on_select.val();
			this.aggregate_on_doctype = this.aggregate_on_select.find(':selected').attr('data-doctype');
		}

		//All necessary fields must be set before applying group by
		if(!this.group_by) {
			this.page.wrapper.find('.groupby').focus();
			return;
		} else if(!this.aggregate_function) {
			this.page.wrapper.find('.aggregate-function').focus();
			return;
		} else if(!this.aggregate_on && this.aggregate_function!=='count') {
			this.page.wrapper.find('.aggregate-on').focus();
			return;
		}

		return true;

	}

	apply_group_by_and_refresh() {
		if (this.apply_group_by()) {
			this.report_view.refresh();
		}
	}

	set_args(args) {
		if (this.aggregate_function && this.group_by) {
			let aggregate_column, aggregate_on_field;
			if (this.aggregate_function === 'count') {
				aggregate_column = 'count(`tab'+ this.doctype + '`.`name`)';
			} else {
				aggregate_column =
					`${this.aggregate_function}(\`tab${this.aggregate_on_doctype}\`.\`${this.aggregate_on}\`)`;
				aggregate_on_field = '`tab' + this.aggregate_on_doctype + '`.`' + this.aggregate_on + '`';
			}

			this.report_view.group_by = this.group_by;
			this.report_view.sort_by = '_aggregate_column';
			this.report_view.sort_order = 'desc';

			// save orignial fields
			if(!this.report_view.fields.map(f => f[0]).includes('_aggregate_column')) {
				this.original_fields = this.report_view.fields.map(f => f);
			}

			this.report_view.fields = [
				[this.group_by_field, this.group_by_doctype]
			];

			// rebuild fields for group by
			args.fields = this.report_view.get_fields();

			// add aggregate column in both query args and report views
			this.report_view.fields.push(['_aggregate_column', this.aggregate_on_doctype || this.doctype]);
			args.fields.push(aggregate_column + ' as _aggregate_column');

			if (aggregate_on_field) {
				args.fields.push(aggregate_on_field);
			}

			// setup columns in datatable
			this.report_view.setup_columns();

			Object.assign(args, {
				with_comment_count: false,
				group_by: this.report_view.group_by || null,
				order_by: '_aggregate_column desc'
			});
		}

	}

	get_group_by_docfield() {
		// called from build_column
		let docfield;
		if (this.aggregate_function === 'count') {
			docfield = {
				fieldtype: 'Int',
				label: __('Count'),
				parent: this.doctype,
				width: 120
			};
		} else {
			// get properties of "aggregate_on", for example Net Total
			docfield = Object.assign({}, frappe.meta.docfield_map[this.aggregate_on_doctype][this.aggregate_on]);
			if (this.aggregate_function === 'sum') {
				docfield.label = __('Sum of {0}', [docfield.label]);
			} else {
				docfield.label = __('Average of {0}', [docfield.label]);
			}
		}
		docfield.fieldname = '_aggregate_column';

		return docfield;
	}

	remove_group_by() {
		this.groupby_edit_area.hide();

		this.order_by = '';
		this.group_by = null;
		this.aggregate_function = null;
		this.aggregate_on = null;
		$(".groupby").val("");
		$(".aggregate-function").val("count");
		$(".aggregate-on").empty().val("").hide();

		// restore original fields
		if (this.original_fields) {
			this.report_view.fields = this.original_fields;
		} else {
			this.report_view.set_default_fields();
		}
		this.report_view.setup_columns();
		this.original_fields = null;
		this.report_view.refresh();
	}

	get_group_by_fields() {
		this.group_by_fields = {};
		this.all_fields = {};

		let fields = this.report_view.meta.fields.filter(f => ["Select", "Link", "Data", "Int"].includes(f.fieldtype));
		this.group_by_fields[this.doctype] = fields;
		this.all_fields[this.doctype] = this.report_view.meta.fields;

		const standard_fields_filter = df =>
			!in_list(frappe.model.no_value_type, df.fieldtype) && !df.report_hide;

		const table_fields = frappe.meta.get_table_fields(this.doctype)
			.filter(df => !df.hidden);

		table_fields.forEach(df => {
			const cdt = df.options;
			const child_table_fields = frappe.meta.get_docfields(cdt).filter(standard_fields_filter);
			this.group_by_fields[cdt] = child_table_fields;
			this.all_fields[cdt] = child_table_fields;
		});
		return this.group_by_fields;
	}

};
<|endoftext|>


<commit_before>Handlebars.registerHelper('cedar', function(options) {
  "use strict";

  var hashCode = function(string) {
    var hash = 0;
    if (string.length == 0) return hash;
    for (var i = 0; i < string.length; i++) {
      var character = string.charCodeAt(i);
      hash = ((hash << 5) - hash) + character;
      hash = hash & hash; // Convert to 32bit integer
    }
    return hash;
  };

  var unescapeHtml = function(string) {
    var MAP = {
      '&': '&',
      '<': '<',
      '>': '>',
      '"': '"',
      ''': "'",
      ''': "'"
    };

    return string.replace(/&#?\w+;/g, function(c) {
      return MAP[c];
    });
  };

  var blockHelperStyle = function() {
    if (typeof options.fn === "function") {
      return true;
    } else {
      return false;
    }
  }

  var tagName = options.hash.tagName || "span";
  if (blockHelperStyle()) {
    tagName = options.hash.tagName || "div";
  }

  options.el = document.createElement(tagName);
  options.el.id = "cedar-js-" + hashCode(options.hash.id);

  new Cedar.ContentEntry({ cedarId: options.hash.id }).retrieve().then(function(contentEntry){

    var domEl = document.getElementById(options.el.id);
    if (domEl === null) {
      domEl = options.el;
    }

    if (blockHelperStyle()) {
      var output = '';
      if (Cedar.auth.isEditMode()) {
        output += contentEntry.getEditOpen();
      }
      output += unescapeHtml(options.fn(contentEntry.toJSON()));
      if (Cedar.auth.isEditMode()) {
        output += contentEntry.getEditClose();
      }
      domEl.innerHTML = output;
    } else {
      domEl.innerHTML = contentEntry.getContent();
    }
  });

  return new Handlebars.SafeString(options.el.outerHTML);
});
<commit_msg>Don't output wrapper element unless content isn't immediately available<commit_after>Handlebars.registerHelper('cedar', function(options) {
  "use strict";

  var hashCode = function(string) {
    var hash = 0;
    if (string.length == 0) return hash;
    for (var i = 0; i < string.length; i++) {
      var character = string.charCodeAt(i);
      hash = ((hash << 5) - hash) + character;
      hash = hash & hash; // Convert to 32bit integer
    }
    return hash;
  };

  var unescapeHtml = function(string) {
    var MAP = {
      '&': '&',
      '<': '<',
      '>': '>',
      '"': '"',
      ''': "'",
      ''': "'"
    };

    return string.replace(/&#?\w+;/g, function(c) {
      return MAP[c];
    });
  };

  var blockHelperStyle = function() {
    if (typeof options.fn === "function") {
      return true;
    } else {
      return false;
    }
  }

  var tagName = options.hash.tagName || "span";
  if (blockHelperStyle()) {
    tagName = options.hash.tagName || "div";
  }

  var outputEl = document.createElement(tagName);
  outputEl.id = "cedar-js-" + hashCode(options.hash.id);

  var output = '';

  new Cedar.ContentEntry({ cedarId: options.hash.id }).retrieve().then(function(contentEntry){
    if (blockHelperStyle()) {
      if (Cedar.auth.isEditMode()) {
        output += contentEntry.getEditOpen();
      }
      output += unescapeHtml(options.fn(contentEntry.toJSON()));
      if (Cedar.auth.isEditMode()) {
        output += contentEntry.getEditClose();
      }
    } else {
      output = contentEntry.getContent();
    }

    // If rendered element exists than insert the content
    var renderedEl = document.getElementById(outputEl.id);
    if (renderedEl !== null) {
      renderedEl.innerHTML = output;
    }
  });

  return new Handlebars.SafeString(output || outputEl.outerHTML);
});
<|endoftext|>


<commit_before>import React from "react";
import markdown from "markdown-in-js";

import DefaultPage from "./DefaultPage";
import WebPlayer from "../components/WebPlayer";
import markdownOptions from "../utils/MarkdownOptions";

const inputField = `import React, { Component } from 'react'
import { render } from 'react-dom'

class Input extends Component {

  state = {value: ''}

  handleChange = (e) => {
    this.setState({value: e.target.value})
  }

  render() {
    const {value} = this.state

    return (

          Label

        <input
          id={'id'}
          type={'text'}
          value={value}
          placeholder={'Placeholder'}
          onChange={this.handleChange}
        />

        My value: {value}

    )
  }
}

render(<Input />, document.querySelector('#app'))
`;

const content = markdown(markdownOptions)`
Traditionally in web development, user input is stored in the DOM, and the data (e.g. what the user typed in the input field) is extracted from the DOM to use in the application logic. React dramatically simplifies input handling by treating input elements as stateless; an input element has a \`value\` prop and an \`onChange\` prop, and together these things give you total control over the input without ever having to touch the DOM.

# Input field

Let's look at a simple input field:

${<WebPlayer code={inputField} />}

Every time we \`render\` the \`input\`, we pass the current value from our component's \`state\`. Every time the user types in the input field, we update \`state\` to include the new value, which triggers a re-render. This essentially keeps the DOM synced up to our component \`state\` automatically. We can control the value of the input field however we'd like, while React handles the DOM operations for us behind the scenes.
`;

export default props => <DefaultPage {...props}>{content}</DefaultPage>;
<commit_msg>Add brief explanation about accessibility<commit_after>import React from "react";
import markdown from "markdown-in-js";

import DefaultPage from "./DefaultPage";
import WebPlayer from "../components/WebPlayer";
import markdownOptions from "../utils/MarkdownOptions";

const inputField = `import React, { Component } from 'react'
import { render } from 'react-dom'

class Input extends Component {

  state = {value: ''}

  handleChange = (e) => {
    this.setState({value: e.target.value})
  }

  render() {
    const {value} = this.state

    return (

          Enter value

        <input
          id={'id'}
          type={'text'}
          value={value}
          placeholder={'Placeholder'}
          onChange={this.handleChange}
        />

        My value: {value}

    )
  }
}

render(<Input />, document.querySelector('#app'))
`;

const content = markdown(markdownOptions)`
Traditionally in web development, user input is stored in the DOM, and the data (e.g. what the user typed in the input field) is extracted from the DOM to use in the application logic. React dramatically simplifies input handling by treating input elements as stateless; an input element has a \`value\` prop and an \`onChange\` prop, and together these things give you total control over the input without ever having to touch the DOM.

# Input field

Let's look at a simple input field:

${<WebPlayer code={inputField} />}

Every time we \`render\` the \`input\`, we pass the current value from our component's \`state\`. Every time the user types in the input field, we update \`state\` to include the new value, which triggers a re-render. This essentially keeps the DOM synced up to our component \`state\` automatically. We can control the value of the input field however we'd like, while React handles the DOM operations for us behind the scenes.

For accessibility, it's best to include labels for input elements. Read more about accessibility in React [here](https://facebook.github.io/react/docs/accessibility.html).
`;

export default props => <DefaultPage {...props}>{content}</DefaultPage>;
<|endoftext|>


<commit_before>/**
 * Copyright (C) 2018-2019  The Software Heritage developers
 * See the AUTHORS file at the top-level directory of this distribution
 * License: GNU Affero General Public License version 3, or any later version
 * See top-level LICENSE file for more information
 */

import {handleFetchError, csrfPost, isGitRepoUrl, removeUrlFragment} from 'utils/functions';
import {validate} from 'validate.js';

let saveRequestsTable;

function originSaveRequest(originType, originUrl,
                           acceptedCallback, pendingCallback, errorCallback) {
  let addSaveOriginRequestUrl = Urls.browse_origin_save_request(originType, originUrl);
  let headers = {
    'Accept': 'application/json',
    'Content-Type': 'application/json'
  };
  $('.swh-processing-save-request').css('display', 'block');
  csrfPost(addSaveOriginRequestUrl, headers)
    .then(handleFetchError)
    .then(response => response.json())
    .then(data => {
      $('.swh-processing-save-request').css('display', 'none');
      if (data.save_request_status === 'accepted') {
        acceptedCallback();
      } else {
        pendingCallback();
      }
    })
    .catch(response => {
      $('.swh-processing-save-request').css('display', 'none');
      if (response.status === 403) {
        errorCallback();
      }
    });
}

export function initOriginSave() {

  $(document).ready(() => {

    $.fn.dataTable.ext.errMode = 'none';

    fetch(Urls.browse_origin_save_types_list())
      .then(response => response.json())
      .then(data => {
        for (let originType of data) {
          $('#swh-input-origin-type').append(`<option value="${originType}">${originType}</option>`);
        }
      });

    saveRequestsTable = $('#swh-origin-save-requests')
      .on('error.dt', (e, settings, techNote, message) => {
        $('#swh-origin-save-request-list-error').text('An error occurred while retrieving the save requests list');
        console.log(message);
      })
      .DataTable({
        serverSide: true,
        ajax: Urls.browse_origin_save_requests_list('all'),
        searchDelay: 1000,
        columns: [
          {
            data: 'save_request_date',
            name: 'request_date',
            render: (data, type, row) => {
              if (type === 'display') {
                let date = new Date(data);
                return date.toLocaleString();
              }
              return data;
            }
          },
          {
            data: 'origin_type',
            name: 'origin_type'
          },
          {
            data: 'origin_url',
            name: 'origin_url',
            render: (data, type, row) => {
              if (type === 'display') {
                const sanitizedURL = $.fn.dataTable.render.text().display(data);
                return `<a href="${sanitizedURL}">${sanitizedURL}</a>`;
              }
              return data;
            }
          },
          {
            data: 'save_request_status',
            name: 'status'
          },
          {
            data: 'save_task_status',
            name: 'loading_task_status',
            render: (data, type, row) => {
              if (data === 'succeed') {
                let browseOriginUrl = Urls.browse_origin(row.origin_url);
                if (row.visit_date) {
                  browseOriginUrl += `visit/${row.visit_date}/`;
                }
                return `<a href="${browseOriginUrl}">${data}</a>`;
              }
              return data;
            }
          }
        ],
        scrollY: '50vh',
        scrollCollapse: true,
        order: [[0, 'desc']],
        responsive: {
          details: {
            type: 'none'
          }
        }
      });

    $('#swh-origin-save-requests-list-tab').on('shown.bs.tab', () => {
      saveRequestsTable.draw();
      window.location.hash = '#requests';
    });

    $('#swh-origin-save-request-create-tab').on('shown.bs.tab', () => {
      removeUrlFragment();
    });

    let saveRequestAcceptedAlert =
      `

        The "save code now" request has been accepted and will be processed as soon as possible.

`;

    let saveRequestPendingAlert =
      `

        The "save code now" request has been put in pending state and may be accepted for processing after manual review.

`;

    let saveRequestRejectedAlert =
      `

        The "save code now" request has been rejected because the provided origin url is blacklisted.

`;

    $('#swh-save-origin-form').submit(event => {
      event.preventDefault();
      event.stopPropagation();
      $('.alert').alert('close');
      if (event.target.checkValidity()) {
        $(event.target).removeClass('was-validated');
        let originType = $('#swh-input-origin-type').val();
        let originUrl = $('#swh-input-origin-url').val();

        originSaveRequest(originType, originUrl,
                          () => $('#swh-origin-save-request-status').html(saveRequestAcceptedAlert),
                          () => $('#swh-origin-save-request-status').html(saveRequestPendingAlert),
                          () => {
                            $('#swh-origin-save-request-status').css('color', 'red');
                            $('#swh-origin-save-request-status').html(saveRequestRejectedAlert);
                          });
      } else {
        $(event.target).addClass('was-validated');
      }
    });

    $('#swh-show-origin-save-requests-list').on('click', (event) => {
      event.preventDefault();
      $('.nav-tabs a[href="#swh-origin-save-requests-list"]').tab('show');
    });

    $('#swh-input-origin-url').on('input', function(event) {
      let originUrl = $(this).val().trim();
      $(this).val(originUrl);
      $('#swh-input-origin-type option').each(function() {
        let val = $(this).val();
        if (val && originUrl.includes(val)) {
          $(this).prop('selected', true);
        }
      });
    });

    if (window.location.hash === '#requests') {
      $('.nav-tabs a[href="#swh-origin-save-requests-list"]').tab('show');
    }

  });

}

export function validateSaveOriginUrl(input) {
  let originUrl = input.value.trim();
  let validUrl = validate({website: originUrl}, {
    website: {
      url: {
        schemes: ['http', 'https', 'svn', 'git']
      }
    }
  }) === undefined;
  let originType = $('#swh-input-origin-type').val();
  if (originType === 'git' && validUrl) {
    // additional checks for well known code hosting providers
    let githubIdx = originUrl.indexOf('://github.com');
    let gitlabIdx = originUrl.indexOf('://gitlab.');
    let gitSfIdx = originUrl.indexOf('://git.code.sf.net');
    let bitbucketIdx = originUrl.indexOf('://bitbucket.org');
    if (githubIdx !== -1 && githubIdx <= 5) {
      validUrl = isGitRepoUrl(originUrl, 'github.com');
    } else if (gitlabIdx !== -1 && gitlabIdx <= 5) {
      let startIdx = gitlabIdx + 3;
      let idx = originUrl.indexOf('/', startIdx);
      if (idx !== -1) {
        let gitlabDomain = originUrl.substr(startIdx, idx - startIdx);
        // GitLab repo url needs to be suffixed by '.git' in order to be successfully loaded
        // This is due to a bug in dulwich < 0.19.11.
        // TODO: remove this check once dulwich >= 0.19.11 is used in production
        validUrl = isGitRepoUrl(originUrl, gitlabDomain) && originUrl.endsWith('.git');
      } else {
        validUrl = false;
      }
    } else if (gitSfIdx !== -1 && gitSfIdx <= 5) {
      validUrl = isGitRepoUrl(originUrl, 'git.code.sf.net/p');
    } else if (bitbucketIdx !== -1 && bitbucketIdx <= 5) {
      validUrl = isGitRepoUrl(originUrl, 'bitbucket.org');
    }
  }
  if (validUrl) {
    input.setCustomValidity('');
  } else {
    input.setCustomValidity('The origin url is not valid or does not reference a code repository');
  }
}

export function initTakeNewSnapshot() {

  let newSnapshotRequestAcceptedAlert =
    `

      The "take new snapshot" request has been accepted and will be processed as soon as possible.

`;

  let newSnapshotRequestPendingAlert =
    `

      The "take new snapshot" request has been put in pending state and may be accepted for processing after manual review.

`;

  let newSnapshotRequestRejectedAlert =
    `

      The "take new snapshot" request has been rejected.

`;

  $(document).ready(() => {
    $('#swh-take-new-snapshot-form').submit(event => {
      event.preventDefault();
      event.stopPropagation();

      let originType = $('#swh-input-origin-type').val();
      let originUrl = $('#swh-input-origin-url').val();

      originSaveRequest(originType, originUrl,
                        () => $('#swh-take-new-snapshot-request-status').html(newSnapshotRequestAcceptedAlert),
                        () => $('#swh-take-new-snapshot-request-status').html(newSnapshotRequestPendingAlert),
                        () => {
                          $('#swh-take-new-snapshot-request-status').css('color', 'red');
                          $('#swh-take-new-snapshot-request-status').html(newSnapshotRequestRejectedAlert);
                        });
    });
  });
}
<commit_msg>assets/browse/origin-save: Robustify save code now request status reporting<commit_after>/**
 * Copyright (C) 2018-2019  The Software Heritage developers
 * See the AUTHORS file at the top-level directory of this distribution
 * License: GNU Affero General Public License version 3, or any later version
 * See top-level LICENSE file for more information
 */

import {handleFetchError, csrfPost, isGitRepoUrl, removeUrlFragment} from 'utils/functions';
import {validate} from 'validate.js';

let saveRequestsTable;

function originSaveRequest(originType, originUrl,
                           acceptedCallback, pendingCallback, errorCallback) {
  let addSaveOriginRequestUrl = Urls.browse_origin_save_request(originType, originUrl);
  let headers = {
    'Accept': 'application/json',
    'Content-Type': 'application/json'
  };
  $('.swh-processing-save-request').css('display', 'block');
  csrfPost(addSaveOriginRequestUrl, headers)
    .then(handleFetchError)
    .then(response => response.json())
    .then(data => {
      $('.swh-processing-save-request').css('display', 'none');
      if (data.save_request_status === 'accepted') {
        acceptedCallback();
      } else {
        pendingCallback();
      }
    })
    .catch(response => {
      $('.swh-processing-save-request').css('display', 'none');
      errorCallback(response.status);
    });
}

function htmlAlert(type, message) {
  return `<div class="alert alert-${type}" role="alert">${message}</div>`;
}

export function initOriginSave() {

  $(document).ready(() => {

    $.fn.dataTable.ext.errMode = 'none';

    fetch(Urls.browse_origin_save_types_list())
      .then(response => response.json())
      .then(data => {
        for (let originType of data) {
          $('#swh-input-origin-type').append(`<option value="${originType}">${originType}</option>`);
        }
      });

    saveRequestsTable = $('#swh-origin-save-requests')
      .on('error.dt', (e, settings, techNote, message) => {
        $('#swh-origin-save-request-list-error').text('An error occurred while retrieving the save requests list');
        console.log(message);
      })
      .DataTable({
        serverSide: true,
        ajax: Urls.browse_origin_save_requests_list('all'),
        searchDelay: 1000,
        columns: [
          {
            data: 'save_request_date',
            name: 'request_date',
            render: (data, type, row) => {
              if (type === 'display') {
                let date = new Date(data);
                return date.toLocaleString();
              }
              return data;
            }
          },
          {
            data: 'origin_type',
            name: 'origin_type'
          },
          {
            data: 'origin_url',
            name: 'origin_url',
            render: (data, type, row) => {
              if (type === 'display') {
                const sanitizedURL = $.fn.dataTable.render.text().display(data);
                return `<a href="${sanitizedURL}">${sanitizedURL}</a>`;
              }
              return data;
            }
          },
          {
            data: 'save_request_status',
            name: 'status'
          },
          {
            data: 'save_task_status',
            name: 'loading_task_status',
            render: (data, type, row) => {
              if (data === 'succeed') {
                let browseOriginUrl = Urls.browse_origin(row.origin_url);
                if (row.visit_date) {
                  browseOriginUrl += `visit/${row.visit_date}/`;
                }
                return `<a href="${browseOriginUrl}">${data}</a>`;
              }
              return data;
            }
          }
        ],
        scrollY: '50vh',
        scrollCollapse: true,
        order: [[0, 'desc']],
        responsive: {
          details: {
            type: 'none'
          }
        }
      });

    $('#swh-origin-save-requests-list-tab').on('shown.bs.tab', () => {
      saveRequestsTable.draw();
      window.location.hash = '#requests';
    });

    $('#swh-origin-save-request-create-tab').on('shown.bs.tab', () => {
      removeUrlFragment();
    });

    let saveRequestAcceptedAlert = htmlAlert(
      'success',
      'The "save code now" request has been accepted and will be processed as soon as possible.'
    );

    let saveRequestPendingAlert = htmlAlert(
      'warning',
      'The "save code now" request has been put in pending state and may be accepted for processing after manual review.'
    );

    let saveRequestRejectedAlert = htmlAlert(
      'danger',
      'The "save code now" request has been rejected because the provided origin url is blacklisted.'
    );

    let saveRequestRateLimitedAlert = htmlAlert(
      'danger',
      'The rate limit for "save code now" requests has been reached. Please try again later.'
    );

    let saveRequestUnknownErrorAlert = htmlAlert(
      'danger',
      'An unexpected error happened when submitting the "save code now request'
    );

    $('#swh-save-origin-form').submit(event => {
      event.preventDefault();
      event.stopPropagation();
      $('.alert').alert('close');
      if (event.target.checkValidity()) {
        $(event.target).removeClass('was-validated');
        let originType = $('#swh-input-origin-type').val();
        let originUrl = $('#swh-input-origin-url').val();

        originSaveRequest(originType, originUrl,
                          () => $('#swh-origin-save-request-status').html(saveRequestAcceptedAlert),
                          () => $('#swh-origin-save-request-status').html(saveRequestPendingAlert),
                          (statusCode) => {
                            $('#swh-origin-save-request-status').css('color', 'red');
                            if (statusCode === 403) {
                              $('#swh-origin-save-request-status').html(saveRequestRejectedAlert);
                            } else if (statusCode === 429) {
                              $('#swh-origin-save-request-status').html(saveRequestRateLimitedAlert);
                            } else {
                              $('#swh-origin-save-request-status').html(saveRequestUnknownErrorAlert);
                            }
                          });
      } else {
        $(event.target).addClass('was-validated');
      }
    });

    $('#swh-show-origin-save-requests-list').on('click', (event) => {
      event.preventDefault();
      $('.nav-tabs a[href="#swh-origin-save-requests-list"]').tab('show');
    });

    $('#swh-input-origin-url').on('input', function(event) {
      let originUrl = $(this).val().trim();
      $(this).val(originUrl);
      $('#swh-input-origin-type option').each(function() {
        let val = $(this).val();
        if (val && originUrl.includes(val)) {
          $(this).prop('selected', true);
        }
      });
    });

    if (window.location.hash === '#requests') {
      $('.nav-tabs a[href="#swh-origin-save-requests-list"]').tab('show');
    }

  });

}

export function validateSaveOriginUrl(input) {
  let originUrl = input.value.trim();
  let validUrl = validate({website: originUrl}, {
    website: {
      url: {
        schemes: ['http', 'https', 'svn', 'git']
      }
    }
  }) === undefined;
  let originType = $('#swh-input-origin-type').val();
  if (originType === 'git' && validUrl) {
    // additional checks for well known code hosting providers
    let githubIdx = originUrl.indexOf('://github.com');
    let gitlabIdx = originUrl.indexOf('://gitlab.');
    let gitSfIdx = originUrl.indexOf('://git.code.sf.net');
    let bitbucketIdx = originUrl.indexOf('://bitbucket.org');
    if (githubIdx !== -1 && githubIdx <= 5) {
      validUrl = isGitRepoUrl(originUrl, 'github.com');
    } else if (gitlabIdx !== -1 && gitlabIdx <= 5) {
      let startIdx = gitlabIdx + 3;
      let idx = originUrl.indexOf('/', startIdx);
      if (idx !== -1) {
        let gitlabDomain = originUrl.substr(startIdx, idx - startIdx);
        // GitLab repo url needs to be suffixed by '.git' in order to be successfully loaded
        // This is due to a bug in dulwich < 0.19.11.
        // TODO: remove this check once dulwich >= 0.19.11 is used in production
        validUrl = isGitRepoUrl(originUrl, gitlabDomain) && originUrl.endsWith('.git');
      } else {
        validUrl = false;
      }
    } else if (gitSfIdx !== -1 && gitSfIdx <= 5) {
      validUrl = isGitRepoUrl(originUrl, 'git.code.sf.net/p');
    } else if (bitbucketIdx !== -1 && bitbucketIdx <= 5) {
      validUrl = isGitRepoUrl(originUrl, 'bitbucket.org');
    }
  }
  if (validUrl) {
    input.setCustomValidity('');
  } else {
    input.setCustomValidity('The origin url is not valid or does not reference a code repository');
  }
}

export function initTakeNewSnapshot() {

  let newSnapshotRequestAcceptedAlert = htmlAlert(
    'success',
    'The "take new snapshot" request has been accepted and will be processed as soon as possible.'
  );

  let newSnapshotRequestPendingAlert = htmlAlert(
    'warning',
    'The "take new snapshot" request has been put in pending state and may be accepted for processing after manual review.'
  );

  let newSnapshotRequestRejectedAlert = htmlAlert(
    'danger',
    'The "take new snapshot" request has been rejected.'
  );

  let newSnapshotRequestRateLimitAlert = htmlAlert(
    'danger',
    'The rate limit for "take new snapshot" requests has been reached. Please try again later.'
  );

  let newSnapshotRequestUnknownErrorAlert = htmlAlert(
    'danger',
    'An unexpected error happened when submitting the "save code now request".'
  );

  $(document).ready(() => {
    $('#swh-take-new-snapshot-form').submit(event => {
      event.preventDefault();
      event.stopPropagation();

      let originType = $('#swh-input-origin-type').val();
      let originUrl = $('#swh-input-origin-url').val();

      originSaveRequest(originType, originUrl,
                        () => $('#swh-take-new-snapshot-request-status').html(newSnapshotRequestAcceptedAlert),
                        () => $('#swh-take-new-snapshot-request-status').html(newSnapshotRequestPendingAlert),
                        (statusCode) => {
                          $('#swh-take-new-snapshot-request-status').css('color', 'red');
                          if (statusCode === 403) {
                            $('#swh-take-new-snapshot-request-status').html(newSnapshotRequestRejectedAlert);
                          } else if (statusCode === 429) {
                            $('#swh-take-new-snapshot-request-status').html(newSnapshotRequestRateLimitAlert);
                          } else {
                            $('#swh-take-new-snapshot-request-status').html(newSnapshotRequestUnknownErrorAlert);
                          }
                        });
    });
  });
}
<|endoftext|>


<commit_before>define(
  'ephox.mcagar.api.Ui',

  [
    'ephox.agar.api.Assertions',
    'ephox.agar.api.Chain',
    'ephox.agar.api.NamedChain',
    'ephox.agar.api.Mouse',
    'ephox.agar.api.UiFinder',
    'ephox.katamari.api.Fun',
    'ephox.katamari.api.Arr',
    'ephox.katamari.api.Merger',
    'ephox.katamari.api.Result',
    'ephox.sugar.api.node.Element',
    'ephox.sugar.api.view.Visibility',
    'global!document'
  ],

  function (Assertions, Chain, NamedChain, Mouse, UiFinder, Fun, Arr, Merger, Result, Element, Visibility, document) {

    var dialogRoot = Element.fromDom(document.body);

    var cToolstripRoot = Chain.mapper(function (editor) {
      return Element.fromDom(editor.getContainer());
    });

    var cEditorRoot = Chain.mapper(function (editor) {
      return Element.fromDom(editor.getBody());
    });

    var cDialogRoot = Chain.inject(dialogRoot);

    var cGetToolbarRoot = Chain.fromChains([
      cToolstripRoot,
      UiFinder.cFindIn('.mce-toolbar-grp')
    ]);

    var cGetMenuRoot = Chain.fromChains([
      cToolstripRoot,
      UiFinder.cFindIn('.mce-menubar')
    ]);

    var cFindIn = function (cRoot, selector) {
      return Chain.fromChains([
        cRoot,
        UiFinder.cFindIn(selector)
      ]);
    };

    var cClickOnToolbar = function (label, selector) {
      return Chain.fromParent(Chain.identity, [
        Chain.fromChains([
          cGetToolbarRoot,
          UiFinder.cFindIn(selector),
          Mouse.cClick
        ])
      ]);
    };

    var cClickOnMenu = function (label, selector) {
      return Chain.fromParent(Chain.identity, [
        Chain.fromChains([
          cGetMenuRoot,
          UiFinder.cFindIn(selector),
          Mouse.cClick
        ])
      ]);
    };

    var cClickOnUi = function (label, selector) {
      return Chain.fromParent(Chain.identity, [
        Chain.fromChains([
          cDialogRoot,
          UiFinder.cFindIn(selector),
          Mouse.cClick
        ])
      ]);
    };

    var sWaitForUi = function (label, selector) {
      return Chain.asStep({}, [
        cWaitForUi(label, selector)
      ]);
    };

    var sWaitForPopup = function (label, selector) {
      return Chain.asStep({}, [
        cWaitForPopup(label, selector)
      ]);
    };

    var cWaitForState = function (hasState) {
      return function (label, selector) {
        return Chain.fromChains([
          cDialogRoot,
          UiFinder.cWaitForState(label, selector, hasState)
        ]);
      };
    };

    var cWaitForPopup = function (label, selector) {
      return cWaitForState(Visibility.isVisible)(label, selector);
    };

    var cWaitForUi = function (label, selector) {
      return cWaitForState(Fun.constant(true))(label, selector);
    };

    var cTriggerContextMenu = function (label, target, menu) {
      return Chain.fromChains([
        cEditorRoot,
        UiFinder.cFindIn(target),
        Mouse.cContextMenu,

        // Ignores input
        cWaitForPopup(label, menu)
      ]);
    };

    var cDialogByPopup = Chain.binder(function (input) {
      var wins = input.editor.windowManager.getWindows();
      var popupId = input.popupNode.dom().id;
      var dialogs =  Arr.filter(wins, function (dialog) {
        return popupId === dialog._id;
      });
      return dialogs.length ? Result.value(dialogs[0]) : Result.error("dialog with id of: " + popupId + " was not found");
    });

    var cWaitForDialog = function (selector) {
      return NamedChain.asChain([
        NamedChain.write('editor', Chain.identity),
        NamedChain.write('popupNode', cWaitForPopup('waiting for popup: ' + selector, selector)),
        NamedChain.merge(['editor', 'popupNode'], 'dialogInputs'),
        NamedChain.direct('dialogInputs', cDialogByPopup, 'dialog'),
        NamedChain.bundle(function (input) {
          return Result.value(input.dialog);
        })
      ]);
    };

    var cAssertDialogContents = function (selector, data) {
      return Chain.fromParent(Chain.identity, [
        Chain.fromChains([
          cWaitForDialog(selector),
          Chain.op(function (dialog) {
            Assertions.assertEq('asserting contents of: ' + selector, data, dialog.toJSON());
          })
        ])
      ]);
    };

    var cAssertActiveDialogContents = function (data) {
      return cAssertDialogContents('[role="dialog"]', data);
    };

    var cFillDialog = function (selector, data) {
      return Chain.fromParent(Chain.identity, [
        Chain.fromChains([
          cWaitForDialog(selector),
          Chain.op(function (dialog) {
            dialog.fromJSON(Merger.merge(dialog.toJSON(), data));
          })
        ])
      ]);
    };

    var cFillActiveDialog = function (data) {
      return cFillDialog('[role="dialog"]', data);
    };

    var cClickPopupButton = function (btnSelector, selector) {
      popupSelector = selector || '[role="dialog"]';
      return  Chain.fromParent(Chain.identity, [
        Chain.fromChains([
          cWaitForPopup('waiting for: ' + popupSelector, popupSelector),
          UiFinder.cFindIn(btnSelector),
          Mouse.cClick
        ])
      ]);
    };

    var cCloseDialog = function (selector) {
      return cClickPopupButton('div[role="button"]:contains(Cancel)', selector);
    };

    var cSubmitDialog = function (selector) {
      return cClickPopupButton('div[role="button"].mce-primary', selector);
    };

    return {
      cClickOnToolbar: cClickOnToolbar,
      cClickOnMenu: cClickOnMenu,
      cClickOnUi: cClickOnUi,

      // Popups need to be visible.
      cWaitForPopup: cWaitForPopup,
      // UI does not need to be visible
      cWaitForUi: cWaitForUi,
      // General state predicate
      cWaitForState: cWaitForState,

      cFillDialog: cFillDialog,
      cFillActiveDialog: cFillActiveDialog,
      cCloseDialog: cCloseDialog,
      cSubmitDialog: cSubmitDialog,
      cAssertDialogContents: cAssertDialogContents,
      cAssertActiveDialogContents: cAssertActiveDialogContents,

      cTriggerContextMenu: cTriggerContextMenu,

      sWaitForUi: sWaitForUi,
      sWaitForPopup: sWaitForPopup
    };
  }
);<commit_msg>TINY-1376: use NamedChain where applicable<commit_after>define(
  'ephox.mcagar.api.Ui',

  [
    'ephox.agar.api.Assertions',
    'ephox.agar.api.Chain',
    'ephox.agar.api.NamedChain',
    'ephox.agar.api.Mouse',
    'ephox.agar.api.UiFinder',
    'ephox.katamari.api.Fun',
    'ephox.katamari.api.Arr',
    'ephox.katamari.api.Merger',
    'ephox.katamari.api.Result',
    'ephox.sugar.api.node.Element',
    'ephox.sugar.api.view.Visibility',
    'global!document'
  ],

  function (Assertions, Chain, NamedChain, Mouse, UiFinder, Fun, Arr, Merger, Result, Element, Visibility, document) {

    var dialogRoot = Element.fromDom(document.body);

    var cToolstripRoot = Chain.mapper(function (editor) {
      return Element.fromDom(editor.getContainer());
    });

    var cEditorRoot = Chain.mapper(function (editor) {
      return Element.fromDom(editor.getBody());
    });

    var cDialogRoot = Chain.inject(dialogRoot);

    var cGetToolbarRoot = Chain.fromChains([
      cToolstripRoot,
      UiFinder.cFindIn('.mce-toolbar-grp')
    ]);

    var cGetMenuRoot = Chain.fromChains([
      cToolstripRoot,
      UiFinder.cFindIn('.mce-menubar')
    ]);

    var cFindIn = function (cRoot, selector) {
      return Chain.fromChains([
        cRoot,
        UiFinder.cFindIn(selector)
      ]);
    };

    var cClickOnWithin = function (label, selector, cContext) {
       return NamedChain.asChain([
         NamedChain.direct(NamedChain.inputName(), cContext, 'context'),
         NamedChain.direct('context', UiFinder.cFindIn(selector), 'ui'),
         NamedChain.direct('ui', Mouse.cClick, '_'),
         NamedChain.output(NamedChain.inputName())
       ]);
     };

    var cClickOnUi = function (label, selector) {
     return cClickOnWithin(label, selector, cDialogRoot);
    };

    var cClickOnToolbar = function (label, selector) {
      return cClickOnWithin(label, selector, cGetToolbarRoot);
    };

    var cClickOnMenu = function (label, selector) {
      return cClickOnWithin(label, selector, cGetMenuRoot);
    };

    var sWaitForUi = function (label, selector) {
      return Chain.asStep({}, [
        cWaitForUi(label, selector)
      ]);
    };

    var sWaitForPopup = function (label, selector) {
      return Chain.asStep({}, [
        cWaitForPopup(label, selector)
      ]);
    };

    var cWaitForState = function (hasState) {
      return function (label, selector) {
        return Chain.fromChains([
          cDialogRoot,
          UiFinder.cWaitForState(label, selector, hasState)
        ]);
      };
    };

    var cWaitForPopup = function (label, selector) {
      return cWaitForState(Visibility.isVisible)(label, selector);
    };

    var cWaitForUi = function (label, selector) {
      return cWaitForState(Fun.constant(true))(label, selector);
    };

    var cTriggerContextMenu = function (label, target, menu) {
      return Chain.fromChains([
        cEditorRoot,
        UiFinder.cFindIn(target),
        Mouse.cContextMenu,

        // Ignores input
        cWaitForPopup(label, menu)
      ]);
    };

    var cDialogByPopup = Chain.binder(function (input) {
      var wins = input.editor.windowManager.getWindows();
      var popupId = input.popupNode.dom().id;
      var dialogs =  Arr.filter(wins, function (dialog) {
        return popupId === dialog._id;
      });
      return dialogs.length ? Result.value(dialogs[0]) : Result.error("dialog with id of: " + popupId + " was not found");
    });

    var cWaitForDialog = function (selector) {
      return NamedChain.asChain([
        NamedChain.direct(NamedChain.inputName(), Chain.identity, 'editor'),
        NamedChain.write('popupNode', cWaitForPopup('waiting for popup: ' + selector, selector)),
        NamedChain.merge(['editor', 'popupNode'], 'dialogInputs'),
        NamedChain.direct('dialogInputs', cDialogByPopup, 'dialog'),
        NamedChain.output('dialog')
      ]);
    };

    var cAssertDialogContents = function (selector, data) {
      return NamedChain.asChain([
        NamedChain.direct(NamedChain.inputName(), cWaitForDialog(selector), 'dialog'),
        NamedChain.direct('dialog', Chain.op(function (dialog) {
          Assertions.assertEq('asserting contents of: ' + selector, data, dialog.toJSON());
        }), '_'),
        NamedChain.output(NamedChain.inputName())
      ]);
    };

    var cAssertActiveDialogContents = function (data) {
      return cAssertDialogContents('[role="dialog"]', data);
    };

    var cFillDialog = function (selector, data) {
      return NamedChain.asChain([
        NamedChain.direct(NamedChain.inputName(), cWaitForDialog(selector), 'dialog'),
        NamedChain.direct('dialog', Chain.op(function (dialog) {
          dialog.fromJSON(Merger.merge(dialog.toJSON(), data));
        }), '_'),
        NamedChain.output(NamedChain.inputName())
      ]);
    };

    var cFillActiveDialog = function (data) {
      return cFillDialog('[role="dialog"]', data);
    };

    var cClickPopupButton = function (btnSelector, selector) {
      popupSelector = selector || '[role="dialog"]';

      return NamedChain.asChain([
        NamedChain.direct(NamedChain.inputName(), cWaitForPopup('waiting for: ' + popupSelector, popupSelector), 'popup'),
        NamedChain.direct('popup', UiFinder.cFindIn(btnSelector), 'button'),
        NamedChain.direct('button', Mouse.cClick, '_'),
        NamedChain.output(NamedChain.inputName())
      ]);
    };

    var cCloseDialog = function (selector) {
      return cClickPopupButton('div[role="button"]:contains(Cancel)', selector);
    };

    var cSubmitDialog = function (selector) {
      return cClickPopupButton('div[role="button"].mce-primary', selector);
    };

    return {
      cClickOnToolbar: cClickOnToolbar,
      cClickOnMenu: cClickOnMenu,
      cClickOnUi: cClickOnUi,

      // Popups need to be visible.
      cWaitForPopup: cWaitForPopup,
      // UI does not need to be visible
      cWaitForUi: cWaitForUi,
      // General state predicate
      cWaitForState: cWaitForState,

      cFillDialog: cFillDialog,
      cFillActiveDialog: cFillActiveDialog,
      cCloseDialog: cCloseDialog,
      cSubmitDialog: cSubmitDialog,
      cAssertDialogContents: cAssertDialogContents,
      cAssertActiveDialogContents: cAssertActiveDialogContents,

      cTriggerContextMenu: cTriggerContextMenu,

      sWaitForUi: sWaitForUi,
      sWaitForPopup: sWaitForPopup
    };
  }
);<|endoftext|>