<commit_before>Ext.define("DARPA.EntityNodeDisplay", {
	extend: "DARPA.AbstractNodeDisplay",

	constructor: function(config) {
		var idPanel = Ext.create("Ext.form.FieldSet",  {
			border: 0,
			padding: 2,
			margin: 2,
			flex: 1,
			layout: {
				type: 'vbox',
				align: 'stretch'
			},
			items:[{
				xtype: 'textfield',
				fieldLabel: 'Identifier Type',
				readOnly: true,
				labelLength: 80
			}, {
				xtype: 'textfield',
				fieldLabel: 'Identifier',
				readOnly: true,
				labelLength: 80
			}, {
				xtype: 'panel',
				flex: 1,
				autoScroll: true
			}]
		});

		this.items = [
			idPanel,
			Ext.create("DARPA.Node_Actions", {
				id: config.id + '-Actions',
				height: 'auto',
				collapsible: true,
				collapseDirection: "bottom"
			}),
			Ext.create("Ext.panel.Panel", {
				title: 'LEGEND',
				id: config.id + '-Legend',
				maxHeight: 300,
				autoScroll: true,
				collapsible: true,
				collapsed: true,
				collapseDirection: "bottom"
				//items: GLegend.getLegendByGroup(GLegend.getDefaultGroupName())
			})
		];

		this.callParent(arguments);
	},

    getIdentifierType: function() {
        var detailsItems = this.items.items[0].items.items;
        return detailsItems[0].getValue();
    },

    getIdentifier: function() {
        var detailsItems = this.items.items[0].items.items;
        return detailsItems[1].getValue();
    },

    getIdentifierDetails: function() {
        var detailsItems = this.items.items[0].items.items;
        return detailsItems[2].getValue();
    },

    getLegendPanel: function() {
    	return this.items.items[2]; //.items.items[0];
    },
	//Called when node(s) are selected, so that the attributes are shown in the panel.
    showNodeAttrs: function(node) {
		var self = this;
		var html = "
";
		var data = node.data();
		var attrs = data.attrs;
		var detailsItems = self.items.items[0].items.items;

		detailsItems[0].setValue(data.idType);
		detailsItems[1].setValue(data.idVal);

		var _showAttrs = function(attrs) {
			var runningHTML = "";
			for (var i = 0; i < attrs.length; ++i) {
				var a = attrs[i];
				runningHTML += "
" + a.key + "	  : 	 " + a.val + "
";
			}
			return runningHTML;
		};

		var _recurse = function(node, index) {
			var isNodeJSON = typeof node.data != "function";
			var subNodes = (!isNodeJSON) ? node.data("subNodes") : node.data.subNodes;
			var attrs = (!isNodeJSON) ? node.data("attrs") : node.data.attrs;
			var name = (!isNodeJSON) ? node.data("name") : node.data.name;
			var runningHTML = "
" + index + "_" + name + "
";

			runningHTML += _showAttrs(attrs);

			// base case -- no subnodes
			if (subNodes === null || typeof subNodes == "undefined" || subNodes.length <= 0) {
				return runningHTML;
			} else {
				for (var i = 0; i < subNodes.length; ++i) {
					runningHTML += _recurse(subNodes[i], ++index);
				}
				return runningHTML;
			}
		};

		//if (typeof node.data().subNodes == "undefined") {
		//	html += _showAttrs(attrs);
		//} else {
			html += _recurse(node, 1);
		//}
		html += "
";
		detailsItems[2].update(html);
	},

	showEdgeAttrs: function(edge) {
		var self = this;
		var html = 	"
";
		var data = edge.data();
		var attrs = data.attrs;
		var detailsItems = self.items.items[0].items.items;

		detailsItems[0].setValue(data.idType);
		detailsItems[1].setValue(data.idVal);

		var _showAttrs = function(attrs) {
			var runningHTML = "";
			for (var i = 0; i < attrs.length; ++i) {
				var a = attrs[i];
				runningHTML += "
" + a.key + "	  : 	 " + a.val + "
";
			}
			return runningHTML;
		};

		html += _showAttrs(attrs);
		html += "
";

		detailsItems[2].update(html);
	}
});<commit_msg>The user's reason (but not the user's name.. yet) appear in the right-hand node display when viewing a merged node.<commit_after>Ext.define("DARPA.EntityNodeDisplay", {
	extend: "DARPA.AbstractNodeDisplay",

	constructor: function(config) {
		var idPanel = Ext.create("Ext.form.FieldSet",  {
			border: 0,
			padding: 2,
			margin: 2,
			flex: 1,
			layout: {
				type: 'vbox',
				align: 'stretch'
			},
			items:[{
				xtype: 'textfield',
				fieldLabel: 'Identifier Type',
				readOnly: true,
				labelLength: 80
			}, {
				xtype: 'textfield',
				fieldLabel: 'Identifier',
				readOnly: true,
				labelLength: 80
			}, {
				xtype: 'panel',
				flex: 1,
				autoScroll: true
			}]
		});

		this.items = [
			idPanel,
			Ext.create("DARPA.Node_Actions", {
				id: config.id + '-Actions',
				height: 'auto',
				collapsible: true,
				collapseDirection: "bottom"
			}),
			Ext.create("Ext.panel.Panel", {
				title: 'LEGEND',
				id: config.id + '-Legend',
				maxHeight: 300,
				autoScroll: true,
				collapsible: true,
				collapsed: true,
				collapseDirection: "bottom"
				//items: GLegend.getLegendByGroup(GLegend.getDefaultGroupName())
			})
		];

		this.callParent(arguments);
	},

    getIdentifierType: function() {
        var detailsItems = this.items.items[0].items.items;
        return detailsItems[0].getValue();
    },

    getIdentifier: function() {
        var detailsItems = this.items.items[0].items.items;
        return detailsItems[1].getValue();
    },

    getIdentifierDetails: function() {
        var detailsItems = this.items.items[0].items.items;
        return detailsItems[2].getValue();
    },

    getLegendPanel: function() {
    	return this.items.items[2]; //.items.items[0];
    },
	//Called when node(s) are selected, so that the attributes are shown in the panel.
    showNodeAttrs: function(node) {
		var self = this;
		var html = "
";
		var data = node.data();
		var attrs = data.attrs;
		var detailsItems = self.items.items[0].items.items;

		detailsItems[0].setValue(data.idType);
		detailsItems[1].setValue(data.idVal);

		var _showAttrs = function(attrs) {
			var runningHTML = "";
			for (var i = 0; i < attrs.length; ++i) {
				var a = attrs[i];
				runningHTML += "
" + a.key + "	  : 	 " + a.val + "
";
			}
			return runningHTML;
		};

		var _recurse = function(node, index) {
			var isNodeJSON = typeof node.data != "function";
			var subNodes = (!isNodeJSON) ? node.data("subNodes") : node.data.subNodes;
			var attrs = (!isNodeJSON) ? node.data("attrs") : node.data.attrs;
			var name = (!isNodeJSON) ? node.data("name") : node.data.name;
			var reason = (!isNodeJSON) ? node.data("reason") : node.data.reason;
			var runningHTML = "
" + index + "_" + name + "
";

			runningHTML += _showAttrs(attrs);
			if (reason !== null && reason !== undefined) {
				runningHTML += "
Reason for Merge	  : 	 " + reason + "
";
			}
			// base case -- no subnodes
			if (subNodes === null || typeof subNodes == "undefined" || subNodes.length <= 0) {
				return runningHTML;
			} else {
				for (var i = 0; i < subNodes.length; ++i) {
					runningHTML += _recurse(subNodes[i], ++index);
				}
				return runningHTML;
			}
		};

		//if (typeof node.data().subNodes == "undefined") {
		//	html += _showAttrs(attrs);
		//} else {
			html += _recurse(node, 1);
		//}
		html += "
";
		detailsItems[2].update(html);
	},

	showEdgeAttrs: function(edge) {
		var self = this;
		var html = 	"
";
		var data = edge.data();
		var attrs = data.attrs;
		var detailsItems = self.items.items[0].items.items;

		detailsItems[0].setValue(data.idType);
		detailsItems[1].setValue(data.idVal);

		var _showAttrs = function(attrs) {
			var runningHTML = "";
			for (var i = 0; i < attrs.length; ++i) {
				var a = attrs[i];
				runningHTML += "
" + a.key + "	  : 	 " + a.val + "
";
			}
			return runningHTML;
		};

		html += _showAttrs(attrs);
		html += "
";

		detailsItems[2].update(html);
	}
});<|endoftext|>


<commit_before>/*********************************
 * jQuery.gaEvent
 * Description:		gaEvent makes it easy to write one-liner Google Event custom events.
 * Author:			Mike Zarandona
 * Version:			1.0.2
 *
 * Variables:		category [REQUIRED] [string] the name supplied for the group of objects to track
 * 					action   [REQUIRED] [string] a unique user-action paired with each category, and commonly used to define the type of user interaction for the web object
 * 					label    [OPTIONAL] [string] optional field to provide additional dimension to the event data
 *										pageURL   | label = the current page's URL
 * 										pageTitle | label = the current page's title
 *										linkDest  | label = the referenced link's destination (reference an a tag)
 *										linkTitle | label = the referenced link's title (reference an a tag)
 * 					value    [OPTIONAL] [string] integer that can be used to provide numerical data about the user event
 * 					testMode [FUNCTION VARIABLE] [bool]   flag to turn on / off test mode which when set to true pushes events to the console
 *
 * Usage:			$('#logo img').gaEvent('Logo', 'Click', 'Home');0
 *					$('a#atag').gaEvent('Header Link', 'Click', 'pageTitle');
 *
 * Note: 			I STRONGLY recommend using the Google Analytics Debugger extension for Chrome (http://tinyurl.com/knv6kos) when implementing this plugin
*********************************/

(function($){
	jQuery.fn.gaEvent = function(category, action, label, value) {

		return this.each(function(){

			// Set label as 'pageURL' to grab the current page URL
			var pageURL = window.location;
			if (label == 'pageURL') { label = pageURL; }

			// Set label as 'pageTitle' to grab the current page title
			var pageTitle = document.title;
			if (label == 'pageTitle') { label = pageTitle; }

			// Set label as 'linkDest' to grab the destination link href attribute value
			var linkDest = $(this).attr('href');
			if (label == 'linkDest') { label = linkDest; }

			// Set label as 'linkTitle' to grab the destination link title attribute value
			var linkTitle = $(this).attr('title');
			if (label == 'linkTitle') { label = linkTitle; }

			// Make sure not to send a label of 'undefined'
			if (label === undefined) { label = ''; }

			// Report to Google Analytics
			$(this).click(function() { _gaq.push(['_trackEvent', category, action, label, value]); });
		});
	};
})(jQuery);

(function($){
})(jQuery);<commit_msg>Maintenance Commit<commit_after>/*********************************
 * jQuery.gaEvent
 * Description:		gaEvent makes it easy to write one-liner Google Event custom events.
 * Author:			Mike Zarandona
 * Version:			1.0.2
 *
 * Variables:		category [REQUIRED] [string] the name supplied for the group of objects to track
 * 					action   [REQUIRED] [string] a unique user-action paired with each category, and commonly used to define the type of user interaction for the web object
 * 					label    [OPTIONAL] [string] optional field to provide additional dimension to the event data
 *										pageURL   | label = the current page's URL
 * 										pageTitle | label = the current page's title
 *										linkDest  | label = the referenced link's destination (reference an a tag)
 *										linkTitle | label = the referenced link's title (reference an a tag)
 * 					value    [OPTIONAL] [string] integer that can be used to provide numerical data about the user event
 *
 * Usage:			$('#logo img').gaEvent('Logo', 'Click', 'Home');0
 *					$('a#atag').gaEvent('Header Link', 'Click', 'pageTitle');
 *
 * Note: 			I STRONGLY recommend using the Google Analytics Debugger extension for Chrome (http://tinyurl.com/knv6kos) when implementing this plugin
*********************************/

(function($){
	jQuery.fn.gaEvent = function(category, action, label, value) {

		return this.each(function(){

			// Set label as 'pageURL' to grab the current page URL
			var pageURL = window.location;
			if (label == 'pageURL') { label = pageURL; }

			// Set label as 'pageTitle' to grab the current page title
			var pageTitle = document.title;
			if (label == 'pageTitle') { label = pageTitle; }

			// Set label as 'linkDest' to grab the destination link href attribute value
			var linkDest = $(this).attr('href');
			if (label == 'linkDest') { label = linkDest; }

			// Set label as 'linkTitle' to grab the destination link title attribute value
			var linkTitle = $(this).attr('title');
			if (label == 'linkTitle') { label = linkTitle; }

			// Make sure not to send a label of 'undefined'
			if (label === undefined) { label = ''; }

			// Report to Google Analytics
			$(this).click(function() { _gaq.push(['_trackEvent', category, action, label, value]); });
		});
	};
})(jQuery);
<|endoftext|>


<commit_before>/* global console, moment */

var EventEditor = (function () {
    "use strict";

    /*****************************************************************
    *                     C O N S T R U C T O R                      *
    *****************************************************************/

    function EventEditor () {

    }

    /******************************************************************/
    /*                P R I V A T E   F U N C T I O N S               */
    /******************************************************************/
    function checkEventEditor() {
      var isValidDate = isValidDateEventEditor();
      var isValidDescription = isValidDescriptionEventEditor();

      $('#saveEvent').prop('disabled', !(isValidDate && isValidDescription));
    }

    function isValidDateEventEditor() {
      if(moment($('#dateStart').val() + " " + $('#timeStart').val()).isBefore(moment($('#dateEnd').val() + " " + $('#timeEnd').val()))) {
        $('#dateEndForm').removeClass('has-error');
        $('#timeEndForm').removeClass('has-error');
        return true;
      } else {
        $('#dateEndForm').addClass('has-error');
        $('#timeEndForm').addClass('has-error');
        return false;
      }
    }

    function isValidDescriptionEventEditor() {
      if($('#description').val() === "") {
        $('#descriptionForm').addClass('has-error');
        return false;
      } else {
        $('#descriptionForm').removeClass('has-error');
        return true;
      }
    }

    function clearEventEditor() {
      $('#descriptionForm').removeClass('has-error');
      $('#dateEndForm').removeClass('has-error');
      $('#timeEndForm').removeClass('has-error');
      $('#saveEvent').prop('disabled', true);
    }

    function saveEvent(object) {
      var event = object.data.oldEvent;
      var callback = object.data.callback;

      event.title = $('#description').val() + "\n" + "Start: " + $('#dateStart').val() + " " + $('#timeStart').val() + "\n" + "End: " + $('#dateEnd').val() + " " + $('#timeEnd').val();
      event.content = $('#description').val();
      event.start = $('#dateStart').val() + " " + $('#timeStart').val() + moment().format("ZZ");
      event.end = $('#dateEnd').val() + " " + $('#timeEnd').val() + moment().format("ZZ");
      callback(event);
    }

    /******************************************************************/
    /*                 P U B L I C   F U N C T I O N S                */
    /******************************************************************/

    EventEditor.prototype = {
        init: function () {

        },
        setUp: function () {
          console.log("Configurando el editor de eventos.");
          $('#modalEventEditor').on('shown.bs.modal', function () {
            $('#description').focus();
          });
          $('#description').keyup(checkEventEditor);
          $('#dateStart').change(checkEventEditor);
          $('#timeStart').change(checkEventEditor);
          $('#dateEnd').change(checkEventEditor);
          $('#tiemEnd').change(checkEventEditor);
        },
        showEventEditor: function (event, saveFunction) {
          clearEventEditor();

          if (event.content === "")
            $('#modalTitle').text("New Event");
          else
            $('#modalTitle').text(event.content);

          $('#description').val(event.content); //Event Content
          $('#dateStart').val(moment(event.start).format("YYYY-MM-DD")); //Add start datetime
          $('#timeStart').val(moment(event.start).format("HH:mm")); //Add start datetime
          $('#dateEnd').val(moment(event.end).format("YYYY-MM-DD")); //Add final datetime
          $('#timeEnd').val(moment(event.end).format("HH:mm")); //Add final datetime

          if (typeof event.id !== 'undefined')
            $('#saveEvent').prop('disabled', false);
          else
            $('#saveEvent').prop('disabled', true);

          //Events
          $('#saveEvent').off("click");
          $('#saveEvent').click({callback: saveFunction, oldEvent: event}, saveEvent);

          $('#modalEventEditor').modal("show");
        },
        hideEventEditor: function () {
          $('#modalEventEditor').modal("hide");
          clearEventEditor();
        }
    };

    return EventEditor;
})();<commit_msg>Update EventEditor to UTC<commit_after>/* global console, moment */

var EventEditor = (function () {
    "use strict";

    /*****************************************************************
    *                     C O N S T R U C T O R                      *
    *****************************************************************/

    function EventEditor () {

    }

    /******************************************************************/
    /*                P R I V A T E   F U N C T I O N S               */
    /******************************************************************/
    function checkEventEditor() {
      var isValidDate = isValidDateEventEditor();
      var isValidDescription = isValidDescriptionEventEditor();

      $('#saveEvent').prop('disabled', !(isValidDate && isValidDescription));
    }

    function isValidDateEventEditor() {
      if(moment.utc($('#dateStart').val() + " " + $('#timeStart').val()).isBefore(moment.utc($('#dateEnd').val() + " " + $('#timeEnd').val()))) {
        $('#dateEndForm').removeClass('has-error');
        $('#timeEndForm').removeClass('has-error');
        return true;
      } else {
        $('#dateEndForm').addClass('has-error');
        $('#timeEndForm').addClass('has-error');
        return false;
      }
    }

    function isValidDescriptionEventEditor() {
      if($('#description').val() === "") {
        $('#descriptionForm').addClass('has-error');
        return false;
      } else {
        $('#descriptionForm').removeClass('has-error');
        return true;
      }
    }

    function clearEventEditor() {
      $('#descriptionForm').removeClass('has-error');
      $('#dateEndForm').removeClass('has-error');
      $('#timeEndForm').removeClass('has-error');
      $('#saveEvent').prop('disabled', true);
    }

    function saveEvent(object) {
      var event = object.data.oldEvent;
      var callback = object.data.callback;

      event.title = $('#description').val() + "\n" + "Start: " + $('#dateStart').val() + " " + $('#timeStart').val() + "\n" + "End: " + $('#dateEnd').val() + " " + $('#timeEnd').val();
      event.content = $('#description').val();
      event.start = $('#dateStart').val() + " " + $('#timeStart').val() + moment.utc().format("ZZ");
      event.end = $('#dateEnd').val() + " " + $('#timeEnd').val() + moment.utc().format("ZZ");
      callback(event);
    }

    /******************************************************************/
    /*                 P U B L I C   F U N C T I O N S                */
    /******************************************************************/

    EventEditor.prototype = {
        init: function () {

        },
        setUp: function () {
          console.log("Configurando el editor de eventos.");
          $('#modalEventEditor').on('shown.bs.modal', function () {
            $('#description').focus();
          });
          $('#description').keyup(checkEventEditor);
          $('#dateStart').change(checkEventEditor);
          $('#timeStart').change(checkEventEditor);
          $('#dateEnd').change(checkEventEditor);
          $('#tiemEnd').change(checkEventEditor);
        },
        showEventEditor: function (event, saveFunction) {
          clearEventEditor();

          if (event.content === "")
            $('#modalTitle').text("New Event");
          else
            $('#modalTitle').text(event.content);

          $('#description').val(event.content); //Event Content
          $('#dateStart').val(moment.utc(event.start).format("YYYY-MM-DD")); //Add start datetime
          $('#timeStart').val(moment.utc(event.start).format("HH:mm")); //Add start datetime
          $('#dateEnd').val(moment.utc(event.end).format("YYYY-MM-DD")); //Add final datetime
          $('#timeEnd').val(moment.utc(event.end).format("HH:mm")); //Add final datetime

          if (typeof event.id !== 'undefined')
            $('#saveEvent').prop('disabled', false);
          else
            $('#saveEvent').prop('disabled', true);

          //Events
          $('#saveEvent').off("click");
          $('#saveEvent').click({callback: saveFunction, oldEvent: event}, saveEvent);

          $('#modalEventEditor').modal("show");
        },
        hideEventEditor: function () {
          $('#modalEventEditor').modal("hide");
          clearEventEditor();
        }
    };

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


<commit_before>import { active } from './drop';
import Class from '../mixin/class';
import Container from '../mixin/container';
import {
    $,
    $$,
    addClass,
    after,
    css,
    findIndex,
    hasAttr,
    hasClass,
    height,
    includes,
    isRtl,
    matches,
    noop,
    observeResize,
    offset,
    once,
    parent,
    query,
    remove,
    selFocusable,
    toFloat,
    Transition,
    within,
} from 'uikit-util';

export default {
    mixins: [Class, Container],

    props: {
        dropdown: String,
        mode: 'list',
        align: String,
        offset: Number,
        boundary: Boolean,
        target: Boolean,
        clsDrop: String,
        delayShow: Number,
        delayHide: Number,
        dropbar: Boolean,
        dropbarAnchor: Boolean,
        duration: Number,
    },

    data: {
        dropdown: '.uk-navbar-nav > li > a, .uk-navbar-item, .uk-navbar-toggle',
        align: isRtl ? 'right' : 'left',
        clsDrop: 'uk-navbar-dropdown',
        mode: undefined,
        offset: undefined,
        delayShow: undefined,
        delayHide: undefined,
        flip: false,
        shift: true,
        boundary: true,
        target: false,
        targetX: false,
        targetY: false,
        dropbar: false,
        dropbarAnchor: false,
        duration: 200,
        container: false,
    },

    computed: {
        boundary({ boundary }, $el) {
            return boundary === true ? $el : boundary;
        },

        target({ target }, $el) {
            return target === true ? $el : target;
        },

        targetX({ targetX }, $el) {
            return targetX === true ? $el : targetX;
        },

        targetY({ targetY }, $el) {
            return targetY === true ? $el : targetY;
        },

        dropbarAnchor({ dropbarAnchor }, $el) {
            return query(dropbarAnchor, $el);
        },

        pos({ align }) {
            return `bottom-${align}`;
        },

        dropbar: {
            get({ dropbar }) {
                if (!dropbar) {
                    return null;
                }

                dropbar =
                    this._dropbar ||
                    query(dropbar, this.$el) ||
                    $('+ .uk-navbar-dropbar', this.$el);

                return dropbar ? dropbar : (this._dropbar = $('

'));
            },

            watch(dropbar) {
                addClass(dropbar, 'uk-dropbar', 'uk-navbar-dropbar', 'uk-navbar-dropbar-top');
            },

            immediate: true,
        },

        dropContainer(_, $el) {
            return this.container || $el;
        },

        dropdowns: {
            get({ clsDrop }, $el) {
                const dropdowns = $$(`.${clsDrop}`, $el);

                if (this.dropContainer !== $el) {
                    for (const el of $$(`.${clsDrop}`, this.dropContainer)) {
                        const target = this.getDropdown(el)?.targetEl;
                        if (!includes(dropdowns, el) && target && within(target, this.$el)) {
                            dropdowns.push(el);
                        }
                    }
                }

                return dropdowns;
            },

            watch(dropdowns) {
                this.$create(
                    'drop',
                    dropdowns.filter((el) => !this.getDropdown(el)),
                    {
                        ...this.$props,
                        boundary: this.boundary,
                        pos: this.pos,
                    }
                );
            },

            immediate: true,
        },

        toggles: {
            get({ dropdown }, $el) {
                return $$(dropdown, $el);
            },

            watch() {
                const justify = hasClass(this.$el, 'uk-navbar-justify');
                for (const container of $$(
                    '.uk-navbar-nav, .uk-navbar-left, .uk-navbar-right',
                    this.$el
                )) {
                    css(container, 'flexGrow', justify ? $$(this.dropdown, container).length : '');
                }
            },

            immediate: true,
        },
    },

    disconnected() {
        this.dropbar && remove(this.dropbar);
        delete this._dropbar;
    },

    events: [
        {
            name: 'mouseover focusin',

            delegate() {
                return this.dropdown;
            },

            handler({ current }) {
                const active = this.getActive();
                if (
                    active &&
                    includes(active.mode, 'hover') &&
                    active.targetEl &&
                    !within(active.targetEl, current) &&
                    !active.isDelaying
                ) {
                    active.hide(false);
                }
            },
        },

        {
            name: 'keydown',

            delegate() {
                return this.dropdown;
            },

            handler(e) {
                const { current, keyCode } = e;
                const active = this.getActive();

                if (keyCode === keyMap.DOWN && hasAttr(current, 'aria-expanded')) {
                    e.preventDefault();

                    if (!active || active.targetEl !== current) {
                        current.click();
                        once(this.dropContainer, 'show', ({ target }) =>
                            focusFirstFocusableElement(target)
                        );
                    } else {
                        focusFirstFocusableElement(active.$el);
                    }
                }

                handleNavItemNavigation(e, this.toggles, active);
            },
        },

        {
            name: 'keydown',

            el() {
                return this.dropContainer;
            },

            delegate() {
                return `.${this.clsDrop}`;
            },

            handler(e) {
                const { current, keyCode } = e;

                if (!includes(this.dropdowns, current)) {
                    return;
                }

                const active = this.getActive();
                const elements = $$(selFocusable, current);
                const i = findIndex(elements, (el) => matches(el, ':focus'));

                if (keyCode === keyMap.UP) {
                    e.preventDefault();
                    if (i > 0) {
                        elements[i - 1].focus();
                    }
                }

                if (keyCode === keyMap.DOWN) {
                    e.preventDefault();
                    if (i < elements.length - 1) {
                        elements[i + 1].focus();
                    }
                }

                if (keyCode === keyMap.ESC) {
                    active?.targetEl?.focus();
                }

                handleNavItemNavigation(e, this.toggles, active);
            },
        },

        {
            name: 'mouseleave',

            el() {
                return this.dropbar;
            },

            filter() {
                return this.dropbar;
            },

            handler() {
                const active = this.getActive();

                if (
                    active &&
                    includes(active.mode, 'hover') &&
                    !this.dropdowns.some((el) => matches(el, ':hover'))
                ) {
                    active.hide();
                }
            },
        },

        {
            name: 'beforeshow',

            el() {
                return this.dropContainer;
            },

            filter() {
                return this.dropbar;
            },

            handler({ target }) {
                if (!this.isDropbarDrop(target)) {
                    return;
                }

                if (!parent(this.dropbar)) {
                    after(this.dropbarAnchor || this.$el, this.dropbar);
                }

                addClass(target, `${this.clsDrop}-dropbar`);
            },
        },

        {
            name: 'show',

            el() {
                return this.dropContainer;
            },

            filter() {
                return this.dropbar;
            },

            handler({ target }) {
                if (!this.isDropbarDrop(target)) {
                    return;
                }

                this._observer = observeResize(target, () =>
                    this.transitionTo(
                        offset(target).bottom -
                            offset(this.dropbar).top +
                            toFloat(css(target, 'marginBottom')),
                        target
                    )
                );
            },
        },

        {
            name: 'beforehide',

            el() {
                return this.dropContainer;
            },

            filter() {
                return this.dropbar;
            },

            handler(e) {
                const active = this.getActive();

                if (
                    matches(this.dropbar, ':hover') &&
                    active?.$el === e.target &&
                    !this.toggles.some((el) => active.targetEl !== el && matches(el, ':focus'))
                ) {
                    e.preventDefault();
                }
            },
        },

        {
            name: 'hide',

            el() {
                return this.dropContainer;
            },

            filter() {
                return this.dropbar;
            },

            handler({ target }) {
                if (!this.isDropbarDrop(target)) {
                    return;
                }

                this._observer.disconnect();

                const active = this.getActive();

                if (!active || active?.$el === target) {
                    this.transitionTo(0);
                }
            },
        },
    ],

    methods: {
        getActive() {
            return active && within(active.targetEl, this.$el) && active;
        },

        transitionTo(newHeight, el) {
            const { dropbar } = this;
            const oldHeight = height(dropbar);

            el = oldHeight < newHeight && el;

            css(el, 'clipPath', `polygon(0 0,100% 0,100% ${oldHeight}px,0 ${oldHeight}px)`);

            height(dropbar, oldHeight);

            Transition.cancel([el, dropbar]);
            Promise.all([
                Transition.start(dropbar, { height: newHeight }, this.duration),
                Transition.start(
                    el,
                    {
                        clipPath: `polygon(0 0,100% 0,100% ${newHeight}px,0 ${newHeight}px)`,
                    },
                    this.duration
                ),
            ])
                .catch(noop)
                .then(() => css(el, { clipPath: '' }));
        },

        getDropdown(el) {
            return this.$getComponent(el, 'drop') || this.$getComponent(el, 'dropdown');
        },

        isDropbarDrop(el) {
            return this.getDropdown(el) && hasClass(el, this.clsDrop);
        },
    },
};

function handleNavItemNavigation(e, toggles, active) {
    const { current, keyCode } = e;
    const target = active?.targetEl || current;
    const i = toggles.indexOf(target);

    // Left
    if (keyCode === keyMap.LEFT && i > 0) {
        active?.hide(false);
        toggles[i - 1].focus();
    }

    // Right
    if (keyCode === keyMap.RIGHT && i < toggles.length - 1) {
        active?.hide(false);
        toggles[i + 1].focus();
    }

    if (keyCode === keyMap.TAB) {
        target.focus();
        active?.hide(false);
    }
}

function focusFirstFocusableElement(el) {
    if (!$(':focus', el)) {
        $(selFocusable, el)?.focus();
    }
}

const keyMap = {
    TAB: 9,
    ESC: 27,
    LEFT: 37,
    UP: 38,
    RIGHT: 39,
    DOWN: 40,
};
<commit_msg>refactor: rename 'uk-navbar-dropbar-top' to 'uk-dropbar-top'<commit_after>import { active } from './drop';
import Class from '../mixin/class';
import Container from '../mixin/container';
import {
    $,
    $$,
    addClass,
    after,
    css,
    findIndex,
    hasAttr,
    hasClass,
    height,
    includes,
    isRtl,
    matches,
    noop,
    observeResize,
    offset,
    once,
    parent,
    query,
    remove,
    selFocusable,
    toFloat,
    Transition,
    within,
} from 'uikit-util';

export default {
    mixins: [Class, Container],

    props: {
        dropdown: String,
        mode: 'list',
        align: String,
        offset: Number,
        boundary: Boolean,
        target: Boolean,
        clsDrop: String,
        delayShow: Number,
        delayHide: Number,
        dropbar: Boolean,
        dropbarAnchor: Boolean,
        duration: Number,
    },

    data: {
        dropdown: '.uk-navbar-nav > li > a, .uk-navbar-item, .uk-navbar-toggle',
        align: isRtl ? 'right' : 'left',
        clsDrop: 'uk-navbar-dropdown',
        mode: undefined,
        offset: undefined,
        delayShow: undefined,
        delayHide: undefined,
        flip: false,
        shift: true,
        boundary: true,
        target: false,
        targetX: false,
        targetY: false,
        dropbar: false,
        dropbarAnchor: false,
        duration: 200,
        container: false,
    },

    computed: {
        boundary({ boundary }, $el) {
            return boundary === true ? $el : boundary;
        },

        target({ target }, $el) {
            return target === true ? $el : target;
        },

        targetX({ targetX }, $el) {
            return targetX === true ? $el : targetX;
        },

        targetY({ targetY }, $el) {
            return targetY === true ? $el : targetY;
        },

        dropbarAnchor({ dropbarAnchor }, $el) {
            return query(dropbarAnchor, $el);
        },

        pos({ align }) {
            return `bottom-${align}`;
        },

        dropbar: {
            get({ dropbar }) {
                if (!dropbar) {
                    return null;
                }

                dropbar =
                    this._dropbar ||
                    query(dropbar, this.$el) ||
                    $('+ .uk-navbar-dropbar', this.$el);

                return dropbar ? dropbar : (this._dropbar = $('

'));
            },

            watch(dropbar) {
                addClass(dropbar, 'uk-dropbar', 'uk-dropbar-top', 'uk-navbar-dropbar');
            },

            immediate: true,
        },

        dropContainer(_, $el) {
            return this.container || $el;
        },

        dropdowns: {
            get({ clsDrop }, $el) {
                const dropdowns = $$(`.${clsDrop}`, $el);

                if (this.dropContainer !== $el) {
                    for (const el of $$(`.${clsDrop}`, this.dropContainer)) {
                        const target = this.getDropdown(el)?.targetEl;
                        if (!includes(dropdowns, el) && target && within(target, this.$el)) {
                            dropdowns.push(el);
                        }
                    }
                }

                return dropdowns;
            },

            watch(dropdowns) {
                this.$create(
                    'drop',
                    dropdowns.filter((el) => !this.getDropdown(el)),
                    {
                        ...this.$props,
                        boundary: this.boundary,
                        pos: this.pos,
                    }
                );
            },

            immediate: true,
        },

        toggles: {
            get({ dropdown }, $el) {
                return $$(dropdown, $el);
            },

            watch() {
                const justify = hasClass(this.$el, 'uk-navbar-justify');
                for (const container of $$(
                    '.uk-navbar-nav, .uk-navbar-left, .uk-navbar-right',
                    this.$el
                )) {
                    css(container, 'flexGrow', justify ? $$(this.dropdown, container).length : '');
                }
            },

            immediate: true,
        },
    },

    disconnected() {
        this.dropbar && remove(this.dropbar);
        delete this._dropbar;
    },

    events: [
        {
            name: 'mouseover focusin',

            delegate() {
                return this.dropdown;
            },

            handler({ current }) {
                const active = this.getActive();
                if (
                    active &&
                    includes(active.mode, 'hover') &&
                    active.targetEl &&
                    !within(active.targetEl, current) &&
                    !active.isDelaying
                ) {
                    active.hide(false);
                }
            },
        },

        {
            name: 'keydown',

            delegate() {
                return this.dropdown;
            },

            handler(e) {
                const { current, keyCode } = e;
                const active = this.getActive();

                if (keyCode === keyMap.DOWN && hasAttr(current, 'aria-expanded')) {
                    e.preventDefault();

                    if (!active || active.targetEl !== current) {
                        current.click();
                        once(this.dropContainer, 'show', ({ target }) =>
                            focusFirstFocusableElement(target)
                        );
                    } else {
                        focusFirstFocusableElement(active.$el);
                    }
                }

                handleNavItemNavigation(e, this.toggles, active);
            },
        },

        {
            name: 'keydown',

            el() {
                return this.dropContainer;
            },

            delegate() {
                return `.${this.clsDrop}`;
            },

            handler(e) {
                const { current, keyCode } = e;

                if (!includes(this.dropdowns, current)) {
                    return;
                }

                const active = this.getActive();
                const elements = $$(selFocusable, current);
                const i = findIndex(elements, (el) => matches(el, ':focus'));

                if (keyCode === keyMap.UP) {
                    e.preventDefault();
                    if (i > 0) {
                        elements[i - 1].focus();
                    }
                }

                if (keyCode === keyMap.DOWN) {
                    e.preventDefault();
                    if (i < elements.length - 1) {
                        elements[i + 1].focus();
                    }
                }

                if (keyCode === keyMap.ESC) {
                    active?.targetEl?.focus();
                }

                handleNavItemNavigation(e, this.toggles, active);
            },
        },

        {
            name: 'mouseleave',

            el() {
                return this.dropbar;
            },

            filter() {
                return this.dropbar;
            },

            handler() {
                const active = this.getActive();

                if (
                    active &&
                    includes(active.mode, 'hover') &&
                    !this.dropdowns.some((el) => matches(el, ':hover'))
                ) {
                    active.hide();
                }
            },
        },

        {
            name: 'beforeshow',

            el() {
                return this.dropContainer;
            },

            filter() {
                return this.dropbar;
            },

            handler({ target }) {
                if (!this.isDropbarDrop(target)) {
                    return;
                }

                if (!parent(this.dropbar)) {
                    after(this.dropbarAnchor || this.$el, this.dropbar);
                }

                addClass(target, `${this.clsDrop}-dropbar`);
            },
        },

        {
            name: 'show',

            el() {
                return this.dropContainer;
            },

            filter() {
                return this.dropbar;
            },

            handler({ target }) {
                if (!this.isDropbarDrop(target)) {
                    return;
                }

                this._observer = observeResize(target, () =>
                    this.transitionTo(
                        offset(target).bottom -
                            offset(this.dropbar).top +
                            toFloat(css(target, 'marginBottom')),
                        target
                    )
                );
            },
        },

        {
            name: 'beforehide',

            el() {
                return this.dropContainer;
            },

            filter() {
                return this.dropbar;
            },

            handler(e) {
                const active = this.getActive();

                if (
                    matches(this.dropbar, ':hover') &&
                    active?.$el === e.target &&
                    !this.toggles.some((el) => active.targetEl !== el && matches(el, ':focus'))
                ) {
                    e.preventDefault();
                }
            },
        },

        {
            name: 'hide',

            el() {
                return this.dropContainer;
            },

            filter() {
                return this.dropbar;
            },

            handler({ target }) {
                if (!this.isDropbarDrop(target)) {
                    return;
                }

                this._observer.disconnect();

                const active = this.getActive();

                if (!active || active?.$el === target) {
                    this.transitionTo(0);
                }
            },
        },
    ],

    methods: {
        getActive() {
            return active && within(active.targetEl, this.$el) && active;
        },

        transitionTo(newHeight, el) {
            const { dropbar } = this;
            const oldHeight = height(dropbar);

            el = oldHeight < newHeight && el;

            css(el, 'clipPath', `polygon(0 0,100% 0,100% ${oldHeight}px,0 ${oldHeight}px)`);

            height(dropbar, oldHeight);

            Transition.cancel([el, dropbar]);
            Promise.all([
                Transition.start(dropbar, { height: newHeight }, this.duration),
                Transition.start(
                    el,
                    {
                        clipPath: `polygon(0 0,100% 0,100% ${newHeight}px,0 ${newHeight}px)`,
                    },
                    this.duration
                ),
            ])
                .catch(noop)
                .then(() => css(el, { clipPath: '' }));
        },

        getDropdown(el) {
            return this.$getComponent(el, 'drop') || this.$getComponent(el, 'dropdown');
        },

        isDropbarDrop(el) {
            return this.getDropdown(el) && hasClass(el, this.clsDrop);
        },
    },
};

function handleNavItemNavigation(e, toggles, active) {
    const { current, keyCode } = e;
    const target = active?.targetEl || current;
    const i = toggles.indexOf(target);

    // Left
    if (keyCode === keyMap.LEFT && i > 0) {
        active?.hide(false);
        toggles[i - 1].focus();
    }

    // Right
    if (keyCode === keyMap.RIGHT && i < toggles.length - 1) {
        active?.hide(false);
        toggles[i + 1].focus();
    }

    if (keyCode === keyMap.TAB) {
        target.focus();
        active?.hide(false);
    }
}

function focusFirstFocusableElement(el) {
    if (!$(':focus', el)) {
        $(selFocusable, el)?.focus();
    }
}

const keyMap = {
    TAB: 9,
    ESC: 27,
    LEFT: 37,
    UP: 38,
    RIGHT: 39,
    DOWN: 40,
};
<|endoftext|>


<commit_before>window.CoreLibrary = (function () {
   'use strict';

   /** Rivets formatters **/
   rivets.formatters['==='] = function ( v1, v2 ) {
      return v1 === v2;
   };
   rivets.formatters['=='] = function ( v1, v2 ) {
      return v1 == v2; // jshint ignore:line
   };
   rivets.formatters['>='] = function ( v1, v2 ) {
      return v1 >= v2;
   };
   rivets.formatters['>'] = function ( v1, v2 ) {
      return v1 > v2;
   };
   rivets.formatters['<='] = function ( v1, v2 ) {
      return v1 <= v2;
   };
   rivets.formatters['<'] = function ( v1, v2 ) {
      return v1 < v2;
   };
   rivets.formatters['!='] = function ( v1, v2 ) {
      return v1 != v2; // jshint ignore:line
   };
   rivets.formatters['!=='] = function ( v1, v2 ) {
      return v1 !== v2;
   };
   rivets.formatters['and'] = function ( v1, v2 ) {
      return v1 && v2;
   };
   rivets.formatters['or'] = function ( v1, v2 ) {
      return v1 || v2;
   };
   rivets.formatters['not'] = function ( v1 ) {
      return !v1;
   };
   rivets.formatters['-'] = function ( v1, v2 ) {
      return v1 - v2;
   };
   rivets.formatters['+'] = function ( v1, v2 ) {
      return v1 + v2;
   };
   rivets.formatters['*'] = function ( v1, v2 ) {
      return v1 * v2;
   };
   rivets.formatters['/'] = function ( v1, v2 ) {
      return v1 / v2;
   };
   rivets.binders['style-*'] = function ( el, value ) {
      el.style.setProperty(this.args[0], value);
   };

   /**
    * Cloaking waits for element to bind and then sets it visible
    * @type {{priority: number, bind: rivets.binders.cloak.bind}}
    */
   rivets.binders.cloak = {
      priority : -1000,
      bind : function ( el ) {
         el.style.opacity = 1;
      }
   };

   /**
    * Binder that adds animation class
    *
    * Used in DOM as

    *
    * @param el
    * @param index
    */
   rivets.binders['anim-stagger'] = function ( el, index ) {
      el.classList.add('anim-stagger');
      setTimeout(function () {
         el.classList.add('anim-enter-active');
      }, 100 * index);
   };

   /**
    * Checks the HTTP status of a response
    */
   function checkStatus ( response ) {
      if ( response.status >= 200 && response.status < 300 ) {
         return response;
      } else {
         var error = new Error(response.statusText);
         error.response = response;
         throw error;
      }
   }

   /**
    * Parses the response as json
    */
   function parseJSON ( response ) {
      return response.json();
   }

   sightglass.adapters = rivets.adapters;
   sightglass.root = '.';

   return {
      expectedApiVersion: '{{expectedApiVersion}}', // this value is replaced with the API version number during the compilation step
      widgetModule: null,
      offeringModule: null,
      statisticsModule: null,
      apiReady: false, // this value is set to true once the kambi API has finished loaded
      config: {
         oddsFormat: 'decimal',
         apiVersion: 'v2',
         streamingAllowedForPlayer: false
      },
      height: 450,
      pageInfo: {},
      init: function ( setDefaultHeight ) {
         return new Promise(function ( resolve, reject ) {
            if ( window.KambiWidget ) {
               // For development purposes we might want to load a widget on it's own so we check if we are in an iframe, if not then load some fake data
               if ( window.self === window.top ) {
                  console.warn(window.location.host + window.location.pathname + ' is being loaded as stand-alone');
                  // Load the mock config data
                  fetch('mockSetupData.json')
                     .then(checkStatus)
                     .then(parseJSON)
                     .then(function ( mockSetupData ) {
                        // Output some debug info that could be helpful
                        console.debug('Loaded mock setup data');
                        console.debug(mockSetupData);
                        // Apply the mock config data to the core
                        this.applySetupData(mockSetupData, setDefaultHeight);
                        if (this.translationModule != null) {
                           this.translationModule.fetchTranslations(mockSetupData.clientConfig.locale).then(function () {
                              resolve(mockSetupData['arguments']);
                           }.bind(this));
                        } else {
                           resolve(mockSetupData['arguments']);
                        }
                     }.bind(this))
                     .catch(function ( error ) {
                        console.debug('Request failed');
                        console.trace(error);
                        reject();
                     });
               } else {
                  window.KambiWidget.apiReady = function ( api ) {
                     this.widgetModule.api = api;
                     if (api.VERSION !== this.expectedApiVersion) {
                        console.warn('Wrong Kambi API version loaded, expected: ' + this.expectedApiVersion + ' got: ' + api.VERSION);
                     }

                     // Request the setup info from the widget api
                     this.requestSetup(function ( setupData ) {
                        // Apply the config data to the core
                        this.applySetupData(setupData, setDefaultHeight);

                        // TODO: Move this to widgets so we don't request them when not needed
                        // Request the outcomes from the betslip so we can update our widget, this will also sets up a subscription for future betslip updates
                        this.widgetModule.requestBetslipOutcomes();
                        // Request the odds format that is set in the sportsbook, this also sets up a subscription for future odds format changes
                        this.widgetModule.requestOddsFormat();

                        if (this.translationModule != null) {
                           this.translationModule.fetchTranslations(setupData.clientConfig.locale).then(function () {
                              resolve(setupData['arguments']);
                           }.bind(this));
                        } else {
                           resolve(setupData['arguments']);
                        }
                     }.bind(this));
                  }.bind(this);
                  // Setup the response handler for the widget api
                  window.KambiWidget.receiveResponse = function ( dataObject ) {
                     this.widgetModule.handleResponse(dataObject);
                  }.bind(this);
               }
            } else {
               console.warn('Kambi widget API not loaded');
               reject();
            }
         }.bind(this));
      },

      applySetupData: function ( setupData, setDefaultHeight ) {
         // Set the odds format
         if ( setupData.clientConfig.oddsFormat != null ) {
            this.setOddsFormat(setupData.clientConfig.oddsFormat);
         }

         // Set the configuration in the offering module
         this.offeringModule.setConfig(setupData.clientConfig);

         // Set the configuration in the widget api module
         this.widgetModule.setConfig(setupData.clientConfig);

         // Set the configuration in the widget api module
         this.statisticsModule.setConfig(setupData.clientConfig);

         // Set page info
         this.setPageInfo(setupData.pageInfo);

         if ( setDefaultHeight === true ) {
            this.setHeight(setupData.height);
         }
         this.apiReady = true;
         this.config = setupData;
      },

      requestSetup: function ( callback ) {
         this.widgetModule.requestSetup(callback);
      },

      receiveRespone: function ( response ) {
         console.debug(response);
      },

      setOddsFormat: function ( oddsFormat ) {
         this.config.oddsFormat = oddsFormat;
      },

      setHeight: function ( height ) {
         this.height = height;
         this.widgetModule.setHeight(height);
      },

      setPageInfo: function ( pageInfo ) {
         // Check if the last character in the pageParam property is a slash, if not add it so we can use this property in filter requests
         if ( pageInfo.pageType === 'filter' && pageInfo.pageParam.substr(-1) !== '/' ) {
            pageInfo.pageParam += '/';
         }
         this.pageInfo = pageInfo;
      },

      getData: function ( url ) {
         return fetch(url)
            .then(checkStatus)
            .then(parseJSON)
            .catch(function ( error ) {
               console.debug('Error fetching data');
               console.trace(error);
               throw error;
            });
      },

      getFile: function ( url ) {
         return fetch(url)
            .then(checkStatus)
            .catch(function ( error ) {
               console.debug('Error fetching file');
               console.trace(error);
               throw error;
            });
      }
   };

})();
<commit_msg>Updated animation delay<commit_after>window.CoreLibrary = (function () {
   'use strict';

   /** Rivets formatters **/
   rivets.formatters['==='] = function ( v1, v2 ) {
      return v1 === v2;
   };
   rivets.formatters['=='] = function ( v1, v2 ) {
      return v1 == v2; // jshint ignore:line
   };
   rivets.formatters['>='] = function ( v1, v2 ) {
      return v1 >= v2;
   };
   rivets.formatters['>'] = function ( v1, v2 ) {
      return v1 > v2;
   };
   rivets.formatters['<='] = function ( v1, v2 ) {
      return v1 <= v2;
   };
   rivets.formatters['<'] = function ( v1, v2 ) {
      return v1 < v2;
   };
   rivets.formatters['!='] = function ( v1, v2 ) {
      return v1 != v2; // jshint ignore:line
   };
   rivets.formatters['!=='] = function ( v1, v2 ) {
      return v1 !== v2;
   };
   rivets.formatters['and'] = function ( v1, v2 ) {
      return v1 && v2;
   };
   rivets.formatters['or'] = function ( v1, v2 ) {
      return v1 || v2;
   };
   rivets.formatters['not'] = function ( v1 ) {
      return !v1;
   };
   rivets.formatters['-'] = function ( v1, v2 ) {
      return v1 - v2;
   };
   rivets.formatters['+'] = function ( v1, v2 ) {
      return v1 + v2;
   };
   rivets.formatters['*'] = function ( v1, v2 ) {
      return v1 * v2;
   };
   rivets.formatters['/'] = function ( v1, v2 ) {
      return v1 / v2;
   };
   rivets.binders['style-*'] = function ( el, value ) {
      el.style.setProperty(this.args[0], value);
   };

   /**
    * Cloaking waits for element to bind and then sets it visible
    * @type {{priority: number, bind: rivets.binders.cloak.bind}}
    */
   rivets.binders.cloak = {
      priority : -1000,
      bind : function ( el ) {
         el.style.opacity = 1;
      }
   };

   /**
    * Binder that adds animation class
    *
    * Used in DOM as

    *
    * @param el DOM element to apply classes
    * @param index List item index
    */
   rivets.binders['anim-stagger'] = function ( el, index ) {
      var speed = 70;
      el.classList.add('anim-stagger');
      setTimeout(function () {
         el.classList.add('anim-enter-active');
      }, speed * index);
   };

   /**
    * Checks the HTTP status of a response
    */
   function checkStatus ( response ) {
      if ( response.status >= 200 && response.status < 300 ) {
         return response;
      } else {
         var error = new Error(response.statusText);
         error.response = response;
         throw error;
      }
   }

   /**
    * Parses the response as json
    */
   function parseJSON ( response ) {
      return response.json();
   }

   sightglass.adapters = rivets.adapters;
   sightglass.root = '.';

   return {
      expectedApiVersion: '{{expectedApiVersion}}', // this value is replaced with the API version number during the compilation step
      widgetModule: null,
      offeringModule: null,
      statisticsModule: null,
      apiReady: false, // this value is set to true once the kambi API has finished loaded
      config: {
         oddsFormat: 'decimal',
         apiVersion: 'v2',
         streamingAllowedForPlayer: false
      },
      height: 450,
      pageInfo: {},
      init: function ( setDefaultHeight ) {
         return new Promise(function ( resolve, reject ) {
            if ( window.KambiWidget ) {
               // For development purposes we might want to load a widget on it's own so we check if we are in an iframe, if not then load some fake data
               if ( window.self === window.top ) {
                  console.warn(window.location.host + window.location.pathname + ' is being loaded as stand-alone');
                  // Load the mock config data
                  fetch('mockSetupData.json')
                     .then(checkStatus)
                     .then(parseJSON)
                     .then(function ( mockSetupData ) {
                        // Output some debug info that could be helpful
                        console.debug('Loaded mock setup data');
                        console.debug(mockSetupData);
                        // Apply the mock config data to the core
                        this.applySetupData(mockSetupData, setDefaultHeight);
                        if (this.translationModule != null) {
                           this.translationModule.fetchTranslations(mockSetupData.clientConfig.locale).then(function () {
                              resolve(mockSetupData['arguments']);
                           }.bind(this));
                        } else {
                           resolve(mockSetupData['arguments']);
                        }
                     }.bind(this))
                     .catch(function ( error ) {
                        console.debug('Request failed');
                        console.trace(error);
                        reject();
                     });
               } else {
                  window.KambiWidget.apiReady = function ( api ) {
                     this.widgetModule.api = api;
                     if (api.VERSION !== this.expectedApiVersion) {
                        console.warn('Wrong Kambi API version loaded, expected: ' + this.expectedApiVersion + ' got: ' + api.VERSION);
                     }

                     // Request the setup info from the widget api
                     this.requestSetup(function ( setupData ) {
                        // Apply the config data to the core
                        this.applySetupData(setupData, setDefaultHeight);

                        // TODO: Move this to widgets so we don't request them when not needed
                        // Request the outcomes from the betslip so we can update our widget, this will also sets up a subscription for future betslip updates
                        this.widgetModule.requestBetslipOutcomes();
                        // Request the odds format that is set in the sportsbook, this also sets up a subscription for future odds format changes
                        this.widgetModule.requestOddsFormat();

                        if (this.translationModule != null) {
                           this.translationModule.fetchTranslations(setupData.clientConfig.locale).then(function () {
                              resolve(setupData['arguments']);
                           }.bind(this));
                        } else {
                           resolve(setupData['arguments']);
                        }
                     }.bind(this));
                  }.bind(this);
                  // Setup the response handler for the widget api
                  window.KambiWidget.receiveResponse = function ( dataObject ) {
                     this.widgetModule.handleResponse(dataObject);
                  }.bind(this);
               }
            } else {
               console.warn('Kambi widget API not loaded');
               reject();
            }
         }.bind(this));
      },

      applySetupData: function ( setupData, setDefaultHeight ) {
         // Set the odds format
         if ( setupData.clientConfig.oddsFormat != null ) {
            this.setOddsFormat(setupData.clientConfig.oddsFormat);
         }

         // Set the configuration in the offering module
         this.offeringModule.setConfig(setupData.clientConfig);

         // Set the configuration in the widget api module
         this.widgetModule.setConfig(setupData.clientConfig);

         // Set the configuration in the widget api module
         this.statisticsModule.setConfig(setupData.clientConfig);

         // Set page info
         this.setPageInfo(setupData.pageInfo);

         if ( setDefaultHeight === true ) {
            this.setHeight(setupData.height);
         }
         this.apiReady = true;
         this.config = setupData;
      },

      requestSetup: function ( callback ) {
         this.widgetModule.requestSetup(callback);
      },

      receiveRespone: function ( response ) {
         console.debug(response);
      },

      setOddsFormat: function ( oddsFormat ) {
         this.config.oddsFormat = oddsFormat;
      },

      setHeight: function ( height ) {
         this.height = height;
         this.widgetModule.setHeight(height);
      },

      setPageInfo: function ( pageInfo ) {
         // Check if the last character in the pageParam property is a slash, if not add it so we can use this property in filter requests
         if ( pageInfo.pageType === 'filter' && pageInfo.pageParam.substr(-1) !== '/' ) {
            pageInfo.pageParam += '/';
         }
         this.pageInfo = pageInfo;
      },

      getData: function ( url ) {
         return fetch(url)
            .then(checkStatus)
            .then(parseJSON)
            .catch(function ( error ) {
               console.debug('Error fetching data');
               console.trace(error);
               throw error;
            });
      },

      getFile: function ( url ) {
         return fetch(url)
            .then(checkStatus)
            .catch(function ( error ) {
               console.debug('Error fetching file');
               console.trace(error);
               throw error;
            });
      }
   };

})();
<|endoftext|>


<commit_before>import Component from 'ben-component';
import DataCanvas from 'ben-canvas';
import TextTool from './text-tool';

const LINE = 'line';
const RECT = 'rect';
const TEXT = 'text';
const EASE = 'ease';
const tools = [LINE, RECT, TEXT, EASE];

const COLOR_RED = '#f00';
const COLOR_DEFAULT = COLOR_RED;

class DrawCavans extends Component {
  constructor(parent, options) {
    super(parent, options);
    this.tool = LINE;
    this.color = COLOR_DEFAULT;
    this.initEvent();
  }

  createEl() {
    const el = super.createEl('canvas', {
      width: this.options.width,
      height: this.options.height,
      style: 'display: block;'
    }, {
      className: 'ben-sketch_canvas-draw'
    });
    this.ctx = el.getContext('2d');
    return el;
  }

  initEvent() {
    this.on('mousedown', (e) => {
      if (e.buttons && e.buttons !== 1) {
        return;
      }
      if (e.button !== 0) {
        return;
      }
      this[`${this.tool}MousedownListener`](e);
    });

    this.on('mouseup', (e) => {
      if (e.buttons && e.buttons !== 1) {
        return;
      }
      if (e.button !== 0) {
        return;
      }
      if (this.tool === 'text') {
        this[`${TEXT}MouseupListener`](e);
      }
    })
  }

  [`${LINE}MousedownListener`](e) {
    const ctx = this.ctx;
    console.log(LINE, 'mousedown', this.color);
    const linePoints = [];
    linePoints.push({
      x: e.offsetX / this.el.width,
      y: e.offsetY / this.el.height
    });
    const ommousemove = (event) => {
      DataCanvas.clear(this.ctx);
      linePoints.push({
        x: event.offsetX / this.el.width,
        y: event.offsetY / this.el.height
      });
      DataCanvas.line(ctx, {
        color: this.color,
        points: linePoints
      });
    }
    const offmousemove = () => {
      DataCanvas.clear(ctx);
      this.trigger('line.submit', {
        points: linePoints,
        color: this.color
      });
      this.off('mousemove');
      this.off('mouseup', offmousemove);
      this.off('mouseleave', offmousemove);
    }
    this.on('mousemove', ommousemove);
    this.on('mouseup', offmousemove);
    this.on('mouseleave', offmousemove);
  }

  [`${RECT}MousedownListener`](event) {
    console.log(RECT, 'mousedown');
    const ctx = this.ctx;
    // store the start position of the rect.
    const x = event.offsetX, y = event.offsetY;
    const rectData = {
      position: {
        x: x / this.ctx.canvas.width,
        y: y / this.ctx.canvas.height
      },
      color: this.color
    }
    // create temp canvas for preview rect in real-time.
    ctx.strokeStyle = this.color;

    const onmousemove = (e) => {
      // clear previous rect.
      DataCanvas.clear(this.ctx);
      // get the current rect width and height;
      const width = e.offsetX - x,
        height = e.offsetY - y;
      // store the width and height of current rect in ratio of canvas demension.
      rectData.width = width / this.ctx.canvas.width;
      rectData.height = height / this.ctx.canvas.height;
      // draw the current rect to temp canvas for preview.
      this.ctx.strokeRect(x, y, width, height);
    }

    const offmousemove = () => {
      DataCanvas.clear(this.ctx);
      this.trigger('rect.submit', rectData);
      this.off('mousemove');
      this.off('mouseup', offmousemove);
      this.off('mouseleave', offmousemove);
    }

    this.on('mousemove', onmousemove);
    this.on('mouseup', offmousemove);
    this.on('mouseleave', offmousemove);
  }

  [`${TEXT}MousedownListener`](e) {

  }

  [`${TEXT}MouseupListener`](e) {
    console.log(TEXT, 'mouseup');
    if (this.textTool) {
      this.textTool = null;
      return;
    }
    const x = e.offsetX,
      y = e.offsetY - 8;
    const textPoints = [];
    textPoints.push({x, y});
    const textTool = this.textTool = new TextTool(this.parent.el, x, y);
    textTool.on('valuechange', (event, data) => {
      this.parent.measureEl.innerHTML = data + '  ';
      textTool.width(this.parent.measureEl.clientWidth);
      textTool.height(this.parent.measureEl.clientHeight);
    });
    textTool.on('submit', (event, data) => {
      if (!data.data) {
        return;
      }
      const textOptions = {
        position: {
          x: x / this.ctx.canvas.width,
          y: y / this.ctx.canvas.height
        },
        color: this.color,
        text: data.data
      }
      this.trigger('text.submit', textOptions);
    });
  }

  [`${EASE}MousedownListener`](e) {
    console.log(EASE, 'mousedown');
    const easePoints = [];
    easePoints.push({
      x: e.offsetX / this.ctx.canvas.width,
      y: e.offsetY / this.ctx.canvas.height
    });
    const mousemove = (e) => {
      easePoints.push({
        x: e.offsetX / this.ctx.canvas.width,
        y: e.offsetY / this.ctx.canvas.height
      });
      DataCanvas.ease(this.parent.ctx, {
        points: easePoints,
        lineWidth: 20
      })
    }
    const mouseup = () => {
      this.trigger('ease.submit', {
        lineWidth: 20,
        points: easePoints
      });
      this.ctx.restore();
      this.off('mousemove', mousemove);
      this.off('mouseup', mouseup);
      this.off('mouseleave', mouseup);
    }
    this.on('mousemove', mousemove);
    this.on('mouseup', mouseup);
    this.on('mouseleave', mouseup);
  }

  setColor(color) {
    this.color = color;
  }

  width(width) {
    return this.options.width;
  }

  height(heihgt) {
    return this.options.height;
  }

  resize() {
    this.el.width = this.width();
    this.el.height = this.height();
  }
}

export default DrawCavans;<commit_msg>未指定工具处理<commit_after>import Component from 'ben-component';
import DataCanvas from 'ben-canvas';
import TextTool from './text-tool';

const LINE = 'line';
const RECT = 'rect';
const TEXT = 'text';
const EASE = 'ease';
const tools = [LINE, RECT, TEXT, EASE];

const COLOR_RED = '#f00';
const COLOR_DEFAULT = COLOR_RED;

class DrawCavans extends Component {
  constructor(parent, options) {
    super(parent, options);
    this.tool = LINE;
    this.color = COLOR_DEFAULT;
    this.initEvent();
  }

  createEl() {
    const el = super.createEl('canvas', {
      width: this.options.width,
      height: this.options.height,
      style: 'display: block;'
    }, {
      className: 'ben-sketch_canvas-draw'
    });
    this.ctx = el.getContext('2d');
    return el;
  }

  initEvent() {
    this.on('mousedown', (e) => {
      if (e.buttons && e.buttons !== 1) {
        return;
      }
      if (e.button !== 0) {
        return;
      }
      this[`${this.tool}MousedownListener`] && this[`${this.tool}MousedownListener`](e);
    });

    this.on('mouseup', (e) => {
      if (e.buttons && e.buttons !== 1) {
        return;
      }
      if (e.button !== 0) {
        return;
      }
      if (this.tool === 'text') {
        this[`${TEXT}MouseupListener`](e);
      }
    })
  }

  [`${LINE}MousedownListener`](e) {
    const ctx = this.ctx;
    console.log(LINE, 'mousedown', this.color);
    const linePoints = [];
    linePoints.push({
      x: e.offsetX / this.el.width,
      y: e.offsetY / this.el.height
    });
    const ommousemove = (event) => {
      DataCanvas.clear(this.ctx);
      linePoints.push({
        x: event.offsetX / this.el.width,
        y: event.offsetY / this.el.height
      });
      DataCanvas.line(ctx, {
        color: this.color,
        points: linePoints
      });
    }
    const offmousemove = () => {
      DataCanvas.clear(ctx);
      this.trigger('line.submit', {
        points: linePoints,
        color: this.color
      });
      this.off('mousemove');
      this.off('mouseup', offmousemove);
      this.off('mouseleave', offmousemove);
    }
    this.on('mousemove', ommousemove);
    this.on('mouseup', offmousemove);
    this.on('mouseleave', offmousemove);
  }

  [`${RECT}MousedownListener`](event) {
    console.log(RECT, 'mousedown');
    const ctx = this.ctx;
    // store the start position of the rect.
    const x = event.offsetX, y = event.offsetY;
    const rectData = {
      position: {
        x: x / this.ctx.canvas.width,
        y: y / this.ctx.canvas.height
      },
      color: this.color
    }
    // create temp canvas for preview rect in real-time.
    ctx.strokeStyle = this.color;

    const onmousemove = (e) => {
      // clear previous rect.
      DataCanvas.clear(this.ctx);
      // get the current rect width and height;
      const width = e.offsetX - x,
        height = e.offsetY - y;
      // store the width and height of current rect in ratio of canvas demension.
      rectData.width = width / this.ctx.canvas.width;
      rectData.height = height / this.ctx.canvas.height;
      // draw the current rect to temp canvas for preview.
      this.ctx.strokeRect(x, y, width, height);
    }

    const offmousemove = () => {
      DataCanvas.clear(this.ctx);
      this.trigger('rect.submit', rectData);
      this.off('mousemove');
      this.off('mouseup', offmousemove);
      this.off('mouseleave', offmousemove);
    }

    this.on('mousemove', onmousemove);
    this.on('mouseup', offmousemove);
    this.on('mouseleave', offmousemove);
  }

  [`${TEXT}MousedownListener`](e) {

  }

  [`${TEXT}MouseupListener`](e) {
    console.log(TEXT, 'mouseup');
    if (this.textTool) {
      this.textTool = null;
      return;
    }
    const x = e.offsetX,
      y = e.offsetY - 8;
    const textPoints = [];
    textPoints.push({x, y});
    const textTool = this.textTool = new TextTool(this.parent.el, x, y);
    textTool.on('valuechange', (event, data) => {
      this.parent.measureEl.innerHTML = data + '  ';
      textTool.width(this.parent.measureEl.clientWidth);
      textTool.height(this.parent.measureEl.clientHeight);
    });
    textTool.on('submit', (event, data) => {
      if (!data.data) {
        return;
      }
      const textOptions = {
        position: {
          x: x / this.ctx.canvas.width,
          y: y / this.ctx.canvas.height
        },
        color: this.color,
        text: data.data
      }
      this.trigger('text.submit', textOptions);
    });
  }

  [`${EASE}MousedownListener`](e) {
    console.log(EASE, 'mousedown');
    const easePoints = [];
    easePoints.push({
      x: e.offsetX / this.ctx.canvas.width,
      y: e.offsetY / this.ctx.canvas.height
    });
    const mousemove = (e) => {
      easePoints.push({
        x: e.offsetX / this.ctx.canvas.width,
        y: e.offsetY / this.ctx.canvas.height
      });
      DataCanvas.ease(this.parent.ctx, {
        points: easePoints,
        lineWidth: 20
      })
    }
    const mouseup = () => {
      this.trigger('ease.submit', {
        lineWidth: 20,
        points: easePoints
      });
      this.ctx.restore();
      this.off('mousemove', mousemove);
      this.off('mouseup', mouseup);
      this.off('mouseleave', mouseup);
    }
    this.on('mousemove', mousemove);
    this.on('mouseup', mouseup);
    this.on('mouseleave', mouseup);
  }

  setColor(color) {
    this.color = color;
  }

  width(width) {
    return this.options.width;
  }

  height(heihgt) {
    return this.options.height;
  }

  resize() {
    this.el.width = this.width();
    this.el.height = this.height();
  }
}

export default DrawCavans;<|endoftext|>


<commit_before>// ==========================================================================
// Style utils
// ==========================================================================

import { closest } from './arrays';
import is from './is';

// Standard/common aspect ratios
const standardRatios = [
  [1, 1],
  [4, 3],
  [3, 4],
  [5, 4],
  [4, 5],
  [3, 2],
  [2, 3],
  [16, 10],
  [10, 16],
  [16, 9],
  [9, 16],
  [21, 9],
  [9, 21],
  [32, 9],
  [9, 32],
].reduce((out, [x, y]) => ({ ...out, [x / y]: [x, y] }), {});

// Validate an aspect ratio
export function validateAspectRatio(input) {
  if (!is.array(input) && (!is.string(input) || !input.includes(':'))) {
    return false;
  }

  const ratio = is.array(input) ? input : input.split(':');

  return ratio.map(Number).every(is.number);
}

// Reduce an aspect ratio to it's lowest form
export function reduceAspectRatio(ratio) {
  if (!is.array(ratio) || !ratio.every(is.number)) {
    return null;
  }

  const [width, height] = ratio;
  const getDivider = (w, h) => (h === 0 ? w : getDivider(h, w % h));
  const divider = getDivider(width, height);

  return [width / divider, height / divider];
}

// Calculate an aspect ratio
export function getAspectRatio(input) {
  const parse = (ratio) => (validateAspectRatio(ratio) ? ratio.split(':').map(Number) : null);
  // Try provided ratio
  let ratio = parse(input);

  // Get from config
  if (ratio === null) {
    ratio = parse(this.config.ratio);
  }

  // Get from embed
  if (ratio === null && !is.empty(this.embed) && is.array(this.embed.ratio)) {
    ({ ratio } = this.embed);
  }

  // Get from HTML5 video
  if (ratio === null && this.isHTML5) {
    const { videoWidth, videoHeight } = this.media;
    ratio = reduceAspectRatio([videoWidth, videoHeight]);
  }

  return ratio;
}

// Set aspect ratio for responsive container
export function setAspectRatio(input) {
  if (!this.isVideo) {
    return {};
  }

  const { wrapper } = this.elements;
  const ratio = getAspectRatio.call(this, input);

  if (!is.array(ratio)) {
    return {};
  }

  const [x, y] = ratio;
  const useNative = window.CSS?.supports(`aspect-ratio: ${x} / ${y}`) ?? false;
  const padding = (100 / x) * y;

  if (useNative) {
    wrapper.style.aspectRatio = `${x}/${y}`;
  } else {
    wrapper.style.paddingBottom = `${padding}%`;
  }

  // For Vimeo we have an extra <div> to hide the standard controls and UI
  if (this.isVimeo && !this.config.vimeo.premium && this.supported.ui) {
    const height = (100 / this.media.offsetWidth) * parseInt(window.getComputedStyle(this.media).paddingBottom, 10);
    const offset = (height - padding) / (height / 50);

    if (this.fullscreen.active) {
      wrapper.style.paddingBottom = null;
    } else {
      this.media.style.transform = `translateY(-${offset}%)`;
    }
  } else if (this.isHTML5) {
    wrapper.classList.toggle(this.config.classNames.videoFixedRatio, ratio !== null);
  }

  return { padding, ratio };
}

// Round an aspect ratio to closest standard ratio
export function roundAspectRatio(x, y, tolerance = 0.05) {
  const ratio = x / y;
  const closestRatio = closest(Object.keys(standardRatios), ratio);

  // Check match is within tolerance
  if (Math.abs(closestRatio - ratio) <= tolerance) {
    return standardRatios[closestRatio];
  }

  // No match
  return [x, y];
}

export default { setAspectRatio };
<commit_msg>fix: syntax fix (#2176)<commit_after>// ==========================================================================
// Style utils
// ==========================================================================

import { closest } from './arrays';
import is from './is';

// Standard/common aspect ratios
const standardRatios = [
  [1, 1],
  [4, 3],
  [3, 4],
  [5, 4],
  [4, 5],
  [3, 2],
  [2, 3],
  [16, 10],
  [10, 16],
  [16, 9],
  [9, 16],
  [21, 9],
  [9, 21],
  [32, 9],
  [9, 32],
].reduce((out, [x, y]) => ({ ...out, [x / y]: [x, y] }), {});

// Validate an aspect ratio
export function validateAspectRatio(input) {
  if (!is.array(input) && (!is.string(input) || !input.includes(':'))) {
    return false;
  }

  const ratio = is.array(input) ? input : input.split(':');

  return ratio.map(Number).every(is.number);
}

// Reduce an aspect ratio to it's lowest form
export function reduceAspectRatio(ratio) {
  if (!is.array(ratio) || !ratio.every(is.number)) {
    return null;
  }

  const [width, height] = ratio;
  const getDivider = (w, h) => (h === 0 ? w : getDivider(h, w % h));
  const divider = getDivider(width, height);

  return [width / divider, height / divider];
}

// Calculate an aspect ratio
export function getAspectRatio(input) {
  const parse = (ratio) => (validateAspectRatio(ratio) ? ratio.split(':').map(Number) : null);
  // Try provided ratio
  let ratio = parse(input);

  // Get from config
  if (ratio === null) {
    ratio = parse(this.config.ratio);
  }

  // Get from embed
  if (ratio === null && !is.empty(this.embed) && is.array(this.embed.ratio)) {
    ({ ratio } = this.embed);
  }

  // Get from HTML5 video
  if (ratio === null && this.isHTML5) {
    const { videoWidth, videoHeight } = this.media;
    ratio = reduceAspectRatio([videoWidth, videoHeight]);
  }

  return ratio;
}

// Set aspect ratio for responsive container
export function setAspectRatio(input) {
  if (!this.isVideo) {
    return {};
  }

  const { wrapper } = this.elements;
  const ratio = getAspectRatio.call(this, input);

  if (!is.array(ratio)) {
    return {};
  }

  const [x, y] = ratio;
  const useNative = window.CSS ? window.CSS.supports(`aspect-ratio: ${x} / ${y}`) : false;
  const padding = (100 / x) * y;

  if (useNative) {
    wrapper.style.aspectRatio = `${x}/${y}`;
  } else {
    wrapper.style.paddingBottom = `${padding}%`;
  }

  // For Vimeo we have an extra <div> to hide the standard controls and UI
  if (this.isVimeo && !this.config.vimeo.premium && this.supported.ui) {
    const height = (100 / this.media.offsetWidth) * parseInt(window.getComputedStyle(this.media).paddingBottom, 10);
    const offset = (height - padding) / (height / 50);

    if (this.fullscreen.active) {
      wrapper.style.paddingBottom = null;
    } else {
      this.media.style.transform = `translateY(-${offset}%)`;
    }
  } else if (this.isHTML5) {
    wrapper.classList.toggle(this.config.classNames.videoFixedRatio, ratio !== null);
  }

  return { padding, ratio };
}

// Round an aspect ratio to closest standard ratio
export function roundAspectRatio(x, y, tolerance = 0.05) {
  const ratio = x / y;
  const closestRatio = closest(Object.keys(standardRatios), ratio);

  // Check match is within tolerance
  if (Math.abs(closestRatio - ratio) <= tolerance) {
    return standardRatios[closestRatio];
  }

  // No match
  return [x, y];
}

export default { setAspectRatio };
<|endoftext|>


<commit_before>/**
 * Warning: if editing this file, be sure to keep the VERSION variable set to 'X.X.X'
 *           without modifying formatting for automation scripts
 * @type {{VERSION: string}}
 */
let VersionInfo = { VERSION : '0.0.7496' };
export default VersionInfo;
<commit_msg>vinfo<commit_after>/**
 * Warning: if editing this file, be sure to keep the VERSION variable set to 'X.X.X'
 *           without modifying formatting for automation scripts
 * @type {{VERSION: string}}
 */
let VersionInfo = { VERSION : '0.0.7497' };
export default VersionInfo;
<|endoftext|>