<commit_before>import {Schema} from "prosemirror-model"

// ::Schema Document schema for the data model used by CommonMark.
export const schema = new Schema({
  nodes: {
    doc: {
      content: "block+"
    },

    paragraph: {
      content: "inline*",
      group: "block",
      parseDOM: [{tag: "p"}],
      toDOM() { return ["p", 0] }
    },

    blockquote: {
      content: "block+",
      group: "block",
      parseDOM: [{tag: "blockquote"}],
      toDOM() { return ["blockquote", 0] }
    },

    horizontal_rule: {
      group: "block",
      parseDOM: [{tag: "hr"}],
      toDOM() { return ["div", ["hr"]] }
    },

    heading: {
      attrs: {level: {default: 1}},
      content: "inline*",
      group: "block",
      defining: true,
      parseDOM: [{tag: "h1", attrs: {level: 1}},
                 {tag: "h2", attrs: {level: 2}},
                 {tag: "h3", attrs: {level: 3}},
                 {tag: "h4", attrs: {level: 4}},
                 {tag: "h5", attrs: {level: 5}},
                 {tag: "h6", attrs: {level: 6}}],
      toDOM(node) { return ["h" + node.attrs.level, 0] }
    },

    code_block: {
      content: "text*",
      group: "block",
      code: true,
      defining: true,
      attrs: {params: {default: ""}},
      parseDOM: [{tag: "pre", preserveWhitespace: true, getAttrs: node => (
        {params: node.getAttribute("data-params") || ""}
      )}],
      toDOM(node) { return ["pre", node.attrs.params ? {"data-params": node.attrs.params} : {}, ["code", 0]] }
    },

    ordered_list: {
      content: "list_item+",
      group: "block",
      attrs: {order: {default: 1}, tight: {default: false}},
      parseDOM: [{tag: "ol", getAttrs(dom) {
        return {order: dom.hasAttribute("start") ? +dom.getAttribute("start") : 1,
                tight: dom.hasAttribute("data-tight")}
      }}],
      toDOM(node) {
        return ["ol", {start: node.attrs.order == 1 ? null : node.attrs.order,
                       "data-tight": node.attrs.tight ? "true" : null}, 0]
      }
    },

    bullet_list: {
      content: "list_item+",
      group: "block",
      attrs: {tight: {default: false}},
      parseDOM: [{tag: "ul", getAttrs: dom => ({tight: dom.hasAttribute("data-tight")})}],
      toDOM(node) { return ["ul", {"data-tight": node.attrs.tight ? "true" : null}, 0] }
    },

    list_item: {
      content: "paragraph block*",
      defining: true,
      parseDOM: [{tag: "li"}],
      toDOM() { return ["li", 0] }
    },

    text: {
      group: "inline",
      toDOM(node) { return node.text }
    },

    image: {
      inline: true,
      attrs: {
        src: {},
        alt: {default: null},
        title: {default: null}
      },
      group: "inline",
      draggable: true,
      parseDOM: [{tag: "img[src]", getAttrs(dom) {
        return {
          src: dom.getAttribute("src"),
          title: dom.getAttribute("title"),
          alt: dom.getAttribute("alt")
        }
      }}],
      toDOM(node) { return ["img", node.attrs] }
    },

    hard_break: {
      inline: true,
      group: "inline",
      selectable: false,
      parseDOM: [{tag: "br"}],
      toDOM() { return ["br"] }
    }
  },

  marks: {
    em: {
      parseDOM: [{tag: "i"}, {tag: "em"},
                 {style: "font-style", getAttrs: value => value == "italic" && null}],
      toDOM() { return ["em"] }
    },

    strong: {
      parseDOM: [{tag: "b"}, {tag: "strong"},
                 {style: "font-weight", getAttrs: value => /^(bold(er)?|[5-9]\d{2,})$/.test(value) && null}],
      toDOM() { return ["strong"] }
    },

    link: {
      attrs: {
        href: {},
        title: {default: null}
      },
      inclusive: false,
      parseDOM: [{tag: "a[href]", getAttrs(dom) {
        return {href: dom.getAttribute("href"), title: dom.getAttribute("title")}
      }}],
      toDOM(node) { return ["a", node.attrs] }
    },

    code: {
      parseDOM: [{tag: "code"}],
      toDOM() { return ["code"] }
    }
  }
})
<commit_msg>Fix some aspects of the schema<commit_after>import {Schema} from "prosemirror-model"

// ::Schema Document schema for the data model used by CommonMark.
export const schema = new Schema({
  nodes: {
    doc: {
      content: "block+"
    },

    paragraph: {
      content: "inline*",
      group: "block",
      parseDOM: [{tag: "p"}],
      toDOM() { return ["p", 0] }
    },

    blockquote: {
      content: "block+",
      group: "block",
      parseDOM: [{tag: "blockquote"}],
      toDOM() { return ["blockquote", 0] }
    },

    horizontal_rule: {
      group: "block",
      parseDOM: [{tag: "hr"}],
      toDOM() { return ["div", ["hr"]] }
    },

    heading: {
      attrs: {level: {default: 1}},
      content: "inline*",
      group: "block",
      defining: true,
      parseDOM: [{tag: "h1", attrs: {level: 1}},
                 {tag: "h2", attrs: {level: 2}},
                 {tag: "h3", attrs: {level: 3}},
                 {tag: "h4", attrs: {level: 4}},
                 {tag: "h5", attrs: {level: 5}},
                 {tag: "h6", attrs: {level: 6}}],
      toDOM(node) { return ["h" + node.attrs.level, 0] }
    },

    code_block: {
      content: "text*",
      group: "block",
      code: true,
      defining: true,
      marks: "",
      attrs: {params: {default: ""}},
      parseDOM: [{tag: "pre", preserveWhitespace: "full", getAttrs: node => (
        {params: node.getAttribute("data-params") || ""}
      )}],
      toDOM(node) { return ["pre", node.attrs.params ? {"data-params": node.attrs.params} : {}, ["code", 0]] }
    },

    ordered_list: {
      content: "list_item+",
      group: "block",
      attrs: {order: {default: 1}, tight: {default: false}},
      parseDOM: [{tag: "ol", getAttrs(dom) {
        return {order: dom.hasAttribute("start") ? +dom.getAttribute("start") : 1,
                tight: dom.hasAttribute("data-tight")}
      }}],
      toDOM(node) {
        return ["ol", {start: node.attrs.order == 1 ? null : node.attrs.order,
                       "data-tight": node.attrs.tight ? "true" : null}, 0]
      }
    },

    bullet_list: {
      content: "list_item+",
      group: "block",
      attrs: {tight: {default: false}},
      parseDOM: [{tag: "ul", getAttrs: dom => ({tight: dom.hasAttribute("data-tight")})}],
      toDOM(node) { return ["ul", {"data-tight": node.attrs.tight ? "true" : null}, 0] }
    },

    list_item: {
      content: "paragraph block*",
      defining: true,
      parseDOM: [{tag: "li"}],
      toDOM() { return ["li", 0] }
    },

    text: {
      group: "inline"
    },

    image: {
      inline: true,
      attrs: {
        src: {},
        alt: {default: null},
        title: {default: null}
      },
      group: "inline",
      draggable: true,
      parseDOM: [{tag: "img[src]", getAttrs(dom) {
        return {
          src: dom.getAttribute("src"),
          title: dom.getAttribute("title"),
          alt: dom.getAttribute("alt")
        }
      }}],
      toDOM(node) { return ["img", node.attrs] }
    },

    hard_break: {
      inline: true,
      group: "inline",
      selectable: false,
      parseDOM: [{tag: "br"}],
      toDOM() { return ["br"] }
    }
  },

  marks: {
    em: {
      parseDOM: [{tag: "i"}, {tag: "em"},
                 {style: "font-style", getAttrs: value => value == "italic" && null}],
      toDOM() { return ["em"] }
    },

    strong: {
      parseDOM: [{tag: "b"}, {tag: "strong"},
                 {style: "font-weight", getAttrs: value => /^(bold(er)?|[5-9]\d{2,})$/.test(value) && null}],
      toDOM() { return ["strong"] }
    },

    link: {
      attrs: {
        href: {},
        title: {default: null}
      },
      inclusive: false,
      parseDOM: [{tag: "a[href]", getAttrs(dom) {
        return {href: dom.getAttribute("href"), title: dom.getAttribute("title")}
      }}],
      toDOM(node) { return ["a", node.attrs] }
    },

    code: {
      parseDOM: [{tag: "code"}],
      toDOM() { return ["code"] }
    }
  }
})
<|endoftext|>


<commit_before>'use strict';
var _ = require('lodash');
var loremIpsum = require('lorem-ipsum');
var Mockjs = require('mockjs');
var MockRandom = Mockjs.Random;
var formatMocker = require('./format');

var DataMocker = function (schema) {
    return Mockers._mocker(schema);
};

var Mockers = {

    _mocker: function (schema) {
        if (schema.enum && schema.enum.length > 0) {
            return schema.enum[_.random(0, schema.enum.length - 1)];
        } else if (schema.format) {
            var format = schema.format.toLowerCase();
            var formatRet = formatMocker(format, schema);

            if (formatRet !== undefined) {
                return formatRet;
            }
        } else if (schema.allOf || schema.anyOf || schema.oneOf || schema.not) {
            // TODO
            return undefined;
        } else if (schema.type) {
            var type = schema.type.toLowerCase();
            if (_.isArray(type)) {
                type = type[0].toLowerCase();
            }
            if (typeof (this[type + 'Mocker']) !== 'undefined') {
                var ret = this[type + 'Mocker'](schema);
                return ret;
            } else {
                return undefined;
            }
        } else {
            return undefined;
        }
    },

    objectMocker: function (schema) {
        var ret = {};
        var self = this;
        /**
         * maxProperties
         * minProperties
         * required
         * additionalProperties, properties and patternProperties
         * dependences
         */
        if (schema.properties) {
            _.each(schema.properties, function (value, key) {
                ret[key] = self._mocker(value);
            });
        }
        return ret;
    },

    arrayMocker: function (schema) {
        var ret = [];
        var self = this;
        /**
         * additionalItems and items
         * maxItems
         * minItems
         * uniqueItems
         */
        if (_.isArray(schema.items)) {
            _.each(schema.items, function (item) {
                ret.push(self._mocker(item));
            });
        } else if (_.isObject(schema.items)) {
            var size = _.random(schema.minItems || 1, schema.maxItems || 5);
            _.times(size, function () {
                ret.push(self._mocker(schema.items));
            });
        }
        return ret;
    },

    stringMocker: function (schema) {
        /**
         * maxLength
         * minLength
         * enum
         * pattern
         * @type {string}
         */
        var ret = null;
        var strLen = MockRandom.integer(schema.minLength || 1, schema.maxLength || ((schema.minLength || 0) < 50 ? 50 : schema.minLength));
        ret = loremIpsum({
            count: strLen
        }).substring(0, strLen).trim();
        return ret;
    },

    /**
     * @param number
     * @param len
     * @private
     */
    _toFloat: function (number, len) {
        var num = String(number);
        var dotIndex = num.indexOf('.');
        if (dotIndex > 0) {
            num = num.substring(0, dotIndex + len + 1);
        }
        return parseFloat(num);
    },

    /**
     * @param num
     * @returns {number}
     * @private
     */
    _getMinFloat: function (num) {
        var ret = /\.(0*)\d*$/.exec(num);
        return ret ? ret[1].length + 1 : 1;
    },

    /**
     * @param schema
     * @param {Boolean} floating
     * @returns {null}
     * @private
     */
    _numberMocker: function (schema, floating) {
        var ret = null;
        /**
         * multipleOf
         * maximum and exclusiveMaximum
         * minimum and exclusiveMinimum
         */
        if (schema.multipleOf) {
            var multipleMin = 1;
            var multipleMax = 5;

            if (schema.maximum !== undefined) {
                if ((schema.maximum === schema.multipleOf && !schema.exclusiveMaximum) || (schema.maximum > schema.multipleOf)) {
                    multipleMax = Math.floor(schema.maximum / schema.multipleOf);
                } else {
                    multipleMin = 0;
                    multipleMax = 0;
                }
            }
            ret = schema.multipleOf * MockRandom.integer(multipleMin, multipleMax);
        } else {
            var minimum = schema.minimum || 0;
            var maximum = schema.maximum || 9999;
            var gap = maximum - minimum;
            /**
             *  - min: 0.000006
             *  - max: 0.000009
             */
            var minFloat = this._getMinFloat(minimum);
            minFloat = minFloat < this._getMinFloat(maximum) ? this._getMinFloat(maximum) : minFloat;
            var maxFloat = minFloat + _.random(0, 2);
            var littleGap = this._toFloat(_.random(0, gap, floating), _.random(minFloat, maxFloat)) / 10;
            ret = this._toFloat(_.random(minimum, maximum, floating), _.random(minFloat, maxFloat));
            if (ret === schema.maximum && schema.exclusiveMaximum) {
                ret -= littleGap;
            }
            if (ret === schema.minimum && schema.exclusiveMinimum) {
                ret += littleGap;
            }
        }
        return ret;
    },

    numberMocker: function (schema) {
        return this._numberMocker(schema, true);
    },

    integerMocker: function (schema) {
        return this._numberMocker(schema, false);
    },

    booleanMocker: function (schema) {
        return MockRandom.boolean();
    },

    nullMocker: function (schema) {
        return null;
    }
};

module.exports = DataMocker;
<commit_msg>Refactor of schema. Now allows a schema and formats<commit_after>'use strict';
var _ = require('lodash');
var loremIpsum = require('lorem-ipsum');
var Mockjs = require('mockjs');
var MockRandom = Mockjs.Random;
var FormatMocker = require('./format');

var DataMocker = function (schema, formats) {
    var formatMocker = new FormatMocker(formats);
    var mocker = new Mocker();
    mocker.formatMocker = formatMocker;
    return mocker._mocker(schema);
};

var Mocker = function () {
    return {
        _mocker: function (schema) {
            if (schema.enum && schema.enum.length > 0) {
                return schema.enum[_.random(0, schema.enum.length - 1)];
            } else if (schema.format) {
                var format = schema.format.toLowerCase();
                var formatRet = this.formatMocker.format(format, schema);
                if (formatRet !== undefined) {
                    return formatRet;
                }
            } else if (schema.allOf || schema.anyOf || schema.oneOf || schema.not) {
                // TODO
                return undefined;
            } else if (schema.type) {
                var type = schema.type.toLowerCase();
                if (_.isArray(type)) {
                    type = type[0].toLowerCase();
                }
                if (typeof (this[type + 'Mocker']) !== 'undefined') {
                    var ret = this[type + 'Mocker'](schema);
                    return ret;
                } else {
                    return undefined;
                }
            } else {
                return undefined;
            }
        },

        objectMocker: function (schema) {
            var ret = {};
            var self = this;
            /**
             * maxProperties
             * minProperties
             * required
             * additionalProperties, properties and patternProperties
             * dependences
             */
            if (schema.properties) {
                _.each(schema.properties, function (value, key) {
                    ret[key] = self._mocker(value);
                });
            }
            return ret;
        },

        arrayMocker: function (schema) {
            var ret = [];
            var self = this;
            /**
             * additionalItems and items
             * maxItems
             * minItems
             * uniqueItems
             */
            if (_.isArray(schema.items)) {
                _.each(schema.items, function (item) {
                    ret.push(self._mocker(item));
                });
            } else if (_.isObject(schema.items)) {
                var size = _.random(schema.minItems || 1, schema.maxItems || 5);
                _.times(size, function () {
                    ret.push(self._mocker(schema.items));
                });
            }
            return ret;
        },

        stringMocker: function (schema) {
            /**
             * maxLength
             * minLength
             * enum
             * pattern
             * @type {string}
             */
            var ret = null;
            var strLen = MockRandom.integer(schema.minLength || 1, schema.maxLength || ((schema.minLength || 0) < 50 ? 50 : schema.minLength));
            ret = loremIpsum({
                count: strLen
            }).substring(0, strLen).trim();
            return ret;
        },

        /**
         * @param number
         * @param len
         * @private
         */
        _toFloat: function (number, len) {
            var num = String(number);
            var dotIndex = num.indexOf('.');
            if (dotIndex > 0) {
                num = num.substring(0, dotIndex + len + 1);
            }
            return parseFloat(num);
        },

        /**
         * @param num
         * @returns {number}
         * @private
         */
        _getMinFloat: function (num) {
            var ret = /\.(0*)\d*$/.exec(num);
            return ret ? ret[1].length + 1 : 1;
        },

        /**
         * @param schema
         * @param {Boolean} floating
         * @returns {null}
         * @private
         */
        _numberMocker: function (schema, floating) {
            var ret = null;
            /**
             * multipleOf
             * maximum and exclusiveMaximum
             * minimum and exclusiveMinimum
             */
            if (schema.multipleOf) {
                var multipleMin = 1;
                var multipleMax = 5;

                if (schema.maximum !== undefined) {
                    if ((schema.maximum === schema.multipleOf && !schema.exclusiveMaximum) || (schema.maximum > schema.multipleOf)) {
                        multipleMax = Math.floor(schema.maximum / schema.multipleOf);
                    } else {
                        multipleMin = 0;
                        multipleMax = 0;
                    }
                }
                ret = schema.multipleOf * MockRandom.integer(multipleMin, multipleMax);
            } else {
                var minimum = schema.minimum || 0;
                var maximum = schema.maximum || 9999;
                var gap = maximum - minimum;
                /**
                 *  - min: 0.000006
                 *  - max: 0.000009
                 */
                var minFloat = this._getMinFloat(minimum);
                minFloat = minFloat < this._getMinFloat(maximum) ? this._getMinFloat(maximum) : minFloat;
                var maxFloat = minFloat + _.random(0, 2);
                var littleGap = this._toFloat(_.random(0, gap, floating), _.random(minFloat, maxFloat)) / 10;
                ret = this._toFloat(_.random(minimum, maximum, floating), _.random(minFloat, maxFloat));
                if (ret === schema.maximum && schema.exclusiveMaximum) {
                    ret -= littleGap;
                }
                if (ret === schema.minimum && schema.exclusiveMinimum) {
                    ret += littleGap;
                }
            }
            return ret;
        },

        numberMocker: function (schema) {
            return this._numberMocker(schema, true);
        },

        integerMocker: function (schema) {
            return this._numberMocker(schema, false);
        },

        booleanMocker: function (schema) {
            return MockRandom.boolean();
        },

        nullMocker: function (schema) {
            return null;
        }
    };
};

module.exports = DataMocker;
<|endoftext|>


<commit_before>/*                ORIGINAL WebApp
 https://io.datasync.orange.com/samples/legorange/ */
require('../assets/styles/app.scss');
require('../assets/styles/style.css');

var webcom = require('./webcom_fct.js'),
    init   = require('./init.js'),
    ev     = require('./events.js');

var drawspace = $(".drawspace"),
    btn_dezoom = $("#btn_dezoom"),
    eraseAll = $("#eraseAll"),
    btn_panel = $('#btn_panel'),
    panel = $('#overlayPanel'),
    mode = "draw",
    topHeight,
    last_move="",
    smartphone,
    last_scale,
    scale = 0.5,
    last_posX = 0,
    last_posY = 0;

module.exports.mode = mode;

var bricksize = webcom.bricksize;
//var mode = webcom.mode;

$(window).on('beforeunload', function(){
  $(window).scrollTop(0);
  $(window).scrollLeft(0);
});

  // $(document).on('swipe', function(e) {
  //   e.stopPropagation();
  //   e.preventDefault();
  // });

$(window).on("load", function (){

  $(document).foundation();

  // Initialisation globale du contexte
  globalInit();

  //drawspace scale from 2 to 1
  btn_dezoom.on('click', function(){
    var offX, offY, scale;

    offY = ($('body').scrollTop()/4) - (window.innerHeight/2);
    offX = ($('body').scrollLeft()/4) - (window.innerWidth/2);
    // console.log("------------------");
    // console.log('offX = ' + offX);
    // console.log('offY = ' + offY);

    scale = 0.5;

    dezoom(offX, offY, scale);
  });

  $(window).resize(function() {
     //globalInit();
     // location.reload();
   });

  // $(function() {
  //   $("body").swipe( {
  //     swipeStatus:function(event, phase, direction, distance , duration , fingerCount) {
  //       if(phase === $.fn.swipe.phases.PHASE_END || phase === $.fn.swipe.phases.PHASE_CANCEL) {
  //         //The handlers below fire after the status,
  //         // so we can change the text here, and it will be replaced if the handlers below fire
  //         $(this).find('#swipe_text').text("No swipe was made");
  //       }
  //     },
  //     swipeLeft:function(event, direction, distance, duration, fingerCount) {
  //       if (fingerCount == 1 && duration < 250) {
  //         console.log("swipeLeft");
  //         panel.open();
  //       }
  //     },
  //     swipeRight:function(event, direction, distance, duration, fingerCount) {
  //       if (fingerCount == 1) {
  //         offCanvas.foundation('close');
  //       }
  //     },
  //     fingers:$.fn.swipe.fingers.ALL
  //   });
  // });

  /* Supprime toutes les briques du drawspace */
  eraseAll.click(function() {
    webcom.eraseAll();
  });

  drawspace.on('mousedown', function(e){
    if (smartphone === 0) {
      if (e.defaultPrevented ) return;

      var handlers = {
        mousemove : function(e){
          if (e.defaultPrevented ) return;
          x=parseInt((e.pageX - drawspace.offset().left) / bricksize);
          y=parseInt((e.pageY - drawspace.offset().top) / bricksize);

          var new_move = x + "-" + y;

          // Disable brick overflow outside drawspace
          if (new_move!=last_move && e.pageX < drawspace.width() && e.pageY < (drawspace.height() + topHeight) && e.pageX > 0 && e.pageY > 0) {
            webcom.updatePos(x,y);
          }
          last_move=new_move;
        },
        mouseup : function(e){
          $(this).off(handlers);
        }
      };
      $(document).on(handlers);
    }
  });

  /* Gère le click simple (ajout/suppression de briques) sur le drawspace  */
  drawspace.bind("click", function(e){
    var x,y;
    var clickX = e.pageX;
    var clickY = e.pageY; // we remove the top-bar height

    // (if no mobile device)
    if (smartphone === 0) {
      x=parseInt((clickX - drawspace.offset().left) / bricksize);
      y=parseInt((clickY - drawspace.offset().top) / bricksize);
      webcom.updatePos(x,y);
    } else { // (mobile device)
      if (panel.hasClass('ui-panel-open') === true) {
        if (e.defaultPrevented ) return;
        panel.panel("close");
        btn_dezoom.show();
        $('html').removeClass('hideOverflow').addClass('showOverflow');
      } else {

        // Add brick if draw mode
        if (scale === 2) {
          x=parseInt(((clickX - drawspace.offset().left) / bricksize)/2);
          y=parseInt(((clickY - drawspace.offset().top) / bricksize)/2);
          webcom.updatePos(x,y);
        }

        if (scale === 0.5) {

          last_scale = 0.5;
          scale = 2;

          var scrollX,
              scrollY,
              viewpWidth = window.innerWidth/3.5,
              viewpHeight = window.innerHeight/3.5,
              overflowX = e.clientX - viewpWidth,
              overflowY = e.clientY - viewpHeight,
              offX = $('body').scrollLeft(),
              offY = $('body').scrollTop() ;

          scrollX = (clickX + overflowX + offX)*2;
          scrollY = (clickY + overflowY + offY)*2;

          // console.log('viewpWidth = ' + viewpWidth);
          // console.log('viewpHeight = ' + viewpHeight);
          // console.log('e.clientX = ' + e.clientX);
          // console.log('e.clientY = ' + e.clientY);
          // console.log('e.pageX = ' + e.pageX);
          // console.log('e.pageY = ' + e.pageY);
          // console.log('overflowX = ' + overflowX);
          // console.log('overflowY = ' + overflowY);
          // console.log('offX = ' + offX);
          // console.log('offY = ' + offY);

          btn_dezoom.show();

          transcale(scrollX, scrollY, scale);
        }
      }
    }
  });
 });

/* Effectue une translation et un scale sur le drawspace */
function transcale (x, y, sc) {
  drawspace.css('margin-top', topHeight);
  drawspace.css('transform', "scale(" + sc + ")");
  if (sc === 0.5) {
    $('div[data-role="main"]').height(2490);
    $('div[data-role="main"]').width(2490);
    document.querySelector('meta[name=viewport]').setAttribute('content', "width=device-width, height=device-height, initial-scale=1, user-scalable=no");
    $('body').scrollLeft(x);
    $('body').scrollTop(y);
  } else {
    $('div[data-role="main"]').height(4980);
    $('div[data-role="main"]').width(4980);
    document.querySelector('meta[name=viewport]').setAttribute('content', "width=device-width, height=device-height, initial-scale=1, user-scalable=no");
    $('body').scrollLeft(x);
    $('body').scrollTop(y);
  }
}

/* Initialisation du contexte global (interface) */
function globalInit() {

  //$('.topbar').css('height', '10vh');

  topHeight = $('.topbar').outerHeight();
  var panel = $('[data-role=panel]').height();
  var panelheight = topHeight - panel;
  var panelwidth = '330px';

  $('.ui-panel').css({
    'top': topHeight,
    'min-height' : 'none !important',
    'width': panelwidth,
    'background' : 'black',
    'text-shadow' : '0 0 0',
    'overflow' : 'auto'
  });

  $("div").removeClass('ui-panel-dismiss');
  $('a').removeClass('ui-link');

  btn_dezoom.removeClass().addClass('dezoom');

  // = 1 si mobile, 0 sinon
  smartphone = init.detectDevice();

  btn_dezoom.hide();
  drawspace.css('margin-top', topHeight);

  var btn_menuicon = $('.menu-icon').height();
  var menutitle = $('.top-bar-title').height();
  var margin_menuicon = ($('.topbar').height() - btn_menuicon)/2;
  var margin_menutitle = ($('.topbar').height() - menutitle)/2;
  $('.menu-icon').css('margin-top', margin_menuicon +'px');
  $('.top-bar-title').css('margin-top', margin_menutitle +'px');
  $('.ui-page-theme-a').css('text-shadow', '0 0 0');

  /* Disable Ctrl+mouseWheel zoom on cross-browser */
  $(window).bind('mousewheel DOMMouseScroll', function (event) {
    if (event.ctrlKey === true) {
      if (event.defaultPrevented ) return;
    }
  });

  // Initialisation of the drawspace's brick size
  initBrickSize(bricksize+"px");

  if (smartphone === 1) {
    transcale(0, 0, 0.5);
  } else {
    transcale(0, 0, 1);
    $('#overlayPanel').panel('open');
    $('.qrcode').qrcode({text:'https://simonbaumannpro.github.io/legorange3.0/', width: 200, height:200 });
  }
}

/* Dezoom le drawspace à son état initial */
function dezoom(x, y, sc) {

  transcale(x, y, sc);

  last_scale = 2;
  scale = 0.5;

  btn_dezoom.hide();
}

/* set the size of the drawspace's background */
function initBrickSize(size) {
  drawspace.css('background-size', size + " " + size);
}

/* Désactive le scroll quand le panel est ouvert */
btn_panel.click(function() {
  if (smartphone === 1)
    ev.disableScroll(scale);
});

/* gère la surbrillance d'une couleur active */
$(".brickMenu").click(function() {
  ev.color_active($(this));
});

/* empèche l'affichage des couleurs lors du déroulement de la liste si on est en mode "erase" */
$("#menu-DT").click(ev.hide_colors());

$('.menu-title').click(function() {
  $('#menu-DT').css('color','#ff7900');
});

$(".mode").click(function(e){
  module.exports.mode = ev.change_mode($(this).attr("id"));
});<commit_msg>code review<commit_after>/*                ORIGINAL WebApp
 https://io.datasync.orange.com/samples/legorange/ */
require('../assets/styles/app.scss');
require('../assets/styles/style.css');

var webcom = require('./webcom_fct.js'),
    init   = require('./init.js'),
    ev     = require('./events.js');

var drawspace = $(".drawspace"),
    btn_dezoom = $("#btn_dezoom"),
    eraseAll = $("#eraseAll"),
    btn_panel = $('#btn_panel'),
    panel = $('#overlayPanel'),
    mode = "draw",
    topHeight,
    last_move="",
    smartphone,
    scale = 0.5;

module.exports.mode = mode;

var bricksize = webcom.bricksize;
//var mode = webcom.mode;

$(window).on('beforeunload', function(){
  $(window).scrollTop(0);
  $(window).scrollLeft(0);
});

$(window).on("load", function (){
  $(document).foundation();

  // Initialisation du contexte global
  globalInit();

  // drawspace scale from 1 to 0.5
  btn_dezoom.on('click', function(){
    var offX, offY, scale;

    offY = ($('body').scrollTop()/4) - (window.innerHeight/2);
    offX = ($('body').scrollLeft()/4) - (window.innerWidth/2);
    scale = 0.5;
    dezoom(offX, offY, scale);
  });

  // remove all bricks from the drawspace
  eraseAll.click(function() {
    webcom.eraseAll();
  });

  // Handle the continuous drawing on the computer
  drawspace.on('mousedown', function(e){
    if (smartphone === 0) {
      if (e.defaultPrevented ) return;

      var new_move,
          last_move="",
          handlers = {
        mousemove : function(e){
          if (e.defaultPrevented ) return;
          x=parseInt((e.pageX - drawspace.offset().left) / bricksize);
          y=parseInt((e.pageY - drawspace.offset().top) / bricksize);

          new_move = x + "-" + y;

          // Disable brick overflow outside drawspace
          if (new_move!=last_move && e.pageX < drawspace.width() && e.pageY < (drawspace.height() + topHeight) && e.pageX > 0 && e.pageY > 0) {
            webcom.updatePos(x,y);
          }
          last_move=new_move;
        },
        mouseup : function(e){
          $(this).off(handlers);
        }
      };
      $(document).on(handlers);
    }
  });

  // handle the simple click (addition/deletion of bricks) on the drawspace
  drawspace.bind("click", function(e){
    var x,y;
    var clickX = e.pageX;
    var clickY = e.pageY;

    // mobile device == false
    if (smartphone === 0) {
      x=parseInt((clickX - drawspace.offset().left) / bricksize);
      y=parseInt((clickY - drawspace.offset().top) / bricksize);
      webcom.updatePos(x,y);
    } else { // mobile device == true
      if (panel.hasClass('ui-panel-open') === true) {
        if (e.defaultPrevented ) return;
        panel.panel("close");
        btn_dezoom.show();
        $('html').removeClass('hideOverflow').addClass('showOverflow');
      } else {
        // Add brick if draw mode
        if (scale === 2) {
          x=parseInt(((clickX - drawspace.offset().left) / bricksize)/2);
          y=parseInt(((clickY - drawspace.offset().top) / bricksize)/2);
          webcom.updatePos(x,y);
        }
        // Zoom if navigation mode
        if (scale === 0.5) {
          scale = 2;

          var scrollX,
              scrollY,
              viewpWidth = window.innerWidth/3.5,
              viewpHeight = window.innerHeight/3.5,
              overflowX = e.clientX - viewpWidth,
              overflowY = e.clientY - viewpHeight,
              offX = $('body').scrollLeft(),
              offY = $('body').scrollTop() ;

          scrollX = (clickX + overflowX + offX)*2;
          scrollY = (clickY + overflowY + offY)*2;

          btn_dezoom.show();
          transcale(scrollX, scrollY, scale);
        }
      }
    }
  });
 });

/* Effectue une translation et un scale sur le drawspace */
function transcale (x, y, sc) {
  drawspace.css('margin-top', topHeight);
  drawspace.css('transform', "scale(" + sc + ")");
  if (sc === 0.5) {
    $('div[data-role="main"]').height(2490);
    $('div[data-role="main"]').width(2490);
  } else {
    $('div[data-role="main"]').height(4980);
    $('div[data-role="main"]').width(4980);
  }
  document.querySelector('meta[name=viewport]').setAttribute('content', "width=device-width, height=device-height, initial-scale=1, user-scalable=no");
  $('body').scrollLeft(x);
  $('body').scrollTop(y);
}

/* Initialisation du contexte global (interface) */
function globalInit() {

  //$('.topbar').css('height', '10vh');
  topHeight = $('.topbar').outerHeight();
  var panel = $('[data-role=panel]').height();
  var panelheight = topHeight - panel;
  var panelwidth = '330px';

  $('.ui-panel').css({
    'top': topHeight,
    'min-height' : 'none !important',
    'width': panelwidth,
    'background' : 'black',
    'text-shadow' : '0 0 0',
    'overflow' : 'auto'
  });

  $("div").removeClass('ui-panel-dismiss');
  $('a').removeClass('ui-link');

  btn_dezoom.removeClass().addClass('dezoom');

  // = 1 si mobile, 0 sinon
  smartphone = init.detectDevice();

  btn_dezoom.hide();
  drawspace.css('margin-top', topHeight);

  var btn_menuicon = $('.menu-icon').height();
  var menutitle = $('.top-bar-title').height();
  var margin_menuicon = ($('.topbar').height() - btn_menuicon)/2;
  var margin_menutitle = ($('.topbar').height() - menutitle)/2;
  $('.menu-icon').css('margin-top', margin_menuicon +'px');
  $('.top-bar-title').css('margin-top', margin_menutitle +'px');
  $('.ui-page-theme-a').css('text-shadow', '0 0 0');

  // Disable Ctrl+mouseWheel zoom on cross-browser
  $(window).bind('mousewheel DOMMouseScroll', function (event) {
    if (event.ctrlKey === true) {
      if (event.defaultPrevented ) return;
    }
  });

  // Initialisation of the drawspace's brick size
  initBrickSize(bricksize+"px");

  if (smartphone === 1) {
    transcale(0, 0, 0.5);
  } else {
    transcale(0, 0, 1);
    $('#overlayPanel').panel('open');
    $('.qrcode').qrcode({text:'https://simonbaumannpro.github.io/legorange3.0/', width: 200, height:200 });
  }
}

// Dezoom the drawspace to the initial state
function dezoom(x, y, sc) {
  transcale(x, y, sc);
  scale = 0.5;
  btn_dezoom.hide();
}

// set the size of the drawspace's background
function initBrickSize(size) {
  drawspace.css('background-size', size + " " + size);
}

// disable the scroll when the panel is open
btn_panel.click(function() {
  if (smartphone === 1)
    ev.disableScroll(scale);
});

// handle the highlighted color chosen
$(".brickMenu").click(function() {
  ev.color_active($(this));
});

// if erase mode, disable color display
$("#menu-DT").click(ev.hide_colors());

// change mode (draw or erase)
$(".mode").click(function(e){
  module.exports.mode = ev.change_mode($(this).attr("id"));
});<|endoftext|>


<commit_before>var bip66 = require('bip66')
var bufferutils = require('./bufferutils')
var typeforce = require('typeforce')
var types = require('./types')

var ecurve = require('ecurve')
var curve = ecurve.getCurveByName('secp256k1')

var OPS = require('./opcodes')
var REVERSE_OPS = []
for (var op in OPS) {
  var code = OPS[op]
  REVERSE_OPS[code] = op
}

function toASM (chunks) {
  if (types.Buffer(chunks)) {
    chunks = decompile(chunks)
  }

  return chunks.map(function (chunk) {
    // data?
    if (Buffer.isBuffer(chunk)) return chunk.toString('hex')

    // opcode!
    return REVERSE_OPS[chunk]
  }).join(' ')
}

function fromASM (asm) {
  typeforce(types.String, asm)

  return compile(asm.split(' ').map(function (chunkStr) {
    // opcode?
    if (OPS[chunkStr] !== undefined) return OPS[chunkStr]

    // data!
    return new Buffer(chunkStr, 'hex')
  }))
}

function compile (chunks) {
  // TODO: remove me
  if (types.Buffer(chunks)) return chunks

  typeforce(types.Array, chunks)

  var bufferSize = chunks.reduce(function (accum, chunk) {
    // data chunk
    if (Buffer.isBuffer(chunk)) {
      return accum + bufferutils.pushDataSize(chunk.length) + chunk.length
    }

    // opcode
    return accum + 1
  }, 0.0)

  var buffer = new Buffer(bufferSize)
  var offset = 0

  chunks.forEach(function (chunk) {
    // data chunk
    if (Buffer.isBuffer(chunk)) {
      offset += bufferutils.writePushDataInt(buffer, chunk.length, offset)

      chunk.copy(buffer, offset)
      offset += chunk.length

    // opcode
    } else {
      buffer.writeUInt8(chunk, offset)
      offset += 1
    }
  })

  if (offset !== buffer.length) throw new Error('Could not decode chunks')
  return buffer
}

function decompile (buffer) {
  // TODO: remove me
  if (types.Array(buffer)) return buffer

  typeforce(types.Buffer, buffer)

  var chunks = []
  var i = 0

  while (i < buffer.length) {
    var opcode = buffer.readUInt8(i)

    // data chunk
    if ((opcode > OPS.OP_0) && (opcode <= OPS.OP_PUSHDATA4)) {
      var d = bufferutils.readPushDataInt(buffer, i)

      // did reading a pushDataInt fail? empty script
      if (d === null) return []
      i += d.size

      // attempt to read too much data? empty script
      if (i + d.number > buffer.length) return []

      var data = buffer.slice(i, i + d.number)
      i += d.number

      chunks.push(data)

    // opcode
    } else {
      chunks.push(opcode)

      i += 1
    }
  }

  return chunks
}

function isCanonicalPubKey (buffer) {
  if (!Buffer.isBuffer(buffer)) return false

  try {
    ecurve.Point.decodeFrom(curve, buffer)
  } catch (e) {
    if (!(e.message.match(/Invalid sequence (length|tag)/))) {
      throw e
    }

    return false
  }

  return true
}

function isCanonicalSignature (buffer) {
  if (!Buffer.isBuffer(buffer)) return false

  return bip66.check(buffer.slice(0, -1))
}

function isPubKeyHashInput (script) {
  var chunks = decompile(script)

  return chunks.length === 2 &&
    isCanonicalSignature(chunks[0]) &&
    isCanonicalPubKey(chunks[1])
}

function isPubKeyHashOutput (script) {
  var chunks = decompile(script)

  return chunks.length === 5 &&
    chunks[0] === OPS.OP_DUP &&
    chunks[1] === OPS.OP_HASH160 &&
    Buffer.isBuffer(chunks[2]) &&
    chunks[2].length === 20 &&
    chunks[3] === OPS.OP_EQUALVERIFY &&
    chunks[4] === OPS.OP_CHECKSIG
}

function isPubKeyInput (script) {
  var chunks = decompile(script)

  return chunks.length === 1 &&
    isCanonicalSignature(chunks[0])
}

function isPubKeyOutput (script) {
  var chunks = decompile(script)

  return chunks.length === 2 &&
    isCanonicalPubKey(chunks[0]) &&
    chunks[1] === OPS.OP_CHECKSIG
}

function isScriptHashInput (script, allowIncomplete) {
  var chunks = decompile(script)
  if (chunks.length < 2) return false

  var lastChunk = chunks[chunks.length - 1]
  if (!Buffer.isBuffer(lastChunk)) return false

  var scriptSigChunks = chunks.slice(0, -1)
  var redeemScriptChunks = decompile(lastChunk)

  // is redeemScript a valid script?
  if (redeemScriptChunks.length === 0) return false

  return classifyInput(scriptSigChunks, allowIncomplete) === classifyOutput(redeemScriptChunks)
}

function isScriptHashOutput (script) {
  var chunks = decompile(script)

  return chunks.length === 3 &&
    chunks[0] === OPS.OP_HASH160 &&
    Buffer.isBuffer(chunks[1]) &&
    chunks[1].length === 20 &&
    chunks[2] === OPS.OP_EQUAL
}

// allowIncomplete is to account for combining signatures
// See https://github.com/bitcoin/bitcoin/blob/f425050546644a36b0b8e0eb2f6934a3e0f6f80f/src/script/sign.cpp#L195-L197
function isMultisigInput (script, allowIncomplete) {
  var chunks = decompile(script)
  if (chunks.length < 2) return false
  if (chunks[0] !== OPS.OP_0) return false

  if (allowIncomplete) {
    return chunks.slice(1).every(function (chunk) {
      return chunk === OPS.OP_0 || isCanonicalSignature(chunk)
    })
  }

  return chunks.slice(1).every(isCanonicalSignature)
}

function isMultisigOutput (script) {
  var chunks = decompile(script)
  if (chunks.length < 4) return false
  if (chunks[chunks.length - 1] !== OPS.OP_CHECKMULTISIG) return false

  var mOp = chunks[0]
  if (mOp === OPS.OP_0) return false
  if (mOp < OPS.OP_1) return false
  if (mOp > OPS.OP_16) return false

  var nOp = chunks[chunks.length - 2]
  if (nOp === OPS.OP_0) return false
  if (nOp < OPS.OP_1) return false
  if (nOp > OPS.OP_16) return false

  var m = mOp - (OPS.OP_1 - 1)
  var n = nOp - (OPS.OP_1 - 1)
  if (n < m) return false

  var pubKeys = chunks.slice(1, -2)
  if (n < pubKeys.length) return false

  return pubKeys.every(isCanonicalPubKey)
}

function isNullDataOutput (script) {
  var chunks = decompile(script)
  return chunks[0] === OPS.OP_RETURN
}

function classifyOutput (script) {
  var chunks = decompile(script)

  if (isPubKeyHashOutput(chunks)) {
    return 'pubkeyhash'
  } else if (isScriptHashOutput(chunks)) {
    return 'scripthash'
  } else if (isMultisigOutput(chunks)) {
    return 'multisig'
  } else if (isPubKeyOutput(chunks)) {
    return 'pubkey'
  } else if (isNullDataOutput(chunks)) {
    return 'nulldata'
  }

  return 'nonstandard'
}

function classifyInput (script, allowIncomplete) {
  var chunks = decompile(script)

  if (isPubKeyHashInput(chunks)) {
    return 'pubkeyhash'
  } else if (isMultisigInput(chunks, allowIncomplete)) {
    return 'multisig'
  } else if (isScriptHashInput(chunks, allowIncomplete)) {
    return 'scripthash'
  } else if (isPubKeyInput(chunks)) {
    return 'pubkey'
  }

  return 'nonstandard'
}

// Standard Script Templates
// {pubKey} OP_CHECKSIG
function pubKeyOutput (pubKey) {
  return compile([pubKey, OPS.OP_CHECKSIG])
}

// OP_DUP OP_HASH160 {pubKeyHash} OP_EQUALVERIFY OP_CHECKSIG
function pubKeyHashOutput (pubKeyHash) {
  typeforce(types.Hash160bit, pubKeyHash)

  return compile([OPS.OP_DUP, OPS.OP_HASH160, pubKeyHash, OPS.OP_EQUALVERIFY, OPS.OP_CHECKSIG])
}

// OP_HASH160 {scriptHash} OP_EQUAL
function scriptHashOutput (scriptHash) {
  typeforce(types.Hash160bit, scriptHash)

  return compile([OPS.OP_HASH160, scriptHash, OPS.OP_EQUAL])
}

// m [pubKeys ...] n OP_CHECKMULTISIG
function multisigOutput (m, pubKeys) {
  typeforce(types.tuple(types.Number, [types.Buffer]), arguments)

  var n = pubKeys.length
  if (n < m) throw new Error('Not enough pubKeys provided')

  return compile([].concat(
    (OPS.OP_1 - 1) + m,
    pubKeys,
    (OPS.OP_1 - 1) + n,
    OPS.OP_CHECKMULTISIG
  ))
}

// {signature}
function pubKeyInput (signature) {
  typeforce(types.Buffer, signature)

  return compile([signature])
}

// {signature} {pubKey}
function pubKeyHashInput (signature, pubKey) {
  typeforce(types.tuple(types.Buffer, types.Buffer), arguments)

  return compile([signature, pubKey])
}

// <scriptSig> {serialized scriptPubKey script}
function scriptHashInput (scriptSig, scriptPubKey) {
  var scriptSigChunks = decompile(scriptSig)
  var serializedScriptPubKey = compile(scriptPubKey)

  return compile([].concat(
    scriptSigChunks,
    serializedScriptPubKey
  ))
}

// OP_0 [signatures ...]
function multisigInput (signatures, scriptPubKey) {
  if (scriptPubKey) {
    var chunks = decompile(scriptPubKey)
    if (!isMultisigOutput(chunks)) throw new Error('Expected multisig scriptPubKey')

    var mOp = chunks[0]
    var nOp = chunks[chunks.length - 2]
    var m = mOp - (OPS.OP_1 - 1)
    var n = nOp - (OPS.OP_1 - 1)

    if (signatures.length < m) throw new Error('Not enough signatures provided')
    if (signatures.length > n) throw new Error('Too many signatures provided')
  }

  return compile([].concat(OPS.OP_0, signatures))
}

function nullDataOutput (data) {
  return compile([OPS.OP_RETURN, data])
}

module.exports = {
  compile: compile,
  decompile: decompile,
  fromASM: fromASM,
  toASM: toASM,

  isCanonicalPubKey: isCanonicalPubKey,
  isCanonicalSignature: isCanonicalSignature,
  isPubKeyHashInput: isPubKeyHashInput,
  isPubKeyHashOutput: isPubKeyHashOutput,
  isPubKeyInput: isPubKeyInput,
  isPubKeyOutput: isPubKeyOutput,
  isScriptHashInput: isScriptHashInput,
  isScriptHashOutput: isScriptHashOutput,
  isMultisigInput: isMultisigInput,
  isMultisigOutput: isMultisigOutput,
  isNullDataOutput: isNullDataOutput,
  classifyOutput: classifyOutput,
  classifyInput: classifyInput,
  pubKeyOutput: pubKeyOutput,
  pubKeyHashOutput: pubKeyHashOutput,
  scriptHashOutput: scriptHashOutput,
  multisigOutput: multisigOutput,
  pubKeyInput: pubKeyInput,
  pubKeyHashInput: pubKeyHashInput,
  scriptHashInput: scriptHashInput,
  multisigInput: multisigInput,
  nullDataOutput: nullDataOutput
}
<commit_msg>script: add isDefinedHashType to check hashType<commit_after>var bip66 = require('bip66')
var bufferutils = require('./bufferutils')
var typeforce = require('typeforce')
var types = require('./types')

var ecurve = require('ecurve')
var curve = ecurve.getCurveByName('secp256k1')

var OPS = require('./opcodes')
var REVERSE_OPS = []
for (var op in OPS) {
  var code = OPS[op]
  REVERSE_OPS[code] = op
}

function toASM (chunks) {
  if (types.Buffer(chunks)) {
    chunks = decompile(chunks)
  }

  return chunks.map(function (chunk) {
    // data?
    if (Buffer.isBuffer(chunk)) return chunk.toString('hex')

    // opcode!
    return REVERSE_OPS[chunk]
  }).join(' ')
}

function fromASM (asm) {
  typeforce(types.String, asm)

  return compile(asm.split(' ').map(function (chunkStr) {
    // opcode?
    if (OPS[chunkStr] !== undefined) return OPS[chunkStr]

    // data!
    return new Buffer(chunkStr, 'hex')
  }))
}

function compile (chunks) {
  // TODO: remove me
  if (types.Buffer(chunks)) return chunks

  typeforce(types.Array, chunks)

  var bufferSize = chunks.reduce(function (accum, chunk) {
    // data chunk
    if (Buffer.isBuffer(chunk)) {
      return accum + bufferutils.pushDataSize(chunk.length) + chunk.length
    }

    // opcode
    return accum + 1
  }, 0.0)

  var buffer = new Buffer(bufferSize)
  var offset = 0

  chunks.forEach(function (chunk) {
    // data chunk
    if (Buffer.isBuffer(chunk)) {
      offset += bufferutils.writePushDataInt(buffer, chunk.length, offset)

      chunk.copy(buffer, offset)
      offset += chunk.length

    // opcode
    } else {
      buffer.writeUInt8(chunk, offset)
      offset += 1
    }
  })

  if (offset !== buffer.length) throw new Error('Could not decode chunks')
  return buffer
}

function decompile (buffer) {
  // TODO: remove me
  if (types.Array(buffer)) return buffer

  typeforce(types.Buffer, buffer)

  var chunks = []
  var i = 0

  while (i < buffer.length) {
    var opcode = buffer.readUInt8(i)

    // data chunk
    if ((opcode > OPS.OP_0) && (opcode <= OPS.OP_PUSHDATA4)) {
      var d = bufferutils.readPushDataInt(buffer, i)

      // did reading a pushDataInt fail? empty script
      if (d === null) return []
      i += d.size

      // attempt to read too much data? empty script
      if (i + d.number > buffer.length) return []

      var data = buffer.slice(i, i + d.number)
      i += d.number

      chunks.push(data)

    // opcode
    } else {
      chunks.push(opcode)

      i += 1
    }
  }

  return chunks
}

function isCanonicalPubKey (buffer) {
  if (!Buffer.isBuffer(buffer)) return false

  try {
    ecurve.Point.decodeFrom(curve, buffer)
  } catch (e) {
    if (!(e.message.match(/Invalid sequence (length|tag)/))) {
      throw e
    }

    return false
  }

  return true
}

function isCanonicalSignature (buffer) {
  if (!Buffer.isBuffer(buffer)) return false
  if (!isDefinedHashType(buffer[buffer.length - 1])) return false

  return bip66.check(buffer.slice(0, -1))
}

function isDefinedHashType (hashType) {
  var hashTypeMod = hashType & ~0x80

// return hashTypeMod > SIGHASH_ALL && hashTypeMod < SIGHASH_SINGLE
  return hashTypeMod > 0x00 && hashTypeMod < 0x04
}

function isPubKeyHashInput (script) {
  var chunks = decompile(script)

  return chunks.length === 2 &&
    isCanonicalSignature(chunks[0]) &&
    isCanonicalPubKey(chunks[1])
}

function isPubKeyHashOutput (script) {
  var chunks = decompile(script)

  return chunks.length === 5 &&
    chunks[0] === OPS.OP_DUP &&
    chunks[1] === OPS.OP_HASH160 &&
    Buffer.isBuffer(chunks[2]) &&
    chunks[2].length === 20 &&
    chunks[3] === OPS.OP_EQUALVERIFY &&
    chunks[4] === OPS.OP_CHECKSIG
}

function isPubKeyInput (script) {
  var chunks = decompile(script)

  return chunks.length === 1 &&
    isCanonicalSignature(chunks[0])
}

function isPubKeyOutput (script) {
  var chunks = decompile(script)

  return chunks.length === 2 &&
    isCanonicalPubKey(chunks[0]) &&
    chunks[1] === OPS.OP_CHECKSIG
}

function isScriptHashInput (script, allowIncomplete) {
  var chunks = decompile(script)
  if (chunks.length < 2) return false

  var lastChunk = chunks[chunks.length - 1]
  if (!Buffer.isBuffer(lastChunk)) return false

  var scriptSigChunks = chunks.slice(0, -1)
  var redeemScriptChunks = decompile(lastChunk)

  // is redeemScript a valid script?
  if (redeemScriptChunks.length === 0) return false

  return classifyInput(scriptSigChunks, allowIncomplete) === classifyOutput(redeemScriptChunks)
}

function isScriptHashOutput (script) {
  var chunks = decompile(script)

  return chunks.length === 3 &&
    chunks[0] === OPS.OP_HASH160 &&
    Buffer.isBuffer(chunks[1]) &&
    chunks[1].length === 20 &&
    chunks[2] === OPS.OP_EQUAL
}

// allowIncomplete is to account for combining signatures
// See https://github.com/bitcoin/bitcoin/blob/f425050546644a36b0b8e0eb2f6934a3e0f6f80f/src/script/sign.cpp#L195-L197
function isMultisigInput (script, allowIncomplete) {
  var chunks = decompile(script)
  if (chunks.length < 2) return false
  if (chunks[0] !== OPS.OP_0) return false

  if (allowIncomplete) {
    return chunks.slice(1).every(function (chunk) {
      return chunk === OPS.OP_0 || isCanonicalSignature(chunk)
    })
  }

  return chunks.slice(1).every(isCanonicalSignature)
}

function isMultisigOutput (script) {
  var chunks = decompile(script)
  if (chunks.length < 4) return false
  if (chunks[chunks.length - 1] !== OPS.OP_CHECKMULTISIG) return false

  var mOp = chunks[0]
  if (mOp === OPS.OP_0) return false
  if (mOp < OPS.OP_1) return false
  if (mOp > OPS.OP_16) return false

  var nOp = chunks[chunks.length - 2]
  if (nOp === OPS.OP_0) return false
  if (nOp < OPS.OP_1) return false
  if (nOp > OPS.OP_16) return false

  var m = mOp - (OPS.OP_1 - 1)
  var n = nOp - (OPS.OP_1 - 1)
  if (n < m) return false

  var pubKeys = chunks.slice(1, -2)
  if (n < pubKeys.length) return false

  return pubKeys.every(isCanonicalPubKey)
}

function isNullDataOutput (script) {
  var chunks = decompile(script)
  return chunks[0] === OPS.OP_RETURN
}

function classifyOutput (script) {
  var chunks = decompile(script)

  if (isPubKeyHashOutput(chunks)) {
    return 'pubkeyhash'
  } else if (isScriptHashOutput(chunks)) {
    return 'scripthash'
  } else if (isMultisigOutput(chunks)) {
    return 'multisig'
  } else if (isPubKeyOutput(chunks)) {
    return 'pubkey'
  } else if (isNullDataOutput(chunks)) {
    return 'nulldata'
  }

  return 'nonstandard'
}

function classifyInput (script, allowIncomplete) {
  var chunks = decompile(script)

  if (isPubKeyHashInput(chunks)) {
    return 'pubkeyhash'
  } else if (isMultisigInput(chunks, allowIncomplete)) {
    return 'multisig'
  } else if (isScriptHashInput(chunks, allowIncomplete)) {
    return 'scripthash'
  } else if (isPubKeyInput(chunks)) {
    return 'pubkey'
  }

  return 'nonstandard'
}

// Standard Script Templates
// {pubKey} OP_CHECKSIG
function pubKeyOutput (pubKey) {
  return compile([pubKey, OPS.OP_CHECKSIG])
}

// OP_DUP OP_HASH160 {pubKeyHash} OP_EQUALVERIFY OP_CHECKSIG
function pubKeyHashOutput (pubKeyHash) {
  typeforce(types.Hash160bit, pubKeyHash)

  return compile([OPS.OP_DUP, OPS.OP_HASH160, pubKeyHash, OPS.OP_EQUALVERIFY, OPS.OP_CHECKSIG])
}

// OP_HASH160 {scriptHash} OP_EQUAL
function scriptHashOutput (scriptHash) {
  typeforce(types.Hash160bit, scriptHash)

  return compile([OPS.OP_HASH160, scriptHash, OPS.OP_EQUAL])
}

// m [pubKeys ...] n OP_CHECKMULTISIG
function multisigOutput (m, pubKeys) {
  typeforce(types.tuple(types.Number, [types.Buffer]), arguments)

  var n = pubKeys.length
  if (n < m) throw new Error('Not enough pubKeys provided')

  return compile([].concat(
    (OPS.OP_1 - 1) + m,
    pubKeys,
    (OPS.OP_1 - 1) + n,
    OPS.OP_CHECKMULTISIG
  ))
}

// {signature}
function pubKeyInput (signature) {
  typeforce(types.Buffer, signature)

  return compile([signature])
}

// {signature} {pubKey}
function pubKeyHashInput (signature, pubKey) {
  typeforce(types.tuple(types.Buffer, types.Buffer), arguments)

  return compile([signature, pubKey])
}

// <scriptSig> {serialized scriptPubKey script}
function scriptHashInput (scriptSig, scriptPubKey) {
  var scriptSigChunks = decompile(scriptSig)
  var serializedScriptPubKey = compile(scriptPubKey)

  return compile([].concat(
    scriptSigChunks,
    serializedScriptPubKey
  ))
}

// OP_0 [signatures ...]
function multisigInput (signatures, scriptPubKey) {
  if (scriptPubKey) {
    var chunks = decompile(scriptPubKey)
    if (!isMultisigOutput(chunks)) throw new Error('Expected multisig scriptPubKey')

    var mOp = chunks[0]
    var nOp = chunks[chunks.length - 2]
    var m = mOp - (OPS.OP_1 - 1)
    var n = nOp - (OPS.OP_1 - 1)

    if (signatures.length < m) throw new Error('Not enough signatures provided')
    if (signatures.length > n) throw new Error('Too many signatures provided')
  }

  return compile([].concat(OPS.OP_0, signatures))
}

function nullDataOutput (data) {
  return compile([OPS.OP_RETURN, data])
}

module.exports = {
  compile: compile,
  decompile: decompile,
  fromASM: fromASM,
  toASM: toASM,

  isCanonicalPubKey: isCanonicalPubKey,
  isCanonicalSignature: isCanonicalSignature,
  isDefinedHashType: isDefinedHashType,
  isPubKeyHashInput: isPubKeyHashInput,
  isPubKeyHashOutput: isPubKeyHashOutput,
  isPubKeyInput: isPubKeyInput,
  isPubKeyOutput: isPubKeyOutput,
  isScriptHashInput: isScriptHashInput,
  isScriptHashOutput: isScriptHashOutput,
  isMultisigInput: isMultisigInput,
  isMultisigOutput: isMultisigOutput,
  isNullDataOutput: isNullDataOutput,
  classifyOutput: classifyOutput,
  classifyInput: classifyInput,
  pubKeyOutput: pubKeyOutput,
  pubKeyHashOutput: pubKeyHashOutput,
  scriptHashOutput: scriptHashOutput,
  multisigOutput: multisigOutput,
  pubKeyInput: pubKeyInput,
  pubKeyHashInput: pubKeyHashInput,
  scriptHashInput: scriptHashInput,
  multisigInput: multisigInput,
  nullDataOutput: nullDataOutput
}
<|endoftext|>


<commit_before>/*
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

var iteratorCode = 0;
var blockSpecs = [
  {
    title: "Alert %s",
    type: "action",
    code: function(args) { return "alert(" + args[0] + ");"; }
  },
  {
    title: "Show copy box %s",
    type: "action",
    code: function(args) { return "prompt(\"Copy this text:\"," + args[0] + ");"; }
  },
  {
    title: "Define variable %e",
    type: "variable",
    code: function(args) { return "var " + args[0] + ";"; }
  },
  {
    title: "Set %e to %s",
    type: "variable",
    code: function(args) { return args[0] + "=" + args[1] + ";"; }
  },
  {
    title: "Repeat %n Times",
    type: "control",
    code: function(args) {
      i++;
      return "for(var i" + iteratorCode + "=0;i" + iteratorCode + "<" + args[0] + ";i" + iteratorCode + "++){";
    }
  },
  {
    title: "End",
    type: "control",
    code: function(args) { return "}"; }
  }
]
function getJS() {
  var blocks = document.getElementById("script").children;
  var code = ""
  for (var i = 0; i < blocks.length; i++) {
    var block = blocks[i];
    blockSpec = blockSpecs[block.getAttribute("data-block-id")];
    var blockSpecTitle = blockSpec.title;
    var isField = false;
    var buffer = "";
    var parts = [];
    for (var c = 0; c < blockSpecTitle.length; c++) {
      var char = blockSpecTitle.charAt(c);
      if (isField) {
        if (char === "s") {
          parts.push({
            type: "string"
          })
        }else if (char === "e") {
          parts.push({
            type: "entity"
          })
        }else if (char === "n") {
          parts.push({
            type: "number"
          })
        }
        isField = false;
      }else{
        if (char === "%") {
          parts.push({
            type: "title",
            value: buffer
          })
          buffer = ""
          isField = true;
        }else{
          buffer += char;
        }
      }
    }
    parts.push({
      type: "title",
      value: buffer
    })
    var args = [];
    for (var b = 0; b < parts.length; b++) {
      var part = parts[b];
      if (part.type === "string") {
        args.push("\"" + block.children[b].value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/\[\[(.*)\]\]/, function(m, v) {
          return "\"+ent_" + v.replace(/[^a-zA-Z_$\-]/g, "___Unknown___") + "+\"";
        }) + "\"")
      }else if (part.type === "entity") {
        args.push("ent_" + block.children[b].value.replace(/[^a-zA-Z_$\-]/g, "___Unknown___"))
      }else if (part.type === "number") {
        args.push(parseFloat(block.children[b].value))
      }
    }
    code += blockSpec.code(args);
  }
  return code;
}
for (var i = 0; i < blockSpecs.length; i++) {
  var blockSpecTitle = blockSpecs[i].title;
  var isField = false;
  var buffer = "";
  var parts = [];
  for (var c = 0; c < blockSpecTitle.length; c++) {
    var char = blockSpecTitle.charAt(c);
    if (isField) {
      if (char === "s") {
        parts.push({
          type: "string"
        })
      }else if (char === "e") {
        parts.push({
          type: "entity"
        })
      }else if (char === "n") {
        parts.push({
          type: "number"
        })
      }
      isField = false;
    }else{
      if (char === "%") {
        parts.push({
          type: "title",
          value: buffer
        })
        buffer = ""
        isField = true;
      }else{
        buffer += char;
      }
    }
  }
  parts.push({
    type: "title",
    value: buffer
  })
  var blockDiv = document.createElement("div");
  blockDiv.setAttribute("data-block-id", i);
  blockDiv.className = "block " + blockSpecs[i].type;
  for (var p = 0; p < parts.length; p++) {
    var part = parts[p];
    if (part.type === "title") {
      var title = document.createElement("span");
      title.textContent = part.value
      blockDiv.appendChild(title)
    }else if (part.type === "string") {
      var input = document.createElement("input");
      input.className = "string";
      blockDiv.appendChild(input);
    }else if (part.type === "entity") {
      var input = document.createElement("input");
      input.className = "entity";
      blockDiv.appendChild(input);
    }else if (part.type === "number") {
      var input = document.createElement("input");
      input.className = "number";
      blockDiv.appendChild(input);
    }
  }
  document.getElementById("library").appendChild(blockDiv);
}
document.getElementById("run").addEventListener("click", function(){
  var code = getJS();
  try {
    eval(code);
  } catch (err) {
    alert(err.message);
  }
});
document.getElementById("getJS").addEventListener("click", function(){
  prompt("The JavaScript for this project is:", getJS());
});
var dragger = dragula({
  containers: [document.getElementById("library"), document.getElementById("script")],
  copy: function (el, source) {
    return source === document.getElementById("library")
  },
  accepts: function (el, target) {
    return target !== document.getElementById("library")
  },
  removeOnSpill: true
});
<commit_msg>📓 Comment-ify the main script so you can read it<commit_after>/*
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

var iteratorCode = 0; // UID For Repeat Loops
/*
Block Spefifications:
Key to properties:
  title - Display name for block use these modifiers to add input:
    %s - string
    %e - entity - variable
    %n - number - float
  type - Tells DropBlox how to color blocks (see style.css)
  code - function that takes one array argument and returns a string contaning the JavaScript run for that block
*/
var blockSpecs = [
  {
    title: "Alert %s",
    type: "action",
    code: function(args) { return "alert(" + args[0] + ");"; }
  },
  {
    title: "Show copy box %s",
    type: "action",
    code: function(args) { return "prompt(\"Copy this text:\"," + args[0] + ");"; }
  },
  {
    title: "Define variable %e",
    type: "variable",
    code: function(args) { return "var " + args[0] + ";"; }
  },
  {
    title: "Set %e to %s",
    type: "variable",
    code: function(args) { return args[0] + "=" + args[1] + ";"; }
  },
  {
    title: "Repeat %n Times",
    type: "control",
    code: function(args) {
      i++;
      return "for(var i" + iteratorCode + "=0;i" + iteratorCode + "<" + args[0] + ";i" + iteratorCode + "++){";
    }
  },
  {
    title: "End",
    type: "control",
    code: function(args) { return "}"; }
  }
]
/*
  This function parses through the blocks and returns the entire JS needed to run the current project.
*/
function getJS() {
  var blocks = document.getElementById("script").children; // Get all of the "block" elements
  var code = ""; // A buffer to store the JS code
  for (var i = 0; i < blocks.length; i++) { // Loop through the "block" elements
    var block = blocks[i];
    blockSpec = blockSpecs[block.getAttribute("data-block-id")]; // Get the blockSpec for the current block
    var blockSpecTitle = blockSpec.title;
    var isField = false;
    var buffer = "";
    var parts = []; // Place to hold all of the block parts
    for (var c = 0; c < blockSpecTitle.length; c++) {
      var char = blockSpecTitle.charAt(c);
      if (isField) { // Check the field type
        if (char === "s") {
          parts.push({
            type: "string"
          })
        }else if (char === "e") {
          parts.push({
            type: "entity"
          })
        }else if (char === "n") {
          parts.push({
            type: "number"
          })
        }
        isField = false;
      }else{
        if (char === "%") { // We got ourselves a field let's handle it
          parts.push({
            type: "title",
            value: buffer
          })
          buffer = ""
          isField = true;
        }else{ // Add to the buffer
          buffer += char;
        }
      }
    }
    parts.push({ // Add the final title (probably could get rid of this)
      type: "title",
      value: buffer
    })
    var args = []; // Place to hold user provided arguments
    for (var b = 0; b < parts.length; b++) {
      var part = parts[b];
      if (part.type === "string") {
        args.push("\"" + block.children[b].value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/\[\[(.*)\]\]/, function(m, v) {
          // This function is cool, it allows you to embed variables in string inputs :)
          return "\"+ent_" + v.replace(/[^a-zA-Z_$\-]/g, "___Unknown___") + "+\"";
        }) + "\"")
      }else if (part.type === "entity") {
        args.push("ent_" + block.children[b].value.replace(/[^a-zA-Z_$\-]/g, "___Unknown___")) // Entity inputs with added saftey feature
      }else if (part.type === "number") {
        args.push(parseFloat(block.children[b].value))
      }
    }
    code += blockSpec.code(args);
  }
  return code;
}
for (var i = 0; i < blockSpecs.length; i++) { // Loop through blockSpecs and add blocks to library
  var blockSpecTitle = blockSpecs[i].title;
  var isField = false;
  var buffer = "";
  var parts = [];
  for (var c = 0; c < blockSpecTitle.length; c++) {
    var char = blockSpecTitle.charAt(c);
    if (isField) { // Check the field type
      if (char === "s") {
        parts.push({
          type: "string"
        })
      }else if (char === "e") {
        parts.push({
          type: "entity"
        })
      }else if (char === "n") {
        parts.push({
          type: "number"
        })
      }
      isField = false;
    }else{
      if (char === "%") { // We got ourselves a field let's handle it
        parts.push({
          type: "title",
          value: buffer
        })
        buffer = ""
        isField = true;
      }else{ // Add to the buffer
        buffer += char;
      }
    }
  }
  parts.push({ // Add the final title
    type: "title",
    value: buffer
  })
  var blockDiv = document.createElement("div"); // Create <div> representing block
  blockDiv.setAttribute("data-block-id", i); // Set block-id (this is important when parsing)
  blockDiv.className = "block " + blockSpecs[i].type; // Set class
  for (var p = 0; p < parts.length; p++) { // Add ALL the fields (insert "ALL THE" meme here)
    var part = parts[p];
    if (part.type === "title") {
      var title = document.createElement("span");
      title.textContent = part.value
      blockDiv.appendChild(title)
    }else if (part.type === "string") {
      var input = document.createElement("input");
      input.className = "string";
      blockDiv.appendChild(input);
    }else if (part.type === "entity") {
      var input = document.createElement("input");
      input.className = "entity";
      blockDiv.appendChild(input);
    }else if (part.type === "number") {
      var input = document.createElement("input");
      input.className = "number";
      blockDiv.appendChild(input);
    }
  }
  document.getElementById("library").appendChild(blockDiv); // Append finished block to the library
}
document.getElementById("run").addEventListener("click", function(){
  // Run user's code
  var code = getJS();
  try {
    // DropBlox isn't perfect, the user's code could error so let's handle that
    eval(code);
  } catch (err) {
    alert(err.message);
  }
});
document.getElementById("getJS").addEventListener("click", function(){
  // Give the user their unreadable code. :P
  prompt("The JavaScript for this project is:", getJS());
});
var dragger = dragula({ // Initialize Dragula (bevacqua/dragula)
  containers: [document.getElementById("library"), document.getElementById("script")],
  copy: function (el, source) {
    return source === document.getElementById("library")
  },
  accepts: function (el, target) {
    return target !== document.getElementById("library")
  },
  removeOnSpill: true
});
<|endoftext|>


<commit_before>import { LightningElement, api, track } from 'lwc';
import {apiNameFor, getSubsetObject, isEmptyObject, isNotEmpty, isUndefined} from 'c/utilCommon';

import DI_ADDITIONAL_OBJECT_JSON_FIELD from '@salesforce/schema/DataImport__c.Additional_Object_JSON__c';
import DI_DONATION_AMOUNT_FIELD from '@salesforce/schema/DataImport__c.Donation_Amount__c';
import DATA_IMPORT_PAYMENT_METHOD from '@salesforce/schema/DataImport__c.Payment_Method__c';

const PAYMENT_SCHEDULER_WIDGET = 'geFormWidgetPaymentScheduler';
const ALLOCATION_WIDGET = 'geFormWidgetAllocation';
const TOKENIZE_CARD_WIDGET = 'geFormWidgetTokenizeCard';
const WIDGET_LIST = [PAYMENT_SCHEDULER_WIDGET, ALLOCATION_WIDGET, TOKENIZE_CARD_WIDGET];

export default class GeFormWidget extends LightningElement {
    @api element;
    // TODO: Is this still in use?
    @api widgetData;

    @track widgetDataFromState = {};

    _formState = {};

    _allocationFields = [apiNameFor(DI_DONATION_AMOUNT_FIELD), apiNameFor(DI_ADDITIONAL_OBJECT_JSON_FIELD)];
    _elevateFields = [apiNameFor(DATA_IMPORT_PAYMENT_METHOD)];

    @api
    get formState() {
        return this._formState;
    }

    set formState(formState) {
        if (isEmptyObject(formState)) {
            return;
        }

        if (this.hasAllocationValuesChanged(formState)) {
            this.sliceWidgetDataFromFormState(formState, this._allocationFields);
        }

        if (this.hasElevateValuesChanged(formState)) {
            this.sliceWidgetDataFromFormState(formState, this._elevateFields);
        }

        this._formState = Object.assign({}, formState);
    }

    sliceWidgetDataFromFormState(formState, fields) {
        this.widgetDataFromState = getSubsetObject(formState, fields);
    }

    handleFormWidgetChange(event) {
        this.dispatchEvent(new CustomEvent('formwidgetchange', {detail: event.detail}))
    }

    hasElevateValuesChanged(formState) {
        const paymentMethodApiName = apiNameFor(DATA_IMPORT_PAYMENT_METHOD);
        if (!paymentMethodApiName) return false;

        const hasChanged = formState[paymentMethodApiName] !== this.formState[paymentMethodApiName];
        return hasChanged;
    }

    hasAllocationValuesChanged(formState) {
        const donationFieldApiName = apiNameFor(DI_DONATION_AMOUNT_FIELD);
        const additionalObjectFieldApiName = apiNameFor(DI_ADDITIONAL_OBJECT_JSON_FIELD)

        return formState[donationFieldApiName] !==
            this.formState[donationFieldApiName]
            ||
            formState[additionalObjectFieldApiName] !==
            this.formState[additionalObjectFieldApiName]
    }

    get isValid() {
        const thisWidget = this.widgetComponent;
        let isValid = false;
        if(thisWidget !== null && typeof thisWidget !== 'undefined'
            && typeof thisWidget.isValid === 'function') {
                isValid = thisWidget.isValid();
        } else if(isUndefined(thisWidget.isValid)) {
            // if no validation function defined, assume widget is valid
            return true;
        }
        return isValid;
    }

    get widgetComponent() {
        return this.template.querySelector('[data-id="widgetComponent"]');
    }

    get isPaymentScheduler() {
        return this.element.componentName === PAYMENT_SCHEDULER_WIDGET;
    }

    @api
    get isElevateTokenizeCard() {
        return this.element.componentName === TOKENIZE_CARD_WIDGET;
    }

    get isAllocation() {
        return this.element.componentName === ALLOCATION_WIDGET;
    }

    get widgetNotFound(){
        return WIDGET_LIST.indexOf(this.element.componentName) < 0
    }

    @api
    get paymentToken() {
        const thisWidget = this.widgetComponent;
        if (this.isValid) {
            return thisWidget.paymentToken;
        }
    }

}<commit_msg>add checks so form state changes only updates the relevant widget<commit_after>import { LightningElement, api, track } from 'lwc';
import {apiNameFor, getSubsetObject, isEmptyObject, isNotEmpty, isUndefined} from 'c/utilCommon';

import DI_ADDITIONAL_OBJECT_JSON_FIELD from '@salesforce/schema/DataImport__c.Additional_Object_JSON__c';
import DI_DONATION_AMOUNT_FIELD from '@salesforce/schema/DataImport__c.Donation_Amount__c';
import DATA_IMPORT_PAYMENT_METHOD from '@salesforce/schema/DataImport__c.Payment_Method__c';

const PAYMENT_SCHEDULER_WIDGET = 'geFormWidgetPaymentScheduler';
const ALLOCATION_WIDGET = 'geFormWidgetAllocation';
const TOKENIZE_CARD_WIDGET = 'geFormWidgetTokenizeCard';
const WIDGET_LIST = [PAYMENT_SCHEDULER_WIDGET, ALLOCATION_WIDGET, TOKENIZE_CARD_WIDGET];

export default class GeFormWidget extends LightningElement {
    @api element;
    // TODO: Is this still in use?
    @api widgetData;

    @track widgetDataFromState = {};

    _formState = {};

    _allocationFields = [apiNameFor(DI_DONATION_AMOUNT_FIELD), apiNameFor(DI_ADDITIONAL_OBJECT_JSON_FIELD)];
    _elevateFields = [apiNameFor(DATA_IMPORT_PAYMENT_METHOD)];

    @api
    get formState() {
        return this._formState;
    }

    set formState(formState) {
        if (isEmptyObject(formState)) {
            return;
        }

        const shouldUpdateAllocationWidgetState = this.isAllocation && this.hasAllocationValuesChanged(formState);
        if (shouldUpdateAllocationWidgetState) {
            this.sliceWidgetDataFromFormState(formState, this._allocationFields);
        }

        const shouldUpdateElevateWidgetState = this.isElevateTokenizeCard && this.hasElevateValuesChanged(formState);
        if (shouldUpdateElevateWidgetState) {
            this.sliceWidgetDataFromFormState(formState, this._elevateFields);
        }

        this._formState = Object.assign({}, formState);
    }

    sliceWidgetDataFromFormState(formState, fields) {
        this.widgetDataFromState = getSubsetObject(formState, fields);
    }

    handleFormWidgetChange(event) {
        this.dispatchEvent(new CustomEvent('formwidgetchange', {detail: event.detail}))
    }

    hasElevateValuesChanged(formState) {
        const paymentMethodApiName = apiNameFor(DATA_IMPORT_PAYMENT_METHOD);
        if (!paymentMethodApiName) return false;

        const hasChanged = formState[paymentMethodApiName] !== this.formState[paymentMethodApiName];
        return hasChanged;
    }

    hasAllocationValuesChanged(formState) {
        const donationFieldApiName = apiNameFor(DI_DONATION_AMOUNT_FIELD);
        const additionalObjectFieldApiName = apiNameFor(DI_ADDITIONAL_OBJECT_JSON_FIELD)

        return formState[donationFieldApiName] !==
            this.formState[donationFieldApiName]
            ||
            formState[additionalObjectFieldApiName] !==
            this.formState[additionalObjectFieldApiName]
    }

    get isValid() {
        const thisWidget = this.widgetComponent;
        let isValid = false;
        if(thisWidget !== null && typeof thisWidget !== 'undefined'
            && typeof thisWidget.isValid === 'function') {
                isValid = thisWidget.isValid();
        } else if(isUndefined(thisWidget.isValid)) {
            // if no validation function defined, assume widget is valid
            return true;
        }
        return isValid;
    }

    get widgetComponent() {
        return this.template.querySelector('[data-id="widgetComponent"]');
    }

    get isPaymentScheduler() {
        return this.element.componentName === PAYMENT_SCHEDULER_WIDGET;
    }

    @api
    get isElevateTokenizeCard() {
        return this.element.componentName === TOKENIZE_CARD_WIDGET;
    }

    get isAllocation() {
        return this.element.componentName === ALLOCATION_WIDGET;
    }

    get widgetNotFound(){
        return WIDGET_LIST.indexOf(this.element.componentName) < 0
    }

    @api
    get paymentToken() {
        const thisWidget = this.widgetComponent;
        if (this.isValid) {
            return thisWidget.paymentToken;
        }
    }

}<|endoftext|>


<commit_before>/**
 * Search module
 * @author Sergey Chikuyonok (serge.che@gmail.com)
 * @link http://chikuyonok.ru
 *
 * @include "utils.js"
 * @include "signals.js"
 */
var xv_search = (function(){
	var search_index = [],
		/** @type {Document} */
		doc,

		/** @type {Array} List of last matched elements */
		last_search,

		last_query,
		/** @type {jQuery} */
		popup = $('

'),
		max_visible_results = 20,
		max_results = 100,

		selected_item = -1,

		is_visible = false,

		/** @type {jQuery} Search panel */
		panel,

		/** @type {jQuery} Search field */
		search_field,

		hover_lock_timeout,
		is_hover_locked = false;

	/**
	 * Creates search index item
	 * @param {Element} node
	 */
	function searchIndexItem(node) {
		var search_str = node.nodeName;
		var attrs = [];
		if (node.attributes) {
			for (var i = 0, il = node.attributes.length; i < il; i++) {
				if (node.attributes[i].name.indexOf('data-xv-') == -1)
					attrs.push(node.attributes[i].name);
			}
		}

		if (attrs.length)
			search_str += ' ' + attrs.join(' ');

		return {
			str: search_str.toLowerCase(),
			node: node
		};
	}

	/**
	 * Recursively build search index on node, preserving node order
	 * @param {Element} node
	 */
	function buildIndex(node) {
		if (node.nodeType != 1)
			return;

		search_index.push(searchIndexItem(node));
		for (var i = 0, il = node.childNodes.length; i < il; i++) {
			buildIndex(node.childNodes[i]);
		}
	}

	/**
	 * Simple textual search on document tree
	 * @param {String} query Search query
	 * @return {Array} Array of matched nodes, null otherwise
	 */
	function searchText(query) {
		var result = [];
		if (query) {
			$.each(search_index, function(i, /* searchIndexItem */ n) {
				var ix = n.str.indexOf(query);
				if (ix != -1)
					result.push({
						ix: ix,
						node: n.node
					});
			});
		}

		return result.length ? result : null;
	}

	function searchXPath(query) {
		var result = [];
		try {
			// TODO handle namespaces
			var nodes = doc.evaluate(query, doc, null, XPathResult.ANY_TYPE, null);
			var n = nodes.iterateNext();
			while (n) {
				result.push({node: n});
				n = nodes.iterateNext();
			}
		} catch(e) {}

		return result.length ? result : null;
	}

	/**
	 * Returns list of search result items
	 * @return {jQuery}
	 */
	function getSearchResultItems() {
		return popup.find('.xv-search-result-item');
	}

	/**
	 * Select search reult item
	 * @param {Number} ix Index of item
	 * @param {Boolean} no_scroll Do not scroll popup content to make shure that
	 * selected item is always visible
	 */
	function selectItem(ix, no_scroll) {
		var cur_item = getSearchResultItems()
			.removeClass('xv-search-result-item-selected')
			.eq(ix)
			.addClass('xv-search-result-item-selected');

		if (!no_scroll && cur_item.length) {
			var content = cur_item.parent();
			// make sure that selected proposal is visible
			var proposal_top = cur_item[0].offsetTop,
				proposal_height = cur_item[0].offsetHeight,
				popup_scroll = content[0].scrollTop,
				popup_height = content[0].offsetHeight;

			if (proposal_top < popup_scroll) {
				content[0].scrollTop = proposal_top;
			} else if (proposal_top + proposal_height > popup_scroll + popup_height) {
				content[0].scrollTop = proposal_top + proposal_height - popup_height;
			}
		}

		selected_item = ix;
		xv_signals.searchItemSelected.dispatch(cur_item[0], selected_item);
	}

	/**
	 * Temporary lock popup hover events.
	 * Hover lock is used to prevent accident mouseover event callback when
	 * mouse cursor is over popup window and user traverses between proposals
	 * with arrow keys
	 */
	function lockHover() {
		if (hover_lock_timeout)
			clearTimeout(hover_lock_timeout);

		is_hover_locked = true;
		setTimeout(function() {
			is_hover_locked = false;
		}, 100);
	}

	/**
	 * Creates label that will be displayed as a search result
	 * @param {Object} item Search result item
	 * @param {String} query Search query
	 */
	function createSearchResultLabel(item, query) {
		/** @type {Element} */
		var node = item.node,
			name = node.nodeName,
			ql = query.length,
			xpath = node.getAttribute('data-xv-xpath');

		if (!xpath) {
			xpath = xv_utils.createXPath(node);
			node.setAttribute('data-xv-xpath', xpath);
		}

		if ('ix' in item) { // simple text search result
			if (item.ix < name.length) {  // mark search result in node name
				name = name.substr(0, item.ix) +
					'' + name.substr(item.ix, ql) + ''
					+ name.substr(item.ix + ql);
			} else { // match found somethere in attribute, add it
				var _ix;
				$.each(node.attributes, function(i, n) {
					_ix = n.name.indexOf(query);
					if (_ix != -1) {
						name += '[@' + n.name.substr(0, _ix) +
							'' + n.name.substr(_ix, ql) + ''
							+ n.name.substr(_ix + ql) + ']';

						return false;
					}
				});
			}
		}

		return name + ' ' + xpath + '';
	}

	/**
	 * Creates HTML list of found nodes
	 * @param {Array} found List of matched nodes
	 * @param {String} query Search query
	 * @return {jQuery}
	 */
	function buildSearchResult(found, query) {
		var items = [];
		$.each(found, function(i, n) {
			/** @type {Element} */
//			var node = n.node,
//				name = node.nodeName,
//				xpath = node.getAttribute('data-xv-xpath');
//
//			if (!xpath) {
//				xpath = xv_utils.createXPath(node);
//				node.setAttribute('data-xv-xpath', xpath);
//			}
//
//			if ('ix' in n && n.ix < name.length) { // mark search result
//				name = name.substr(0, n.ix) +
//					'' + name.substr(n.ix, query.length) + ''
//					+ name.substr(n.ix + query.length);
//			}
//
//			var label = name + ' ' + xpath + '';

			items.push('
' + createSearchResultLabel(n, query) + '
');

			// reset selected item
			selected_item = -1;
		});

		popup.find('.xv-search-result-content').empty().append(items.join(''));

		if (items.length > max_visible_results) {
			popup.addClass('xv-search-result-overflow');
			popup.find('.xv-search-result-content').css('height', getSearchResultItems().eq(0).height() * max_visible_results);
		} else {
			popup.removeClass('xv-search-result-overflow');
			popup.find('.xv-search-result-content').css('height', 'auto');
		}
	}

	function hidePopup() {
		popup.hide();
		is_visible = false;
	}

	function performSearch() {
		var query = $.trim(search_field.val()).toLowerCase();

		if (!query) {
			hidePopup();
			return;
		}

		if (query == last_query && is_visible)
			return;

		last_query = query;
		last_search = xv_utils.isXPath(query) ? searchXPath(query) : searchText(query);

		if (last_search) {
			popup.show();
			buildSearchResult(last_search, query);
			is_visible = true;
		} else {
			hidePopup();
		}
	}

	function applyProposal(ix) {
		xv_signals.nodeFocused.dispatch(last_search[ix].node, 'search');
		hidePopup();
	}

	// bind events to search field
	$(function(){
		var search_timer;
		panel = $('.xv-search-panel');
		panel.append(popup.hide());

		search_field = $('.xv-search-field').keydown(function(evt) {
			if (is_visible) {
				switch (evt.keyCode) {
					case 38: //up
						selectItem(Math.max(selected_item - 1, 0));
						lockHover();
						evt.preventDefault();
						return;
					case 40: //down
						selectItem(Math.min(selected_item + 1, last_search.length - 1));
						lockHover();
						evt.preventDefault();
						return;
					case 13: //enter
						applyProposal(selected_item);
						hidePopup();
						evt.preventDefault();
						return;
					case 27: // escape
						hidePopup();
						evt.preventDefault();
						return;
				}
			}

			if (search_timer)
				clearTimeout(search_timer);

			search_timer = setTimeout(performSearch, 150);
		});

		popup
			// delegate hover event: hilight proposal
			.delegate('.xv-search-result-item', 'mouseover', function(/* Event */ evt) {
				if (is_hover_locked) return;

				var ix = getSearchResultItems().index(this);
				if (ix != -1)
					selectItem(ix, true);
			})
			// delegate click event: apply proposal
			.delegate('.xv-search-result-item', 'click', function(/* Event */ evt) {
				var ix = getSearchResultItems().index(this);
				if (ix != -1) {
					applyProposal(ix);
					hidePopup();
				}
			});

		var dont_hide = false,
			hide_timeout;

		search_field
			.blur(function() {
				// use delayed execution in to handle popup click event correctly
				hide_timeout = setTimeout(function() {
					if (!dont_hide) hidePopup();
					dont_hide = false;
				}, 200);
			})
			.focus(performSearch);

		popup.mousedown(function(/* Event */ evt) {
			evt.preventDefault();
			evt.stopPropagation();
			dont_hide = true;
			return false;
		});

		$(document).mousedown(hidePopup);
	});

	return {
		/**
		 * Init search module
		 * @param {Document} tree
		 */
		init: function(tree) {
			search_index.length = 0;
			buildIndex(tree.documentElement);
			doc = tree;
		}
	};
})();<commit_msg>Limit max search result<commit_after>/**
 * Search module
 * @author Sergey Chikuyonok (serge.che@gmail.com)
 * @link http://chikuyonok.ru
 *
 * @include "utils.js"
 * @include "signals.js"
 */
var xv_search = (function(){
	var search_index = [],
		/** @type {Document} */
		doc,

		/** @type {Array} List of last matched elements */
		last_search,

		last_query,
		/** @type {jQuery} */
		popup = $('

'),
		max_visible_results = 20,
		max_results = 200,

		selected_item = -1,

		is_visible = false,

		/** @type {jQuery} Search panel */
		panel,

		/** @type {jQuery} Search field */
		search_field,

		hover_lock_timeout,
		is_hover_locked = false;

	/**
	 * Creates search index item
	 * @param {Element} node
	 */
	function searchIndexItem(node) {
		var search_str = node.nodeName;
		var attrs = [];
		if (node.attributes) {
			for (var i = 0, il = node.attributes.length; i < il; i++) {
				if (node.attributes[i].name.indexOf('data-xv-') == -1)
					attrs.push(node.attributes[i].name);
			}
		}

		if (attrs.length)
			search_str += ' ' + attrs.join(' ');

		return {
			str: search_str.toLowerCase(),
			node: node
		};
	}

	/**
	 * Recursively build search index on node, preserving node order
	 * @param {Element} node
	 */
	function buildIndex(node) {
		if (node.nodeType != 1)
			return;

		search_index.push(searchIndexItem(node));
		for (var i = 0, il = node.childNodes.length; i < il; i++) {
			buildIndex(node.childNodes[i]);
		}
	}

	/**
	 * Simple textual search on document tree
	 * @param {String} query Search query
	 * @return {Array} Array of matched nodes, null otherwise
	 */
	function searchText(query) {
		var result = [];
		if (query) {
			$.each(search_index, function(i, /* searchIndexItem */ n) {
				var ix = n.str.indexOf(query);
				if (ix != -1) {
					result.push({
						ix: ix,
						node: n.node
					});

					if (result.length >= max_results)
						return false;
				}
			});
		}

		return result.length ? result : null;
	}

	function searchXPath(query) {
		var result = [], i = 0;
		try {
			// TODO handle namespaces
			var nodes = doc.evaluate(query, doc, null, XPathResult.ANY_TYPE, null);
			var n = nodes.iterateNext();
			while (n && i < max_results) {
				result.push({node: n});
				n = nodes.iterateNext();
				i++;
			}
		} catch(e) {}

		return result.length ? result : null;
	}

	/**
	 * Returns list of search result items
	 * @return {jQuery}
	 */
	function getSearchResultItems() {
		return popup.find('.xv-search-result-item');
	}

	/**
	 * Select search reult item
	 * @param {Number} ix Index of item
	 * @param {Boolean} no_scroll Do not scroll popup content to make shure that
	 * selected item is always visible
	 */
	function selectItem(ix, no_scroll) {
		var cur_item = getSearchResultItems()
			.removeClass('xv-search-result-item-selected')
			.eq(ix)
			.addClass('xv-search-result-item-selected');

		if (!no_scroll && cur_item.length) {
			var content = cur_item.parent();
			// make sure that selected proposal is visible
			var proposal_top = cur_item[0].offsetTop,
				proposal_height = cur_item[0].offsetHeight,
				popup_scroll = content[0].scrollTop,
				popup_height = content[0].offsetHeight;

			if (proposal_top < popup_scroll) {
				content[0].scrollTop = proposal_top;
			} else if (proposal_top + proposal_height > popup_scroll + popup_height) {
				content[0].scrollTop = proposal_top + proposal_height - popup_height;
			}
		}

		selected_item = ix;
		xv_signals.searchItemSelected.dispatch(cur_item[0], selected_item);
	}

	/**
	 * Temporary lock popup hover events.
	 * Hover lock is used to prevent accident mouseover event callback when
	 * mouse cursor is over popup window and user traverses between proposals
	 * with arrow keys
	 */
	function lockHover() {
		if (hover_lock_timeout)
			clearTimeout(hover_lock_timeout);

		is_hover_locked = true;
		setTimeout(function() {
			is_hover_locked = false;
		}, 100);
	}

	/**
	 * Creates label that will be displayed as a search result
	 * @param {Object} item Search result item
	 * @param {String} query Search query
	 */
	function createSearchResultLabel(item, query) {
		/** @type {Element} */
		var node = item.node,
			name = node.nodeName,
			ql = query.length,
			xpath = node.getAttribute('data-xv-xpath');

		if (!xpath) {
			xpath = xv_utils.createXPath(node);
			node.setAttribute('data-xv-xpath', xpath);
		}

		if ('ix' in item) { // simple text search result
			if (item.ix < name.length) {  // mark search result in node name
				name = name.substr(0, item.ix) +
					'' + name.substr(item.ix, ql) + ''
					+ name.substr(item.ix + ql);
			} else { // match found somethere in attribute, add it
				var _ix;
				$.each(node.attributes, function(i, n) {
					_ix = n.name.indexOf(query);
					if (_ix != -1) {
						name += '[@' + n.name.substr(0, _ix) +
							'' + n.name.substr(_ix, ql) + ''
							+ n.name.substr(_ix + ql) + ']';

						return false;
					}
				});
			}
		}

		return name + ' ' + xpath + '';
	}

	/**
	 * Creates HTML list of found nodes
	 * @param {Array} found List of matched nodes
	 * @param {String} query Search query
	 * @return {jQuery}
	 */
	function buildSearchResult(found, query) {
		var items = [];
		$.each(found, function(i, n) {
			/** @type {Element} */
//			var node = n.node,
//				name = node.nodeName,
//				xpath = node.getAttribute('data-xv-xpath');
//
//			if (!xpath) {
//				xpath = xv_utils.createXPath(node);
//				node.setAttribute('data-xv-xpath', xpath);
//			}
//
//			if ('ix' in n && n.ix < name.length) { // mark search result
//				name = name.substr(0, n.ix) +
//					'' + name.substr(n.ix, query.length) + ''
//					+ name.substr(n.ix + query.length);
//			}
//
//			var label = name + ' ' + xpath + '';

			items.push('
' + createSearchResultLabel(n, query) + '
');

			// reset selected item
			selected_item = -1;
		});

		popup.find('.xv-search-result-content').empty().append(items.join(''));

		if (items.length > max_visible_results) {
			popup.addClass('xv-search-result-overflow');
			popup.find('.xv-search-result-content').css('height', getSearchResultItems().eq(0).height() * max_visible_results);
		} else {
			popup.removeClass('xv-search-result-overflow');
			popup.find('.xv-search-result-content').css('height', 'auto');
		}
	}

	function hidePopup() {
		popup.hide();
		is_visible = false;
	}

	function performSearch() {
		var query = $.trim(search_field.val()).toLowerCase();

		if (!query) {
			hidePopup();
			return;
		}

		if (query == last_query && is_visible)
			return;

		last_query = query;
		last_search = xv_utils.isXPath(query) ? searchXPath(query) : searchText(query);

		if (last_search) {
			popup.show();
			buildSearchResult(last_search, query);
			is_visible = true;
		} else {
			hidePopup();
		}
	}

	function applyProposal(ix) {
		xv_signals.nodeFocused.dispatch(last_search[ix].node, 'search');
		hidePopup();
	}

	// bind events to search field
	$(function(){
		var search_timer;
		panel = $('.xv-search-panel');
		panel.append(popup.hide());

		search_field = $('.xv-search-field').keydown(function(evt) {
			if (is_visible) {
				switch (evt.keyCode) {
					case 38: //up
						selectItem(Math.max(selected_item - 1, 0));
						lockHover();
						evt.preventDefault();
						return;
					case 40: //down
						selectItem(Math.min(selected_item + 1, last_search.length - 1));
						lockHover();
						evt.preventDefault();
						return;
					case 13: //enter
						applyProposal(selected_item);
						hidePopup();
						evt.preventDefault();
						return;
					case 27: // escape
						hidePopup();
						evt.preventDefault();
						return;
				}
			}

			if (search_timer)
				clearTimeout(search_timer);

			search_timer = setTimeout(performSearch, 150);
		});

		popup
			// delegate hover event: hilight proposal
			.delegate('.xv-search-result-item', 'mouseover', function(/* Event */ evt) {
				if (is_hover_locked) return;

				var ix = getSearchResultItems().index(this);
				if (ix != -1)
					selectItem(ix, true);
			})
			// delegate click event: apply proposal
			.delegate('.xv-search-result-item', 'click', function(/* Event */ evt) {
				var ix = getSearchResultItems().index(this);
				if (ix != -1) {
					applyProposal(ix);
					hidePopup();
				}
			});

		var dont_hide = false,
			hide_timeout;

		search_field
			.blur(function() {
				// use delayed execution in to handle popup click event correctly
				hide_timeout = setTimeout(function() {
					if (!dont_hide) hidePopup();
					dont_hide = false;
				}, 200);
			})
			.focus(performSearch);

		popup.mousedown(function(/* Event */ evt) {
			evt.preventDefault();
			evt.stopPropagation();
			dont_hide = true;
			return false;
		});

		$(document).mousedown(hidePopup);
	});

	return {
		/**
		 * Init search module
		 * @param {Document} tree
		 */
		init: function(tree) {
			search_index.length = 0;
			buildIndex(tree.documentElement);
			doc = tree;
		}
	};
})();<|endoftext|>


<commit_before>import React, { useState, useEffect } from 'react';
import DocumentSummary from "./document_summary";
import PropTypes from 'prop-types';
import LoadingDocumentPlaceholder from "./loading_document_placeholder";
import { useParams } from "react-router-dom";

function SearchResults(props) {

    const { searchTerm} = useParams();

    const [searchResults, setSearchResults] = useState([]);
    const [isLoading, setIsLoading] = useState(true);

    useEffect(() => {
        const query = `query {
            search(term: ${searchTerm} {
              id
              title
              description
              date
              tags {
                title
                context
              }
            }
          }
        `;

        fetch('http://localhost:9090/query', {
            method: "POST",
            body: JSON.stringify({query: query}),
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json'
            },
        })
            .then(res => res.json())
            .then((data) => {
                setSearchResults(data.data.searchResults);
                setIsLoading(false);
            })
            .catch(function(e) {
                console.error(e);
                setIsLoading(false);
            })
    }, []);

    if (isLoading) {
        return

            { [...Array(20)].map((e, i) => <LoadingDocumentPlaceholder key={i}/>) }

;
    }

    return

        {(searchResults || []).map((recentChange) =>
            <DocumentSummary
                documentId={recentChange.id}
                title={recentChange.title}
                description={recentChange.description}
                date={recentChange.date}
                tags={recentChange.tags} />)
        }

;
}

SearchResults.propTypes = {
  searchTerm: PropTypes.string.isRequired,
};

export default SearchResults;<commit_msg>Process data from search endpoint and show it<commit_after>import React, { useState, useEffect } from 'react';
import DocumentSummary from "./document_summary";
import PropTypes from 'prop-types';
import LoadingDocumentPlaceholder from "./loading_document_placeholder";
import { useParams } from "react-router-dom";

function SearchResults(props) {

    const {searchTerm} = useParams();

    const [searchResults, setSearchResults] = useState([]);
    const [isLoading, setIsLoading] = useState(true);

    useEffect(() => {
        const query = `query {
            search(term: "${searchTerm}") {
              id
              title
              description
              date
              tags {
                title
                context
              }
            }
          }
        `;

        fetch('http://localhost:9090/query', {
            method: "POST",
            body: JSON.stringify({query: query}),
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json'
            },
        })
            .then(res => res.json())
            .then((data) => {
                setIsLoading(false);
                if (data.errors) {
                    // TODO does not render - why?
                    return
ERROR!
;
                }
                setSearchResults(data.data.search);
            })
            .catch(function(e) {
                console.error(e);
                setIsLoading(false);
            })
    }, [searchTerm]);

    if (isLoading) {
        return

            { [...Array(20)].map((e, i) => <LoadingDocumentPlaceholder key={i}/>) }

;
    }

    return

        {(searchResults || []).map((recentChange) =>
            <DocumentSummary
                documentId={recentChange.id}
                title={recentChange.title}
                description={recentChange.description}
                date={recentChange.date}
                tags={recentChange.tags} />)
        }

;
}

export default SearchResults;<|endoftext|>