<commit_before>/**
 * Checkout.com
 * Authorized and regulated as an electronic money institution
 * by the UK Financial Conduct Authority (FCA) under number 900816.
 *
 * PHP version 7
 *
 * @category  Magento2
 * @package   Checkout.com
 * @author    Platforms Development Team <platforms@checkout.com>
 * @copyright 2010-2019 Checkout.com
 * @license   https://opensource.org/licenses/mit-license.html MIT License
 * @link      https://docs.checkout.com/
 */

define(
    [
        'jquery',
        'CheckoutCom_Magento2/js/view/payment/config-loader',
        'Magento_Checkout/js/model/quote',
        'Magento_Checkout/js/checkout-data',
        'mage/url',
        'Magento_Checkout/js/action/redirect-on-success',
        'Magento_Checkout/js/model/full-screen-loader',
        'Magento_Customer/js/model/customer',
        'mage/translate',
        'mage/cookies'
    ],
    function ($, Config, Quote, CheckoutData, Url, RedirectOnSuccessAction, FullScreenLoader, Customer, __) {
        'use strict';

        const KEY_CONFIG = 'checkoutcom_configuration';
        const KEY_DATA = 'checkoutcom_data';

        return {
            /**
             * Gets a field value.
             *
             * @param  {string}  methodId The method id
             * @param  {string}  field    The field
             * @param  {bool}  strict     The strict value
             * @return {mixed}            The value
             */
            getValue: function (methodId, field, strict) {
                var val = null;
                strict = (strict === undefined ? false : strict);
                if (methodId && Config.hasOwnProperty(methodId) && Config[methodId].hasOwnProperty(field)) {
                    val = Config[methodId][field]
                } else if (Config.hasOwnProperty(KEY_CONFIG) && Config[KEY_CONFIG].hasOwnProperty(field) && !strict) {
                    val = Config[KEY_CONFIG][field];
                }

                return val;
            },

            /**
             * Load a CSS file
             *
             * @return {void}
             */
            loadCss: function (fileName, folderPath) {
                // Prepare the folder path
                folderPath = (folderPath) ? '/' + folderPath : '';

                // Get the CSS config parameters
                var useMinCss = window.checkoutConfig.payment.checkoutcom_magento2.checkoutcom_data.use_minified_css;
                var ext = (useMinCss == '1') ? '.min.css' : '.css';

                // Build the payment form CSS path
                var cssPath = window.checkoutConfig.payment.checkoutcom_magento2.checkoutcom_data.css_path;
                cssPath += folderPath + '/' + fileName + ext;

                // Append the CSS file
                $('head').append('<link rel="stylesheet" href="' + cssPath + '" type="text/css"/>');
            },

            /**
             * Load a remote JS file
             *
             * @return {void}
             */
            loadRemoteJs: function (jsUrl) {
                // Append the CSS file
                $('head').append('');
            },

            /**
             * Get the store name.
             *
             * @return {string}  The store name.
             */
            getStoreName: function () {
                return Config[KEY_DATA].store.name;
            },

            /**
             * Get the quote value.
             *
             * @return {float}  The quote value.
             */
            getQuoteValue: function () {
                var data = this.getRestQuoteData('payment-information');
                var amount = parseFloat(data.totals.base_grand_total);

                return amount.toFixed(2);
            },

            /**
             * Get the updated quote data from the core REST API.
             *
             * @return {object}  The quote data.
             */
            getRestQuoteData: function (endpoint) {
                endpoint = (endpoint === null ? '' : '/' + endpoint);

                // Prepare the required parameters
                var self = this;
                var result = null;
                var restUrl = window.BASE_URL;

                // Build the rest URL
                if (Customer.isLoggedIn()) {
                    restUrl += 'rest/';
                    restUrl += window.checkoutConfig.payment.checkoutcom_magento2.checkoutcom_data.store.code;
                    restUrl += '/V1/';
                    restUrl += 'carts/mine';
                    restUrl += endpoint;
                    restUrl += '?form_key=' + window.checkoutConfig.formKey;
                } else {
                    restUrl += 'rest/all/V1/guest-carts/' + window.checkoutConfig.quoteData.entity_id;
                    restUrl += endpoint;
                    restUrl += '?form_key=' + window.checkoutConfig.formKey;
                }

                // Set the event to update data on any button click
                $('button[type="submit"]')
                    .off('click', self.getRestQuoteData)
                    .on('click', self.getRestQuoteData);

                // Send the AJAX request
                $.ajax({
                    url: restUrl,
                    type: 'GET',
                    contentType: "application/json",
                    dataType: "json",
                    async: false,
                    showLoader: true,
                    success: function (data, status, xhr) {
                        result = data;
                    },
                    error: function (request, status, error) {
                        self.log(error);
                    }
                });

                return result;
            },

            /**
             * Get the quote currency.
             *
             * @return {string}  The quote currency.
             */
            getQuoteCurrency: function () {
                var data = this.getRestQuoteData('payment-information');
                return data.totals.quote_currency_code;
            },

            /**
             * Check if APM should be auto selected.
             *
             * @return {void}
             */
            checkLastPaymentMethod: function () {
                var userData = this.getValue('checkoutcom_data', 'user');

                if (userData['previous_method'] == 'checkoutcom_apm') {
                    // Select the previous apm if it's available
                    if ($('.cko-apm#' + userData['previous_source']).length) {
                        $('.cko-apm#' + userData['previous_source']).trigger('click');
                    }
                }
            },

            /**
             * Check if stored card should be auto selected.
             *
             * @return {void}
             */
            checkStoredCard: function () {
                var userData = this.getValue('checkoutcom_data', 'user');
                if (userData['previous_method'] == 'checkoutcom_vault'
                && $('input[name=\'publicHash\'][value=\''+userData['previous_source']+'\']').length) {
                    $('input[name=\'publicHash\'][value=\''+userData['previous_source']+'\']').trigger('click');
                }
            },

            /**
             * Gets the card form language fallback.
             *
             * @return {string}
             */
            getLangageFallback: function () {
                return Config[KEY_DATA].user.language_fallback;
            },

            /**
             * Get the card form shop language
             *
             * @return {string}
             */
            getShopLanguage: function () {
                let mageShopLanguage = Config[KEY_DATA].store.language;
                let framesLanguage;
                switch (mageShopLanguage) {
                    case 'nl_NL':
                        framesLanguage = 'NL-NL';
                        break;
                    case 'en_GB':
                        framesLanguage = 'EN-GB';
                        break;
                    case 'fr_FR':
                        framesLanguage = 'FR-FR';
                        break;
                    case 'de_DE':
                        framesLanguage = 'DE-DE';
                        break;
                    case 'it_IT':
                        framesLanguage = 'IT-IT';
                        break;
                    case 'ko_KR':
                        framesLanguage = 'KR-KR';
                        break;
                    case 'es_ES':
                        framesLanguage = 'ES-ES';
                        break;
                    default:
                        framesLanguage = this.getLangageFallback().toUpperCase().split("_").join('-');
                }

                return framesLanguage;
            },

            /**
             * Get the supported cards.
             *
             * @return {array}
             */
            getSupportedCards: function () {
                return Config[KEY_DATA].cards;
            },

            /**
             * Builds the controller URL.
             *
             * @param  {string}  path  The path
             * @return {string}
             */
            getUrl: function (path) {
                return Url.build('checkout_com/' + path);
            },

            /**
             * Customer name.
             *
             * @param  {bool} return in object format.
             * @return {mixed}  The billing address.
             */
            getCustomerName: function () {
                var billingAddress = this.getBillingAddress();
                var customerName = '';
                if (billingAddress) {
                    customerName += billingAddress.firstname;
                    customerName += ' ' + billingAddress.lastname;
                }

                return customerName;
            },

            /**
             * Billing address.
             *
             * @return {object}  The billing address.
             */
            getBillingAddress: function () {
                return this.getRestQuoteData('billing-address');
            },

            /**
             * @return {string}
             */
            getEmail: function () {
                var emailCookieName = this.getValue(null, 'email_cookie_name');
                return window.checkoutConfig.customerData.email
                || Quote.guestEmail
                || CheckoutData.getValidatedEmailValue()
                || $.cookie(emailCookieName);
            },

            /**
             * @return {void}
             */
            setEmail: function () {
                var userEmail = this.getEmail();
                var emailCookieName = this.getValue(null, 'email_cookie_name');
                $.cookie(emailCookieName, userEmail);

                // If no email found, observe the core email field
                if (!userEmail) {
                    $('#customer-email').off('change').on('change', function () {
                        userEmail = Quote.guestEmail || CheckoutData.getValidatedEmailValue();
                        $.cookie(emailCookieName, userEmail);
                    });
                }
            },

            /**
             * @return {object}
             */
            getPhone: function () {
                var billingAddress = this.getBillingAddress();

                return {
                    number: billingAddress.telephone
                };
            },

            /**
             * Handle error logging.
             */
            log: function (val) {
                if (this.getValue(null, 'debug')
                    && this.getValue(null, 'console_logging')
                ) {
                    console.log(val);
                }
            },

            /**
             * Show a message.
             */
            showMessage: function (type, message, methodId) {
                this.clearMessages(methodId);
                var messageContainer = this.getMethodContainer(methodId).find('.message-cko');
                messageContainer.addClass('message-' + type + ' ' + type);
                messageContainer.append('
' + __(message) + '
');
                messageContainer.show();
            },

            /**
             * Show debug message.
             */
            showDebugMessage: function (type, message, methodId) {
                var messageContainer = this.getMethodContainer(methodId).find('.debug-message');
                messageContainer.addClass('message-' + type + ' ' + type);
                messageContainer.append('

' + __(message) + '

');
                messageContainer.show();
            },

            /**
             * Show response code.
             */
            showResponseCode: function (type, message, methodId) {
                var messageContainer = this.getMethodContainer(methodId).find('.message-response-code');
                messageContainer.addClass('message-' + type + ' ' + type);
                messageContainer.append('
Response Code: ' + __(message) + '
');
                messageContainer.show();
            },

            /**
             * Clear all messages.
             */
            clearMessages: function (methodId) {
                var messageContainer = this.getMethodContainer(methodId).find('.message');
                messageContainer.hide();
                messageContainer.empty();
            },

            /**
             * Get a payment method container instance.
             */
            getMethodContainer: function (methodId) {
                return $('#' + methodId + '_container');
            },

            /**
             * Check if an URL is valid.
             */
            isUrl: function (str) {
                var pattern = /^(?:\w+:)?\/\/([^\s\.]+\.\S{2}|localhost[\:?\d]*)\S*$/;
                return pattern.test(str);
            },

            /**
             * Handle the place order button state.
             */
            allowPlaceOrder: function (buttonId, yesNo) {
                $('#' + buttonId).prop('disabled', !yesNo);
            },

            /**
             * Check if a payment option is active.
             */
            methodIsSelected: function (idSelector) {
                var id = idSelector.replace('#', '');
                var selected = CheckoutData.getSelectedPaymentMethod();
                return id == selected || selected == null;
            },

            /**
             * Place a new order.
             *
             * @return {void}
             */
            placeOrder: function (payload, methodId) {
                var self = this;

                // Start the loader
                FullScreenLoader.startLoader();

                // Send the request
                $.ajax({
                    type: 'POST',
                    url: self.getUrl('payment/placeorder'),
                    data: payload,
                    success: function (data) {
                        if (!data.success) {
                            FullScreenLoader.stopLoader();
                            self.showMessage('error', data.message, methodId);
                            if (data.debugMessage) {
                                self.showDebugMessage('error', data.debugMessage, methodId);
                            }
                            if (data.responseCode) {
                                self.showResponseCode('error', data.responseCode, methodId);
                            }
                            self.allowPlaceOrder(methodId + '_btn', false)
                        } else if (data.success && data.url) {
                            // Handle 3DS redirection
                            window.location.href = data.url;
                        } else {
                            // Normal redirection
                            RedirectOnSuccessAction.execute();
                        }
                    },
                    error: function (request, status, error) {
                        self.showMessage('error', error, methodId);
                        FullScreenLoader.stopLoader();
                    }
                });
            }
        };
    }
);<commit_msg>chore: removed pointless code<commit_after>/**
 * Checkout.com
 * Authorized and regulated as an electronic money institution
 * by the UK Financial Conduct Authority (FCA) under number 900816.
 *
 * PHP version 7
 *
 * @category  Magento2
 * @package   Checkout.com
 * @author    Platforms Development Team <platforms@checkout.com>
 * @copyright 2010-2019 Checkout.com
 * @license   https://opensource.org/licenses/mit-license.html MIT License
 * @link      https://docs.checkout.com/
 */

define(
    [
        'jquery',
        'CheckoutCom_Magento2/js/view/payment/config-loader',
        'Magento_Checkout/js/model/quote',
        'Magento_Checkout/js/checkout-data',
        'mage/url',
        'Magento_Checkout/js/action/redirect-on-success',
        'Magento_Checkout/js/model/full-screen-loader',
        'Magento_Customer/js/model/customer',
        'mage/translate',
        'mage/cookies'
    ],
    function ($, Config, Quote, CheckoutData, Url, RedirectOnSuccessAction, FullScreenLoader, Customer, __) {
        'use strict';

        const KEY_CONFIG = 'checkoutcom_configuration';
        const KEY_DATA = 'checkoutcom_data';

        return {
            /**
             * Gets a field value.
             *
             * @param  {string}  methodId The method id
             * @param  {string}  field    The field
             * @param  {bool}  strict     The strict value
             * @return {mixed}            The value
             */
            getValue: function (methodId, field, strict) {
                var val = null;
                strict = (strict === undefined ? false : strict);
                if (methodId && Config.hasOwnProperty(methodId) && Config[methodId].hasOwnProperty(field)) {
                    val = Config[methodId][field]
                } else if (Config.hasOwnProperty(KEY_CONFIG) && Config[KEY_CONFIG].hasOwnProperty(field) && !strict) {
                    val = Config[KEY_CONFIG][field];
                }

                return val;
            },

            /**
             * Load a CSS file
             *
             * @return {void}
             */
            loadCss: function (fileName, folderPath) {
                // Prepare the folder path
                folderPath = (folderPath) ? '/' + folderPath : '';

                // Get the CSS config parameters
                var useMinCss = window.checkoutConfig.payment.checkoutcom_magento2.checkoutcom_data.use_minified_css;
                var ext = (useMinCss == '1') ? '.min.css' : '.css';

                // Build the payment form CSS path
                var cssPath = window.checkoutConfig.payment.checkoutcom_magento2.checkoutcom_data.css_path;
                cssPath += folderPath + '/' + fileName + ext;

                // Append the CSS file
                $('head').append('<link rel="stylesheet" href="' + cssPath + '" type="text/css"/>');
            },

            /**
             * Load a remote JS file
             *
             * @return {void}
             */
            loadRemoteJs: function (jsUrl) {
                // Append the CSS file
                $('head').append('');
            },

            /**
             * Get the store name.
             *
             * @return {string}  The store name.
             */
            getStoreName: function () {
                return Config[KEY_DATA].store.name;
            },

            /**
             * Get the quote value.
             *
             * @return {float}  The quote value.
             */
            getQuoteValue: function () {
                var data = this.getRestQuoteData('payment-information');
                var amount = parseFloat(data.totals.base_grand_total);

                return amount.toFixed(2);
            },

            /**
             * Get the updated quote data from the core REST API.
             *
             * @return {object}  The quote data.
             */
            getRestQuoteData: function (endpoint) {
                endpoint = (endpoint === null ? '' : '/' + endpoint);

                // Prepare the required parameters
                var self = this;
                var result = null;
                var restUrl = window.BASE_URL;

                // Build the rest URL
                if (Customer.isLoggedIn()) {
                    restUrl += 'rest/';
                    restUrl += window.checkoutConfig.payment.checkoutcom_magento2.checkoutcom_data.store.code;
                    restUrl += '/V1/';
                    restUrl += 'carts/mine';
                    restUrl += endpoint;
                    restUrl += '?form_key=' + window.checkoutConfig.formKey;
                } else {
                    restUrl += 'rest/all/V1/guest-carts/' + window.checkoutConfig.quoteData.entity_id;
                    restUrl += endpoint;
                    restUrl += '?form_key=' + window.checkoutConfig.formKey;
                }

                // Send the AJAX request
                $.ajax({
                    url: restUrl,
                    type: 'GET',
                    contentType: "application/json",
                    dataType: "json",
                    async: false,
                    showLoader: true,
                    success: function (data, status, xhr) {
                        result = data;
                    },
                    error: function (request, status, error) {
                        self.log(error);
                    }
                });

                return result;
            },

            /**
             * Get the quote currency.
             *
             * @return {string}  The quote currency.
             */
            getQuoteCurrency: function () {
                var data = this.getRestQuoteData('payment-information');
                return data.totals.quote_currency_code;
            },

            /**
             * Check if APM should be auto selected.
             *
             * @return {void}
             */
            checkLastPaymentMethod: function () {
                var userData = this.getValue('checkoutcom_data', 'user');

                if (userData['previous_method'] == 'checkoutcom_apm') {
                    // Select the previous apm if it's available
                    if ($('.cko-apm#' + userData['previous_source']).length) {
                        $('.cko-apm#' + userData['previous_source']).trigger('click');
                    }
                }
            },

            /**
             * Check if stored card should be auto selected.
             *
             * @return {void}
             */
            checkStoredCard: function () {
                var userData = this.getValue('checkoutcom_data', 'user');
                if (userData['previous_method'] == 'checkoutcom_vault'
                && $('input[name=\'publicHash\'][value=\''+userData['previous_source']+'\']').length) {
                    $('input[name=\'publicHash\'][value=\''+userData['previous_source']+'\']').trigger('click');
                }
            },

            /**
             * Gets the card form language fallback.
             *
             * @return {string}
             */
            getLangageFallback: function () {
                return Config[KEY_DATA].user.language_fallback;
            },

            /**
             * Get the card form shop language
             *
             * @return {string}
             */
            getShopLanguage: function () {
                let mageShopLanguage = Config[KEY_DATA].store.language;
                let framesLanguage;
                switch (mageShopLanguage) {
                    case 'nl_NL':
                        framesLanguage = 'NL-NL';
                        break;
                    case 'en_GB':
                        framesLanguage = 'EN-GB';
                        break;
                    case 'fr_FR':
                        framesLanguage = 'FR-FR';
                        break;
                    case 'de_DE':
                        framesLanguage = 'DE-DE';
                        break;
                    case 'it_IT':
                        framesLanguage = 'IT-IT';
                        break;
                    case 'ko_KR':
                        framesLanguage = 'KR-KR';
                        break;
                    case 'es_ES':
                        framesLanguage = 'ES-ES';
                        break;
                    default:
                        framesLanguage = this.getLangageFallback().toUpperCase().split("_").join('-');
                }

                return framesLanguage;
            },

            /**
             * Get the supported cards.
             *
             * @return {array}
             */
            getSupportedCards: function () {
                return Config[KEY_DATA].cards;
            },

            /**
             * Builds the controller URL.
             *
             * @param  {string}  path  The path
             * @return {string}
             */
            getUrl: function (path) {
                return Url.build('checkout_com/' + path);
            },

            /**
             * Customer name.
             *
             * @param  {bool} return in object format.
             * @return {mixed}  The billing address.
             */
            getCustomerName: function () {
                var billingAddress = this.getBillingAddress();
                var customerName = '';
                if (billingAddress) {
                    customerName += billingAddress.firstname;
                    customerName += ' ' + billingAddress.lastname;
                }

                return customerName;
            },

            /**
             * Billing address.
             *
             * @return {object}  The billing address.
             */
            getBillingAddress: function () {
                return this.getRestQuoteData('billing-address');
            },

            /**
             * @return {string}
             */
            getEmail: function () {
                var emailCookieName = this.getValue(null, 'email_cookie_name');
                return window.checkoutConfig.customerData.email
                || Quote.guestEmail
                || CheckoutData.getValidatedEmailValue()
                || $.cookie(emailCookieName);
            },

            /**
             * @return {void}
             */
            setEmail: function () {
                var userEmail = this.getEmail();
                var emailCookieName = this.getValue(null, 'email_cookie_name');
                $.cookie(emailCookieName, userEmail);

                // If no email found, observe the core email field
                if (!userEmail) {
                    $('#customer-email').off('change').on('change', function () {
                        userEmail = Quote.guestEmail || CheckoutData.getValidatedEmailValue();
                        $.cookie(emailCookieName, userEmail);
                    });
                }
            },

            /**
             * @return {object}
             */
            getPhone: function () {
                var billingAddress = this.getBillingAddress();

                return {
                    number: billingAddress.telephone
                };
            },

            /**
             * Handle error logging.
             */
            log: function (val) {
                if (this.getValue(null, 'debug')
                    && this.getValue(null, 'console_logging')
                ) {
                    console.log(val);
                }
            },

            /**
             * Show a message.
             */
            showMessage: function (type, message, methodId) {
                this.clearMessages(methodId);
                var messageContainer = this.getMethodContainer(methodId).find('.message-cko');
                messageContainer.addClass('message-' + type + ' ' + type);
                messageContainer.append('
' + __(message) + '
');
                messageContainer.show();
            },

            /**
             * Show debug message.
             */
            showDebugMessage: function (type, message, methodId) {
                var messageContainer = this.getMethodContainer(methodId).find('.debug-message');
                messageContainer.addClass('message-' + type + ' ' + type);
                messageContainer.append('

' + __(message) + '

');
                messageContainer.show();
            },

            /**
             * Show response code.
             */
            showResponseCode: function (type, message, methodId) {
                var messageContainer = this.getMethodContainer(methodId).find('.message-response-code');
                messageContainer.addClass('message-' + type + ' ' + type);
                messageContainer.append('
Response Code: ' + __(message) + '
');
                messageContainer.show();
            },

            /**
             * Clear all messages.
             */
            clearMessages: function (methodId) {
                var messageContainer = this.getMethodContainer(methodId).find('.message');
                messageContainer.hide();
                messageContainer.empty();
            },

            /**
             * Get a payment method container instance.
             */
            getMethodContainer: function (methodId) {
                return $('#' + methodId + '_container');
            },

            /**
             * Check if an URL is valid.
             */
            isUrl: function (str) {
                var pattern = /^(?:\w+:)?\/\/([^\s\.]+\.\S{2}|localhost[\:?\d]*)\S*$/;
                return pattern.test(str);
            },

            /**
             * Handle the place order button state.
             */
            allowPlaceOrder: function (buttonId, yesNo) {
                $('#' + buttonId).prop('disabled', !yesNo);
            },

            /**
             * Check if a payment option is active.
             */
            methodIsSelected: function (idSelector) {
                var id = idSelector.replace('#', '');
                var selected = CheckoutData.getSelectedPaymentMethod();
                return id == selected || selected == null;
            },

            /**
             * Place a new order.
             *
             * @return {void}
             */
            placeOrder: function (payload, methodId) {
                var self = this;

                // Start the loader
                FullScreenLoader.startLoader();

                // Send the request
                $.ajax({
                    type: 'POST',
                    url: self.getUrl('payment/placeorder'),
                    data: payload,
                    success: function (data) {
                        if (!data.success) {
                            FullScreenLoader.stopLoader();
                            self.showMessage('error', data.message, methodId);
                            if (data.debugMessage) {
                                self.showDebugMessage('error', data.debugMessage, methodId);
                            }
                            if (data.responseCode) {
                                self.showResponseCode('error', data.responseCode, methodId);
                            }
                            self.allowPlaceOrder(methodId + '_btn', false)
                        } else if (data.success && data.url) {
                            // Handle 3DS redirection
                            window.location.href = data.url;
                        } else {
                            // Normal redirection
                            RedirectOnSuccessAction.execute();
                        }
                    },
                    error: function (request, status, error) {
                        self.showMessage('error', error, methodId);
                        FullScreenLoader.stopLoader();
                    }
                });
            }
        };
    }
);<|endoftext|>


<commit_before>var mag = (function(mag, configs, document, undefined) {

  var ELEMENT_NODE = 1
  var cached = []

  // helper method to detect arrays -- silly javascript
    function _isArray(obj) {
      return Object.prototype.toString.call(obj) === '[object Array]'
    }

    // the user can inject a logger function to get some feedback from fill
    function log(msg) {
      if (typeof fill.logger === 'function') fill.logger(msg)
    }

  var templates = {}

  // this is the entry point for this module, to fill the dom with data
    function fill(nodeList, data, key, index) {
      var node
      var parent
      var dataIsArray

      // there is nothing to do if there is nothing to fill
      if (!nodeList) return

      // remove all child nodes if there is no data
      if (data == null) data = {
        _text: ''
      }

      // CACHE
      // DIFF
      // CHANGE? then modify only the changes
      // KEYS for indentification

      // nodeList updates as the dom changes, so freeze it in an array
      var elements = nodeListToArray(nodeList)

      dataIsArray = _isArray(data)

      // match the number of nodes to the number of data elements
      if (dataIsArray) {

        if (templates[key + index] && elements.length === 0) {

          templates[key + index].parent.insertAdjacentHTML("beforeend", templates[key + index].node);
          elements = nodeListToArray(templates[key + index].parent.children)

        }

        if (elements.length === 0) {

          //=====================================================================
          // Warning: the following is a case where we could end up here: A page
          // that returns search results as the user is typing. If the results
          // are empty, then the child nodes that display the results will all
          // be removed. Then a subsequent attempt to fill in the search results
          // with data won't have any dom elements to clone.
          //=====================================================================

          // cannot fill empty nodeList with an array of data
          return
        }

        // clone the first node if more nodes are needed
        parent = elements[0].parentNode

        if (!templates[key + index]) {
          templates[key + index] = {
            node: elements[0].cloneNode(true).outerHTML,
            parent: parent
          }
          //remove from dom
          parent.removeChild(elements[0])
        }

        while (elements.length < data.length) {
          if (templates[key + index]) {
            parent.insertAdjacentHTML("beforeend", templates[key + index].node)
            node = parent.lastChild
          } else {
            node = elements[0].cloneNode(true)
          }

          elements.push(node)
          if (parent) parent.appendChild(node)
        }

        // remove the last node until the number of nodes matches the data
        while (elements.length > data.length) {
          node = elements.pop()
          parent = node.parentNode
          if (parent) parent.removeChild(node)
        }
      }

      // now fill each node with the data
      for (var i = 0; i < elements.length; i++) {
        if (dataIsArray) {
          if (elements[i]) {
            fill(elements[i], data[i])
          }
        } else {
          fillNode(elements[i], data)
        }
      }
      return nodeList
    }

    function fillNode(node, data) {
      var attributes,
        attrValue,
        element,
        elements

        // ignore functions
      if (typeof data === 'function') {

        return
      }

      // if the value is a simple property wrap it in the attributes hash
      if (typeof data !== 'object') return fillNode(node, {
        _text: data
      })

      // find all the attributes
      for (var key in data) {
        var value = data[key]

        // null values are treated like empty strings
        if (value === undefined) value = ''

        // anything that starts with an underscore is an attribute
        if (key[0] === '_') {
          // store the properties to set them all at once
          // if (typeof value === 'string' || typeof value === 'number') {
          attributes = attributes || {}
          attributes[key.substr(1)] = value;
          // } else {
          //   throw new Error('Expected a string or number for "' + key +
          //                   '", got: "' + JSON.stringify(value) + '"');
          // }
        }
      }

      // fill in all the attributes
      if (attributes) {
        fillAttributes(node, attributes)
      }

      var index = 0
      // look for non-attribute keys and recurse into those elements
      for (var key in data) {
        var value = data[key]

        // only attributes start with an underscore
        if (key[0] !== '_') {
          elements = matchingElements(node, key);

          // function
          if (typeof value === 'function' && value.type == 'fun') {
            try {
              value = value()
            } catch (e) {}
          }

          // check for key replacement within the element
          //domElement.replaceWithin(node, key, value)

          fill(elements, value, key, index);

          index++
        }
      }
    }

    // freeze the NodeList into a real Array so it can't update as DOM changes
    function nodeListToArray(nodeList) {
      var temp;

      // wrap single item into an array for iteration
      // NOTE: can't use _isArray here, because it could be a NodeList (array-ish)
      if (nodeList.length == null) {
        nodeList = [nodeList];
      }

      // convert array-like object into a real array
      if (!_isArray(nodeList)) {
        temp = [];
        for (var i = 0; i < nodeList.length; i += 1) {
          // Note: occassionaly jsdom returns undefined elements in the NodeList
          if (nodeList[i]) {
            temp.push(nodeList[i]);
          }
        }
        nodeList = temp;
      }

      return nodeList;
    }

    // fill in the attributes on an element (setting text and html first)
    function fillAttributes(node, attributes) {

      // set html after setting text because html overrides text
      setText(node, attributes.text)
      setHtml(node, attributes.html)
      node._events = node._events || []

      // set the rest of the attributes
      for (var attrName in attributes) {

        // skip text and html, they've already been set
        if (attrName === 'text' || attrName === 'html') continue

        // events
        if (attrName.indexOf('on') == 0) {
          if (node._events.indexOf(attrName) !== -1) continue

          node.addEventListener(attrName.substr(2), attributes[attrName])
          node._events.push(attrName)

        } else {

          if (attrName == 'config') {

            // have we been here before?
            // does the element already exist in cache
            // useful to know if this is newly added
            var isNew = true

            // bind
            var callback = function(data, args) {
              return function() {
                return data.apply(data, args)
              }
            };

            configs.push(callback(attributes[attrName], [node, isNew]))
            continue;
          }

          if (attributes[attrName] === null) {
            node.removeAttribute(attrName)
          } else {
            node.setAttribute(attrName, attributes[attrName].toString())
          }
        }
      }
    }

    function setText(node, text) {
      var child
      var children

      // make sure that we have a node and text to insert
      if (!node || text == null) return

      // cache all of the child nodes
      if (!children) {
        children = [];
        for (var i = 0; i < node.childNodes.length; i += 1) {
          child = node.childNodes[i];
          if (child.nodeType === ELEMENT_NODE) {
            children.push(child)
          }
        }
      }

      // remove all of the children
      //WHY?
      while (node.firstChild) {
        node.removeChild(node.firstChild)
      }

      // SELECT|INPUT|TEXTAREA
      // now add the text
      if (node.nodeName.toLowerCase() === 'input') {
        // special case for input elements
        node.setAttribute('value', text.toString());
      } else {
        // create a new text node and stuff in the value
        node.appendChild(node.ownerDocument.createTextNode(text.toString()));
      }

      // reattach all the child nodes
      for (var i = 0; i < children.length; i += 1) {
        node.appendChild(children[i]);
      }
    }

    function setHtml(node, html) {
      if (!node || html == null) return;
      node.innerHTML = html;
      // CAN'T do below since it will append on every new call
      // node.insertAdjacentHTML("afterbegin", html)
    };

  //===========================================================================
  // TODO: Decide if the caching of element matching should be reintroduced.
  // The original implementation cached the lookup of elements, but it seems
  // like this will only be useful in cases where the same DOM elements are
  // getting filled mutliple times -- that seems like it would only happen
  // when someone is running performance benchmarks.
  //===========================================================================

  // find all of the matching elements (breadth-first)

  function matchingElements(node, key, nested) {
    var elements = childElements(node)
    var matches = []
    var keyName = key

    if (!(node.queryCache || {})[key]) {

      node.queryCache = (node.queryCache || {})[key] = [];

      var globalSearch = key[0] === '$'

      if (keyName[0] === '$') keyName = keyName.substr(1)

      // search all child elements for a match
      for (var i = 0; i < elements.length; i += 1) {
        if (elementMatcher(elements[i], keyName)) {
          matches.push(elements[i]);
        }
      }

      // if there is no match, recursively search the childNodes
      if (!matches.length || globalSearch) {
        for (var i = 0; i < elements.length; i++) {
          // NOTE: pass in a flag to prevent recursive calls from logging
          matches = matches.concat(matchingElements(elements[i], key, true))
          if (matches.length && !globalSearch) break
        }
      }

      if (!nested && !matches.length) log('FILL - Warning: no matches found for "' + key + '"');

      // return matches
      node.queryCache[key] = matches
    }
    return node.queryCache[key];
  }

  // return just the child nodes that are elements
  function childElements(node) {
    var children = node.childNodes
    var elements = []

    for (var i = 0; i < children.length; i += 1) {
      if (children[i].nodeType === ELEMENT_NODE) {
        elements.push(children[i])
      }
    }

    return elements
  }

  // match elements on tag, id, name, class name, data-bind, etc.
  function elementMatcher(element, key) {
    var paddedClass = ' ' + element.className + ' ';

    return (
      element.id === key ||
      paddedClass.indexOf(' ' + key + ' ') > -1 ||
      element.name === key ||
      element.nodeName.toLowerCase() === key.toLowerCase() ||
      element.getAttribute('data-bind') === key
    );
  }

  // attach fill to current context (in the browser this will be window.fill)
  // this.fill = fill;
  // this.configs = configs

  mag.fill = {
    fill: fill,
    configs: configs
  }
  return mag
}(window.mag || {}, [], document))
<commit_msg>Update fill.js<commit_after>var mag = (function(mag, configs, document, undefined) {

  var ELEMENT_NODE = 1
  var cached = []

  // helper method to detect arrays -- silly javascript
    function _isArray(obj) {
      return Object.prototype.toString.call(obj) === '[object Array]'
    }

  var templates = {}

  // this is the entry point for this module, to fill the dom with data
    function fill(nodeList, data, key, index) {
      var node
      var parent
      var dataIsArray

      // there is nothing to do if there is nothing to fill
      if (!nodeList) return

      // remove all child nodes if there is no data
      if (data == null) data = {
        _text: ''
      }

      // CACHE
      // DIFF
      // CHANGE? then modify only the changes
      // KEYS for indentification

      // nodeList updates as the dom changes, so freeze it in an array
      var elements = nodeListToArray(nodeList)

      dataIsArray = _isArray(data)

      // match the number of nodes to the number of data elements
      if (dataIsArray) {

        if (templates[key + index] && elements.length === 0) {

          templates[key + index].parent.insertAdjacentHTML("beforeend", templates[key + index].node);
          elements = nodeListToArray(templates[key + index].parent.children)

        }

        if (elements.length === 0) {

          //=====================================================================
          // Warning: the following is a case where we could end up here: A page
          // that returns search results as the user is typing. If the results
          // are empty, then the child nodes that display the results will all
          // be removed. Then a subsequent attempt to fill in the search results
          // with data won't have any dom elements to clone.
          //=====================================================================

          // cannot fill empty nodeList with an array of data
          return
        }

        // clone the first node if more nodes are needed
        parent = elements[0].parentNode

        if (!templates[key + index]) {
          templates[key + index] = {
            node: elements[0].cloneNode(true).outerHTML,
            parent: parent
          }
          //remove from dom
          parent.removeChild(elements[0])
        }

        while (elements.length < data.length) {
          if (templates[key + index]) {
            parent.insertAdjacentHTML("beforeend", templates[key + index].node)
            node = parent.lastChild
          } else {
            node = elements[0].cloneNode(true)
          }

          elements.push(node)
          if (parent) parent.appendChild(node)
        }

        // remove the last node until the number of nodes matches the data
        while (elements.length > data.length) {
          node = elements.pop()
          parent = node.parentNode
          if (parent) parent.removeChild(node)
        }
      }

      // now fill each node with the data
      for (var i = 0; i < elements.length; i++) {
        if (dataIsArray) {
          if (elements[i]) {
            fill(elements[i], data[i])
          }
        } else {
          fillNode(elements[i], data)
        }
      }
      return nodeList
    }

    function fillNode(node, data) {
      var attributes,
        attrValue,
        element,
        elements

        // ignore functions
      if (typeof data === 'function') {

        return
      }

      // if the value is a simple property wrap it in the attributes hash
      if (typeof data !== 'object') return fillNode(node, {
        _text: data
      })

      // find all the attributes
      for (var key in data) {
        var value = data[key]

        // null values are treated like empty strings
        if (value === undefined) value = ''

        // anything that starts with an underscore is an attribute
        if (key[0] === '_') {
          // store the properties to set them all at once
          // if (typeof value === 'string' || typeof value === 'number') {
          attributes = attributes || {}
          attributes[key.substr(1)] = value;
          // } else {
          //   throw new Error('Expected a string or number for "' + key +
          //                   '", got: "' + JSON.stringify(value) + '"');
          // }
        }
      }

      // fill in all the attributes
      if (attributes) {
        fillAttributes(node, attributes)
      }

      var index = 0
      // look for non-attribute keys and recurse into those elements
      for (var key in data) {
        var value = data[key]

        // only attributes start with an underscore
        if (key[0] !== '_') {
          elements = matchingElements(node, key);

          // function
          if (typeof value === 'function' && value.type == 'fun') {
            try {
              value = value()
            } catch (e) {}
          }

          // check for key replacement within the element
          //domElement.replaceWithin(node, key, value)

          fill(elements, value, key, index);

          index++
        }
      }
    }

    // freeze the NodeList into a real Array so it can't update as DOM changes
    function nodeListToArray(nodeList) {
      var temp;

      // wrap single item into an array for iteration
      // NOTE: can't use _isArray here, because it could be a NodeList (array-ish)
      if (nodeList.length == null) {
        nodeList = [nodeList];
      }

      // convert array-like object into a real array
      if (!_isArray(nodeList)) {
        temp = [];
        for (var i = 0; i < nodeList.length; i += 1) {
          // Note: occassionaly jsdom returns undefined elements in the NodeList
          if (nodeList[i]) {
            temp.push(nodeList[i]);
          }
        }
        nodeList = temp;
      }

      return nodeList;
    }

    // fill in the attributes on an element (setting text and html first)
    function fillAttributes(node, attributes) {

      // set html after setting text because html overrides text
      setText(node, attributes.text)
      setHtml(node, attributes.html)
      node._events = node._events || []

      // set the rest of the attributes
      for (var attrName in attributes) {

        // skip text and html, they've already been set
        if (attrName === 'text' || attrName === 'html') continue

        // events
        if (attrName.indexOf('on') == 0) {
          if (node._events.indexOf(attrName) !== -1) continue

          node.addEventListener(attrName.substr(2), attributes[attrName])
          node._events.push(attrName)

        } else {

          if (attrName == 'config') {

            // have we been here before?
            // does the element already exist in cache
            // useful to know if this is newly added
            var isNew = true

            // bind
            var callback = function(data, args) {
              return function() {
                return data.apply(data, args)
              }
            };

            configs.push(callback(attributes[attrName], [node, isNew]))
            continue;
          }

          if (attributes[attrName] === null) {
            node.removeAttribute(attrName)
          } else {
            node.setAttribute(attrName, attributes[attrName].toString())
          }
        }
      }
    }

    function setText(node, text) {
      var child
      var children

      // make sure that we have a node and text to insert
      if (!node || text == null) return

      // cache all of the child nodes
      if (!children) {
        children = [];
        for (var i = 0; i < node.childNodes.length; i += 1) {
          child = node.childNodes[i];
          if (child.nodeType === ELEMENT_NODE) {
            children.push(child)
          }
        }
      }

      // remove all of the children
      //WHY?
      while (node.firstChild) {
        node.removeChild(node.firstChild)
      }

      // SELECT|INPUT|TEXTAREA
      // now add the text
      if (node.nodeName.toLowerCase() === 'input') {
        // special case for input elements
        node.setAttribute('value', text.toString());
      } else {
        // create a new text node and stuff in the value
        node.appendChild(node.ownerDocument.createTextNode(text.toString()));
      }

      // reattach all the child nodes
      for (var i = 0; i < children.length; i += 1) {
        node.appendChild(children[i]);
      }
    }

    function setHtml(node, html) {
      if (!node || html == null) return;
      node.innerHTML = html;
      // CAN'T do below since it will append on every new call
      // node.insertAdjacentHTML("afterbegin", html)
    };

  //===========================================================================
  // TODO: Decide if the caching of element matching should be reintroduced.
  // The original implementation cached the lookup of elements, but it seems
  // like this will only be useful in cases where the same DOM elements are
  // getting filled mutliple times -- that seems like it would only happen
  // when someone is running performance benchmarks.
  //===========================================================================

  // find all of the matching elements (breadth-first)

  function matchingElements(node, key, nested) {
    var elements = childElements(node)
    var matches = []
    var keyName = key

    if (!(node.queryCache || {})[key]) {

      node.queryCache = (node.queryCache || {})[key] = [];

      var globalSearch = key[0] === '$'

      if (keyName[0] === '$') keyName = keyName.substr(1)

      // search all child elements for a match
      for (var i = 0; i < elements.length; i += 1) {
        if (elementMatcher(elements[i], keyName)) {
          matches.push(elements[i]);
        }
      }

      // if there is no match, recursively search the childNodes
      if (!matches.length || globalSearch) {
        for (var i = 0; i < elements.length; i++) {
          // NOTE: pass in a flag to prevent recursive calls from logging
          matches = matches.concat(matchingElements(elements[i], key, true))
          if (matches.length && !globalSearch) break
        }
      }

      if (!nested && !matches.length) log('FILL - Warning: no matches found for "' + key + '"');

      // return matches
      node.queryCache[key] = matches
    }
    return node.queryCache[key];
  }

  // return just the child nodes that are elements
  function childElements(node) {
    var children = node.childNodes
    var elements = []

    for (var i = 0; i < children.length; i += 1) {
      if (children[i].nodeType === ELEMENT_NODE) {
        elements.push(children[i])
      }
    }

    return elements
  }

  // match elements on tag, id, name, class name, data-bind, etc.
  function elementMatcher(element, key) {
    var paddedClass = ' ' + element.className + ' ';

    return (
      element.id === key ||
      paddedClass.indexOf(' ' + key + ' ') > -1 ||
      element.name === key ||
      element.nodeName.toLowerCase() === key.toLowerCase() ||
      element.getAttribute('data-bind') === key
    );
  }

  // attach fill to current context (in the browser this will be window.fill)
  // this.fill = fill;
  // this.configs = configs

  // the user can inject a logger function to get some feedback from fill
  function log(methodName) {
    return function() {
      if (typeof mag.logger === 'object') {
        mag.logger[methodName || 'log'].apply(mag.logger, arguments)
      }
    }
  }

  mag.fill = {
    fill: fill,
    log: log,
    configs: configs
  }
  return mag
}(window.mag || {}, [], document))
<|endoftext|>


<commit_before>// $Revision$

var Ensembl = new Base();

Ensembl.extend({
  constructor: null,

  initialize: function () {
    var hints       = this.cookie.get('ENSEMBL_HINTS');
    var imagePanels = $('.image_panel');
    var bodyClass   = $('body')[0].className.split(' ');
    var modalOpen   = window.location.hash.match(/(modal_.+)/);

    if (!window.name) {
      window.name = 'ensembl_' + new Date().getTime() + '_' + Math.floor(Math.random() * 10000);
    }

    this.browser         = {};
    this.locationURL     = typeof window.history.pushState === 'function' ? 'search' : 'hash';
    this.hashParamRegex  = '([#?;&])(__PARAM__=)[^;&]+((;&)?)';
    this.locationMatch   = new RegExp(/[#?;&]r=([^;&]+)/);
    this.locationReplace = new RegExp(this.hashParamRegex.replace('__PARAM__', 'r'));
    this.width           = parseInt(this.cookie.get('ENSEMBL_WIDTH'), 10) || this.setWidth(undefined, 1);
    this.dynamicWidth    = !!this.cookie.get('DYNAMIC_WIDTH');
    this.hideHints       = {};
    this.initialPanels   = $('.initial_panel');
    this.minWidthEl      = $('#min_width_container');
    this.maxRegionLength = parseInt($('#max_region_length').val() || 0, 10);
    this.speciesPath     = $('#species_path').val()        || '';
    this.speciesCommon   = $('#species_common_name').val() || '';
    this.species         = this.speciesPath.split('/').pop();
    this.images          = { total: imagePanels.length, last: imagePanels.last()[0] }; // Store image panel details for highlighting

    for (var i in bodyClass) {
      if (bodyClass[i]) {
        this.browser[bodyClass[i]] = true;
      }
    }

    if (this.dynamicWidth && !window.name.match(/^popup_/)) {
      var width = this.imageWidth();

      if (width > 0 && this.width !== width) {
        this.width = width;
        this.cookie.set('ENSEMBL_WIDTH', width);
      }
    }

    this.cookie.set('WINDOW_WIDTH', $(window).width());

    if (hints) {
      $.each(hints.split(/:/), function () {
        Ensembl.hideHints[this] = 1;
      });
    }

    imagePanels = null;

    this.setCoreParams();

    this.LayoutManager.initialize();

    // If there's a hash in the URL with a new location in it, and the browser supports history API,
    // update window.location.search to contain the new location.
    // Also change all ajax_load values, so panels are loaded matching the new location.
    var removeHash = this.locationURL === 'hash' ? '' : window.location.hash.match('=');
    var hashChange = removeHash ? window.location.hash.match(this.locationMatch) : false;

    $('input.ajax_load').val(function (i, val) { return Ensembl.urlFromHash(val); });

    if (removeHash) {
      window.history.replaceState({}, '', Ensembl.urlFromHash(window.location.search));
    }

    this.PanelManager.initialize();

    if (modalOpen) {
      this.EventManager.trigger('modalOpen', { className: 'force', rel: modalOpen[1] });
      window.location.hash = '';
    }

    if (hashChange) {
      this.EventManager.trigger('hashChange', hashChange[1]); // update links and HTML for the new location
    }
  },

  cookie: {
    set: function (name, value, expiry, unescaped) {
      var cookie = [
        unescaped === true ? (name + '=' + (value || '')) : (escape(name) + '=' + escape(value || '')),
        '; expires=',
        ((expiry === -1 || value === '') ? 'Thu, 01 Jan 1970' : 'Tue, 19 Jan 2038'),
        ' 00:00:00 GMT; path=/'
      ].join('');

      document.cookie = cookie;

      return value;
    },

    get: function (name, unescaped) {
      var cookie = document.cookie.match(new RegExp('(^|;)\\s*' + (unescaped === true ? name : escape(name)) + '=([^;\\s]*)'));
      return cookie ? unescape(cookie[2]) : '';
    }
  },

  imageWidth: function () {
    return Math.floor(($(window).width() - 240) / 100) * 100;
  },

  setWidth: function (w, changed) {
    var numeric = !isNaN(w);

    w = numeric ? w : this.imageWidth();

    this.width = w < 500 ? 500 : w;

    if (changed) {
      this.cookie.set('ENSEMBL_WIDTH', this.width);
      this.cookie.set('DYNAMIC_WIDTH', numeric ? '' : 1);
      this.dynamicWidth = !numeric;
    }

    return this.width;
  },

  setCoreParams: function () {
    var regex       = '[#?;&]%s=([^;&]+)';
    var url         = window.location.search;
    var hash        = window.location.hash;
    var locationURL = this.locationURL === 'hash' ? hash : url;
    var lastR       = this.coreParams ? this.coreParams.r : '';
    var match, m, i, r;

    this.hash         = hash;
    this.coreParams   = {};
    this.initialR     = $('input[name=r]', '#core_params').val();
    this.location     = { length: 100000 };
    this.multiSpecies = {};

    $('input', '#core_params').each(function () {
      var hashMatch = locationURL.match(regex.replace('%s', this.name));
      Ensembl.coreParams[this.name] = hashMatch ? unescape(hashMatch[1]) : this.value;
    });

    this.lastR = lastR || (hash ? this.coreParams.r : this.initialR);

    match = this.coreParams.r ? this.coreParams.r.match(/(.+):(\d+)-(\d+)/) : false;

    if (match) {
      this.location = { name: match[1], start: parseInt(match[2], 10), end: parseInt(match[3], 10) };
      this.location.length = this.location.end - this.location.start + 1;
    }

    match = url.match(/s\d+=([^;&]+)/g);

    if (match) {
      $.each(match, function () {
        m = this.split('=');
        i = m[0].substr(1);

        Ensembl.multiSpecies[i] = {};

        $.each(['r', 'g', 's'], function (j, param) {
          Ensembl.multiSpecies[i][param] = url.match(regex.replace('%s', param + i));

          if (Ensembl.multiSpecies[i][param]) {
            Ensembl.multiSpecies[i][param] = unescape(Ensembl.multiSpecies[i][param][1]);
          }

          if (param === 'r' && Ensembl.multiSpecies[i].r) {
            r = Ensembl.multiSpecies[i].r.match(/(.+):(\d+)-(\d+)/);

            Ensembl.multiSpecies[i].location = { name: r[1], start: parseInt(r[2], 10), end: parseInt(r[3], 10) };
          }
        });
      });
    }
  },

  cleanURL: function (url) {
    return unescape(url.replace(/&/g, ';').replace(/#.*$/g, '').replace(/([?;])time=[^;]+;?/g, '$1').replace(/[?;]$/g, ''));
  },

  // Remove the old time stamp from a URL and replace with a new one
  replaceTimestamp: function (url) {
    var d    = new Date();
    var time = d.getTime() + d.getMilliseconds() / 1000;

    url  = this.cleanURL(url);
    url += (url.match(/\?/) ? ';' : '?') + 'time=' + time;

    return url;
  },

  redirect: function (url) {
    for (var p in this.PanelManager.panels) {
      this.PanelManager.panels[p].destructor('cleanup');
    }

    url = url || this.replaceTimestamp(window.location.href);

    if (window.location.hash) {
      url = this.urlFromHash(url);
    }

    window.location = url;
  },

  updateLocation: function (r) {
    this.historyReady = true;

    if (this.updateURL({ r: r }) === true && this.locationURL === 'search') {
      this.setCoreParams();
      this.EventManager.trigger('hashChange', r);
    }
  },

  updateURL: function (params, inputURL) {
    var url = inputURL ? (inputURL + (inputURL.match(/\?/) ? '' : '?')) : window.location[this.locationURL];

    for (var i in params) {
      if (params[i] === false) {
        url = url.replace(new RegExp(this.hashParamRegex.replace('__PARAM__', i)), '$1');
      } else if (url.match(i + '=')) {
        var regex = new RegExp(this.hashParamRegex.replace('__PARAM__', i));

        if (url.match(regex)) {
          url = url.replace(regex, '$1$2' + params[i] + '$3');
        } else {
          url = url.replace(i + '=', i + '=' + params[i]);
        }
      } else {
        url += (url ? ';' : '') + i + '=' + params[i];
      }
    }

    url = url.replace(/([?;]);+/g, '$1');

    if (inputURL) {
      return url;
    }

    if (window.location[this.locationURL] !== url) {
      if (this.locationURL === 'hash') {
        window.location.hash = url;
      } else {
        window.history.pushState({}, '', url);
      }

      return true;
    }
  },

  urlFromHash: function (url, paramOnly) {
    var location = window.location[this.locationURL].replace(/^#/, '?') + ';';
    var match    = location.match(this.locationMatch);
    var r        = match ? match[1] : this.initialR || '';

    if (paramOnly) {
      return r;
    }

    var hash = r && this.locationURL === 'search' ? { r: r } : {};

    $.each(window.location.hash.replace('#', '').split(/[;&]/), function () {
      var param = this.split('=');

      if (param.length === 2) {
        hash[param[0]] = param[1];
      }
    });

    return this.updateURL(hash, url);
  },

  thousandify: function (str) {
    str += '';

    var rgx = /(\d+)(\d{3})/;
    var x   = str.split('.');
    var x1  = x[0];
    var x2  = x.length > 1 ? '.' + x[1] : '';

    while (rgx.test(x1)) {
      x1 = x1.replace(rgx, '$1' + ',' + '$2');
    }

    return x1 + x2;
  }
});

window.Ensembl = Ensembl; // Make Ensembl namespace available on window - needed for upload iframes because the minifier will compress the variable name Ensembl
<commit_msg>add '?' to the URL if it doesn't have one<commit_after>// $Revision$

var Ensembl = new Base();

Ensembl.extend({
  constructor: null,

  initialize: function () {
    var hints       = this.cookie.get('ENSEMBL_HINTS');
    var imagePanels = $('.image_panel');
    var bodyClass   = $('body')[0].className.split(' ');
    var modalOpen   = window.location.hash.match(/(modal_.+)/);

    if (!window.name) {
      window.name = 'ensembl_' + new Date().getTime() + '_' + Math.floor(Math.random() * 10000);
    }

    this.browser         = {};
    this.locationURL     = typeof window.history.pushState === 'function' ? 'search' : 'hash';
    this.hashParamRegex  = '([#?;&])(__PARAM__=)[^;&]+((;&)?)';
    this.locationMatch   = new RegExp(/[#?;&]r=([^;&]+)/);
    this.locationReplace = new RegExp(this.hashParamRegex.replace('__PARAM__', 'r'));
    this.width           = parseInt(this.cookie.get('ENSEMBL_WIDTH'), 10) || this.setWidth(undefined, 1);
    this.dynamicWidth    = !!this.cookie.get('DYNAMIC_WIDTH');
    this.hideHints       = {};
    this.initialPanels   = $('.initial_panel');
    this.minWidthEl      = $('#min_width_container');
    this.maxRegionLength = parseInt($('#max_region_length').val() || 0, 10);
    this.speciesPath     = $('#species_path').val()        || '';
    this.speciesCommon   = $('#species_common_name').val() || '';
    this.species         = this.speciesPath.split('/').pop();
    this.images          = { total: imagePanels.length, last: imagePanels.last()[0] }; // Store image panel details for highlighting

    for (var i in bodyClass) {
      if (bodyClass[i]) {
        this.browser[bodyClass[i]] = true;
      }
    }

    if (this.dynamicWidth && !window.name.match(/^popup_/)) {
      var width = this.imageWidth();

      if (width > 0 && this.width !== width) {
        this.width = width;
        this.cookie.set('ENSEMBL_WIDTH', width);
      }
    }

    this.cookie.set('WINDOW_WIDTH', $(window).width());

    if (hints) {
      $.each(hints.split(/:/), function () {
        Ensembl.hideHints[this] = 1;
      });
    }

    imagePanels = null;

    this.setCoreParams();

    this.LayoutManager.initialize();

    // If there's a hash in the URL with a new location in it, and the browser supports history API,
    // update window.location.search to contain the new location.
    // Also change all ajax_load values, so panels are loaded matching the new location.
    var removeHash = this.locationURL === 'hash' ? '' : window.location.hash.match('=');
    var hashChange = removeHash ? window.location.hash.match(this.locationMatch) : false;

    $('input.ajax_load').val(function (i, val) { return Ensembl.urlFromHash(val); });

    if (removeHash) {
      window.history.replaceState({}, '', Ensembl.urlFromHash(window.location.search));
    }

    this.PanelManager.initialize();

    if (modalOpen) {
      this.EventManager.trigger('modalOpen', { className: 'force', rel: modalOpen[1] });
      window.location.hash = '';
    }

    if (hashChange) {
      this.EventManager.trigger('hashChange', hashChange[1]); // update links and HTML for the new location
    }
  },

  cookie: {
    set: function (name, value, expiry, unescaped) {
      var cookie = [
        unescaped === true ? (name + '=' + (value || '')) : (escape(name) + '=' + escape(value || '')),
        '; expires=',
        ((expiry === -1 || value === '') ? 'Thu, 01 Jan 1970' : 'Tue, 19 Jan 2038'),
        ' 00:00:00 GMT; path=/'
      ].join('');

      document.cookie = cookie;

      return value;
    },

    get: function (name, unescaped) {
      var cookie = document.cookie.match(new RegExp('(^|;)\\s*' + (unescaped === true ? name : escape(name)) + '=([^;\\s]*)'));
      return cookie ? unescape(cookie[2]) : '';
    }
  },

  imageWidth: function () {
    return Math.floor(($(window).width() - 240) / 100) * 100;
  },

  setWidth: function (w, changed) {
    var numeric = !isNaN(w);

    w = numeric ? w : this.imageWidth();

    this.width = w < 500 ? 500 : w;

    if (changed) {
      this.cookie.set('ENSEMBL_WIDTH', this.width);
      this.cookie.set('DYNAMIC_WIDTH', numeric ? '' : 1);
      this.dynamicWidth = !numeric;
    }

    return this.width;
  },

  setCoreParams: function () {
    var regex       = '[#?;&]%s=([^;&]+)';
    var url         = window.location.search;
    var hash        = window.location.hash;
    var locationURL = this.locationURL === 'hash' ? hash : url;
    var lastR       = this.coreParams ? this.coreParams.r : '';
    var match, m, i, r;

    this.hash         = hash;
    this.coreParams   = {};
    this.initialR     = $('input[name=r]', '#core_params').val();
    this.location     = { length: 100000 };
    this.multiSpecies = {};

    $('input', '#core_params').each(function () {
      var hashMatch = locationURL.match(regex.replace('%s', this.name));
      Ensembl.coreParams[this.name] = hashMatch ? unescape(hashMatch[1]) : this.value;
    });

    this.lastR = lastR || (hash ? this.coreParams.r : this.initialR);

    match = this.coreParams.r ? this.coreParams.r.match(/(.+):(\d+)-(\d+)/) : false;

    if (match) {
      this.location = { name: match[1], start: parseInt(match[2], 10), end: parseInt(match[3], 10) };
      this.location.length = this.location.end - this.location.start + 1;
    }

    match = url.match(/s\d+=([^;&]+)/g);

    if (match) {
      $.each(match, function () {
        m = this.split('=');
        i = m[0].substr(1);

        Ensembl.multiSpecies[i] = {};

        $.each(['r', 'g', 's'], function (j, param) {
          Ensembl.multiSpecies[i][param] = url.match(regex.replace('%s', param + i));

          if (Ensembl.multiSpecies[i][param]) {
            Ensembl.multiSpecies[i][param] = unescape(Ensembl.multiSpecies[i][param][1]);
          }

          if (param === 'r' && Ensembl.multiSpecies[i].r) {
            r = Ensembl.multiSpecies[i].r.match(/(.+):(\d+)-(\d+)/);

            Ensembl.multiSpecies[i].location = { name: r[1], start: parseInt(r[2], 10), end: parseInt(r[3], 10) };
          }
        });
      });
    }
  },

  cleanURL: function (url) {
    return unescape(url.replace(/&/g, ';').replace(/#.*$/g, '').replace(/([?;])time=[^;]+;?/g, '$1').replace(/[?;]$/g, ''));
  },

  // Remove the old time stamp from a URL and replace with a new one
  replaceTimestamp: function (url) {
    var d    = new Date();
    var time = d.getTime() + d.getMilliseconds() / 1000;

    url  = this.cleanURL(url);
    url += (url.match(/\?/) ? ';' : '?') + 'time=' + time;

    return url;
  },

  redirect: function (url) {
    for (var p in this.PanelManager.panels) {
      this.PanelManager.panels[p].destructor('cleanup');
    }

    url = url || this.replaceTimestamp(window.location.href);

    if (window.location.hash) {
      url = this.urlFromHash(url);
    }

    window.location = url;
  },

  updateLocation: function (r) {
    this.historyReady = true;

    if (this.updateURL({ r: r }) === true && this.locationURL === 'search') {
      this.setCoreParams();
      this.EventManager.trigger('hashChange', r);
    }
  },

  updateURL: function (params, inputURL) {
    var url = inputURL || window.location[this.locationURL];
    if (!url.match(/\?/)) {
      url += '?';
    }

    for (var i in params) {
      if (params[i] === false) {
        url = url.replace(new RegExp(this.hashParamRegex.replace('__PARAM__', i)), '$1');
      } else if (url.match(i + '=')) {
        var regex = new RegExp(this.hashParamRegex.replace('__PARAM__', i));

        if (url.match(regex)) {
          url = url.replace(regex, '$1$2' + params[i] + '$3');
        } else {
          url = url.replace(i + '=', i + '=' + params[i]);
        }
      } else {
        url += (url ? ';' : '') + i + '=' + params[i];
      }
    }

    url = url.replace(/([?;]);+/g, '$1');

    if (inputURL) {
      return url;
    }

    if (window.location[this.locationURL] !== url) {
      if (this.locationURL === 'hash') {
        window.location.hash = url;
      } else {
        window.history.pushState({}, '', url);
      }

      return true;
    }
  },

  urlFromHash: function (url, paramOnly) {
    var location = window.location[this.locationURL].replace(/^#/, '?') + ';';
    var match    = location.match(this.locationMatch);
    var r        = match ? match[1] : this.initialR || '';

    if (paramOnly) {
      return r;
    }

    var hash = r && this.locationURL === 'search' ? { r: r } : {};

    $.each(window.location.hash.replace('#', '').split(/[;&]/), function () {
      var param = this.split('=');

      if (param.length === 2) {
        hash[param[0]] = param[1];
      }
    });

    return this.updateURL(hash, url);
  },

  thousandify: function (str) {
    str += '';

    var rgx = /(\d+)(\d{3})/;
    var x   = str.split('.');
    var x1  = x[0];
    var x2  = x.length > 1 ? '.' + x[1] : '';

    while (rgx.test(x1)) {
      x1 = x1.replace(rgx, '$1' + ',' + '$2');
    }

    return x1 + x2;
  }
});

window.Ensembl = Ensembl; // Make Ensembl namespace available on window - needed for upload iframes because the minifier will compress the variable name Ensembl
<|endoftext|>


<commit_before>function randomInt(low, high){
  return Math.floor(Math.random() * (high - (low - 1))) + low;
}
Sprite.extend('Block',{
  url: "images/sprites/mario/1.png",
  setup: function(){
    this.active = true;
    this.y = 0;
  },
  logic : function(){
      if(this.active){
        this.y = this.y + 1 * memblox.environment.level.multiplier ;
      }
      if(this.left){
        this.x = this.x - 40;
      }
      else if (this.right){
        this.x = this.x + 40;
      }
      if (this.flip) {
        this.doFlip();
        this.flip = false;
      }
  }
});
(function(window, document, undefined) {
  if(!window.console || !console.log){
    console = {};
    console.log = alert;
  }
  /* randomInt
   *  @param low : the low number in the return set
   *  @param high : the high number in the return set
   */

  // EventTarget class acts as base for custom events
  var memblox = {
    pause : false,
    init : function(){

    },
    objects : {
      block : function(theme){
        var block = {};
        var number = randomInt(0, 16);
        Block.add({
          setup: function(){
            // this needs to establish the tile
          },
          logic: function(clock){

          }
        });

        return block;
      }
    },
    play : function(){
      (function game(){
        function renderCanvas(buffer, output){
          var board = {size:{height:440, width:320}}
          buffcontext = buffer.getContext('2d');
          boardback = buffcontext.createLinearContext(0, 0, board.size.height, board.size.width);
          boardback.addColorStop(0, 'rgba(100, 100, 100, 1)');
          boardback.addColorStop(1, 'rgba(180, 180, 180, 1)');
          buffcontext.fillStyle = boardback;
          buffcontext.fillRect(0, 0, board.size.height, board.size.width);
        };
        renderCanvas();
        // play the game cycle yo
        // check for halt or pause
        setTimeout("game()", 50);
      })()
    },
    options : {
      soundEnabled: true,
      bufferMin: 3,
      bufferMax: 10,
      pSize:40,
      boardHeight: 0,
      boardWidth: 0,
      numberOfMatches: 16,
    },
    io : {
      boardDisplay: {},
      scoreDisplay: {},
      levelDisplay: {}
    },
    actions: {
      flipBlock : function(block){/**/return;},
      moveBlock : function(block, direction){/**/return;},
    },
    events: {
      blockCleared : function(block){/**/return;},
      blockMoved : function(block, direction){/**/return;},
      blockFell : function(block, spaces){/**/return;},
      blockFlipped : function(block){/**/return;},
      levelCleared : function(level){/**/return;}
    },
    environment: {
      board : [],
      player : "",
      score : 0,
      currentLevel : 0,
      level : [1.1,1.2,1.3,1.4],
      flipped : {
        count : 0,
        blocks : []
      },
      topScores : [],
      players : [],
      theme : 1,
      themes : ["default","mario"],
      activeblock : null
    },
    data: {
      db: {},
      text : {}
    },
    assets: {
      sprite : ["Block"],
      images : [],
      sounds : []
    }
  }
  window.memblox = memblox;
})(window, window.document)

Effect.Game.addEventListener( 'onLoadGame',function(){
  memblox.init();
  var number = randomInt(1, 16);

  block = memblox.environment.activeblock;
  Effect.Game.addEventListener( 'onKeyDown', function(id){
    switch(id) {
      case 'left':
        block.left = true;
        break;
      case 'right':
        block.right = true;
        break;
    }
  });
  Effect.Game.addEventListener( 'onKeyUp', function(id){
    switch (id) {
      case 'left':
        block.left = false;
        break;
      case 'right':
        block.right = false;
    }
  });
  var splane = new SpritePlane( 'Blocks' );
  splane.setZIndex( 2 );
  var music = Effect.Audio.getTrack("/audio/music/mario/bg-music.mp3");
  Effect.Port.setBackground({
    url: '/images/background/mario/bg1.jpg',
    xMode : 'infinite',
    xSpeed : 2
  });
  Effect.Port.attach( splane );
  Effect.Port.addEventListener( 'onMouseDown', function(pt, buttonIdx){
    // there needs to be useful
    alert( "You clicked " + pt.x + " by " + pt.y );
  });
  Effect.Game.loadLevel( 'Default', function(){
    splane = Effect.Port.getPlane("Blocks");
    splane.createSprite("Block",{
      x: 40,
      y: 0
    });
    music.playSound();
  });
     var hud = new HUD( 'myhud' );
   hud.setFont( 'Optimer18Test' );
   hud.setTableSize( 15, 4 );  // This sets the total number of characters allowed horizontally and vertically
   hud.setTracking( .8, 1.0 );  // Spacing between letters horiz and vert, where 1.0 means normal, 0.5 means more squeezed together, and 1.5 means more spaced apart
   hud.setPosition( 40, 50 );
   hud.setZIndex( 3 );
   Effect.Port.attach( hud );

  hud.setString( 0, 0, "Game HUD" );
  hud.setString( 0, 1, "Second Line" );
  hud.setString( 0, 2, "Third Line" );
  hud.setString( 0, 3, "1234567890123456" );

});<commit_msg>got the damn block moving<commit_after>function randomInt(low, high){
  return Math.floor(Math.random() * (high - (low - 1))) + low;
}
Sprite.extend('Block',{
  url: "images/sprites/mario/1.png",
  setup: function(){
    this.active = true;
    this.y = 0;
  },
  logic : function(){
      if(this.active){
        this.y = this.y + 1 * memblox.environment.level.multiplier ;
      }
      if(this.left){
        this.x = this.x - 40;
      }
      else if (this.right){
        this.x = this.x + 40;
      }
      if (this.flip) {
        this.doFlip();
        this.flip = false;
      }
  }
});
(function(window, document, undefined) {
  if(!window.console || !console.log){
    console = {};
    console.log = alert;
  }
  /* randomInt
   *  @param low : the low number in the return set
   *  @param high : the high number in the return set
   */

  // EventTarget class acts as base for custom events
  var memblox = {
    pause : false,
    init : function(){

    },
    objects : {
      block : function(theme){
        var block = {};
        var number = randomInt(0, 16);
        Block.add({
          setup: function(){
            // this needs to establish the tile
          },
          logic: function(clock){

          }
        });

        return block;
      }
    },
    play : function(){
      (function game(){
        function renderCanvas(buffer, output){
          var board = {size:{height:440, width:320}}
          buffcontext = buffer.getContext('2d');
          boardback = buffcontext.createLinearContext(0, 0, board.size.height, board.size.width);
          boardback.addColorStop(0, 'rgba(100, 100, 100, 1)');
          boardback.addColorStop(1, 'rgba(180, 180, 180, 1)');
          buffcontext.fillStyle = boardback;
          buffcontext.fillRect(0, 0, board.size.height, board.size.width);
        };
        renderCanvas();
        // play the game cycle yo
        // check for halt or pause
        setTimeout("game()", 50);
      })()
    },
    options : {
      soundEnabled: true,
      bufferMin: 3,
      bufferMax: 10,
      pSize:40,
      boardHeight: 0,
      boardWidth: 0,
      numberOfMatches: 16,
    },
    io : {
      boardDisplay: {},
      scoreDisplay: {},
      levelDisplay: {}
    },
    actions: {
      flipBlock : function(block){/**/return;},
      moveBlock : function(block, direction){/**/return;},
    },
    events: {
      blockCleared : function(block){/**/return;},
      blockMoved : function(block, direction){/**/return;},
      blockFell : function(block, spaces){/**/return;},
      blockFlipped : function(block){/**/return;},
      levelCleared : function(level){/**/return;}
    },
    environment: {
      board : [],
      player : "",
      score : 0,
      currentLevel : 0,
      level : [1.1,1.2,1.3,1.4],
      flipped : {
        count : 0,
        blocks : []
      },
      topScores : [],
      players : [],
      theme : 1,
      themes : ["default","mario"],
      activeblock : null
    },
    data: {
      db: {},
      text : {}
    },
    assets: {
      sprite : ["Block"],
      images : [],
      sounds : []
    }
  }
  window.memblox = memblox;
})(window, window.document)

Effect.Game.addEventListener( 'onLoadGame',function(){
  memblox.init();
  var number = randomInt(1, 16);

  block = memblox.environment.activeblock;
  Effect.Game.addEventListener( 'onKeyDown', function(id){
    switch(id) {
      case 'left':
        block.left = true;
        break;
      case 'right':
        block.right = true;
        break;
    }
  });
  Effect.Game.addEventListener( 'onKeyUp', function(id){
    switch (id) {
      case 'left':
        block.left = false;
        break;
      case 'right':
        block.right = false;
        break;
    }
  });
  var splane = new SpritePlane( 'Blocks' );
  splane.setZIndex( 2 );
  var music = Effect.Audio.getTrack("/audio/music/mario/bg-music.mp3");
  Effect.Port.setBackground({
    url: '/images/background/mario/bg1.jpg',
    xMode : 'infinite',
    xSpeed : 2
  });
  Effect.Port.attach( splane );
  Effect.Port.addEventListener( 'onMouseDown', function(pt, buttonIdx){
    // there needs to be useful
    alert( "You clicked " + pt.x + " by " + pt.y );
  });
  Effect.Game.loadLevel( 'Default', function(){
    splane = Effect.Port.getPlane("Blocks");
    splane.createSprite("Block",{
      x: 40,
      y: 0,
      height: 40,
      width: 40,
      setup: function(clock){
        this.active = true;
        memblox.environment.activeblock = this;
      },
      logic: function(clock){
        if(this.active){
          if(this.y > 440){
            return false;
          }
          this.y++;
        }
      }
    });
    splane.draw();
    music.playSound();
  });
     var hud = new HUD( 'myhud' );
   hud.setFont( 'Optimer18Test' );
   hud.setTableSize( 15, 4 );  // This sets the total number of characters allowed horizontally and vertically
   hud.setTracking( .8, 1.0 );  // Spacing between letters horiz and vert, where 1.0 means normal, 0.5 means more squeezed together, and 1.5 means more spaced apart
   hud.setPosition( 40, 50 );
   hud.setZIndex( 3 );
   Effect.Port.attach( hud );

  hud.setString( 0, 0, "Game HUD" );
  hud.setString( 0, 1, "Second Line" );
  hud.setString( 0, 2, "Third Line" );
  hud.setString( 0, 3, "1234567890123456" );

});<|endoftext|>


<commit_before>var Sequelize = require('sequelize');

db = new Sequelize('postgres', 'postgres', ' ', {
  dialect: 'postgres',
  port: 5432
});

db.authenticate()
  .then((err) => {
    console.log('Database connection established');
  }, (err) => {
    console.log('Unable to connect to the database: ', err);
  });

  module.exports = {database: db, Sequelize:Sequelize};<commit_msg>Fix minor syntax bug in database.js<commit_after>var Sequelize = require('sequelize');

var db = new Sequelize('postgres', 'postgres', ' ', {
  dialect: 'postgres',
  port: 5432
});

db.authenticate()
  .then((err) => {
    console.log('Database connection established');
  }, (err) => {
    console.log('Unable to connect to the database: ', err);
  });

  module.exports = {database: db, Sequelize:Sequelize};<|endoftext|>