<commit_before>var defaultSettings;

function showControls(pivotTableID,id)
{
   //saving default config
    //checking if default settings are not saved
       defaultSettings=saveCurrentConfig(pivotTableID);

	var hiddenControls=new Array(".pvtVals",".pvtAxisContainer",".pvtUnused",".pvtRenderer",".pvtAxisContainer");

    for(i=0;i<hiddenControls.length;i++)
	  $(pivotTableID+' '+hiddenControls[i]).fadeIn('slow');

	//display restore and save button
	$(pivotTableID+"_opControls").fadeIn();
	//hide edit button
	$("#pivotControls_"+id).fadeOut();

}

function createEditBtn(pivotTableID){

		var pivotTable="#output_"+pivotTableID;
		var edit_btn_div="#pivotControls_"+pivotTableID;
		var edit_btn="#pivotEditBtn_"+pivotTableID;

		$("#container_"+pivotTableID).hover(function () {
		  if(!$(pivotTable+"_opControls").is(":visible"))
		  {
			var bleft = Math.round($(pivotTable+" .pvtUi").width()-$(edit_btn_div).width()+10);
			var btop = Math.round($(pivotTable).offset().top - $(pivotTable).offsetParent().offset().top + $(pivotTable+" .pvtUi").height()-20);

            //checking if not in edit mode then show edit button

               $(edit_btn_div).css({top: btop, left: bleft, position:'absolute'});
			   $(edit_btn_div).show();
		 } }, function(){ //mouseleave
               $(edit_btn_div).hide();

		});

}

//function to save current configuration for restore button

function saveCurrentConfig(pivotTableID){

                var config = $(pivotTableID).data("pivotUIOptions");
                var config_copy = JSON.parse(JSON.stringify(config));
				 delete config_copy["aggregators"];
                    delete config_copy["renderers"];
                    //delete some bulky default values
                    delete config_copy["rendererOptions"];
                    delete config_copy["localeStrings"];
				return JSON.stringify(config_copy, undefined, 2);

	}

function saveConfig(pivotTableID,page,index,tracker,fieldsArr){
	            var config = $(pivotTableID).data("pivotUIOptions");
                var config_copy = JSON.parse(JSON.stringify(config));
				;
				//formatting data
				var rows=(config_copy['rows']).toString().split(',');
				var cols=(config_copy['cols']).toString().split(',');
				var vals=(config_copy['vals']).toString().split(',');

				var rowsStr='';
				var colsStr='';
				var valsStr='';
				//mapping data from title to param name
		        for(var i=0;i<fieldsArr.length;i+=2)
				{

					for(var j=0;j<rows.length;j++)
				     {

					 if(rows[j]==fieldsArr[i])
				       rowsStr+=fieldsArr[i+1]+":";
					 }
					for(var j=0;j<cols.length;j++)
				     { if(cols[j]==fieldsArr[i])
					   colsStr+=fieldsArr[i+1]+":";
					 }

					 for(var j=0;j<vals.length;j++)
				     { if(vals[j]==fieldsArr[i])
					   valsStr+=fieldsArr[i+1]+":";
					 }
				}

				var argsStr='{"data":"tracker:'+tracker+'","rows":"'+rowsStr+'","cols":"'+colsStr+'","vals":"'+valsStr+'","rendererName":"'+config_copy["rendererName"]+'","aggregatorName":"'+config_copy["aggregatorName"]+'"}';
                var paramsArr=JSON.parse(argsStr);
				ajaxLoadingShow("output_pivottable"+index);

				//calling ajax edit plugin function
				$.ajax({
						type: 'POST',
						url: 'tiki-wikiplugin_edit.php',
						dataType: 'json',
						data: {
			              page: page,
						  message:"Modified by Pivot Table Plugin",
				          type: 'pivottable',
						  content:'',
				          index:index,
						  args:argsStr,
						  params:paramsArr

		                  },
					complete: function(){
						location.reload();
						}
				      });

	}	<commit_msg>[Fix]Preserve order of rows and columns order while edit/saving through PivotUI(). Moved "Edit Pivot Table" button down, so it dont overlap data. <commit_after>var defaultSettings;

function showControls(pivotTableID,id)
{
   //saving default config
    //checking if default settings are not saved
       defaultSettings=saveCurrentConfig(pivotTableID);

	var hiddenControls=new Array(".pvtVals",".pvtAxisContainer",".pvtUnused",".pvtRenderer",".pvtAxisContainer");

    for(i=0;i<hiddenControls.length;i++)
	  $(pivotTableID+' '+hiddenControls[i]).fadeIn('slow');

	//display restore and save button
	$(pivotTableID+"_opControls").fadeIn();
	//hide edit button
	$("#pivotControls_"+id).fadeOut();

}

function createEditBtn(pivotTableID){

		var pivotTable="#output_"+pivotTableID;
		var edit_btn_div="#pivotControls_"+pivotTableID;
		var edit_btn="#pivotEditBtn_"+pivotTableID;

		$("#container_"+pivotTableID).hover(function () {
		  if(!$(pivotTable+"_opControls").is(":visible"))
		  {
			var bleft = Math.round($(pivotTable+" .pvtUi").width()-$(edit_btn_div).width()+10);
			var btop = Math.round($(pivotTable).offset().top - $(pivotTable).offsetParent().offset().top + $(pivotTable+" .pvtUi").height()-5);

            //checking if not in edit mode then show edit button
			    $(edit_btn_div).css({top: btop, left: bleft, position:'absolute'});
			   $(edit_btn_div).show();
		 } }, function(){ //mouseleave
		       $(edit_btn_div).hide();

		});

}

//function to save current configuration for restore button

function saveCurrentConfig(pivotTableID){

                var config = $(pivotTableID).data("pivotUIOptions");
                var config_copy = JSON.parse(JSON.stringify(config));
				 delete config_copy["aggregators"];
                    delete config_copy["renderers"];
                    //delete some bulky default values
                    delete config_copy["rendererOptions"];
                    delete config_copy["localeStrings"];
				return JSON.stringify(config_copy, undefined, 2);

	}

    function saveConfig(pivotTableID,page,index,tracker,fieldsArr){
	            var config = $(pivotTableID).data("pivotUIOptions");
                var config_copy = JSON.parse(JSON.stringify(config));
				;
				//formatting data
				var rows=(config_copy['rows']).toString().split(',');
				var cols=(config_copy['cols']).toString().split(',');
				var vals=(config_copy['vals']).toString().split(',');

				var rowsStr='';
				var colsStr='';
				var valsStr='';
				//mapping data from title to param name

				//mapping for rows
				for(var j=0;j<rows.length;j++)
				{
				  for(var i=0;i<fieldsArr.length;i+=2)
				  {

					 if(rows[j]==fieldsArr[i])
				       rowsStr+=fieldsArr[i+1]+":";
				  }
				}
				//mapping for cols
				for(var j=0;j<cols.length;j++)
				{
				   for(var i=0;i<fieldsArr.length;i+=2)
				   {
				     if(cols[j]==fieldsArr[i])
					   colsStr+=fieldsArr[i+1]+":";
				   }
				}

				//mapping for vals
				for(var j=0;j<vals.length;j++)
				{
				   for(var i=0;i<fieldsArr.length;i+=2)
				   {
				     if(vals[j]==fieldsArr[i])
					   valsStr+=fieldsArr[i+1]+":";
				   }
				}

				//formatting argument string
				var argsStr='{"data":"tracker:'+tracker+'","rows":"'+rowsStr+'","cols":"'+colsStr+'","vals":"'+valsStr+'","rendererName":"'+config_copy["rendererName"]+'","aggregatorName":"'+config_copy["aggregatorName"]+'"}';
                var paramsArr=JSON.parse(argsStr);
				ajaxLoadingShow("output_pivottable"+index);

				//calling ajax edit plugin function
				 $.ajax({
						type: 'POST',
						url: 'tiki-wikiplugin_edit.php',
						dataType: 'json',
						data: {
			              page: page,
						  message:"Modified by Pivot Table Plugin",
				          type: 'pivottable',
						  content:'',
				          index:index,
						  args:argsStr,
						  params:paramsArr

		                  },
					complete: function(){
						location.reload();
						}
				      });
   }	<|endoftext|>


<commit_before>/**
 * Redirects naked(root domain) requests to www or its reverse.
 *
 * @author GONZO <oss@dp.farm>
 */

var subdomainParser = function() {
    const parseDomain = require('parse-domain');
    const parsedDomain = {};

    return {
        get: function(hostname) {
            // Cache, Touch
            if (parsedDomain[hostname] == undefined) {
                try {
                    var parsed = parseDomain(hostname);

                    parsedDomain[hostname] = [
                        parsed.subdomain,
                        parsed.domain + '.' + parsed.tld
                    ];
                }
                catch (e) {
                    parsedDomain[hostname] = [null, null];
                }
            }

            return parsedDomain[hostname];
        }
    }
}();

module.exports = function(reverse, subdomain) {
    return function(req, res, next) {
        var domain = subdomainParser.get(req.hostname);

        if (domain[0] == '' && !reverse) {
            subdomain = subdomain || 'www';
            res.redirect(req.protocol + '://' + subdomain + '.' + domain[1] + req.url);
            return;
        }
        else if (domain[0] == 'www' && reverse) {
            res.redirect(req.protocol + '://' + domain[1] + req.url);
            return;
        }

        return next();
    }
};
<commit_msg>provide default submain as www.<commit_after>/**
 * Redirects naked(root domain) requests to www or its reverse.
 *
 * @author GONZO <oss@dp.farm>
 */

var subdomainParser = function() {
    const parseDomain = require('parse-domain');
    const parsedDomain = {};

    return {
        get: function(hostname) {
            // Cache, Touch
            if (parsedDomain[hostname] == undefined) {
                try {
                    var parsed = parseDomain(hostname);

                    parsedDomain[hostname] = [
                        parsed.subdomain,
                        parsed.domain + '.' + parsed.tld
                    ];
                }
                catch (e) {
                    parsedDomain[hostname] = [null, null];
                }
            }

            return parsedDomain[hostname];
        }
    }
}();

module.exports = function(reverse, subdomain) {
    return function(req, res, next) {
        var domain = subdomainParser.get(req.hostname);
        subdomain = subdomain || 'www';

        if (domain[0] == '' && !reverse) {
            res.redirect(req.protocol + '://' + subdomain + '.' + domain[1] + req.url);
            return;
        }
        else if (domain[0] == subdomain && reverse) {
            res.redirect(req.protocol + '://' + domain[1] + req.url);
            return;
        }

        return next();
    }
};
<|endoftext|>


<commit_before>var Immutable = require('immutable');

var ContentFinder = require('../ContentFinder');
var RangeSet = require('../RangeSet');

class ToggleMarkup {
  constructor(map) {
    this.map = map;
  }

  execute(guids, offsets, options) {
    var type  = options.type;
    var value = options.value;

    var range = this._finder().findRange(guids, offsets);
    var paths = range.map( (guid) => {
      return this._finder().findPath(guid);
    });

    if (paths.length === 1) {
      this._toggleSingleBlockMarkup(paths, offsets, type, value);
    } else {
      this._toggleMultiBlockMarkup(paths, offsets, type, value);
    }

    return { content: this.map };
  }

  /**
   * Just toggle markup on/off
   */
  _toggleSingleBlockMarkup(paths, offsets, type, value) {
    var hasMarkup = this._hasMarkup(paths[0], offsets, type, value);
    var remove = hasMarkup || value === '';
    this._toggleBlockMarkup(remove, paths[0], offsets, type, value);
  }

  /**
   * multi block requires 'all' text to be selected to remove. So if your
   * selection is partially bolded, it will add bold to the whole selection
   *
   * however if we have a value, we require 'any'. So if you have selected
   * text that is partially linked, it will remove links fro the selection
   */
  _toggleMultiBlockMarkup(paths, offsets, type, value) {
    // check if everything is selected
    var withMarkup = paths.filter( (path, i) => {
      var block = this.map.getIn(path);

      if (i === 0) {
        return this._hasMarkup(
          path, { anchor: offsets.anchor, focus: block.get('text').length }, type, value
        );
      } else if (i === paths.length - 1) {
        return this._hasMarkup(
          path, { anchor: 0, focus: offsets.focus }, type, value
        );
      } else {
        return this._hasMarkup(
          path, { anchor: 0, focus: block.get('text').length }, type, value
        );
      }
    });

    var remove = paths.length === withMarkup.length || value === '';

    // perform toggle
    paths.forEach( (path, i) => {
      var block = this.map.getIn(path);

      if (i === 0) {
        this._toggleBlockMarkup(
          remove, path, { anchor: offsets.anchor, focus: block.get('text').length }, type, value
        );
      } else if (i === paths.length - 1) {
        this._toggleBlockMarkup(
          remove, path, { anchor: 0, focus: offsets.focus }, type, value
        );
      } else {
        this._toggleBlockMarkup(
          remove, path, { anchor: 0, focus: block.get('text').length }, type, value
        );
      }
    });
  }

  // check if the path has the given markup offsets range
  _hasMarkup(path, offsets, type, value) {
    var block = this.map.getIn(path);

    var markup = this._newMarkupRange(offsets, value);
    var set = this._getRangeSet(block, type);
    return set.includes(markup);
  }

  // add or remove markup for a block
  _toggleBlockMarkup(remove, path, offsets, type, value) {
    var block = this.map.getIn(path);
    var markups = this._getCurrentBlockMarkups(block, type);

    var markup = this._newMarkupRange(offsets, value);
    var set = this._getRangeSet(block, type);

    if (remove) {
      markups = markups.set(type, Immutable.fromJS(set.remove(markup)));
    } else {
      markups = markups.set(type, Immutable.fromJS(set.add(markup)));
    }

    this.map = this.map.setIn(path.concat('markups'), markups);
  }

  _newMarkupRange(offsets, value) {
    var markup = { 'range': [offsets.anchor, offsets.focus] };
    if (value) { markup.value = value; } // links need values
    return markup;
  }

  // for now "RangeSet" only works with js objects, so convert to get working
  _getRangeSet(block, type) {
    var markups = this._getCurrentBlockMarkups(block, type);
    return new RangeSet(markups.get(type).toJS());
  }

  // get the current markups for this block/markup-type
  _getCurrentBlockMarkups(block, type) {
    var { List, Map } = Immutable;

    var markups = block.get("markups", Map());
    return markups.set(type, markups.get(type, List()));
  }

  _finder() {
    return new ContentFinder(this.map);
  }
}

module.exports = ToggleMarkup;
<commit_msg>fix issue bolding across lists<commit_after>var Immutable = require('immutable');

var ContentFinder = require('../ContentFinder');
var RangeSet = require('../RangeSet');

class ToggleMarkup {
  constructor(map) {
    this.map = map;
  }

  execute(guids, offsets, options) {
    var type  = options.type;
    var value = options.value;

    var range = this._finder().findRange(guids, offsets);
    var paths = range.map( (guid) => {
      return this._finder().findPath(guid);
    });

    if (paths.length === 1) {
      this._toggleSingleBlockMarkup(paths, offsets, type, value);
    } else {
      this._toggleMultiBlockMarkup(paths, offsets, type, value);
    }

    return { content: this.map };
  }

  /**
   * Just toggle markup on/off
   */
  _toggleSingleBlockMarkup(paths, offsets, type, value) {
    var hasMarkup = this._hasMarkup(paths[0], offsets, type, value);
    var remove = hasMarkup || value === '';
    this._toggleBlockMarkup(remove, paths[0], offsets, type, value);
  }

  /**
   * multi block requires 'all' text to be selected to remove. So if your
   * selection is partially bolded, it will add bold to the whole selection
   *
   * however if we have a value, we require 'any'. So if you have selected
   * text that is partially linked, it will remove links fro the selection
   */
  _toggleMultiBlockMarkup(paths, offsets, type, value) {
    // check if everything is selected
    var withMarkup = paths.filter( (path, i) => {
      var block = this.map.getIn(path);

      if (i === 0) {
        return this._hasMarkup(
          path, { anchor: offsets.anchor, focus: block.get('text').length }, type, value
        );
      } else if (i === paths.length - 1) {
        return this._hasMarkup(
          path, { anchor: 0, focus: offsets.focus }, type, value
        );
      } else {
        if (!block.get('text')) return true; // some items (ul) don't have text
        return this._hasMarkup(
          path, { anchor: 0, focus: block.get('text').length }, type, value
        );
      }
    });

    var remove = paths.length === withMarkup.length || value === '';

    // perform toggle
    paths.forEach( (path, i) => {
      var block = this.map.getIn(path);

      if (i === 0) {
        this._toggleBlockMarkup(
          remove, path, { anchor: offsets.anchor, focus: block.get('text').length }, type, value
        );
      } else if (i === paths.length - 1) {
        this._toggleBlockMarkup(
          remove, path, { anchor: 0, focus: offsets.focus }, type, value
        );
      } else {
        if (!block.get('text')) return; // some items (ul) don't have text
        this._toggleBlockMarkup(
          remove, path, { anchor: 0, focus: block.get('text').length }, type, value
        );
      }
    });
  }

  // check if the path has the given markup offsets range
  _hasMarkup(path, offsets, type, value) {
    var block = this.map.getIn(path);

    var markup = this._newMarkupRange(offsets, value);
    var set = this._getRangeSet(block, type);
    return set.includes(markup);
  }

  // add or remove markup for a block
  _toggleBlockMarkup(remove, path, offsets, type, value) {
    var block = this.map.getIn(path);
    var markups = this._getCurrentBlockMarkups(block, type);

    var markup = this._newMarkupRange(offsets, value);
    var set = this._getRangeSet(block, type);

    if (remove) {
      markups = markups.set(type, Immutable.fromJS(set.remove(markup)));
    } else {
      markups = markups.set(type, Immutable.fromJS(set.add(markup)));
    }

    this.map = this.map.setIn(path.concat('markups'), markups);
  }

  _newMarkupRange(offsets, value) {
    var markup = { 'range': [offsets.anchor, offsets.focus] };
    if (value) { markup.value = value; } // links need values
    return markup;
  }

  // for now "RangeSet" only works with js objects, so convert to get working
  _getRangeSet(block, type) {
    var markups = this._getCurrentBlockMarkups(block, type);
    return new RangeSet(markups.get(type).toJS());
  }

  // get the current markups for this block/markup-type
  _getCurrentBlockMarkups(block, type) {
    var { List, Map } = Immutable;

    var markups = block.get("markups", Map());
    return markups.set(type, markups.get(type, List()));
  }

  _finder() {
    return new ContentFinder(this.map);
  }
}

module.exports = ToggleMarkup;
<|endoftext|>


<commit_before>'use strict';

const Rule = require('./base');
const isInteractiveElement = require('../helpers/is-interactive-element');
const isAngleBracketComponent = require('../helpers/is-angle-bracket-component');
const parseConfig = require('../helpers/parse-interactive-element-config');

const DISALLOWED_DOM_EVENTS = [
  // Mouse events:
  'click',
  'dblclick',
  'mousedown',
  'mousemove',
  'mouseover',
  'mouseout',
  'mouseup',

  // Keyboard events:
  'keydown',
  'keypress',
  'keyup',

  // TODO: add any more relevant events.
];

function isDisallowedDomEvent(name) {
  const nameLower = name.toLowerCase();
  return nameLower.startsWith('on') && DISALLOWED_DOM_EVENTS.includes(name.substring(2));
}

module.exports = class InvalidInteractive extends Rule {
  parseConfig(config) {
    return parseConfig(this.ruleName, config);
  }

  isCustomInteractiveElement(node) {
    let additionalInteractiveTags = this.config.additionalInteractiveTags || [];

    if (additionalInteractiveTags.indexOf(node.tag) > -1) {
      return true;
    } else {
      return false;
    }
  }

  visitor() {
    this._element = null;

    let visitor = {
      enter(node) {
        let isInteractive =
          isInteractiveElement(node) ||
          this.isCustomInteractiveElement(node) ||
          isAngleBracketComponent(this.scope, node);
        this._element = !isInteractive ? node : null;
      },

      exit(node) {
        if (this._element === node) {
          this._element = null;
        }
      },
    };

    return {
      ElementModifierStatement(node) {
        if (!this._element) {
          return;
        }

        let modifierName = node.path.original;

        if (modifierName === 'action') {
          // Allow {{action "foo" on="submit"}} on form tags
          if (this._element.tag === 'form' && isSubmitAction(node)) {
            return;
          }

          // Allow {{action "foo" on="reset"}} on form tags
          if (this._element.tag === 'form' && isResetAction(node)) {
            return;
          }

          this.log({
            message: 'Interaction added to non-interactive element',
            line: node.loc && node.loc.start.line,
            column: node.loc && node.loc.start.column,
            source: this.sourceForNode(this._element),
          });
        }
      },

      AttrNode(node) {
        if (!this._element) {
          return;
        }

        if (node.value.type !== 'MustacheStatement') {
          return;
        }

        let helperName = node.value.path.original;

        // Allow onsubmit={{action "foo"}} on form tags
        if (this._element.tag === 'form' && node.name === 'onsubmit') {
          return;
        }

        // Allow onreset={{action "foo"}} on form tags
        if (this._element.tag === 'form' && node.name === 'onreset') {
          return;
        }

        // Allow onerror={{action "foo"}} on img tags
        if (this._element.tag === 'img' && node.name === 'onerror') {
          return;
        }

        if (helperName === 'action') {
          this.log({
            message: 'Interaction added to non-interactive element',
            line: node.loc && node.loc.start.line,
            column: node.loc && node.loc.start.column,
            source: this.sourceForNode(this._element),
          });
        } else if (isDisallowedDomEvent(node.name)) {
          this.log({
            message: 'Interaction added to non-interactive element',
            line: node.loc && node.loc.start.line,
            column: node.loc && node.loc.start.column,
            source: this.sourceForNode(this._element),
          });
        }
      },

      ElementNode: visitor,
      ComponentNode: visitor,
    };
  }
};

function isActionName(node, name) {
  let hashPairs = node.hash.pairs || [];
  let i;
  let l = hashPairs.length;
  let hashItem;

  for (i = 0; i < l; i++) {
    hashItem = hashPairs[i];
    if (hashItem.key === 'on' && hashItem.value.value === name) {
      return true;
    }
  }

  return false;
}

function isSubmitAction(node) {
  return isActionName(node, 'submit');
}

function isResetAction(node) {
  return isActionName(node, 'reset');
}
<commit_msg>Allow load/error events on non-interactive elements<commit_after>'use strict';

const Rule = require('./base');
const isInteractiveElement = require('../helpers/is-interactive-element');
const isAngleBracketComponent = require('../helpers/is-angle-bracket-component');
const parseConfig = require('../helpers/parse-interactive-element-config');

const DISALLOWED_DOM_EVENTS = [
  // Mouse events:
  'click',
  'dblclick',
  'mousedown',
  'mousemove',
  'mouseover',
  'mouseout',
  'mouseup',

  // Keyboard events:
  'keydown',
  'keypress',
  'keyup',

  // TODO: add any more relevant events.
];

function isDisallowedDomEvent(name) {
  const nameLower = name.toLowerCase();
  return nameLower.startsWith('on') && DISALLOWED_DOM_EVENTS.includes(name.substring(2));
}

module.exports = class InvalidInteractive extends Rule {
  parseConfig(config) {
    return parseConfig(this.ruleName, config);
  }

  isCustomInteractiveElement(node) {
    let additionalInteractiveTags = this.config.additionalInteractiveTags || [];

    if (additionalInteractiveTags.indexOf(node.tag) > -1) {
      return true;
    } else {
      return false;
    }
  }

  visitor() {
    this._element = null;

    let visitor = {
      enter(node) {
        let isInteractive =
          isInteractiveElement(node) ||
          this.isCustomInteractiveElement(node) ||
          isAngleBracketComponent(this.scope, node);
        this._element = !isInteractive ? node : null;
      },

      exit(node) {
        if (this._element === node) {
          this._element = null;
        }
      },
    };

    return {
      ElementModifierStatement(node) {
        if (!this._element) {
          return;
        }

        let modifierName = node.path.original;

        if (modifierName === 'action') {
          // Allow {{action "foo" on="submit"}} on form tags
          if (this._element.tag === 'form' && isSubmitAction(node)) {
            return;
          }

          // Allow {{action "foo" on="reset"}} on form tags
          if (this._element.tag === 'form' && isResetAction(node)) {
            return;
          }

          this.log({
            message: 'Interaction added to non-interactive element',
            line: node.loc && node.loc.start.line,
            column: node.loc && node.loc.start.column,
            source: this.sourceForNode(this._element),
          });
        }
      },

      AttrNode(node) {
        if (!this._element) {
          return;
        }

        if (node.value.type !== 'MustacheStatement') {
          return;
        }

        let helperName = node.value.path.original;

        // Allow onsubmit={{action "foo"}} on form tags
        if (this._element.tag === 'form' && node.name === 'onsubmit') {
          return;
        }

        // Allow onreset={{action "foo"}} on form tags
        if (this._element.tag === 'form' && node.name === 'onreset') {
          return;
        }

        // Allow onerror={{action "foo"}} and onload={{action "foo"}} on any tag
        if (this._element.tag === 'img' && ['onerror', 'onload'].includes(node.name)) {
          return;
        }

        if (helperName === 'action') {
          this.log({
            message: 'Interaction added to non-interactive element',
            line: node.loc && node.loc.start.line,
            column: node.loc && node.loc.start.column,
            source: this.sourceForNode(this._element),
          });
        } else if (isDisallowedDomEvent(node.name)) {
          this.log({
            message: 'Interaction added to non-interactive element',
            line: node.loc && node.loc.start.line,
            column: node.loc && node.loc.start.column,
            source: this.sourceForNode(this._element),
          });
        }
      },

      ElementNode: visitor,
      ComponentNode: visitor,
    };
  }
};

function isActionName(node, name) {
  let hashPairs = node.hash.pairs || [];
  let i;
  let l = hashPairs.length;
  let hashItem;

  for (i = 0; i < l; i++) {
    hashItem = hashPairs[i];
    if (hashItem.key === 'on' && hashItem.value.value === name) {
      return true;
    }
  }

  return false;
}

function isSubmitAction(node) {
  return isActionName(node, 'submit');
}

function isResetAction(node) {
  return isActionName(node, 'reset');
}
<|endoftext|>


<commit_before>define(function(require, exports, module) {
    "use strict";

    main.consumes = ["Plugin", "auth", "http", "api", "error_handler", "metrics"];
    main.provides = ["vfs.endpoint"];

    var PARALLEL_SEARCHES=2;

    return main;

    function main(options, imports, register) {
        var Plugin = imports.Plugin;
        var auth = imports.auth;
        var http = imports.http;
        var api = imports.api;
        var errorHandler = imports.error_handler;
        var metrics = imports.metrics;

        /***** Initialization *****/

        var plugin = new Plugin("Ajax.org", main.consumes);
        var emit = plugin.getEmitter();

        var urlServers, lastVfs;
        var query = require("url").parse(document.location.href, true).query;
        if (query.vfs) {
            if (!query.vfs.match(/^https:\/\/.*\/vfs$/))
                alert("Bad VFS URL passed, expected: https://host/vfs");
            urlServers = [{
                url: query.vfs,
                region: "url"
            }];
        }
        if (query.vfs || query.region) {
            var vfs = recallVfs();
            if (vfs) {
                if (query.vfs && query.vfs !== vfs.url)
                    deleteOldVfs();
                else if (query.region && query.region !== vfs.region)
                    deleteOldVfs();
            }
        }
        if (query.vfs)
            options.updateServers = false;

        var region = query.region || options.region;

        var servers;
        var pendingServerReqs = [];

        initDefaultServers();

        options.pid = options.pid || 1;

        /***** Methods *****/

        function initDefaultServers(baseURI) {
            if (options.getServers)
                return options.getServers(init);
            init();

            function init() {
                options.getServers = undefined;
                var loc = require("url").parse(baseURI || document.baseURI || window.location.href);
                var defaultServers = [{
                    url: loc.protocol + "//" + loc.hostname + (loc.port ? ":" + loc.port : "") + "/vfs",
                    region: "default"
                }];
                servers = (urlServers || options.servers || defaultServers).map(function(server) {
                    server.url = server.url.replace(/\/*$/, "");
                    return server;
                });
                pendingServerReqs.forEach(function(cb) {
                    cb(null, servers);
                });
            }
        }

        function getServers(callback) {
            if (typeof options.getServers == "function")
                return pendingServerReqs.push(callback);

            if (!options.updateServers)
                return callback(null, servers);

            // first time take the ones from the options
            var _servers = servers;
            if (_servers) {
                servers = null;
                return callback(null, _servers);
            }

            api.vfs.get("servers", function(err, servers) {
                if (err) return callback(err);

                return callback(null, servers.servers);
            });
        }

        function getVfsEndpoint(version, callback) {
            getServers(function(err, _servers) {
                if (err) {
                    if (err.code !== "EDISCONNECT")
                        errorHandler.reportError(new Error("Could not get list of VFS servers"), { cause: err });
                    metrics.increment("vfs.failed.connect_getservers", 1, true);
                    initDefaultServers();
                    _servers = servers;
                }

                getVfsUrl(version, _servers, function(err, vfsid, url, region) {
                    if (err) return callback(err);

                    callback(null, {
                        url: url,
                        region: region,
                        home: vfsid + "/home",
                        project: vfsid + "/workspace",
                        socket: vfsid + "/socket",
                        ping: vfsid,
                        serviceUrl: vfsid,
                    });
                });
            });
        }

        function isOnline(callback) {
            http.request("/_ping", {
                timeout: 3000,
                headers: {
                    Accept: "application/json"
                }
            }, function(err, data, res) {
                callback(err, !err);
            });
        }

        function isServerAlive(url, callback) {
            auth.request(url, {
                headers: {
                    Accept: "application/json"
                }
            }, function(err, data, res) {
                if (err)
                    deleteOldVfs();

                callback(err, !err);
            });
        }

        function getVfsUrl(version, vfsServers, callback) {
            var vfs = recallVfs();

            if (vfs && vfs.vfsid) {
                auth.request(vfs.vfsid, {
                    method: "GET",
                    headers: {
                        Accept: "application/json"
                    }
                }, function(err, res) {
                    if (err) {
                        deleteOldVfs();
                        return getVfsUrl(version, vfsServers, callback);
                    }
                    callback(null, vfs.vfsid, vfs.url, vfs.region);
                });
                return;
            }

            var servers = shuffleServers(vfsServers);

            // check for version
            if (servers.length && !servers.filter(function(s) { return s.version !== version; }).length)
                return onProtocolChange(callback);

            var latestServer = 0;
            var foundServer = false;

            /* Create a callback that is only ever called once */
            var mainCallback = callback;
            callback = function() {
                if (!foundServer) {
                    foundServer = true;
                    var args = Array.prototype.slice.call(arguments);
                    return mainCallback.apply(this, args);
                }
            };

            // just take the first server that doesn't return an error
            function tryNext(i) {
                if (foundServer) return false;
                if (i >= servers.length) {
                    metrics.increment("vfs.failed.connect_all", 1, true);
                    return callback(new Error("Disconnected: Could not reach your workspace. Please try again later."));
                }

                var server = servers[i];
                auth.request(server.url + "/" + options.pid, {
                    method: "POST",
                    timeout: 120000,
                    body: {
                        version: version
                    },
                    headers: {
                        Accept: "application/json"
                    }
                }, function(err, res) {
                    // the workspace is not configured correctly
                    if (err && res && res.error) {
                        if (err.code == 429) {
                            // rate limited
                            setTimeout(function() {
                                tryNext(i);
                            }, res.error.retryIn || 10000);
                            return;
                        }
                        else if (err.code == 412 && res.error && res.error.subtype == "protocol_mismatch") {
                            return onProtocolChange(callback);
                        }
                        else if (err.code == 412) {
                            callback(fatalError(res.error.message, "dashboard"));
                            return;
                        }
                        else if (err.code === 428 && res.error) {
                            emit("restore", {
                                projectState: res.error.projectState,
                                premium: res.error.premium,
                                progress: res.error.progress || {
                                    progress: 0,
                                    nextProgress: 0,
                                    message: ""
                                }
                            });
                            setTimeout(function() {
                                tryNext(i);
                            }, res.error.retryIn || 10000);
                            return;
                        }
                        else if (err.code == 403) {
                            if (res.error.blocked)
                                callback(fatalError(res.error.message, "dashboard"));

                            // forbidden. User doesn't have access
                            // wait a while before trying again
                            setTimeout(function() {
                                tryNext(i);
                            }, 10000);
                            return;
                        }
                    }

                    if (err) {
                        setTimeout(function() {
                            tryNext(++latestServer);
                        }, 2000);
                        return;
                    }

                    var vfs = rememberVfs(server, res.vfsid);
                    callback(null, vfs.vfsid, server.url, server.region);
                });
            };

            function startParallelSearches (totalRunners) {
                var attemptedServers = {};
                for (var s = 0; s < servers.length && s < totalRunners; s++)  {
                    latestServer = s;
                    var server = servers[s];
                    var serverHostUrl = getHostFromServerUrl(server.url);
                    if (!attemptedServers[serverHostUrl]) {
                        attemptedServers[serverHostUrl] = true;
                        tryNext(s);
                    }
                }
            }

            startParallelSearches(PARALLEL_SEARCHES);
        }

        function getHostFromServerUrl(serverUrl) {
            // server.url looks like: https://vfs-gce-ae-09-2.c9.io or https://vfs.c9.dev/vfs we're grabbing the base url of the host (without the -2)
            var serverHostUrl = serverUrl.replace(/^(https:..[^.]+-\d+)(-\d+)(.*)/, "$1$3");
            if (serverHostUrl) {
                return serverHostUrl;
            }
            return serverUrl;
        }

        function onProtocolChange(callback) {
            // I'm keeping this vague because we don't want users to blame
            // a "cloud9 update" for losing work
            deleteOldVfs();
            return callback(fatalError("Protocol change detected", "reload"));
        }

        function shuffleServers(servers) {
            servers = servers.slice();
            var isBeta = region == "beta";
            servers = servers.filter(function(s) {
                return isBeta || s.region !== "beta";
            });
            return servers.sort(function(a, b) {
                if (a.region == b.region) {
                    if (a.load < b.load)
                        return -1;
                    else
                        return 1;
                }
                else if (a.region == region)
                    return -1;
                else if (b.region == region)
                    return 1;
                else
                    return 0;
            });
        }

        function rememberVfs(server, vfsid) {
            var vfs = {
                url: server.url,
                region: server.region,
                pid: options.pid,
                vfsid: server.url + "/" + options.pid + "/" + vfsid,
                readonly: options.readonly
            };

            var data = JSON.stringify(vfs);

            var oldData = lastVfs || window.sessionStorage.getItem("vfsid");
            if (oldData && oldData !== data)
                deleteOldVfs();

            lastVfs = data;

            return vfs;
        }

        function recallVfs() {
            var vfs;
            try {
                vfs = JSON.parse(lastVfs || window.sessionStorage.getItem("vfsid"));
                if (!lastVfs) {
                    window.sessionStorage.removeItem("vfsid");
                    lastVfs = JSON.stringify(vfs);
                }
            } catch (e) {}

            if (!vfs)
                return null;

            if (vfs.pid !== options.pid || vfs.readonly != options.readonly) {
                deleteOldVfs();
                return null;
            }

            return vfs;
        }

        function deleteOldVfs() {
            var vfs;
            try {
                vfs = JSON.parse(lastVfs || window.sessionStorage.getItem("vfsid"));
            } catch (e) {}

            window.sessionStorage.removeItem("vfsid");
            lastVfs = null;
            if (!vfs) return;

            auth.request(vfs.vfsid, {
                method: "DELETE",
                headers: {
                    Accept: "application/json"
                }
            }, function(err) {
                if (err) console.error(vfs.vfsid, "deleted", err);
                });
        }

        function fatalError(msg, action) {
            var err = new Error(msg);
            err.fatal = true;
            err.action = action || "reload";
            return err;
        }

        function saveToSessionStorage() {
            try {
                window.sessionStorage.setItem("vfsid", lastVfs);
            } catch(e) {
                // could throw a quota exception
            }
        }

        plugin.on("load", function() {
            window.addEventListener("unload", saveToSessionStorage);
        });

        plugin.on("unload", function() {
            window.removeEventListener("unload", saveToSessionStorage);
        });

        /***** Register and define API *****/

        /**
         **/
        plugin.freezePublicAPI({
            /**
             * Returns the URLs for the home and project REST API and the socket
             */
            get: getVfsEndpoint,

            /**
             * Checks if the client has a network connection
             */
            isOnline: isOnline,

            /**
             *
             */
            clearCache: deleteOldVfs,

            /**
             * Checks if the current VFS server is still alive
             */
            isServerAlive: isServerAlive
        });

        register(null, {
            "vfs.endpoint": plugin
        });
    }
});<commit_msg>filter out nonbeta vfs servers from beta config<commit_after>define(function(require, exports, module) {
    "use strict";

    main.consumes = ["Plugin", "auth", "http", "api", "error_handler", "metrics"];
    main.provides = ["vfs.endpoint"];

    return main;

    function main(options, imports, register) {
        var Plugin = imports.Plugin;
        var auth = imports.auth;
        var http = imports.http;
        var api = imports.api;
        var errorHandler = imports.error_handler;
        var metrics = imports.metrics;

        var PARALLEL_SEARCHES = 2;

        /***** Initialization *****/

        var plugin = new Plugin("Ajax.org", main.consumes);
        var emit = plugin.getEmitter();

        var urlServers, lastVfs;
        var query = require("url").parse(document.location.href, true).query;
        if (query.vfs) {
            if (!query.vfs.match(/^https:\/\/.*\/vfs$/))
                alert("Bad VFS URL passed, expected: https://host/vfs");
            urlServers = [{
                url: query.vfs,
                region: "url"
            }];
        }
        if (query.vfs || query.region) {
            var vfs = recallVfs();
            if (vfs) {
                if (query.vfs && query.vfs !== vfs.url)
                    deleteOldVfs();
                else if (query.region && query.region !== vfs.region)
                    deleteOldVfs();
            }
        }
        if (query.vfs)
            options.updateServers = false;

        var region = query.region || options.region;

        var servers;
        var pendingServerReqs = [];

        initDefaultServers();

        options.pid = options.pid || 1;

        /***** Methods *****/

        function initDefaultServers(baseURI) {
            if (options.getServers)
                return options.getServers(init);
            init();

            function init() {
                options.getServers = undefined;
                var loc = require("url").parse(baseURI || document.baseURI || window.location.href);
                var defaultServers = [{
                    url: loc.protocol + "//" + loc.hostname + (loc.port ? ":" + loc.port : "") + "/vfs",
                    region: "default"
                }];
                servers = (urlServers || options.servers || defaultServers).map(function(server) {
                    server.url = server.url.replace(/\/*$/, "");
                    return server;
                });
                pendingServerReqs.forEach(function(cb) {
                    cb(null, servers);
                });
            }
        }

        function getServers(callback) {
            if (typeof options.getServers == "function")
                return pendingServerReqs.push(callback);

            if (!options.updateServers)
                return callback(null, servers);

            // first time take the ones from the options
            var _servers = servers;
            if (_servers) {
                servers = null;
                return callback(null, _servers);
            }

            api.vfs.get("servers", function(err, servers) {
                if (err) return callback(err);

                return callback(null, servers.servers);
            });
        }

        function getVfsEndpoint(version, callback) {
            getServers(function(err, _servers) {
                if (err) {
                    if (err.code !== "EDISCONNECT")
                        errorHandler.reportError(new Error("Could not get list of VFS servers"), { cause: err });
                    metrics.increment("vfs.failed.connect_getservers", 1, true);
                    initDefaultServers();
                    _servers = servers;
                }

                getVfsUrl(version, _servers, function(err, vfsid, url, region) {
                    if (err) return callback(err);

                    callback(null, {
                        url: url,
                        region: region,
                        home: vfsid + "/home",
                        project: vfsid + "/workspace",
                        socket: vfsid + "/socket",
                        ping: vfsid,
                        serviceUrl: vfsid,
                    });
                });
            });
        }

        function isOnline(callback) {
            http.request("/_ping", {
                timeout: 3000,
                headers: {
                    Accept: "application/json"
                }
            }, function(err, data, res) {
                callback(err, !err);
            });
        }

        function isServerAlive(url, callback) {
            auth.request(url, {
                headers: {
                    Accept: "application/json"
                }
            }, function(err, data, res) {
                if (err)
                    deleteOldVfs();

                callback(err, !err);
            });
        }

        function getVfsUrl(version, vfsServers, callback) {
            var vfs = recallVfs();

            if (vfs && vfs.vfsid) {
                auth.request(vfs.vfsid, {
                    method: "GET",
                    headers: {
                        Accept: "application/json"
                    }
                }, function(err, res) {
                    if (err) {
                        deleteOldVfs();
                        return getVfsUrl(version, vfsServers, callback);
                    }
                    callback(null, vfs.vfsid, vfs.url, vfs.region);
                });
                return;
            }

            var servers = shuffleServers(version, vfsServers);

            // check for version
            if (vfsServers.length && !servers.length)
                return onProtocolChange(callback);

            var latestServer = 0;
            var foundServer = false;

            /* Create a callback that is only ever called once */
            var mainCallback = callback;
            callback = function() {
                if (!foundServer) {
                    foundServer = true;
                    var args = Array.prototype.slice.call(arguments);
                    return mainCallback.apply(this, args);
                }
            };

            // just take the first server that doesn't return an error
            function tryNext(i) {
                if (foundServer) return false;
                if (i >= servers.length) {
                    metrics.increment("vfs.failed.connect_all", 1, true);
                    return callback(new Error("Disconnected: Could not reach your workspace. Please try again later."));
                }

                var server = servers[i];
                auth.request(server.url + "/" + options.pid, {
                    method: "POST",
                    timeout: 120000,
                    body: {
                        version: version
                    },
                    headers: {
                        Accept: "application/json"
                    }
                }, function(err, res) {
                    // the workspace is not configured correctly
                    if (err && res && res.error) {
                        if (err.code == 429) {
                            // rate limited
                            setTimeout(function() {
                                tryNext(i);
                            }, res.error.retryIn || 10000);
                            return;
                        }
                        else if (err.code == 412 && res.error && res.error.subtype == "protocol_mismatch") {
                            return onProtocolChange(callback);
                        }
                        else if (err.code == 412) {
                            callback(fatalError(res.error.message, "dashboard"));
                            return;
                        }
                        else if (err.code === 428 && res.error) {
                            emit("restore", {
                                projectState: res.error.projectState,
                                premium: res.error.premium,
                                progress: res.error.progress || {
                                    progress: 0,
                                    nextProgress: 0,
                                    message: ""
                                }
                            });
                            setTimeout(function() {
                                tryNext(i);
                            }, res.error.retryIn || 10000);
                            return;
                        }
                        else if (err.code == 403) {
                            if (res.error.blocked)
                                callback(fatalError(res.error.message, "dashboard"));

                            // forbidden. User doesn't have access
                            // wait a while before trying again
                            setTimeout(function() {
                                tryNext(i);
                            }, 10000);
                            return;
                        }
                    }

                    if (err) {
                        setTimeout(function() {
                            tryNext(++latestServer);
                        }, 2000);
                        return;
                    }

                    var vfs = rememberVfs(server, res.vfsid);
                    callback(null, vfs.vfsid, server.url, server.region);
                });
            }

            function startParallelSearches (totalRunners) {
                var attemptedServers = {};
                for (var s = 0; s < servers.length && s < totalRunners; s++)  {
                    latestServer = s;
                    var server = servers[s];
                    var serverHostUrl = getHostFromServerUrl(server.url);
                    if (!attemptedServers[serverHostUrl]) {
                        attemptedServers[serverHostUrl] = true;
                        tryNext(s);
                    }
                }
            }

            startParallelSearches(PARALLEL_SEARCHES);
        }

        function getHostFromServerUrl(serverUrl) {
            // server.url looks like: https://vfs-gce-ae-09-2.c9.io or https://vfs.c9.dev/vfs we're grabbing the base url of the host (without the -2)
            var serverHostUrl = serverUrl.replace(/^(https:..[^.]+-\d+)(-\d+)(.*)/, "$1$3");
            if (serverHostUrl) {
                return serverHostUrl;
            }
            return serverUrl;
        }

        function onProtocolChange(callback) {
            // I'm keeping this vague because we don't want users to blame
            // a "cloud9 update" for losing work
            deleteOldVfs();
            return callback(fatalError("Protocol change detected", "reload"));
        }

        function shuffleServers(version, servers) {
            servers = servers.slice();
            var isBetaClient = region === "beta";
            servers = servers.filter(function(s) {
                var isBetaServer = s.region === "beta";
                return isBetaServer === isBetaClient;
            });
            servers = servers.filter(function(s) {
                return s.version == undefined || s.version == version;
            });
            return servers.sort(function(a, b) {
                if (a.region == b.region) {
                    if (a.load < b.load)
                        return -1;
                    else
                        return 1;
                }
                else if (a.region == region)
                    return -1;
                else if (b.region == region)
                    return 1;
                else
                    return 0;
            });
        }

        function rememberVfs(server, vfsid) {
            var vfs = {
                url: server.url,
                region: server.region,
                pid: options.pid,
                vfsid: server.url + "/" + options.pid + "/" + vfsid,
                readonly: options.readonly
            };

            var data = JSON.stringify(vfs);

            var oldData = lastVfs || window.sessionStorage.getItem("vfsid");
            if (oldData && oldData !== data)
                deleteOldVfs();

            lastVfs = data;

            return vfs;
        }

        function recallVfs() {
            var vfs;
            try {
                vfs = JSON.parse(lastVfs || window.sessionStorage.getItem("vfsid"));
                if (!lastVfs) {
                    window.sessionStorage.removeItem("vfsid");
                    lastVfs = JSON.stringify(vfs);
                }
            } catch (e) {}

            if (!vfs)
                return null;

            if (vfs.pid !== options.pid || vfs.readonly != options.readonly) {
                deleteOldVfs();
                return null;
            }

            return vfs;
        }

        function deleteOldVfs() {
            var vfs;
            try {
                vfs = JSON.parse(lastVfs || window.sessionStorage.getItem("vfsid"));
            } catch (e) {}

            window.sessionStorage.removeItem("vfsid");
            lastVfs = null;
            if (!vfs) return;

            auth.request(vfs.vfsid, {
                method: "DELETE",
                headers: {
                    Accept: "application/json"
                }
            }, function(err) {
                if (err) console.error(vfs.vfsid, "deleted", err);
                });
        }

        function fatalError(msg, action) {
            var err = new Error(msg);
            err.fatal = true;
            err.action = action || "reload";
            return err;
        }

        function saveToSessionStorage() {
            try {
                window.sessionStorage.setItem("vfsid", lastVfs);
            } catch(e) {
                // could throw a quota exception
            }
        }

        plugin.on("load", function() {
            window.addEventListener("unload", saveToSessionStorage);
        });

        plugin.on("unload", function() {
            window.removeEventListener("unload", saveToSessionStorage);
        });

        /***** Register and define API *****/

        /**
         **/
        plugin.freezePublicAPI({
            /**
             * Returns the URLs for the home and project REST API and the socket
             */
            get: getVfsEndpoint,

            /**
             * Checks if the client has a network connection
             */
            isOnline: isOnline,

            /**
             *
             */
            clearCache: deleteOldVfs,

            /**
             * Checks if the current VFS server is still alive
             */
            isServerAlive: isServerAlive
        });

        register(null, {
            "vfs.endpoint": plugin
        });
    }
});<|endoftext|>


<commit_before>/**
 * jspsych-reconstruction
 * a jspsych plugin for a reconstruction task where the subject recreates
 * a stimulus from memory
 *
 * Josh de Leeuw
 *
 * documentation: docs.jspsych.org
 *
 */

(function($) {
  jsPsych['reconstruction'] = (function() {

    var plugin = {};

    plugin.create = function(params) {

      params = jsPsych.pluginAPI.enforceArray(params, ['data']);

      var n_trials = (typeof params.starting_value == 'undefined') ? 1 : params.starting_value.length

      var trials = [];
      for (var i = 0; i < n_trials; i++) {
        trials.push({
          starting_value: (typeof params.starting_value == 'undefined') ? [0.5] : params.starting_value[i],
          stim_function: params.stim_function,
          step_size: params.step_size || 0.05,
          key_increase: params.key_increase || 'h',
          key_decrease: params.key_decrease || 'g'
        });
      }
      return trials;
    };

    plugin.trial = function(display_element, trial) {

      // if any trial variables are functions
      // this evaluates the function and replaces
      // it with the output of the function
      trial = jsPsych.pluginAPI.normalizeTrialVariables(trial, ['stim_function']);

      // current param level
      var param = trial.starting_value;

      // set-up key listeners
      var after_response = function(info){
        // get new param value
        if(info.key == key_increase) {
          param = param + step_size;
        } else if(info.key == key_decrease) {
          param = param - step_size;
        }
        param = Math.max(Math.min(1,param),0);

        // refresh the display
        draw(param);
      }

      // listen for responses
      var key_listener = jsPsych.pluginAPI.getKeyboardResponse(after_response, [trial.key_increase, trial.key_decrease], 'date', true);

      // draw first iteration
      draw(param);

      function draw(param){
        display_element.html('');

        display_element.append($('

'));

        $('#jspsych-reconstruction-stim-container').html(trial.stim_function(param));

        // add submit button
        display_element.append($('<button>', {
          'id': 'jspsych-survey-text-next',
          'class': 'jspsych-survey-text'
        }));
        $("#jspsych-survey-text-next").html('Submit Answers');
        $("#jspsych-survey-text-next").click(

      }

      function endTrial(){
        // measure response time
        var endTime = (new Date()).getTime();
        var response_time = endTime - startTime;

        // save data
        jsPsych.data.write($.extend({}, {
          "rt": response_time,
          "final_value": param,
          "start_value": trial.starting_value
        }, trial.data));

        display_element.html('');

        // next trial
        if (trial.timing_post_trial > 0) {
          setTimeout(function() {
            jsPsych.finishTrial();
          }, trial.timing_post_trial);
        } else {
          jsPsych.finishTrial();
        }
      }

      var startTime = (new Date()).getTime();

    };

    return plugin;
  })();
})(jQuery);
<commit_msg>fix unfinished code<commit_after>/**
* jspsych-reconstruction
* a jspsych plugin for a reconstruction task where the subject recreates
* a stimulus from memory
*
* Josh de Leeuw
*
* documentation: docs.jspsych.org
*
*/

(function($) {
  jsPsych['reconstruction'] = (function() {

    var plugin = {};

    plugin.create = function(params) {

      params = jsPsych.pluginAPI.enforceArray(params, ['data']);

      var n_trials = (typeof params.starting_value == 'undefined') ? 1 : params.starting_value.length

      var trials = [];
      for (var i = 0; i < n_trials; i++) {
        trials.push({
          starting_value: (typeof params.starting_value == 'undefined') ? 0.5 : params.starting_value[i],
          stim_function: params.stim_function,
          step_size: params.step_size || 0.05,
          key_increase: params.key_increase || 'h',
          key_decrease: params.key_decrease || 'g'
        });
      }
      return trials;
    };

    plugin.trial = function(display_element, trial) {

      // if any trial variables are functions
      // this evaluates the function and replaces
      // it with the output of the function
      trial = jsPsych.pluginAPI.normalizeTrialVariables(trial, ['stim_function']);

      // current param level
      var param = trial.starting_value;

      // set-up key listeners
      var after_response = function(info){

        console.log('fire');

        var key_i = (typeof trial.key_increase == 'string') ? jsPsych.pluginAPI.convertKeyCharacterToKeyCode(trial.key_increase) : trial.key_increase;
        var key_d = (typeof trial.key_decrease == 'string') ? jsPsych.pluginAPI.convertKeyCharacterToKeyCode(trial.key_decrease) : trial.key_decrease;

        // get new param value
        if(info.key == key_i) {
          param = param + trial.step_size;
        } else if(info.key == key_d) {
          param = param - trial.step_size;
        }
        param = Math.max(Math.min(1,param),0);

        // refresh the display
        draw(param);
      }

      // listen for responses
      var key_listener = jsPsych.pluginAPI.getKeyboardResponse(after_response, [trial.key_increase, trial.key_decrease], 'date', true);

      // draw first iteration
      draw(param);

      function draw(param){

        console.log(param);

        display_element.html('');

        display_element.append($('

'));

        $('#jspsych-reconstruction-stim-container').html(trial.stim_function(param));

        // add submit button
        display_element.append($('<button>', {
          'id': 'jspsych-survey-text-next',
          'class': 'jspsych-survey-text'
        }));
        $("#jspsych-survey-text-next").html('Submit Answers');
        $("#jspsych-survey-text-next").click(endTrial);
      }

      function endTrial(){
        // measure response time
        var endTime = (new Date()).getTime();
        var response_time = endTime - startTime;

        // save data
        jsPsych.data.write($.extend({}, {
          "rt": response_time,
          "final_value": param,
          "start_value": trial.starting_value
        }, trial.data));

        display_element.html('');

        // next trial
        if (trial.timing_post_trial > 0) {
          setTimeout(function() {
            jsPsych.finishTrial();
          }, trial.timing_post_trial);
        } else {
          jsPsych.finishTrial();
        }
      }

      var startTime = (new Date()).getTime();

    };

    return plugin;
  })();
})(jQuery);
<|endoftext|>


<commit_before>/* eslint-env node */
/* eslint-disable no-console */
const axios = require('axios');
const cheerio = require('cheerio');
const fs = require('fs/promises');

async function makeReactLayout() {
    const headerUrl = process.env.HEADER_FILE || 'https://www.jenkins.io/template/index.html';
    const manifestUrl = new URL('/site.webmanifest', headerUrl).toString();

    if (!headerUrl) {
        return null;
    }

    const jsxLines = [
        'import React from \'react\';',
        'import { Helmet } from \'react-helmet\';',
        'import SiteVersion from \'./components/SiteVersion\';',
        'import ReportAProblem from \'./components/ReportAProblem\';',
        'import \'./layout.css\';',
    ];

    const cssLines = [
        '@import \'./styles/ubuntu-fonts.css\';',
        '@import \'./styles/lato-fonts.css\';',
        '@import \'./styles/roboto-fonts.css\';',
        '@import \'./styles/base.css\';',
        '@import \'./styles/font-icons.css\';',
        '@import \'github-syntax-light/lib/github-light.css\';'
    ];

    console.info(`Downloading header file from '${headerUrl}'`);
    const parsedHeaderUrl = new URL(headerUrl);
    const baseUrl = `${parsedHeaderUrl.protocol}//${parsedHeaderUrl.hostname}${ parsedHeaderUrl.port ? `:${parsedHeaderUrl.port}` : ''}`;
    const content = await axios
        .get(headerUrl)
        .then((results) => {
            if (results.status !== 200) {
                throw results.data;
            }
            return results.data;
        });

    const $ = cheerio.load(content, {decodeEntities: false});
    $('title').text('Title must not be empty');
    $('img, script').each(function () {
        const src = $(this).attr('src');
        if (!src) { return; }
        if ( src.startsWith('/')) {
            $(this).attr('src', `${baseUrl}${src}`);
        } else {
            $(this).attr('src', src.replace('https://jenkins.io', baseUrl).replace('https://www.jenkins.io', baseUrl));
        }
    });
    $('a, link').each(function () {
        const href = $(this).attr('href');
        if (!href) { return; }
        if (href.startsWith('/')) {
            $(this).attr('href', `${baseUrl}${href}`);
        } else {
            $(this).attr('href', href.replace('https://jenkins.io', baseUrl).replace('https://www.jenkins.io', baseUrl));
        }
    });
    // remove canonical as we add our own
    $('link[rel="canonical"]').remove();
    // Even though we're supplying our own this one still causes a conflict.
    $('link[href$="/css/font-icons.css"]').remove();
    // Prevents: Access to resource at 'https://jenkins.io/site.webmanifest' from origin 'https://plugins.jenkins.io' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
    $('link[href$="site.webmanifest"]').attr('href', '/site.webmanifest');
    // lets get rid of all the head tags since we are populating them with the SEO component
    $('meta[content*="{{"]').remove();
    //
    // padd as per https://stackoverflow.com/questions/11124777/twitter-bootstrap-navbar-fixed-top-overlapping-site
    $('head').append('');
    $('head').append('');

    $('.nav-link[href="https://plugins.jenkins.io/"]').attr('href', '/');
    $('#grid-box').empty();
    $('#grid-box').append('{children}');
    if (process.env.NETLIFY) {
        $('#footer .col-md-4').prepend('

');
    }
    $('#footer .col-md-4').prepend('<ReportAProblem />');
    $('#creativecommons').append('<SiteVersion />');
    $('link[rel="stylesheet"]').each((_, elm) => {
        elm = $(elm);
        cssLines.push(`@import url('${elm.attr('href')}');`);
        elm.remove();
    });
    $('.searchbox').remove();
    $('script[src*="docsearch"]').remove();
    $('script:contains("docsearch")').remove();
    $('script:contains("google-analytics.com")').remove();

    const keyConversion = {
        class: 'className',
        'charSet': 'charset',
        'http-equiv': 'httpEquiv',
        'stop-color': 'stopColor',
        'crossorigin': 'crossOrigin'
    };

    const handleNode = (node, indent = 0) => {
        const prefix = ''.padStart(6+indent);

        if (node.name === 'link' && node.attribs && node.attribs.rel === 'stylesheet') {
            delete node.attribs.crossorigin;
            node.attribs.type = 'text/css';
            node.attribs.media = 'all';
        }
        const attrs = Object.entries(node.attribs || {}).map(([key, val]) => {
            key = keyConversion[key] || key;
            val = val.replace(/"/g, '\\"');
            return `${key}="${val}"`;
        }).join(' ');
        if (node.name === 'script') {
            // FIXME - handle me
            const text = node.children.map(child => {
                if (child.type === 'text') {
                    return child.data;
                }
                throw new Error(`not sure how to handle ${child.type}`);
            });
            jsxLines.push(`${prefix}<${node.name} ${attrs} dangerouslySetInnerHTML={{__html: ${JSON.stringify(text)}}} />`);
            return;
        } else if (node.type === 'comment') {
            return;
        } else if (node.type === 'text') {
            const text = node.data.replace('\u00A0', ' ');
            jsxLines.push(`${prefix}${text}`);
        } else if (node.children && node.children.length) {
            jsxLines.push(`${prefix}<${node.name} ${attrs}>`);
            node.children.forEach(child => handleNode(child, indent+2));
            jsxLines.push(`${prefix}</${node.name}>`);
        } else {
            let tempAttrs = attrs;

            if (!node.name) {
                console.log(node);
            }
            if (node.name === 'siteversion') {
                node.name = 'SiteVersion';
            } else if (node.name === 'reportaproblem') {
                tempAttrs = 'reportProblemUrl={reportProblemUrl} reportProblemTitle={reportProblemTitle} reportProblemRelativeSourcePath={reportProblemRelativeSourcePath}';
                node.name = 'ReportAProblem';
            }
            jsxLines.push(`${prefix}<${node.name} ${tempAttrs} />`);
        }
    };

    jsxLines.push('export default function Layout({ children, id, reportProblemUrl, reportProblemTitle, reportProblemRelativeSourcePath}) {');
    jsxLines.push('  return (');
    jsxLines.push('
');
    jsxLines.push('      <Helmet>');
    $('head').children(':not(link[rel="stylesheet"])').each((_, child) => handleNode(child, 2));
    $('head').children('link[rel="stylesheet"]').each((_, child) => handleNode(child, 2));
    jsxLines.push('      </Helmet>');
    $('body').children().each((_, child) => handleNode(child, 0));
    jsxLines.push('
');
    jsxLines.push('  );');

    jsxLines.push('}');

    console.info(`Downloading site manifest file from '${manifestUrl}'`);
    const manifest = await axios
        .get(manifestUrl)
        .then((results) => {
            if (results.status !== 200) {
                throw results.data;
            }
            results.data.icons.forEach(icon => {
                icon.src = new URL(icon.src, manifestUrl).toString();
            });
            results.data.start_url = 'https://plugins.jenkins.io';
            return JSON.stringify(results.data);
        });

    return {
        manifest: manifest,
        jsxLines: jsxLines.map(str => str.trimEnd()).filter(Boolean).join('\n'),
        cssLines: cssLines.map(str => str.trimEnd()).filter(Boolean).join('\n')
    };
}

async function saveReactLayout({jsxLines, cssLines, manifest}) {
    if (manifest) {
        await fs.mkdir('static', {recursive: true});
        await fs.writeFile('./static/site.webmanifest', manifest);
    }
    if (jsxLines) {
        await fs.writeFile('./src/layout.jsx', jsxLines);
    }
    if (cssLines) {
        await fs.writeFile('./src/layout.css', cssLines);
    }
}

exports.makeReactLayout = makeReactLayout;
exports.saveReactLayout = saveReactLayout;

if (require.main === module) {
    makeReactLayout().then(saveReactLayout).catch(console.error);
}
<commit_msg>CodeQL warning: unsafe escape<commit_after>/* eslint-env node */
/* eslint-disable no-console */
const axios = require('axios');
const cheerio = require('cheerio');
const fs = require('fs/promises');

async function makeReactLayout() {
    const headerUrl = process.env.HEADER_FILE || 'https://www.jenkins.io/template/index.html';
    const manifestUrl = new URL('/site.webmanifest', headerUrl).toString();

    if (!headerUrl) {
        return null;
    }

    const jsxLines = [
        'import React from \'react\';',
        'import { Helmet } from \'react-helmet\';',
        'import SiteVersion from \'./components/SiteVersion\';',
        'import ReportAProblem from \'./components/ReportAProblem\';',
        'import \'./layout.css\';',
    ];

    const cssLines = [
        '@import \'./styles/ubuntu-fonts.css\';',
        '@import \'./styles/lato-fonts.css\';',
        '@import \'./styles/roboto-fonts.css\';',
        '@import \'./styles/base.css\';',
        '@import \'./styles/font-icons.css\';',
        '@import \'github-syntax-light/lib/github-light.css\';'
    ];

    console.info(`Downloading header file from '${headerUrl}'`);
    const parsedHeaderUrl = new URL(headerUrl);
    const baseUrl = `${parsedHeaderUrl.protocol}//${parsedHeaderUrl.hostname}${ parsedHeaderUrl.port ? `:${parsedHeaderUrl.port}` : ''}`;
    const content = await axios
        .get(headerUrl)
        .then((results) => {
            if (results.status !== 200) {
                throw results.data;
            }
            return results.data;
        });

    const $ = cheerio.load(content, {decodeEntities: false});
    $('title').text('Title must not be empty');
    $('img, script').each(function () {
        const src = $(this).attr('src');
        if (!src) { return; }
        if ( src.startsWith('/')) {
            $(this).attr('src', `${baseUrl}${src}`);
        } else {
            $(this).attr('src', src.replace('https://jenkins.io', baseUrl).replace('https://www.jenkins.io', baseUrl));
        }
    });
    $('a, link').each(function () {
        const href = $(this).attr('href');
        if (!href) { return; }
        if (href.startsWith('/')) {
            $(this).attr('href', `${baseUrl}${href}`);
        } else {
            $(this).attr('href', href.replace('https://jenkins.io', baseUrl).replace('https://www.jenkins.io', baseUrl));
        }
    });
    // remove canonical as we add our own
    $('link[rel="canonical"]').remove();
    // Even though we're supplying our own this one still causes a conflict.
    $('link[href$="/css/font-icons.css"]').remove();
    // Prevents: Access to resource at 'https://jenkins.io/site.webmanifest' from origin 'https://plugins.jenkins.io' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
    $('link[href$="site.webmanifest"]').attr('href', '/site.webmanifest');
    // lets get rid of all the head tags since we are populating them with the SEO component
    $('meta[content*="{{"]').remove();
    //
    // padd as per https://stackoverflow.com/questions/11124777/twitter-bootstrap-navbar-fixed-top-overlapping-site
    $('head').append('');
    $('head').append('');

    $('.nav-link[href="https://plugins.jenkins.io/"]').attr('href', '/');
    $('#grid-box').empty();
    $('#grid-box').append('{children}');
    if (process.env.NETLIFY) {
        $('#footer .col-md-4').prepend('

');
    }
    $('#footer .col-md-4').prepend('<ReportAProblem />');
    $('#creativecommons').append('<SiteVersion />');
    $('link[rel="stylesheet"]').each((_, elm) => {
        elm = $(elm);
        cssLines.push(`@import url('${elm.attr('href')}');`);
        elm.remove();
    });
    $('.searchbox').remove();
    $('script[src*="docsearch"]').remove();
    $('script:contains("docsearch")').remove();
    $('script:contains("google-analytics.com")').remove();

    const keyConversion = {
        class: 'className',
        'charSet': 'charset',
        'http-equiv': 'httpEquiv',
        'stop-color': 'stopColor',
        'crossorigin': 'crossOrigin'
    };

    const handleNode = (node, indent = 0) => {
        const prefix = ''.padStart(6+indent);

        if (node.name === 'link' && node.attribs && node.attribs.rel === 'stylesheet') {
            delete node.attribs.crossorigin;
            node.attribs.type = 'text/css';
            node.attribs.media = 'all';
        }
        const attrs = Object.entries(node.attribs || {}).map(([key, val]) => {
            key = keyConversion[key] || key;
            return `${key}=${JSON.stringify(val)}`;
        }).join(' ');
        if (node.name === 'script') {
            // FIXME - handle me
            const text = node.children.map(child => {
                if (child.type === 'text') {
                    return child.data;
                }
                throw new Error(`not sure how to handle ${child.type}`);
            });
            jsxLines.push(`${prefix}<${node.name} ${attrs} dangerouslySetInnerHTML={{__html: ${JSON.stringify(text)}}} />`);
            return;
        } else if (node.type === 'comment') {
            return;
        } else if (node.type === 'text') {
            const text = node.data.replace('\u00A0', ' ');
            jsxLines.push(`${prefix}${text}`);
        } else if (node.children && node.children.length) {
            jsxLines.push(`${prefix}<${node.name} ${attrs}>`);
            node.children.forEach(child => handleNode(child, indent+2));
            jsxLines.push(`${prefix}</${node.name}>`);
        } else {
            let tempAttrs = attrs;

            if (!node.name) {
                console.log(node);
            }
            if (node.name === 'siteversion') {
                node.name = 'SiteVersion';
            } else if (node.name === 'reportaproblem') {
                tempAttrs = 'reportProblemUrl={reportProblemUrl} reportProblemTitle={reportProblemTitle} reportProblemRelativeSourcePath={reportProblemRelativeSourcePath}';
                node.name = 'ReportAProblem';
            }
            jsxLines.push(`${prefix}<${node.name} ${tempAttrs} />`);
        }
    };

    jsxLines.push('export default function Layout({ children, id, reportProblemUrl, reportProblemTitle, reportProblemRelativeSourcePath}) {');
    jsxLines.push('  return (');
    jsxLines.push('
');
    jsxLines.push('      <Helmet>');
    $('head').children(':not(link[rel="stylesheet"])').each((_, child) => handleNode(child, 2));
    $('head').children('link[rel="stylesheet"]').each((_, child) => handleNode(child, 2));
    jsxLines.push('      </Helmet>');
    $('body').children().each((_, child) => handleNode(child, 0));
    jsxLines.push('
');
    jsxLines.push('  );');

    jsxLines.push('}');

    console.info(`Downloading site manifest file from '${manifestUrl}'`);
    const manifest = await axios
        .get(manifestUrl)
        .then((results) => {
            if (results.status !== 200) {
                throw results.data;
            }
            results.data.icons.forEach(icon => {
                icon.src = new URL(icon.src, manifestUrl).toString();
            });
            results.data.start_url = 'https://plugins.jenkins.io';
            return JSON.stringify(results.data);
        });

    return {
        manifest: manifest,
        jsxLines: jsxLines.map(str => str.trimEnd()).filter(Boolean).join('\n'),
        cssLines: cssLines.map(str => str.trimEnd()).filter(Boolean).join('\n')
    };
}

async function saveReactLayout({jsxLines, cssLines, manifest}) {
    if (manifest) {
        await fs.mkdir('static', {recursive: true});
        await fs.writeFile('./static/site.webmanifest', manifest);
    }
    if (jsxLines) {
        await fs.writeFile('./src/layout.jsx', jsxLines);
    }
    if (cssLines) {
        await fs.writeFile('./src/layout.css', cssLines);
    }
}

exports.makeReactLayout = makeReactLayout;
exports.saveReactLayout = saveReactLayout;

if (require.main === module) {
    makeReactLayout().then(saveReactLayout).catch(console.error);
}
<|endoftext|>


<commit_before>function pos_keyboard_widgets(instance, module){

    module.PosWidget.include({
        start: function() {
            self = this;
            res = this._super();
            res.done(function(e){
                self.pos.keypad.connect();
                self.pos.keypad.set_action_callback(function(data){
                     self.keypad_action(data, self.pos.keypad.type);
                 });
            });
            return res;
        },
        close: function() {
            this._super();
            this.pos.keypad.disconnect();
        },
        keypad_action: function(data, type){
             var numpad =  this.pos_widget.numpad;
             if (data.type === type.bmode) {
                 numpad.state.changeMode(data.val);
             }
             else if (data.type === type.sign){
                 numpad.clickSwitchSign();
             }
             else if (data.type === type.numchar){
                 numpad.state.appendNewChar(data.val);
             }
             else if (data.type === type.backspace){
                 numpad.clickDeleteLastChar();
             }
        },
    });

    module.NumpadWidget.include({
        init: function(parent, options) {
            this._super(parent, options);
            this.modeButton = {
                qty: 'quantity',
                disc: 'discount',
                price: 'price'
            }
        }
    });

    var PosModelSuper = module.PosModel;
    module.PosModel = module.PosModel.extend({
        initialize: function(session, attributes) {
            this.keypad = new module.Keypad({'pos': this});
            PosModelSuper.prototype.initialize.call(this, session, attributes);
          },
    });

    // this module mimics a keypad-only cash register. Use connect() and
    // disconnect() to activate and deactivate it.
    module.Keypad = instance.web.Class.extend({
        init: function(attributes){
            this.pos = attributes.pos;
            this.pos_widget = this.pos.pos_widget;
            this.type = {
                 numchar: 'number, dot',
                 bmode: 'qty, disc, price',
                 sign: '+, -',
                 backspace: 'backspace'
            }
            this.data = {
                type: undefined,
                val: undefined
            }
            this.action_callback = undefined;
        },

        save_callback: function(){
            this.saved_callback_stack.push(this.action_callback);
        },

        restore_callback: function(){
            if (this.saved_callback_stack.length > 0) {
                this.action_callback = this.saved_callback_stack.pop();
            }
        },

        set_action_callback: function(callback){
            this.action_callback = callback
        },

        //remove action callback
        reset_action_callback: function(){
            this.action_callback = undefined;
        },

        // starts catching keyboard events and tries to interpret keystrokes,
        // calling the callback when needed.
        connect: function(){
            var self = this;
            var KC_PLU = 107;      // KeyCode: Product Code (Keypad '+')
            var KC_QTY = 111;      // KeyCode: Quantity (Keypad '/')
            var KC_AMT = 106;      // KeyCode: Price (Keypad '*')
            var KC_DISC = 109;     // KeyCode: Discount Percentage [0..100] (Keypad '-')
            var KC_BACKSPACE = 8;  // KeyCode: Backspace (Keypad 'backspace')
            var kc_lookup = {
                96: '0', 97: '1', 98: '2',  99: '3', 100: '4',
                101: '5', 102: '6', 103: '7', 104: '8', 105: '9',
                106: '*', 107: '+', 109: '-', 110: '.', 111: '/',
            };

            //cancel return to the previous page when press backspace
            var rx = /INPUT|SELECT|TEXTAREA/i;
            $(document).bind("keydown keypress", function(e){
                if( e.which == 8 ){ // 8 == backspace
                    if(!rx.test(e.target.tagName) || e.target.disabled || e.target.readOnly ){
                        e.preventDefault();
                    }
                }
            });

            //usb keyboard keyup event
            $('body').delegate('','keyup', function (e){
                var type = self.type;
                var buttonMode = self.pos.pos_widget.numpad.modeButton
                token = e.keyCode;
                if ((token >= 96 && token <= 111) || token === KC_PLU  || token === KC_QTY || token === KC_AMT) {

                    if (token === KC_PLU) {
                        self.data.type = type.sign;
                    } else if (token === KC_QTY) {
                        self.data.type = type.bmode;
                        self.data.val = buttonMode.qty
                    } else if (token === KC_AMT) {
                        self.data.type = type.bmode;
                        self.data.val = buttonMode.price;
                    } else if (token === KC_DISC) {
                        self.data.type = type.bmode;
                        self.data.val = buttonMode.disc;
                    } else {
                        self.data.type = type.numchar;
                        self.data.val = kc_lookup[token];
                    }

                    self.action_callback(self.data);

                } else if (token === KC_BACKSPACE && !rx.test(e.target.tagName)) {
                    self.data.type = type.backspace;
                    self.action_callback(self.data);
                }
            });
        },

        // stops catching keyboard events
        disconnect: function(){
            $('body').undelegate('', 'keyup')
        },
    });
}

(function(){
    var _super = window.openerp.point_of_sale;
    window.openerp.point_of_sale = function(instance){
        _super(instance);
        var module = instance.point_of_sale;
        pos_keyboard_widgets(instance, module);
    }
})()
<commit_msg>1. added support for basic keyboard 2. handling has been omitted in input<commit_after>function pos_keyboard_widgets(instance, module){

    module.PosWidget.include({
        start: function() {
            self = this;
            resSuper = this._super();
            res = resSuper.done(function(e){
                self.pos.keypad.connect();
                self.pos.keypad.set_action_callback(function(data){
                     self.keypad_action(data, self.pos.keypad.type);
                 });
            });
            return res;
        },
        close: function() {
            this._super();
            this.pos.keypad.disconnect();
        },
        keypad_action: function(data, type){
             var numpad =  this.pos_widget.numpad;
             if (data.type === type.numchar){
                 numpad.state.appendNewChar(data.val);
             }
             else if (data.type === type.bmode) {
                 numpad.state.changeMode(data.val);
             }
             else if (data.type === type.sign){
                 numpad.clickSwitchSign();
             }
             else if (data.type === type.backspace){
                 numpad.clickDeleteLastChar();
             }
        },
    });

    module.NumpadWidget.include({
        init: function(parent, options) {
            this._super(parent, options);
            this.modeButton = {
                qty: 'quantity',
                disc: 'discount',
                price: 'price'
            }
        }
    });

    var PosModelSuper = module.PosModel;
    module.PosModel = module.PosModel.extend({
        initialize: function(session, attributes) {
            this.keypad = new module.Keypad({'pos': this});
            PosModelSuper.prototype.initialize.call(this, session, attributes);
          },
    });

    // this module mimics a keypad-only cash register. Use connect() and
    // disconnect() to activate and deactivate it.
    module.Keypad = instance.web.Class.extend({
        init: function(attributes){
            this.pos = attributes.pos;
            this.pos_widget = this.pos.pos_widget;
            this.type = {
                 numchar: 'number, dot',
                 bmode: 'qty, disc, price',
                 sign: '+, -',
                 backspace: 'backspace'
            }
            this.data = {
                type: undefined,
                val: undefined
            }
            this.action_callback = undefined;
        },

        save_callback: function(){
            this.saved_callback_stack.push(this.action_callback);
        },

        restore_callback: function(){
            if (this.saved_callback_stack.length > 0) {
                this.action_callback = this.saved_callback_stack.pop();
            }
        },

        set_action_callback: function(callback){
            this.action_callback = callback
        },

        //remove action callback
        reset_action_callback: function(){
            this.action_callback = undefined;
        },

        // starts catching keyboard events and tries to interpret keystrokes,
        // calling the callback when needed.
        connect: function(){
            var self = this;
            // --- additional keyboard ---//
            var KC_PLU = 107;      // KeyCode: + or - (Keypad '+')
            var KC_QTY = 111;      // KeyCode: Quantity (Keypad '/')
            var KC_AMT = 106;      // KeyCode: Price (Keypad '*')
            var KC_DISC = 109;     // KeyCode: Discount Percentage [0..100] (Keypad '-')
            // --- basic keyboard --- //
            var KC_PLU_1 = 83;    // KeyCode: sign + or - (Keypad 's')
            var KC_QTY_1 = 81;     // KeyCode: Quantity (Keypad 'q')
            var KC_AMT_1 = 80;     // KeyCode: Price (Keypad 'p')
            var KC_DISC_1 = 68;    // KeyCode: Discount Percentage [0..100] (Keypad 'd')

            var KC_BACKSPACE = 8;  // KeyCode: Backspace (Keypad 'backspace')
            var kc_lookup = {
                48: '0', 49: '1', 50: '2',  51: '3', 52: '4',
                53: '5', 54: '6', 55: '7', 56: '8', 57: '9',
                80: 'p', 83: 's', 68: 'd', 190: '.', 81: 'q',
                96: '0', 97: '1', 98: '2',  99: '3', 100: '4',
                101: '5', 102: '6', 103: '7', 104: '8', 105: '9',
                106: '*', 107: '+', 109: '-', 110: '.', 111: '/',
            };

            //cancel return to the previous page when press backspace
            var rx = /INPUT|SELECT|TEXTAREA/i;
            $(document).bind("keydown keypress", function(e){
                if( e.which == 8 ){ // 8 == backspace
                    if(!rx.test(e.target.tagName) || e.target.disabled || e.target.readOnly ){
                        e.preventDefault();
                    }
                }
            });

            //usb keyboard keyup event
            $('body').delegate('','keyup', function (e){
                var statusHandler  =  !rx.test(e.target.tagName)  ||
                    e.target.disabled || e.target.readOnly;
                if (statusHandler){
                    var ok =false;
                    var type = self.type;
                    var buttonMode = self.pos.pos_widget.numpad.modeButton
                    token = e.keyCode;
                    if ((token >= 96 && token <= 105 || token == 110) ||
                        (token >= 48 && token <= 57 || token == 190)) {
                            self.data.type = type.numchar;
                            self.data.val = kc_lookup[token];
                            ok = true;
                    }
                    else if (token == KC_PLU || token == KC_PLU_1) {
                        self.data.type = type.sign;
                        ok = true;
                    }
                    else if (token == KC_QTY || token == KC_QTY_1) {
                        self.data.type = type.bmode;
                        self.data.val = buttonMode.qty
                        ok = true;
                    }
                    else if (token == KC_AMT || token == KC_AMT_1) {
                        self.data.type = type.bmode;
                        self.data.val = buttonMode.price;
                        ok = true;
                    }
                    else if (token == KC_DISC || token == KC_DISC_1) {
                        self.data.type = type.bmode;
                        self.data.val = buttonMode.disc;
                        ok = true;
                    }
                    else if (token == KC_BACKSPACE) {
                        self.data.type = type.backspace;
                        self.action_callback(self.data);
                        ok = true;
                    }
                    if (ok) {self.action_callback(self.data);}
                }
            });
        },

        // stops catching keyboard events
        disconnect: function(){
            $('body').undelegate('', 'keyup')
        },
    });
}

(function(){
    var _super = window.openerp.point_of_sale;
    window.openerp.point_of_sale = function(instance){
        _super(instance);
        var module = instance.point_of_sale;
        pos_keyboard_widgets(instance, module);
    }
})()
<|endoftext|>