<commit_before>$(function () {
  var Fulfil = {
    csrfToken: "{{ csrf_token() }}",
    urls: {},
    form: {},
    cart: {"stripe": {}},
    user: {},
    ux: {},
    product: {},
    address: {}
  };

  // All the URLs this file needs to know
  Fulfil.urls.view_cart = "{{ url_for('cart.view_cart') }}";
  Fulfil.urls.remove_from_cart = "{{ url_for('cart.remove_from_cart') }}";
  Fulfil.urls.getVariations = "{{ url_for('products.get_variations') }}";
  Fulfil.urls.payUsingProfile = "{{ url_for('checkout.payment') }}";
  Fulfil.urls.setBillingAddress = "{{ url_for('checkout.billing_address') }}";

  /**
   * Helper method to change formSubmission to ajax
   *
   * @param formElement HTMLElement
   * @param options Object with successCallback, errorCallback,
   *                alwaysCallback, onSubmit as keys
   */
  Fulfil.form.ajaxSubmit = function (formElement, options) {
    var form = $(formElement);

    options = options || {}

    form.on('submit', function (event) {
      event.preventDefault();

      // Call onSubmit if function
      if ($.isFunction(options.onSubmit)) {
        options.onSubmit(event);
      }

      $.ajax({
        'url': form.attr("action"),
        'type': form.attr('method') || 'GET',
        'data': form.serialize(),
        'dataType': "json"
      })
        .done(options.successCallback)
        .fail(options.errorCallback)
        .always(options.alwaysCallback);
    });
  };

  /**
   * Method to show errors in form
   */
  Fulfil.form.showErrors = function (formElement, errorsObj) {
    var form = $(formElement);

    $.each(errorsObj, function (key, value) {
      // TODO: show errors
    });
  };

  /**
   * Helper method to initialize login form
   */
  Fulfil.form.initLoginForm =  function (formElement) {
    var errorContainer = formElement.find('.error-message');

    // by default hide error container
    errorContainer.html('').hide();

    var options = {
      onSubmit: function () {
        errorContainer.html('').hide();
      },
      successCallback: function (result) {
        location.reload();
      },
      errorCallback: function (error) {
        if (error.status == 400) {
          if (!error.responseJSON.errors) {
            console.error("No 'errors' in response on bad request.");
          }

          var errors = [];
          $.each(error.responseJSON.errors, function (key, value) {
            errors = errors.concat(value);
          });

          // Show errors in error container
          errorContainer.html(errors.join(',')).show();
          return;
        }
        console.log(error.statusText);
      }
    };

    Fulfil.form.ajaxSubmit(formElement, options);
  };

  /*
   *
   * Cart related logic
   * ==================
   *
   */

   /*
    * Refreshes the cart and updates Fulfil.cart.current_cart
    * Also returns the request promise.
    *
    */
   Fulfil.cart.refresh = function() {
    console.debug("Refreshing Cart");
    return $.ajax({
      cache: false,
      url: Fulfil.urls.view_cart,
      dataType: "json",
      success: function(data){
        Fulfil.cart.current_cart = data.cart;
      }
    })
   };

   /*
    * Delete a item from the cart.
    *
    */
   Fulfil.cart.deleteItem = function(lineId) {
    console.debug("Removing Line from Cart");
    return $.ajax({
      url: Fulfil.urls.remove_from_cart,
      method: "POST",
      data: {
        "line_id": lineId,
        "csrf_token": Fulfil.csrfToken
       },
       dataType: "json",
       success: function() {
         Fulfil.cart.refresh();
       }
    });
   }

  /*
   *
   * Product related logic
   * =====================
   *
   */

  /*
   *
   * Fetch variation data for a product template
   *
   */
  Fulfil.product.getVariations = function(templateId) {
    return $.ajax({
      url: Fulfil.urls.getVariations,
      method: "GET",
      data: {
        "template": templateId
       },
       dataType: "json",
       success: function(data) {
         Fulfil.product.loadVariations(data);
       }
    });
  };

  /*
   * Load the variation data locally to serve more
   * requests.
   */
  Fulfil.product.loadVariations = function(variationData) {
    Fulfil.product.variationData = variationData;
  };

  /*
   * Given a set of attributes, return a variant
   * that fits the attributes
   *
   */
  Fulfil.product.findMatchingVariant = function(attributeSelection) {
    return _.find(Fulfil.product.variationData['variants'], function(variant) {
      return _.isEqual(variant.attributes, attributeSelection)
    });
  };

  /*
   * Return the data of the variant with id
   *
   */
  Fulfil.product.getVariant = function(variantId) {
    return _.find(Fulfil.product.variationData['variants'], function(variant) {
      return (variant.id == variantId) ;
    });
  };

  /*
   *
   * Address related logic
   * =====================
   *
   */

  /*
   * Return list of all available countries
   */
  Fulfil.address.getCountries = function() {
    return $.getJSON('{{ url_for("public.get_countries") }}');
  };

  /*
   * Helper method to fill country options in select field
   */
  Fulfil.address.fillCountriesOpts = function(selectField, currentValue) {
    selectField.html('');
    return Fulfil.address.getCountries()
      .success(function (data) {
        var optionsHtml = '';
        $.each(data.result, function(i, country){
          optionsHtml +=
            '<option value="'+ country.code +'">' + country.name + '</option>';
        });
        selectField.html(optionsHtml);

        if (currentValue) {
          $(selectField).val(currentValue).change();
        }
      });
  };

  /*
   * Return a list of all addresses of the user
   */
   Fulfil.address.getAddresses = function() {
     return $.getJSON(
       '{{ url_for("user.addresses") }}',
       {csrf_token: Fulfil.csrfToken}
     );
   };

   /*
   * Create a stripe token using card data and address
   */
   Fulfil.cart.stripe.createToken = function(card, address, callback) {
     if (typeof Stripe === 'undefined') {
       console.debug("Stripe.js is not added");
       return;
     }
     Stripe.setPublishableKey("{{ current_channel.payment_gateway.stripe_publishable_key }}");
     Stripe.card.createToken({
       'number': card.number,
       'cvc': card.cvc,
       'exp_month': card.exp_month,
       'exp_year': card.exp_year,
       'name': card.name,
       'address_zip': address.zip,
       'address_line1': address.street,
       'address_line2': address.streetbis,
       'address_city': address.city,
       'address_state': address.subdivision,
       'address_country': address.country
     }, callback);
   };

   /*
   * Pay using stripe payment profile or token
   */
   Fulfil.cart.payUsingProfile = function(profile, amount) {
    return $.ajax({
      url: Fulfil.urls.payUsingProfile,
      method: "POST",
      data: {
        "payment_profile_id": profile.payment_profile_id,
        "stripe_token": profile.stripe_token,
        "amount": amount,
        "csrf_token": Fulfil.csrfToken
       },
       dataType: "json"
    });
   };

   /*
   * Set billing address
   */
   Fulfil.cart.setBillingAddress = function(address) {
    return $.ajax({
      url: Fulfil.urls.setBillingAddress,
      method: "POST",
      data: {
        "billing_address": address.billing_address,
        "name": address.name,
        "street": address.street,
        "streetbis": address.streetbis,
        "city": address.city,
        "zip": address.zip,
        "country": address.country,
        "subdivision": address.subdivision,
        "csrf_token": Fulfil.csrfToken
       },
       dataType: "json"
    });
   };

   Fulfil.ux.notify = function(message, level, title) {
      if (!level) {
        level = 'info'
      };
      if (toastr) {
        toastr[level](message, title);
      }
   }

  /**
   * Helper method to init form with countries
   */
  Fulfil.address._initForm = function (formElm, noGoogleInit) {
    var countryField = formElm.find('select[name="country"]');
    var subdivisionField = formElm.find('select[name="subdivision"]');

    // On change of country
    countryField.change(function () {
      // Clear options as soon as country change
      subdivisionField.empty();

      var reqUrl = "/countries/" + $(this).val() +"/subdivisions";
      $.getJSON(reqUrl, function(data){
        $.each(data.result, function(_, subdivision) {
          subdivisionField
            .append($("<option></option>")
              .attr("value", subdivision.code)
              .attr("code", subdivision.code)
              .text(subdivision.name));
        });
        if (subdivisionField.data('value')) {
          // If data-value set that as field value and clear.
          // This is helpful in setting value of subdivision without waiting
          // for subdivison options to load.
          subdivisionField.val(subdivisionField.data('value'));
          subdivisionField.data('value', null);
        }
        subdivisionField.triggerHandler("change");
      });
    });

    // Countries are loaded by jinja template, just trigger onChange to load
    // subdivisions
    countryField.change();

    if (!noGoogleInit) {
      Fulfil.address.googlePlaceInitForm(formElm);
    }
  };

  Fulfil.address.initForm = function (selector, noGoogleInit) {
    $(selector).each(function () {
      Fulfil.address._initForm($(this));
    });
  };

  Fulfil.address.updateAddress = function (addressId, addressFormData) {
    var action_url = "/my/addresses/" + addressId + "/edit";
    return $.post(action_url, addressFormData);
  };

  /**
   * Helper method to convert google place to address object
   */
  Fulfil.address.googlePlaceToAddress = function (place) {
    var parsedPlaceObj = {};
    // place to object
    $.each(place.address_components, function (i, elm) {
      $.each(elm.types, function (i, type) {
        parsedPlaceObj[type] = {
          long_name: elm.long_name,
          short_name: elm.short_name,
        };
      });
    });

    var addressData = {};
    addressData.street = [
      parsedPlaceObj.street_number.long_name,
      parsedPlaceObj.route.long_name,
    ].join(', ');
    addressData.city = parsedPlaceObj.locality.long_name;
    addressData.subdivision =
      parsedPlaceObj.administrative_area_level_1.short_name;
    addressData.country = parsedPlaceObj.country.short_name;
    addressData.zip = parsedPlaceObj.postal_code.long_name;

    return addressData;
  };

  Fulfil.address.googlePlaceInitForm = function (formElm) {
    var inputElm = formElm.find('input[name="street"]');
    var autocomplete = new google.maps.places.Autocomplete(inputElm[0], {
      types: ['geocode']
    });
    autocomplete.addListener('place_changed', function () {
      var addressData =
        Fulfil.address.googlePlaceToAddress(autocomplete.getPlace());
      $.each(addressData, function (fname, value) {
        if (fname == 'subdivision') {
          formElm.find('[name="' + fname + '"]').val(value)
            .data('value', value);
        }
        else {
          formElm.find('[name="' + fname + '"]').val(value).change();
        }
      });
    });
  };

  /*
   *
   * User related logic
   * ==================
   *
   */

  window.Fulfil = Fulfil;
});
<commit_msg>Process smarty street address validation response<commit_after>$(function () {
  var Fulfil = {
    csrfToken: "{{ csrf_token() }}",
    urls: {},
    form: {},
    cart: {"stripe": {}},
    user: {},
    ux: {},
    product: {},
    address: {}
  };

  // All the URLs this file needs to know
  Fulfil.urls.view_cart = "{{ url_for('cart.view_cart') }}";
  Fulfil.urls.remove_from_cart = "{{ url_for('cart.remove_from_cart') }}";
  Fulfil.urls.getVariations = "{{ url_for('products.get_variations') }}";
  Fulfil.urls.payUsingProfile = "{{ url_for('checkout.payment') }}";
  Fulfil.urls.setBillingAddress = "{{ url_for('checkout.billing_address') }}";

  /**
   * Helper method to change formSubmission to ajax
   *
   * @param formElement HTMLElement
   * @param options Object with successCallback, errorCallback,
   *                alwaysCallback, onSubmit as keys
   */
  Fulfil.form.ajaxSubmit = function (formElement, options) {
    var form = $(formElement);

    options = options || {}

    form.on('submit', function (event) {
      event.preventDefault();

      // Call onSubmit if function
      if ($.isFunction(options.onSubmit)) {
        options.onSubmit(event);
      }

      $.ajax({
        'url': form.attr("action"),
        'type': form.attr('method') || 'GET',
        'data': form.serialize(),
        'dataType': "json"
      })
        .done(options.successCallback)
        .fail(options.errorCallback)
        .always(options.alwaysCallback);
    });
  };

  /**
   * Method to show errors in form
   */
  Fulfil.form.showErrors = function (formElement, errorsObj) {
    var form = $(formElement);

    $.each(errorsObj, function (key, value) {
      // TODO: show errors
    });
  };

  /**
   * Helper method to initialize login form
   */
  Fulfil.form.initLoginForm =  function (formElement) {
    var errorContainer = formElement.find('.error-message');

    // by default hide error container
    errorContainer.html('').hide();

    var options = {
      onSubmit: function () {
        errorContainer.html('').hide();
      },
      successCallback: function (result) {
        location.reload();
      },
      errorCallback: function (error) {
        if (error.status == 400) {
          if (!error.responseJSON.errors) {
            console.error("No 'errors' in response on bad request.");
          }

          var errors = [];
          $.each(error.responseJSON.errors, function (key, value) {
            errors = errors.concat(value);
          });

          // Show errors in error container
          errorContainer.html(errors.join(',')).show();
          return;
        }
        console.log(error.statusText);
      }
    };

    Fulfil.form.ajaxSubmit(formElement, options);
  };

  /*
   *
   * Cart related logic
   * ==================
   *
   */

   /*
    * Refreshes the cart and updates Fulfil.cart.current_cart
    * Also returns the request promise.
    *
    */
   Fulfil.cart.refresh = function() {
    console.debug("Refreshing Cart");
    return $.ajax({
      cache: false,
      url: Fulfil.urls.view_cart,
      dataType: "json",
      success: function(data){
        Fulfil.cart.current_cart = data.cart;
      }
    })
   };

   /*
    * Delete a item from the cart.
    *
    */
   Fulfil.cart.deleteItem = function(lineId) {
    console.debug("Removing Line from Cart");
    return $.ajax({
      url: Fulfil.urls.remove_from_cart,
      method: "POST",
      data: {
        "line_id": lineId,
        "csrf_token": Fulfil.csrfToken
       },
       dataType: "json",
       success: function() {
         Fulfil.cart.refresh();
       }
    });
   }

  /*
   *
   * Product related logic
   * =====================
   *
   */

  /*
   *
   * Fetch variation data for a product template
   *
   */
  Fulfil.product.getVariations = function(templateId) {
    return $.ajax({
      url: Fulfil.urls.getVariations,
      method: "GET",
      data: {
        "template": templateId
       },
       dataType: "json",
       success: function(data) {
         Fulfil.product.loadVariations(data);
       }
    });
  };

  /*
   * Load the variation data locally to serve more
   * requests.
   */
  Fulfil.product.loadVariations = function(variationData) {
    Fulfil.product.variationData = variationData;
  };

  /*
   * Given a set of attributes, return a variant
   * that fits the attributes
   *
   */
  Fulfil.product.findMatchingVariant = function(attributeSelection) {
    return _.find(Fulfil.product.variationData['variants'], function(variant) {
      return _.isEqual(variant.attributes, attributeSelection)
    });
  };

  /*
   * Return the data of the variant with id
   *
   */
  Fulfil.product.getVariant = function(variantId) {
    return _.find(Fulfil.product.variationData['variants'], function(variant) {
      return (variant.id == variantId) ;
    });
  };

  /*
   *
   * Address related logic
   * =====================
   *
   */

  /*
   * Return list of all available countries
   */
  Fulfil.address.getCountries = function() {
    return $.getJSON('{{ url_for("public.get_countries") }}');
  };

  /*
   * Helper method to fill country options in select field
   */
  Fulfil.address.fillCountriesOpts = function(selectField, currentValue) {
    selectField.html('');
    return Fulfil.address.getCountries()
      .success(function (data) {
        var optionsHtml = '';
        $.each(data.result, function(i, country){
          optionsHtml +=
            '<option value="'+ country.code +'">' + country.name + '</option>';
        });
        selectField.html(optionsHtml);

        if (currentValue) {
          $(selectField).val(currentValue).change();
        }
      });
  };

  /*
   * Return a list of all addresses of the user
   */
   Fulfil.address.getAddresses = function() {
     return $.getJSON(
       '{{ url_for("user.addresses") }}',
       {csrf_token: Fulfil.csrfToken}
     );
   };

   /*
   * Create a stripe token using card data and address
   */
   Fulfil.cart.stripe.createToken = function(card, address, callback) {
     if (typeof Stripe === 'undefined') {
       console.debug("Stripe.js is not added");
       return;
     }
     Stripe.setPublishableKey("{{ current_channel.payment_gateway.stripe_publishable_key }}");
     Stripe.card.createToken({
       'number': card.number,
       'cvc': card.cvc,
       'exp_month': card.exp_month,
       'exp_year': card.exp_year,
       'name': card.name,
       'address_zip': address.zip,
       'address_line1': address.street,
       'address_line2': address.streetbis,
       'address_city': address.city,
       'address_state': address.subdivision,
       'address_country': address.country
     }, callback);
   };

   /*
   * Pay using stripe payment profile or token
   */
   Fulfil.cart.payUsingProfile = function(profile, amount) {
    return $.ajax({
      url: Fulfil.urls.payUsingProfile,
      method: "POST",
      data: {
        "payment_profile_id": profile.payment_profile_id,
        "stripe_token": profile.stripe_token,
        "amount": amount,
        "csrf_token": Fulfil.csrfToken
       },
       dataType: "json"
    });
   };

   /*
   * Set billing address
   */
   Fulfil.cart.setBillingAddress = function(address) {
    return $.ajax({
      url: Fulfil.urls.setBillingAddress,
      method: "POST",
      data: {
        "billing_address": address.billing_address,
        "name": address.name,
        "street": address.street,
        "streetbis": address.streetbis,
        "city": address.city,
        "zip": address.zip,
        "country": address.country,
        "subdivision": address.subdivision,
        "csrf_token": Fulfil.csrfToken
       },
       dataType: "json"
    });
   };

   Fulfil.ux.notify = function(message, level, title) {
      if (!level) {
        level = 'info'
      };
      if (toastr) {
        toastr[level](message, title);
      }
   }

  /**
   * Helper method to validate an address
   */
  Fulfil.address.validateAddress = function (addressId) {
    var formData = {
      'address_id': addressId,
      'csrf_token': Fulfil.csrfToken,
    };
    return $.post('{{ url_for("validate_address") }}', formData)
      .success(function (result) {
        var res = {};
        switch(result.validation_result.dpv_match_code) {
          case 'Y':
            // Confirmed; entire address was DPV confirmed deliverable.
            res.state = 'valid';
            res.message = 'Address good for delivery.';
            break;
          case 'N':
            // Not Confirmed; address could not be DPV confirmed as deliverable.
            res.state = 'invalid';
            res.message = 'Invalid address';
            break;
          case 'S':
          case 'D':
            // S - Confirmed By Dropping Secondary; address was DPV confirmed by
            // dropping secondary info (apartment, suite, etc.).
            // D — Confirmed - Missing Secondary Info; the address was DPV
            // confirmed, but it is missing secondary information
            // (apartment, suite, etc.).
            res.state = 'invalid';
            res.message = 'Appartment/Suite information is missing or invalid';
            break;
          default:
            // The address was not submitted for DPV. This is usually because
            // the address does not have a ZIP Code and a +4 add-on code, or
            // the address has already been determined to be Not Deliverable
            // (only returned as part of the XML response).
            res.state = 'invalid';
            res.message = 'Invalid Address';
            break;
        }
        result.processed_validation_status = res;
      });
  };

  /**
   * Helper method to init form with countries
   */
  Fulfil.address._initForm = function (formElm, noGoogleInit) {
    var countryField = formElm.find('select[name="country"]');
    var subdivisionField = formElm.find('select[name="subdivision"]');

    // On change of country
    countryField.change(function () {
      // Clear options as soon as country change
      subdivisionField.empty();

      var reqUrl = "/countries/" + $(this).val() +"/subdivisions";
      $.getJSON(reqUrl, function(data){
        $.each(data.result, function(_, subdivision) {
          subdivisionField
            .append($("<option></option>")
              .attr("value", subdivision.code)
              .attr("code", subdivision.code)
              .text(subdivision.name));
        });
        if (subdivisionField.data('value')) {
          // If data-value set that as field value and clear.
          // This is helpful in setting value of subdivision without waiting
          // for subdivison options to load.
          subdivisionField.val(subdivisionField.data('value'));
          subdivisionField.data('value', null);
        }
        subdivisionField.triggerHandler("change");
      });
    });

    // Countries are loaded by jinja template, just trigger onChange to load
    // subdivisions
    countryField.change();

    if (!noGoogleInit) {
      Fulfil.address.googlePlaceInitForm(formElm);
    }
  };

  Fulfil.address.initForm = function (selector, noGoogleInit) {
    $(selector).each(function () {
      Fulfil.address._initForm($(this));
    });
  };

  Fulfil.address.updateAddress = function (addressId, addressFormData) {
    var action_url = "/my/addresses/" + addressId + "/edit";
    return $.post(action_url, addressFormData);
  };

  /**
   * Helper method to convert google place to address object
   */
  Fulfil.address.googlePlaceToAddress = function (place) {
    var parsedPlaceObj = {};
    // place to object
    $.each(place.address_components, function (i, elm) {
      $.each(elm.types, function (i, type) {
        parsedPlaceObj[type] = {
          long_name: elm.long_name,
          short_name: elm.short_name,
        };
      });
    });

    var addressData = {};
    addressData.street = [
      parsedPlaceObj.street_number.long_name,
      parsedPlaceObj.route.long_name,
    ].join(', ');
    addressData.city = parsedPlaceObj.locality.long_name;
    addressData.subdivision =
      parsedPlaceObj.administrative_area_level_1.short_name;
    addressData.country = parsedPlaceObj.country.short_name;
    addressData.zip = parsedPlaceObj.postal_code.long_name;

    return addressData;
  };

  Fulfil.address.googlePlaceInitForm = function (formElm) {
    var inputElm = formElm.find('input[name="street"]');
    var autocomplete = new google.maps.places.Autocomplete(inputElm[0], {
      types: ['geocode']
    });
    autocomplete.addListener('place_changed', function () {
      var addressData =
        Fulfil.address.googlePlaceToAddress(autocomplete.getPlace());
      $.each(addressData, function (fname, value) {
        if (fname == 'subdivision') {
          formElm.find('[name="' + fname + '"]').val(value)
            .data('value', value);
        }
        else {
          formElm.find('[name="' + fname + '"]').val(value).change();
        }
      });
    });
  };

  /*
   *
   * User related logic
   * ==================
   *
   */

  window.Fulfil = Fulfil;
});
<|endoftext|>


<commit_before>(function(addon) {

    if (typeof define == "function" && define.amd) { // AMD
        define("uikit-markdownarea", ["uikit"], function(){
            return jQuery.UIkit.markdownarea ? jQuery.UIkit.markdownarea : addon(window, window.jQuery, window.jQuery.UIkit);
        });
    }

    if(window && window.jQuery && window.jQuery.UIkit) {
        addon(window, window.jQuery, window.jQuery.UIkit);
    }

})(function(global, $, UI){

    var Markdownarea = function(element, options){

        var $element = $(element);

        if($element.data("markdownarea")) return;

        this.element = $element;
        this.options = $.extend({}, Markdownarea.defaults, options);

        this.marked     = this.options.marked || marked;
        this.CodeMirror = this.options.CodeMirror || CodeMirror;

        this.marked.setOptions({
          gfm: true,
          tables: true,
          breaks: true,
          pedantic: false,
          sanitize: false,
          smartLists: true,
          smartypants: false,
          langPrefix: 'lang-'
        });

        this.init();

        this.element.data("markdownarea", this);
    };

    $.extend(Markdownarea.prototype, {

        init: function(){

            var $this = this, tpl = Markdownarea.template;

            tpl = tpl.replace(/\{\:lblPreview\}/g, this.options.lblPreview);
            tpl = tpl.replace(/\{\:lblCodeview\}/g, this.options.lblCodeview);

            this.markdownarea = $(tpl);
            this.content      = this.markdownarea.find(".uk-markdownarea-content");
            this.toolbar      = this.markdownarea.find(".uk-markdownarea-toolbar");
            this.preview      = this.markdownarea.find(".uk-markdownarea-preview").children().eq(0);
            this.code         = this.markdownarea.find(".uk-markdownarea-code");

            this.element.before(this.markdownarea).appendTo(this.code);

            this.editor = this.CodeMirror.fromTextArea(this.element[0], this.options.codemirror);

            this.editor.markdownarea = this;

            this.editor.on("change", (function(){
                var render = function(){

                    var value   = $this.editor.getValue();

                    $this.currentvalue  = String(value);

                    $this.element.trigger("markdownarea-before", [$this]);

                    $this.applyPlugins();

                    $this.marked($this.currentvalue, function (err, markdown) {

                      if (err) throw err;

                      $this.preview.html(markdown);
                      $this.element.val($this.currentvalue).trigger("markdownarea-update", [$this]);
                    });
                };
                render();
                return UI.Utils.debounce(render, 150);
            })());

            this.code.find(".CodeMirror").css("height", this.options.height);

            this._buildtoolbar();
            this.fit();

            $(window).on("resize", UI.Utils.debounce(function(){
                $this.fit();
            }, 200));

            var previewContainer = $this.preview.parent(),
                codeContent      = this.code.find('.CodeMirror-sizer'),
                codeScroll       = this.code.find('.CodeMirror-scroll').on('scroll',UI.Utils.debounce(function() {

                    if($this.markdownarea.attr("data-mode")=="tab") return;

                    // calc position
                    var codeHeight       = codeContent.height()   - codeScroll.height(),
                        previewHeight    = previewContainer[0].scrollHeight - previewContainer.height(),
                        ratio            = previewHeight / codeHeight,
                        previewPostition = codeScroll.scrollTop() * ratio;

                    // apply new scroll
                    previewContainer.scrollTop(previewPostition);
            }, 10));

            this.markdownarea.on("click", ".uk-markdown-button-markdown, .uk-markdown-button-preview", function(e){

                e.preventDefault();

                if($this.markdownarea.attr("data-mode")=="tab") {

                    $this.markdownarea.find(".uk-markdown-button-markdown, .uk-markdown-button-preview").removeClass("uk-active").filter(this).addClass("uk-active");

                    $this.activetab = $(this).hasClass("uk-markdown-button-markdown") ? "code":"preview";
                    $this.markdownarea.attr("data-active-tab", $this.activetab);
                }
            });

            this.preview.parent().css("height", this.code.height());
        },

        applyPlugins: function(){

            var $this   = this,
                plugins = Object.keys(Markdownarea.plugins),
                plgs    = Markdownarea.plugins;

            this.markers = {};

            if(plugins.length) {

                var lines = this.currentvalue.split("\n");

                plugins.forEach(function(name){
                    this.markers[name] = [];
                }, this);

                for(var line=0,max=lines.length;line<max;line++) {

                    (function(line){
                        plugins.forEach(function(name){

                            var i = 0;

                            lines[line] = lines[line].replace(plgs[name].identifier, function(){

                                var replacement =  plgs[name].cb({
                                    "area" : $this,
                                    "found": arguments,
                                    "line" : line,
                                    "pos"  : i++,
                                    "uid"  : [name, line, i, (new Date().getTime())+"RAND"+(Math.ceil(Math.random() *100000))].join('-'),
                                    "replace": function(strwith){
                                        var src   = this.area.editor.getLine(this.line),
                                            start = src.indexOf(this.found[0]);
                                            end   = this.found[0].length;

                                        this.area.editor.replaceRange(strwith, {"line": this.line, "ch":start}, {"line": this.line, "ch":end} );
                                    }
                                });

                                return replacement;
                            });
                        });
                    })(line);
                }

                this.currentvalue = lines.join("\n");

            }
        },

        _buildtoolbar: function(){

            if(!(this.options.toolbar && this.options.toolbar.length)) return;

            var $this = this, bar = [];

            this.options.toolbar.forEach(function(cmd){
                if(Markdownarea.commands[cmd]) {

                   var title = Markdownarea.commands[cmd].title ? Markdownarea.commands[cmd].title : cmd;

                   bar.push('
'+Markdownarea.commands[cmd].label+'
');

                   if(Markdownarea.commands[cmd].shortcut) {
                       $this.registerShortcut(Markdownarea.commands[cmd].shortcut, Markdownarea.commands[cmd].action);
                   }
                }
            });

            this.toolbar.html(bar.join("\n"));

            this.markdownarea.on("click", "a[data-markdownarea-cmd]", function(){
                var cmd = $(this).data("markdownareaCmd");

                if(cmd && Markdownarea.commands[cmd] && (!$this.activetab || $this.activetab=="code" || cmd=="fullscreen")) {
                    Markdownarea.commands[cmd].action.apply($this, [$this.editor])
                }

            });
        },

        fit: function() {

            var mode = this.options.mode;

            if(mode=="split" && this.markdownarea.width() < this.options.maxsplitsize) {
                mode = "tab";
            }

            if(mode=="tab") {

                if(!this.activetab) {
                    this.activetab = "code";
                    this.markdownarea.attr("data-active-tab", this.activetab);
                }

                this.markdownarea.find(".uk-markdown-button-markdown, .uk-markdown-button-preview").removeClass("uk-active")
                                 .filter(this.activetab=="code" ? '.uk-markdown-button-markdown':'.uk-markdown-button-preview').addClass("uk-active");

            }

            this.editor.refresh();
            this.preview.parent().css("height", this.code.height());

            this.markdownarea.attr("data-mode", mode);
        },

        registerShortcut: function(combination, callback){

            var $this = this;

            combination = $.isArray(combination) ? combination : [combination];

            for(var i=0,max=combination.length;i < max;i++) {
                var map = {};

                map[combination[i]] = function(){
                    callback.apply($this, [$this.editor]);
                };

                $this.editor.addKeyMap(map);
            }
        }
    });

    //jQuery plugin

    $.fn.markdownarea = function(options){

        return this.each(function(){

            var ele = $(this);

            if(!ele.data("markdownarea")) {
                var obj = new Markdownarea(ele, options);
            }
        });
    };

    var baseReplacer = function(replace, editor){
        var text     = editor.getSelection(),
            markdown = replace.replace('$1', text);

        editor.replaceSelection(markdown, 'end');
    };

    Markdownarea.commands = {
        "fullscreen": {
            "title"  : 'Fullscreen',
            "label"  : '',
            "action" : function(editor){

                editor.markdownarea.markdownarea.toggleClass("uk-markdownarea-fullscreen");

                var wrap = editor.getWrapperElement();

                if(editor.markdownarea.markdownarea.hasClass("uk-markdownarea-fullscreen")) {

                    editor.state.fullScreenRestore = {scrollTop: window.pageYOffset, scrollLeft: window.pageXOffset, width: wrap.style.width, height: wrap.style.height};
                    wrap.style.width  = "";
                    wrap.style.height = editor.markdownarea.content.height()+"px";
                    document.documentElement.style.overflow = "hidden";

                } else {

                    document.documentElement.style.overflow = "";
                    var info = editor.state.fullScreenRestore;
                    wrap.style.width = info.width; wrap.style.height = info.height;
                    window.scrollTo(info.scrollLeft, info.scrollTop);
                }

                editor.refresh();
                editor.markdownarea.preview.parent().css("height", editor.markdownarea.code.height());
            }
        },

        "bold" : {
            "title"  : "Bold",
            "label"  : '',
            "shortcut": ['Ctrl-B', 'Cmd-B'],
            "action" : function(editor){

                baseReplacer("**$1**", editor);
            }
        },
        "italic" : {
            "title"  : "Italic",
            "label"  : '',
            "action" : function(editor){
                baseReplacer("*$1*", editor);
            }
        },
        "strike" : {
            "title"  : "Strikethrough",
            "label"  : '',
            "action" : function(editor){
                baseReplacer("~~$1~~", editor);
            }
        },
        "blockquote" : {
            "title"  : "Blockquote",
            "label"  : '',
            "action" : function(editor){
                baseReplacer("> $1", editor);
            }
        },
        "link" : {
            "title"  : "Link",
            "label"  : '',
            "action" : function(editor){
                baseReplacer("[$1](http://)", editor);
            }
        },
        "picture" : {
            "title"  : "Picture",
            "label"  : '',
            "action" : function(editor){
                baseReplacer("![$1](http://)", editor);
            }
        },
        "listUl" : {
            "title"  : "Unordered List",
            "label"  : '',
            "action" : function(editor){
                baseReplacer("* $1", editor);
            }
        },
        "listOl" : {
            "title"  : "Ordered List",
            "label"  : '',
            "action" : function(editor){
                baseReplacer("1. $1", editor);
            }
        }
    }

    Markdownarea.defaults = {
        "mode"         : "split",
        "height"       : 500,
        "maxsplitsize" : 1000,
        "codemirror"   : { mode: 'gfm', tabMode: 'indent', tabindex: "2", lineWrapping: true, dragDrop: false },
        "toolbar"      : [ "bold", "italic", "strike", "link", "picture", "blockquote", "listUl", "listOl" ],
        "lblPreview"   : "Preview",
        "lblCodeview"  : "Markdown"
    };

    Markdownarea.template = '
' +
                                '
' +
                                    '

' +
                                    '
' +
                                        '
' +
                                            '
{:lblCodeview}
' +
                                            '
{:lblPreview}
' +
                                            '

' +
                                        '
' +
                                    '
' +
                                '
' +
                                '
' +
                                    '

' +
                                    '

' +
                                '
' +
                            '
';

    Markdownarea.plugins   = {};
    Markdownarea.addPlugin = function(name, identifier, callback) {
        Markdownarea.plugins[name] = {"identifier":identifier, "cb":callback};
    };

    UI["markdownarea"] = Markdownarea;

    // init code
    $(function() {

        $("textarea[data-uk-markdownarea]").each(function() {
            var area = $(this), obj;

            if (!area.data("markdownarea")) {
                obj = new Markdownarea(area, UI.Utils.options(area.attr("data-uk-markdownarea")));
            }
        });
    });

    return Markdownarea;
});<commit_msg>markdown area restore issue fixed<commit_after>(function(addon) {

    if (typeof define == "function" && define.amd) { // AMD
        define("uikit-markdownarea", ["uikit"], function(){
            return jQuery.UIkit.markdownarea ? jQuery.UIkit.markdownarea : addon(window, window.jQuery, window.jQuery.UIkit);
        });
    }

    if(window && window.jQuery && window.jQuery.UIkit) {
        addon(window, window.jQuery, window.jQuery.UIkit);
    }

})(function(global, $, UI){

    var Markdownarea = function(element, options){

        var $element = $(element);

        if($element.data("markdownarea")) return;

        this.element = $element;
        this.options = $.extend({}, Markdownarea.defaults, options);

        this.marked     = this.options.marked || marked;
        this.CodeMirror = this.options.CodeMirror || CodeMirror;

        this.marked.setOptions({
          gfm: true,
          tables: true,
          breaks: true,
          pedantic: false,
          sanitize: false,
          smartLists: true,
          smartypants: false,
          langPrefix: 'lang-'
        });

        this.init();

        this.element.data("markdownarea", this);
    };

    $.extend(Markdownarea.prototype, {

        init: function(){

            var $this = this, tpl = Markdownarea.template;

            tpl = tpl.replace(/\{\:lblPreview\}/g, this.options.lblPreview);
            tpl = tpl.replace(/\{\:lblCodeview\}/g, this.options.lblCodeview);

            this.markdownarea = $(tpl);
            this.content      = this.markdownarea.find(".uk-markdownarea-content");
            this.toolbar      = this.markdownarea.find(".uk-markdownarea-toolbar");
            this.preview      = this.markdownarea.find(".uk-markdownarea-preview").children().eq(0);
            this.code         = this.markdownarea.find(".uk-markdownarea-code");

            this.element.before(this.markdownarea).appendTo(this.code);

            this.editor = this.CodeMirror.fromTextArea(this.element[0], this.options.codemirror);

            this.editor.markdownarea = this;

            this.editor.on("change", (function(){
                var render = function(){

                    var value   = $this.editor.getValue();

                    $this.currentvalue  = String(value);

                    $this.element.trigger("markdownarea-before", [$this]);

                    $this.applyPlugins();

                    $this.marked($this.currentvalue, function (err, markdown) {

                      if (err) throw err;

                      $this.preview.html(markdown);
                      $this.element.val($this.editor.getValue()).trigger("markdownarea-update", [$this]);
                    });
                };
                render();
                return UI.Utils.debounce(render, 150);
            })());

            this.code.find(".CodeMirror").css("height", this.options.height);

            this._buildtoolbar();
            this.fit();

            $(window).on("resize", UI.Utils.debounce(function(){
                $this.fit();
            }, 200));

            var previewContainer = $this.preview.parent(),
                codeContent      = this.code.find('.CodeMirror-sizer'),
                codeScroll       = this.code.find('.CodeMirror-scroll').on('scroll',UI.Utils.debounce(function() {

                    if($this.markdownarea.attr("data-mode")=="tab") return;

                    // calc position
                    var codeHeight       = codeContent.height()   - codeScroll.height(),
                        previewHeight    = previewContainer[0].scrollHeight - previewContainer.height(),
                        ratio            = previewHeight / codeHeight,
                        previewPostition = codeScroll.scrollTop() * ratio;

                    // apply new scroll
                    previewContainer.scrollTop(previewPostition);
            }, 10));

            this.markdownarea.on("click", ".uk-markdown-button-markdown, .uk-markdown-button-preview", function(e){

                e.preventDefault();

                if($this.markdownarea.attr("data-mode")=="tab") {

                    $this.markdownarea.find(".uk-markdown-button-markdown, .uk-markdown-button-preview").removeClass("uk-active").filter(this).addClass("uk-active");

                    $this.activetab = $(this).hasClass("uk-markdown-button-markdown") ? "code":"preview";
                    $this.markdownarea.attr("data-active-tab", $this.activetab);
                }
            });

            this.preview.parent().css("height", this.code.height());
        },

        applyPlugins: function(){

            var $this   = this,
                plugins = Object.keys(Markdownarea.plugins),
                plgs    = Markdownarea.plugins;

            this.markers = {};

            if(plugins.length) {

                var lines = this.currentvalue.split("\n");

                plugins.forEach(function(name){
                    this.markers[name] = [];
                }, this);

                for(var line=0,max=lines.length;line<max;line++) {

                    (function(line){
                        plugins.forEach(function(name){

                            var i = 0;

                            lines[line] = lines[line].replace(plgs[name].identifier, function(){

                                var replacement =  plgs[name].cb({
                                    "area" : $this,
                                    "found": arguments,
                                    "line" : line,
                                    "pos"  : i++,
                                    "uid"  : [name, line, i, (new Date().getTime())+"RAND"+(Math.ceil(Math.random() *100000))].join('-'),
                                    "replace": function(strwith){
                                        var src   = this.area.editor.getLine(this.line),
                                            start = src.indexOf(this.found[0]);
                                            end   = this.found[0].length;

                                        this.area.editor.replaceRange(strwith, {"line": this.line, "ch":start}, {"line": this.line, "ch":end} );
                                    }
                                });

                                return replacement;
                            });
                        });
                    })(line);
                }

                this.currentvalue = lines.join("\n");

            }
        },

        _buildtoolbar: function(){

            if(!(this.options.toolbar && this.options.toolbar.length)) return;

            var $this = this, bar = [];

            this.options.toolbar.forEach(function(cmd){
                if(Markdownarea.commands[cmd]) {

                   var title = Markdownarea.commands[cmd].title ? Markdownarea.commands[cmd].title : cmd;

                   bar.push('
'+Markdownarea.commands[cmd].label+'
');

                   if(Markdownarea.commands[cmd].shortcut) {
                       $this.registerShortcut(Markdownarea.commands[cmd].shortcut, Markdownarea.commands[cmd].action);
                   }
                }
            });

            this.toolbar.html(bar.join("\n"));

            this.markdownarea.on("click", "a[data-markdownarea-cmd]", function(){
                var cmd = $(this).data("markdownareaCmd");

                if(cmd && Markdownarea.commands[cmd] && (!$this.activetab || $this.activetab=="code" || cmd=="fullscreen")) {
                    Markdownarea.commands[cmd].action.apply($this, [$this.editor])
                }

            });
        },

        fit: function() {

            var mode = this.options.mode;

            if(mode=="split" && this.markdownarea.width() < this.options.maxsplitsize) {
                mode = "tab";
            }

            if(mode=="tab") {

                if(!this.activetab) {
                    this.activetab = "code";
                    this.markdownarea.attr("data-active-tab", this.activetab);
                }

                this.markdownarea.find(".uk-markdown-button-markdown, .uk-markdown-button-preview").removeClass("uk-active")
                                 .filter(this.activetab=="code" ? '.uk-markdown-button-markdown':'.uk-markdown-button-preview').addClass("uk-active");

            }

            this.editor.refresh();
            this.preview.parent().css("height", this.code.height());

            this.markdownarea.attr("data-mode", mode);
        },

        registerShortcut: function(combination, callback){

            var $this = this;

            combination = $.isArray(combination) ? combination : [combination];

            for(var i=0,max=combination.length;i < max;i++) {
                var map = {};

                map[combination[i]] = function(){
                    callback.apply($this, [$this.editor]);
                };

                $this.editor.addKeyMap(map);
            }
        }
    });

    //jQuery plugin

    $.fn.markdownarea = function(options){

        return this.each(function(){

            var ele = $(this);

            if(!ele.data("markdownarea")) {
                var obj = new Markdownarea(ele, options);
            }
        });
    };

    var baseReplacer = function(replace, editor){
        var text     = editor.getSelection(),
            markdown = replace.replace('$1', text);

        editor.replaceSelection(markdown, 'end');
    };

    Markdownarea.commands = {
        "fullscreen": {
            "title"  : 'Fullscreen',
            "label"  : '',
            "action" : function(editor){

                editor.markdownarea.markdownarea.toggleClass("uk-markdownarea-fullscreen");

                var wrap = editor.getWrapperElement();

                if(editor.markdownarea.markdownarea.hasClass("uk-markdownarea-fullscreen")) {

                    editor.state.fullScreenRestore = {scrollTop: window.pageYOffset, scrollLeft: window.pageXOffset, width: wrap.style.width, height: wrap.style.height};
                    wrap.style.width  = "";
                    wrap.style.height = editor.markdownarea.content.height()+"px";
                    document.documentElement.style.overflow = "hidden";

                } else {

                    document.documentElement.style.overflow = "";
                    var info = editor.state.fullScreenRestore;
                    wrap.style.width = info.width; wrap.style.height = info.height;
                    window.scrollTo(info.scrollLeft, info.scrollTop);
                }

                editor.refresh();
                editor.markdownarea.preview.parent().css("height", editor.markdownarea.code.height());
            }
        },

        "bold" : {
            "title"  : "Bold",
            "label"  : '',
            "shortcut": ['Ctrl-B', 'Cmd-B'],
            "action" : function(editor){

                baseReplacer("**$1**", editor);
            }
        },
        "italic" : {
            "title"  : "Italic",
            "label"  : '',
            "action" : function(editor){
                baseReplacer("*$1*", editor);
            }
        },
        "strike" : {
            "title"  : "Strikethrough",
            "label"  : '',
            "action" : function(editor){
                baseReplacer("~~$1~~", editor);
            }
        },
        "blockquote" : {
            "title"  : "Blockquote",
            "label"  : '',
            "action" : function(editor){
                baseReplacer("> $1", editor);
            }
        },
        "link" : {
            "title"  : "Link",
            "label"  : '',
            "action" : function(editor){
                baseReplacer("[$1](http://)", editor);
            }
        },
        "picture" : {
            "title"  : "Picture",
            "label"  : '',
            "action" : function(editor){
                baseReplacer("![$1](http://)", editor);
            }
        },
        "listUl" : {
            "title"  : "Unordered List",
            "label"  : '',
            "action" : function(editor){
                baseReplacer("* $1", editor);
            }
        },
        "listOl" : {
            "title"  : "Ordered List",
            "label"  : '',
            "action" : function(editor){
                baseReplacer("1. $1", editor);
            }
        }
    }

    Markdownarea.defaults = {
        "mode"         : "split",
        "height"       : 500,
        "maxsplitsize" : 1000,
        "codemirror"   : { mode: 'gfm', tabMode: 'indent', tabindex: "2", lineWrapping: true, dragDrop: false },
        "toolbar"      : [ "bold", "italic", "strike", "link", "picture", "blockquote", "listUl", "listOl" ],
        "lblPreview"   : "Preview",
        "lblCodeview"  : "Markdown"
    };

    Markdownarea.template = '
' +
                                '
' +
                                    '

' +
                                    '
' +
                                        '
' +
                                            '
{:lblCodeview}
' +
                                            '
{:lblPreview}
' +
                                            '

' +
                                        '
' +
                                    '
' +
                                '
' +
                                '
' +
                                    '

' +
                                    '

' +
                                '
' +
                            '
';

    Markdownarea.plugins   = {};
    Markdownarea.addPlugin = function(name, identifier, callback) {
        Markdownarea.plugins[name] = {"identifier":identifier, "cb":callback};
    };

    UI["markdownarea"] = Markdownarea;

    // init code
    $(function() {

        $("textarea[data-uk-markdownarea]").each(function() {
            var area = $(this), obj;

            if (!area.data("markdownarea")) {
                obj = new Markdownarea(area, UI.Utils.options(area.attr("data-uk-markdownarea")));
            }
        });
    });

    return Markdownarea;
});<|endoftext|>


<commit_before><commit_msg>insector-utils: importConstantsToClass fix<commit_after><|endoftext|>


<commit_before>import $ from 'jquery';
export default class Toolbar {
  constructor(context) {
    this.context = context;

    this.$window = $(window);
    this.$document = $(document);

    this.ui = $.summernote.ui;
    this.$note = context.layoutInfo.note;
    this.$editor = context.layoutInfo.editor;
    this.$toolbar = context.layoutInfo.toolbar;
    this.$editable = context.layoutInfo.editable;
    this.options = context.options;

    this.followScroll = this.followScroll.bind(this);
  }

  shouldInitialize() {
    return !this.options.airMode;
  }

  initialize() {
    this.options.toolbar = this.options.toolbar || [];

    if (!this.options.toolbar.length) {
      this.$toolbar.hide();
    } else {
      this.context.invoke('buttons.build', this.$toolbar, this.options.toolbar);
    }

    if (this.options.toolbarContainer) {
      this.$toolbar.appendTo(this.options.toolbarContainer);
    }

    this.changeContainer(false);

    this.$note.on('summernote.keyup summernote.mouseup summernote.change', () => {
      this.context.invoke('buttons.updateCurrentStyle');
    });

    this.context.invoke('buttons.updateCurrentStyle');
    if (this.options.followingToolbar) {
      this.$window.on('scroll resize', this.followScroll);
    }
  }

  destroy() {
    this.$toolbar.children().remove();

    if (this.options.followingToolbar) {
      this.$window.off('scroll resize', this.followScroll);
    }
  }

  followScroll() {
    if (this.$editor.hasClass('fullscreen')) {
      return false;
    }

    const $toolbarWrapper = this.$toolbar.parent('.note-toolbar-wrapper');
    const editorHeight = this.$editor.outerHeight();
    const editorWidth = this.$editor.width();

    const toolbarHeight = this.$toolbar.height();
    $toolbarWrapper.css({
      height: toolbarHeight,
    });

    // check if the web app is currently using another static bar
    let otherBarHeight = 0;
    if (this.options.otherStaticBar) {
      otherBarHeight = $(this.options.otherStaticBar).outerHeight();
    }

    const currentOffset = this.$document.scrollTop();
    const editorOffsetTop = this.$editor.offset().top;
    const editorOffsetBottom = editorOffsetTop + editorHeight;
    const activateOffset = editorOffsetTop - otherBarHeight;
    const deactivateOffsetBottom = editorOffsetBottom - otherBarHeight - toolbarHeight;

    if ((currentOffset > activateOffset) && (currentOffset < deactivateOffsetBottom)) {
      this.$toolbar.css({
        position: 'fixed',
        top: otherBarHeight,
        width: editorWidth,
        zIndex: 1
      });
      this.$editable.css({
       	paddingTop: this.$toolbar.height() + 10
      });
    } else {
      this.$toolbar.css({
        position: 'relative',
        top: 0,
        width: '100%',
      });
      this.$editable.css({
       	paddingTop: ''
      });
    }
  }

  changeContainer(isFullscreen) {
    if (isFullscreen) {
      this.$toolbar.prependTo(this.$editor);
    } else {
      if (this.options.toolbarContainer) {
        this.$toolbar.appendTo(this.options.toolbarContainer);
      }
    }
  }

  updateFullscreen(isFullscreen) {
    this.ui.toggleBtnActive(this.$toolbar.find('.btn-fullscreen'), isFullscreen);

    this.changeContainer(isFullscreen);
  }

  updateCodeview(isCodeview) {
    this.ui.toggleBtnActive(this.$toolbar.find('.btn-codeview'), isCodeview);
    if (isCodeview) {
      this.deactivate();
    } else {
      this.activate();
    }
  }

  activate(isIncludeCodeview) {
    let $btn = this.$toolbar.find('button');
    if (!isIncludeCodeview) {
      $btn = $btn.not('.btn-codeview');
    }
    this.ui.toggleBtn($btn, true);
  }

  deactivate(isIncludeCodeview) {
    let $btn = this.$toolbar.find('button');
    if (!isIncludeCodeview) {
      $btn = $btn.not('.btn-codeview');
    }
    this.ui.toggleBtn($btn, false);
  }
}
<commit_msg>Fix sitcky toolbar problem while toggling fullscreen<commit_after>import $ from 'jquery';
export default class Toolbar {
  constructor(context) {
    this.context = context;

    this.$window = $(window);
    this.$document = $(document);

    this.ui = $.summernote.ui;
    this.$note = context.layoutInfo.note;
    this.$editor = context.layoutInfo.editor;
    this.$toolbar = context.layoutInfo.toolbar;
    this.$editable = context.layoutInfo.editable;
    this.options = context.options;

    this.followScroll = this.followScroll.bind(this);
  }

  shouldInitialize() {
    return !this.options.airMode;
  }

  initialize() {
    this.options.toolbar = this.options.toolbar || [];

    if (!this.options.toolbar.length) {
      this.$toolbar.hide();
    } else {
      this.context.invoke('buttons.build', this.$toolbar, this.options.toolbar);
    }

    if (this.options.toolbarContainer) {
      this.$toolbar.appendTo(this.options.toolbarContainer);
    }

    this.changeContainer(false);

    this.$note.on('summernote.keyup summernote.mouseup summernote.change', () => {
      this.context.invoke('buttons.updateCurrentStyle');
    });

    this.context.invoke('buttons.updateCurrentStyle');
    if (this.options.followingToolbar) {
      this.$window.on('scroll resize', this.followScroll);
    }
  }

  destroy() {
    this.$toolbar.children().remove();

    if (this.options.followingToolbar) {
      this.$window.off('scroll resize', this.followScroll);
    }
  }

  followScroll() {
    if (this.$editor.hasClass('fullscreen')) {
      return false;
    }

    const $toolbarWrapper = this.$toolbar.parent('.note-toolbar-wrapper');
    const editorHeight = this.$editor.outerHeight();
    const editorWidth = this.$editor.width();

    const toolbarHeight = this.$toolbar.height();
    $toolbarWrapper.css({
      height: toolbarHeight,
    });

    // check if the web app is currently using another static bar
    let otherBarHeight = 0;
    if (this.options.otherStaticBar) {
      otherBarHeight = $(this.options.otherStaticBar).outerHeight();
    }

    const currentOffset = this.$document.scrollTop();
    const editorOffsetTop = this.$editor.offset().top;
    const editorOffsetBottom = editorOffsetTop + editorHeight;
    const activateOffset = editorOffsetTop - otherBarHeight;
    const deactivateOffsetBottom = editorOffsetBottom - otherBarHeight - toolbarHeight;

    if ((currentOffset > activateOffset) && (currentOffset < deactivateOffsetBottom)) {
      this.$toolbar.css({
        position: 'fixed',
        top: otherBarHeight,
        width: editorWidth,
      });
      this.$editable.css({
        marginTop: this.$toolbar.height() + 5,
      });
    } else {
      this.$toolbar.css({
        position: 'relative',
        top: 0,
        width: '100%',
      });
      this.$editable.css({
        marginTop: '',
      });
    }
  }

  changeContainer(isFullscreen) {
    if (isFullscreen) {
      this.$toolbar.prependTo(this.$editor);
    } else {
      if (this.options.toolbarContainer) {
        this.$toolbar.appendTo(this.options.toolbarContainer);
      }
    }
    this.followScroll();
  }

  updateFullscreen(isFullscreen) {
    this.ui.toggleBtnActive(this.$toolbar.find('.btn-fullscreen'), isFullscreen);

    this.changeContainer(isFullscreen);
  }

  updateCodeview(isCodeview) {
    this.ui.toggleBtnActive(this.$toolbar.find('.btn-codeview'), isCodeview);
    if (isCodeview) {
      this.deactivate();
    } else {
      this.activate();
    }
  }

  activate(isIncludeCodeview) {
    let $btn = this.$toolbar.find('button');
    if (!isIncludeCodeview) {
      $btn = $btn.not('.btn-codeview');
    }
    this.ui.toggleBtn($btn, true);
  }

  deactivate(isIncludeCodeview) {
    let $btn = this.$toolbar.find('button');
    if (!isIncludeCodeview) {
      $btn = $btn.not('.btn-codeview');
    }
    this.ui.toggleBtn($btn, false);
  }
}
<|endoftext|>


<commit_before>'use strict';
var _ = require('lodash'),
	log = require('gulp-util').log;

var Configuration = require('./configuration'),
	ConfigurationError = require('./configuration_error'),
	UniqueNames = require('../helpers/unique_names'),
	metadata = require('./metadata');

function ConfigurableTaskFactory(stuff, runnerFactory, registry) {
	this.stuff = stuff;
	this.runnerFactory = runnerFactory;
	this.registry = registry;
}

function buildMetadataTree(task, subTasks) {
	var nodes;

	if (subTasks) {
		nodes = subTasks.map(function (task) {
			var meta = metadata.get(task);
			return meta.tree;
		});
	} else {
		nodes = [];
	}
	metadata.set(task, task.displayName, nodes);
}

ConfigurableTaskFactory.prototype.one = function (prefix, name, rawConfig, parentConfig) {
	var self, stuff, schema, configs, taskInfo, runner, task, subTasks;

	self = this;
	stuff = this.stuff;

	taskInfo = Configuration.getTaskRuntimeInfo(name);

	if (rawConfig.debug) {
		debugger;
	}

	schema = getTaskSchema(taskInfo.name);
	configs = Configuration.sort(taskInfo, rawConfig, parentConfig, schema);

	if (Configuration.isDisabled(configs.taskInfo)) {
		return null;
	}

	runner = this.runnerFactory.create(prefix, configs, createSubTasks);
	if (! runner) {
		log("Warning: can't infer to a proper recipe task: " + taskInfo.name + ': task will do nothing.');
		runner = function (gulp, config, stream, done) { done(); };
	}
	task = this.create(prefix, taskInfo, configs.taskConfig, runner);
	buildMetadataTree(task, subTasks);
	return task;

	function getTaskSchema(name) {
		var configurableTask = stuff.streams.lookup(name) || stuff.recipes.lookup(name);
		return configurableTask && configurableTask.schema;
	}

	function createSubTasks(prefix, subTaskConfigs, parentConfig) {
		subTasks = self.multiple(prefix, subTaskConfigs, parentConfig);
		return subTasks;
	}
};

ConfigurableTaskFactory.prototype.multiple = function (prefix, subTaskConfigs, parentConfig) {
	var self;

	self = this;
	subTaskConfigs = _array() || _object();
	return subTaskConfigs.reduce(function (tasks, config) {
		var task = self.one(prefix, config.name, config, parentConfig);
		if (task) {
			tasks.push(task);
		}
		return tasks;
	}, []);

	function _array() {
		var names;

		if (Array.isArray(subTaskConfigs)) {
			names = new UniqueNames();
			return subTaskConfigs.map(objectify).map(uniquify);
		}

		function objectify(config) {
			if (typeof config === 'string') {
				config = {
					name: config,
					task: config
				};
			} else if (typeof config === 'function') {
				config = {
					name: config.displayName || config.name,
					task: config
				};
			}
			names.put(config.name);
			return config;
		}

		function uniquify(config) {
			config.name = names.get(config.name);
			return config;
		}
	}

	function _object() {
		var orders;

		if (_.isPlainObject(subTaskConfigs)) {
			orders = 0;
			subTaskConfigs = _.map(subTaskConfigs, uniquify);	// NOTE: becomes an array
			return sort(subTaskConfigs);
		}

		function uniquify(config, name) {
			if ('order' in config) {
				++orders;
			}
			config.name = name;
			return config;
		}

		function sort(subTaskConfigs) {
			if (orders !== 0) {
				if (orders !== _.size(subTaskConfigs)) {
					throw new ConfigurationError('ConfigurableTaskFactory', 'some sub-tasks defined "order" some don\'t, don\'t know how to sort');
				}
				subTaskConfigs = subTaskConfigs.sort(comparator);
			}
			return subTaskConfigs;
		}

		function comparator(a, b) {
			if ('order' in a && 'order' in b) {
				return a.order - b.order;
			}
			// try to make it a stable sort even if 'order' property not present.
			return 0;
		}
	}

	function create(tasks, prefix, taskConfig, parentConfig) {
		var task = self.one(prefix, taskConfig.name, taskConfig, parentConfig);
		if (task) {
			tasks.push(task);
		}
		return tasks;
	}
};

ConfigurableTaskFactory.prototype.create = function (prefix, taskInfo, taskConfig, configurableRunner) {
	var registry = this.registry;
	// make sure config is inherited at config time and injected, realized at runtime.
	// invoked from stream processor
	var run = function (gulp, injectConfig, stream, done) {
		// inject and realize runtime configuration.
		var config = Configuration.realize(taskConfig, injectConfig, configurableRunner.defaults);
		return configurableRunner(gulp, config, stream, done);
	};
	// invoked from gulp
	var configurableTask = function (done) {
		// NOTE: gulp 4.0 task are called on undefined context. So we need gulp reference from registry here.
		return run(registry.gulp, taskConfig, null, done);
	};
	var name = (taskInfo.name || configurableRunner.displayName || configurableRunner.name || '<anonymous>');
	configurableTask.displayName = prefix + name;
	configurableTask.description = taskInfo.description || configurableRunner.description || '';
	configurableTask.visibility = taskInfo.visibility;
	configurableTask.runtime = taskInfo.runtime;
	configurableTask.run = run;
	configurableTask.config = taskConfig;
	if (Configuration.isVisible(configurableTask)) {
		this.registry.set(configurableTask.displayName, configurableTask);
		metadata.set(configurableTask, configurableTask.displayName);
	} else {
		metadata.set(configurableTask, '<' + name + '>');
	}
	return configurableTask;
};

module.exports = ConfigurableTaskFactory;
<commit_msg>fix incorrect visibility test that make task not registered<commit_after>'use strict';
var _ = require('lodash'),
	log = require('gulp-util').log;

var Configuration = require('./configuration'),
	ConfigurationError = require('./configuration_error'),
	UniqueNames = require('../helpers/unique_names'),
	metadata = require('./metadata');

function ConfigurableTaskFactory(stuff, runnerFactory, registry) {
	this.stuff = stuff;
	this.runnerFactory = runnerFactory;
	this.registry = registry;
}

function buildMetadataTree(task, subTasks) {
	var nodes;

	if (subTasks) {
		nodes = subTasks.map(function (task) {
			var meta = metadata.get(task);
			return meta.tree;
		});
	} else {
		nodes = [];
	}
	metadata.set(task, task.displayName, nodes);
}

ConfigurableTaskFactory.prototype.one = function (prefix, name, rawConfig, parentConfig) {
	var self, stuff, schema, configs, taskInfo, runner, task, subTasks;

	self = this;
	stuff = this.stuff;

	taskInfo = Configuration.getTaskRuntimeInfo(name);

	if (rawConfig.debug) {
		debugger;
	}

	schema = getTaskSchema(taskInfo.name);
	configs = Configuration.sort(taskInfo, rawConfig, parentConfig, schema);

	if (Configuration.isDisabled(configs.taskInfo)) {
		return null;
	}

	runner = this.runnerFactory.create(prefix, configs, createSubTasks);
	if (! runner) {
		log("Warning: can't infer to a proper recipe task: " + taskInfo.name + ': task will do nothing.');
		runner = function (gulp, config, stream, done) { done(); };
	}
	task = this.create(prefix, taskInfo, configs.taskConfig, runner);
	buildMetadataTree(task, subTasks);
	return task;

	function getTaskSchema(name) {
		var configurableTask = stuff.streams.lookup(name) || stuff.recipes.lookup(name);
		return configurableTask && configurableTask.schema;
	}

	function createSubTasks(prefix, subTaskConfigs, parentConfig) {
		subTasks = self.multiple(prefix, subTaskConfigs, parentConfig);
		return subTasks;
	}
};

ConfigurableTaskFactory.prototype.multiple = function (prefix, subTaskConfigs, parentConfig) {
	var self;

	self = this;
	subTaskConfigs = _array() || _object();
	return subTaskConfigs.reduce(function (tasks, config) {
		var task = self.one(prefix, config.name, config, parentConfig);
		if (task) {
			tasks.push(task);
		}
		return tasks;
	}, []);

	function _array() {
		var names;

		if (Array.isArray(subTaskConfigs)) {
			names = new UniqueNames();
			return subTaskConfigs.map(objectify).map(uniquify);
		}

		function objectify(config) {
			if (typeof config === 'string') {
				config = {
					name: config,
					task: config
				};
			} else if (typeof config === 'function') {
				config = {
					name: config.displayName || config.name,
					task: config
				};
			}
			names.put(config.name);
			return config;
		}

		function uniquify(config) {
			config.name = names.get(config.name);
			return config;
		}
	}

	function _object() {
		var orders;

		if (_.isPlainObject(subTaskConfigs)) {
			orders = 0;
			subTaskConfigs = _.map(subTaskConfigs, uniquify);	// NOTE: becomes an array
			return sort(subTaskConfigs);
		}

		function uniquify(config, name) {
			if ('order' in config) {
				++orders;
			}
			config.name = name;
			return config;
		}

		function sort(subTaskConfigs) {
			if (orders !== 0) {
				if (orders !== _.size(subTaskConfigs)) {
					throw new ConfigurationError('ConfigurableTaskFactory', 'some sub-tasks defined "order" some don\'t, don\'t know how to sort');
				}
				subTaskConfigs = subTaskConfigs.sort(comparator);
			}
			return subTaskConfigs;
		}

		function comparator(a, b) {
			if ('order' in a && 'order' in b) {
				return a.order - b.order;
			}
			// try to make it a stable sort even if 'order' property not present.
			return 0;
		}
	}

	function create(tasks, prefix, taskConfig, parentConfig) {
		var task = self.one(prefix, taskConfig.name, taskConfig, parentConfig);
		if (task) {
			tasks.push(task);
		}
		return tasks;
	}
};

ConfigurableTaskFactory.prototype.create = function (prefix, taskInfo, taskConfig, configurableRunner) {
	var registry = this.registry;
	// make sure config is inherited at config time and injected, realized at runtime.
	// invoked from stream processor
	var run = function (gulp, injectConfig, stream, done) {
		// inject and realize runtime configuration.
		var config = Configuration.realize(taskConfig, injectConfig, configurableRunner.defaults);
		return configurableRunner(gulp, config, stream, done);
	};
	// invoked from gulp
	var configurableTask = function (done) {
		// NOTE: gulp 4.0 task are called on undefined context. So we need gulp reference from registry here.
		return run(registry.gulp, taskConfig, null, done);
	};
	var name = (taskInfo.name || configurableRunner.displayName || configurableRunner.name || '<anonymous>');
	set(configurableTask, 'displayName', prefix + name);
	set(configurableTask, 'description', taskInfo.description || configurableRunner.description || '');
	set(configurableTask, 'visibility', taskInfo.visibility);
	set(configurableTask, 'runtime', taskInfo.runtime);
	configurableTask.run = run;
	configurableTask.config = taskConfig;
	if (Configuration.isVisible(configurableTask)) {
		this.registry.set(configurableTask.displayName, configurableTask);
		metadata.set(configurableTask, configurableTask.displayName);
	} else {
		metadata.set(configurableTask, '<' + name + '>');
	}
	return configurableTask;

	function set(target, property, value) {
		if (typeof value !== 'undefined') {
			target[property] = value;
		}
	}
};

module.exports = ConfigurableTaskFactory;
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react'
import _ from 'lodash'

import LineItemHeader from '../components/LineItemHeader'
import LineSelectDays from '../components/LineSelectDays'
import LineTable from '../components/LineTable'
import { maskLegend } from '../utils/legends'
import Headroom from 'react-headroom'

export default class LineItem extends Component {

  constructor (props) {
    super(props)

    this.state = {
      line: this.getLineCurrent(props),
      day: 1
    }

    this.onSelectDay = this.onSelectDay.bind(this)
  }

  componentWillReceiveProps (nextProps) {
    this.setState({
      line: this.getLineCurrent(nextProps)
    })
  }

  getLineCurrent (props) {
    let line = _.filter(window.api[0].lines, {lineNumber: props.params.id})
    if (line.length > 0) {
      return line[0]
    } else {
      false
    }
  }

  getDay (direction) {
    let filterDay = {type: this.state.day}

    return _.filter(this.state.line[direction], trip => {
      return _.filter(trip.departures, filterDay).length > 0
    }).map(trip => {
      return Object.assign({}, trip, {
        departure: _.filter(trip.departures, filterDay)[0]
      })
    })
  }

  onSelectDay ({type}) {
    this.setState({
      day: type
    })
  }

  getLegends (hours) {
    let legends = []
    hours.map((item, i) => {
      legends.push({
        position: `${_.padStart(i + 1, 2, '0')}`,
        description: maskLegend(item, i)
      })
    })
    return legends
  }

  render () {
    let { line } = this.state, view
    const ida = this.getDay('ida')
    const volta = this.getDay('volta')
    const legends = this.getLegends(ida.concat(volta))

    if (ida.length > 0 || volta.length > 0) {
      view = [

Ida

            <LineTable hours={ida} legends={legends} />

Volta

            <LineTable hours={volta} legends={legends} />

,

          Destino:
          {legends.map(legend => {
            return
{legend.position + ': ' + legend.description}

          })}

      ]
    } else {
      view = (

Sem ônibus para esse dia :(

      )
    }

    return (

        <LineItemHeader {...this.context} line={line} />
        <Headroom
          disable={this.context.lineItemTop ? false : true}
          parent={() => document.getElementById('headRoom') }
        >
          <LineSelectDays onSelect={this.onSelectDay} />
        </Headroom>
        {view}

    )
  }
}

LineItem.contextTypes = {
  lineItemScroll: PropTypes.number,
  lineItemTop: PropTypes.bool
}
<commit_msg>go to 404 where line not found<commit_after>import React, { Component, PropTypes } from 'react'
import { browserHistory } from 'react-router'
import _ from 'lodash'

import LineItemHeader from '../components/LineItemHeader'
import LineSelectDays from '../components/LineSelectDays'
import NotFound from '../components/NotFound'
import LineTable from '../components/LineTable'
import { maskLegend } from '../utils/legends'
import Headroom from 'react-headroom'

export default class LineItem extends Component {

  constructor (props) {
    super(props)

    this.state = {
      line: this.getLineCurrent(props),
      day: 1
    }

    this.onSelectDay = this.onSelectDay.bind(this)
  }

  componentWillReceiveProps (nextProps) {
    this.setState({
      line: this.getLineCurrent(nextProps)
    })
  }

  getLineCurrent (props) {
    let line = _.filter(window.api[0].lines, {lineNumber: props.params.id})
    if (line.length > 0) {
      return line[0]
    } else {
      false
    }
  }

  getDay (direction) {

    if (!this.state.line) return []

    let filterDay = {type: this.state.day}

    return _.filter(this.state.line[direction], trip => {
      return _.filter(trip.departures, filterDay).length > 0
    }).map(trip => {
      return Object.assign({}, trip, {
        departure: _.filter(trip.departures, filterDay)[0]
      })
    })
  }

  onSelectDay ({type}) {
    this.setState({
      day: type
    })
  }

  getLegends (hours) {
    let legends = []
    hours.map((item, i) => {
      legends.push({
        position: `${_.padStart(i + 1, 2, '0')}`,
        description: maskLegend(item, i)
      })
    })
    return legends
  }

  render () {
    let { line } = this.state, view
    const ida = this.getDay('ida')
    const volta = this.getDay('volta')
    const legends = this.getLegends(ida.concat(volta))

    if (!line) {
      return <NotFound isPage={false} />
    }

    if (ida.length > 0 || volta.length > 0) {
      view = [

Ida

            <LineTable hours={ida} legends={legends} />

Volta

            <LineTable hours={volta} legends={legends} />

,

          Destino:
          {legends.map(legend => {
            return
{legend.position + ': ' + legend.description}

          })}

      ]
    } else {
      view = (

Sem ônibus para esse dia :(

      )
    }

    return (

        <LineItemHeader {...this.context} line={line} />
        <Headroom
          disable={this.context.lineItemTop ? false : true}
          parent={() => document.getElementById('headRoom') }
        >
          <LineSelectDays onSelect={this.onSelectDay} />
        </Headroom>
        {view}

    )
  }
}

LineItem.contextTypes = {
  lineItemScroll: PropTypes.number,
  lineItemTop: PropTypes.bool
}
<|endoftext|>


<commit_before>import classNames from 'classnames';
import mixin from 'reactjs-mixin';
import React from 'react';
import {StoreMixin} from 'mesosphere-shared-reactjs';

import FilterBar from './FilterBar';
import FilterButtons from './FilterButtons';
import FilterHeadline from './FilterHeadline';
import FilterInputText from './FilterInputText';
import KillTaskModal from './KillTaskModal';
import MesosStateStore from '../stores/MesosStateStore';
import RequestErrorMsg from './RequestErrorMsg';
import SaveStateMixin from '../mixins/SaveStateMixin';
import StringUtil from '../utils/StringUtil';
import TaskStates from '../constants/TaskStates';
import TaskTable from './TaskTable';

const METHODS_TO_BIND = [
  'handleItemCheck',
  'handleKillClose',
  'handleKillSuccess',
  'handleSearchStringChange',
  'handleStatusFilterChange',
  'onStateStoreSuccess',
  'onStateStoreError',
  'resetFilter'
];

const STATUS_FILTER_BUTTONS = ['all', 'active', 'completed'];

class TaskView extends mixin(SaveStateMixin, StoreMixin) {
  constructor() {
    super();

    this.state = {
      checkedItems: {},
      killAction: '',
      mesosStateErrorCount: 0,
      searchString: '',
      filterByStatus: 'active'
    };

    this.saveState_properties = ['filterByStatus'];

    this.store_listeners = [
      {
        name: 'state',
        events: ['success', 'error'],
        suppressUpdate: true
      }
    ];

    METHODS_TO_BIND.forEach(function (method) {
      this[method] = this[method].bind(this);
    }, this);
  }

  componentWillMount() {
    this.saveState_key = `taskView#${this.props.itemID}`;
    super.componentWillMount();
  }

  componentWillReceiveProps(nextProps) {
    let prevCheckedItems = this.state.checkedItems;
    let checkedItems = {};

    nextProps.tasks.forEach(function (task) {
      if (prevCheckedItems[task.id]) {
        checkedItems[task.id] = true;
      }
    });

    this.setState({checkedItems});
  }

  onStateStoreSuccess() {
    if (this.state.mesosStateErrorCount !== 0) {
      this.setState({mesosStateErrorCount: 0});
    }
  }

  onStateStoreError() {
    this.setState({mesosStateErrorCount: this.state.mesosStateErrorCount + 1});
  }

  handleItemCheck(idsChecked) {
    let checkedItems = {};
    idsChecked.forEach(function (id) {
      checkedItems[id] = true;
    });

    this.setState({checkedItems});
  }

  handleKillClick(killAction) {
    this.setState({killAction});
  }

  handleKillClose() {
    this.setState({killAction: ''});
  }

  handleSearchStringChange(searchString) {
    this.setState({searchString});
  }

  handleStatusFilterChange(filterByStatus) {
    this.setState({filterByStatus});
  }

  handleKillSuccess() {
    this.setState({checkedItems: {}, killAction: ''});
  }

  filterByCurrentStatus(tasks, filterByStatus) {
    if (filterByStatus === 'all') {
      return tasks;
    }

    return tasks.filter(function (task) {
      return TaskStates[task.state].stateTypes.includes(filterByStatus);
    });
  }

  hasLoadingError() {
    return this.state.mesosStateErrorCount >= 5;
  }

  getFilteredTasks() {
    let {tasks} = this.props;
    let {filterByStatus, searchString} = this.state;

    if (searchString !== '') {
      tasks = StringUtil.filterByString(tasks, 'id', searchString);
    }

    tasks = this.filterByCurrentStatus(tasks, filterByStatus);

    return tasks;
  }

  getLoadingScreen() {
    if (this.hasLoadingError()) {
      return <RequestErrorMsg />;
    }

    return (

    );
  }

  getTaskTable(tasks, checkedItems) {
    let {inverseStyle, parentRouter} = this.props;

    let classSet = classNames({
      'table table-borderless-outer table-borderless-inner-columns': true,
      'flush-bottom': true,
      'inverse': inverseStyle
    });

    return (
      <TaskTable
        checkedItemsMap={checkedItems}
        className={classSet}
        onCheckboxChange={this.handleItemCheck}
        parentRouter={parentRouter}
        tasks={tasks} />
    );
  }

  resetFilter() {
    this.setState({
      searchString: '',
      filterByStatus: 'all'
    });
  }

  getButtonContent(filterName, count) {
    return (

        {StringUtil.capitalize(filterName)}
        {count || 0}

    );
  }

  getKillButtons(hasCheckedTasks) {
    if (!hasCheckedTasks) {
      return null;
    }

    return (

          Kill and Scale

          Kill

    );
  }

  getKillTaskModal(checkedItems, hasCheckedTasks) {
    if (!hasCheckedTasks) {
      return null;
    }

    let {killAction} = this.state;
    let tasks = Object.keys(checkedItems);

    return (
      <KillTaskModal
        action={killAction}
        selectedItems={tasks}
        onClose={this.handleKillClose}
        onSuccess={this.handleKillSuccess}
        open={!!killAction} />
    );
  }

  getContent() {
    let {inverseStyle, tasks} = this.props;
    let {checkedItems, filterByStatus, searchString} = this.state;

    let totalNumberOfTasks = tasks.length;

    // Get task states based on TaskStates types
    let taskStates = tasks.map(function (task) {
      let {stateTypes} = TaskStates[task.state];

      return stateTypes.find(function (state) {
        return state === 'active' || state === 'completed';
      });
    });

    tasks = this.getFilteredTasks();

    let rightAlignLastNChildren = 0;
    let hasCheckedTasks = Object.keys(checkedItems).length !== 0;
    if (hasCheckedTasks) {
      rightAlignLastNChildren = 1;
    }

    return (

        <FilterHeadline
          currentLength={tasks.length}
          inverseStyle={inverseStyle}
          isFiltering={filterByStatus !== 'all' || searchString !== ''}
          onReset={this.resetFilter}
          name="Task"
          totalLength={totalNumberOfTasks} />
        <FilterBar rightAlignLastNChildren={rightAlignLastNChildren}>
          <FilterInputText
            className="flush-bottom"
            searchString={searchString}
            handleFilterChange={this.handleSearchStringChange}
            inverseStyle={inverseStyle} />
          <FilterButtons
            renderButtonContent={this.getButtonContent}
            filters={STATUS_FILTER_BUTTONS}
            onFilterChange={this.handleStatusFilterChange}
            inverseStyle={inverseStyle}
            itemList={taskStates}
            selectedFilter={filterByStatus} />
          {this.getKillButtons(hasCheckedTasks)}
        </FilterBar>
        {this.getTaskTable(tasks, checkedItems)}
        {this.getKillTaskModal(checkedItems, hasCheckedTasks)}

    );
  }

  render() {
    var showLoading = this.hasLoadingError() ||
      Object.keys(MesosStateStore.get('lastMesosState')).length === 0;

    if (showLoading) {
      return this.getLoadingScreen();
    } else {
      return this.getContent();
    }
  }
}

TaskTable.defaultProps = {
  inverseStyle: false,
  itemID: '',
  tasks: []
};

TaskView.propTypes = {
  inverseStyle: React.PropTypes.bool,
  itemID: React.PropTypes.string,
  parentRouter: React.PropTypes.func,
  tasks: React.PropTypes.array
};

module.exports = TaskView;
<commit_msg>Fixes from comments<commit_after>import classNames from 'classnames';
import mixin from 'reactjs-mixin';
import React from 'react';
import {StoreMixin} from 'mesosphere-shared-reactjs';

import FilterBar from './FilterBar';
import FilterButtons from './FilterButtons';
import FilterHeadline from './FilterHeadline';
import FilterInputText from './FilterInputText';
import KillTaskModal from './KillTaskModal';
import MesosStateStore from '../stores/MesosStateStore';
import RequestErrorMsg from './RequestErrorMsg';
import SaveStateMixin from '../mixins/SaveStateMixin';
import StringUtil from '../utils/StringUtil';
import TaskStates from '../constants/TaskStates';
import TaskTable from './TaskTable';

const METHODS_TO_BIND = [
  'handleItemCheck',
  'handleKillClose',
  'handleKillSuccess',
  'handleSearchStringChange',
  'handleStatusFilterChange',
  'onStateStoreSuccess',
  'onStateStoreError',
  'resetFilter'
];

const STATUS_FILTER_BUTTONS = ['all', 'active', 'completed'];

class TaskView extends mixin(SaveStateMixin, StoreMixin) {
  constructor() {
    super();

    this.state = {
      checkedItems: {},
      killAction: '',
      mesosStateErrorCount: 0,
      searchString: '',
      filterByStatus: 'active'
    };

    this.saveState_properties = ['filterByStatus'];

    this.store_listeners = [
      {
        name: 'state',
        events: ['success', 'error'],
        suppressUpdate: true
      }
    ];

    METHODS_TO_BIND.forEach(function (method) {
      this[method] = this[method].bind(this);
    }, this);
  }

  componentWillMount() {
    this.saveState_key = `taskView#${this.props.itemID}`;
    super.componentWillMount();
  }

  componentWillReceiveProps(nextProps) {
    let prevCheckedItems = this.state.checkedItems;
    let checkedItems = {};

    nextProps.tasks.forEach(function (task) {
      if (prevCheckedItems[task.id]) {
        checkedItems[task.id] = true;
      }
    });

    this.setState({checkedItems});
  }

  onStateStoreSuccess() {
    if (this.state.mesosStateErrorCount !== 0) {
      this.setState({mesosStateErrorCount: 0});
    }
  }

  onStateStoreError() {
    this.setState({mesosStateErrorCount: this.state.mesosStateErrorCount + 1});
  }

  handleItemCheck(idsChecked) {
    let checkedItems = {};
    idsChecked.forEach(function (id) {
      checkedItems[id] = true;
    });

    this.setState({checkedItems});
  }

  handleKillClick(killAction) {
    this.setState({killAction});
  }

  handleKillClose() {
    this.setState({killAction: ''});
  }

  handleSearchStringChange(searchString) {
    this.setState({searchString});
  }

  handleStatusFilterChange(filterByStatus) {
    this.setState({filterByStatus});
  }

  handleKillSuccess() {
    this.setState({checkedItems: {}, killAction: ''});
  }

  hasLoadingError() {
    return this.state.mesosStateErrorCount >= 5;
  }

  getFilteredTasks() {
    let {tasks} = this.props;
    let {filterByStatus, searchString} = this.state;

    if (searchString !== '') {
      tasks = StringUtil.filterByString(tasks, 'id', searchString);
    }

    if (filterByStatus !== 'all') {
      tasks = tasks.filter(function (task) {
        return TaskStates[task.state].stateTypes.includes(filterByStatus);
      });
    }

    return tasks;
  }

  getLoadingScreen() {
    if (this.hasLoadingError()) {
      return <RequestErrorMsg />;
    }

    return (

    );
  }

  getTaskTable(tasks, checkedItems) {
    let {inverseStyle, parentRouter} = this.props;

    let classSet = classNames({
      'table table-borderless-outer table-borderless-inner-columns': true,
      'flush-bottom': true,
      'inverse': inverseStyle
    });

    return (
      <TaskTable
        checkedItemsMap={checkedItems}
        className={classSet}
        onCheckboxChange={this.handleItemCheck}
        parentRouter={parentRouter}
        tasks={tasks} />
    );
  }

  resetFilter() {
    this.setState({
      searchString: '',
      filterByStatus: 'all'
    });
  }

  getButtonContent(filterName, count) {
    return (

        {StringUtil.capitalize(filterName)}
        {count || 0}

    );
  }

  getKillButtons(hasCheckedTasks) {
    if (!hasCheckedTasks) {
      return null;
    }

    return (

          Kill and Scale

          Kill

    );
  }

  getKillTaskModal(checkedItems, hasCheckedTasks) {
    if (!hasCheckedTasks) {
      return null;
    }

    let {killAction} = this.state;
    let tasks = Object.keys(checkedItems);

    return (
      <KillTaskModal
        action={killAction}
        selectedItems={tasks}
        onClose={this.handleKillClose}
        onSuccess={this.handleKillSuccess}
        open={!!killAction} />
    );
  }

  getContent() {
    let {inverseStyle, tasks} = this.props;
    let {checkedItems, filterByStatus, searchString} = this.state;
    let filteredTasks = this.getFilteredTasks();

    // Get task states based on TaskStates types
    let taskStates = tasks.map(function (task) {
      let {stateTypes} = TaskStates[task.state];

      return stateTypes.find(function (state) {
        return state === 'active' || state === 'completed';
      });
    });

    let rightAlignLastNChildren = 0;
    let hasCheckedTasks = Object.keys(checkedItems).length !== 0;

    if (hasCheckedTasks) {
      rightAlignLastNChildren = 1;
    }

    return (

        <FilterHeadline
          currentLength={filteredTasks.length}
          inverseStyle={inverseStyle}
          isFiltering={filterByStatus !== 'all' || searchString !== ''}
          onReset={this.resetFilter}
          name="Task"
          totalLength={tasks.length} />
        <FilterBar rightAlignLastNChildren={rightAlignLastNChildren}>
          <FilterInputText
            className="flush-bottom"
            searchString={searchString}
            handleFilterChange={this.handleSearchStringChange}
            inverseStyle={inverseStyle} />
          <FilterButtons
            renderButtonContent={this.getButtonContent}
            filters={STATUS_FILTER_BUTTONS}
            onFilterChange={this.handleStatusFilterChange}
            inverseStyle={inverseStyle}
            itemList={taskStates}
            selectedFilter={filterByStatus} />
          {this.getKillButtons(hasCheckedTasks)}
        </FilterBar>
        {this.getTaskTable(filteredTasks, checkedItems)}
        {this.getKillTaskModal(checkedItems, hasCheckedTasks)}

    );
  }

  render() {
    var showLoading = this.hasLoadingError() ||
      Object.keys(MesosStateStore.get('lastMesosState')).length === 0;

    if (showLoading) {
      return this.getLoadingScreen();
    } else {
      return this.getContent();
    }
  }
}

TaskTable.defaultProps = {
  inverseStyle: false,
  itemID: '',
  tasks: []
};

TaskView.propTypes = {
  inverseStyle: React.PropTypes.bool,
  itemID: React.PropTypes.string,
  parentRouter: React.PropTypes.func,
  tasks: React.PropTypes.array
};

module.exports = TaskView;
<|endoftext|>


<commit_before>/*global require, module, openExternalUrl, minimizeWindow*/
/** @jsx React.DOM */
var React = require('react'),
    AppActions = require('../actions/app-actions'),
    TextField = require('../components/form/app-TextField'),
    DropDown = require('../components/form/app-Dropdown');

var Task = React.createClass({
    getInitialState: function () {
        "use strict";
        return {
            open: false
        };
    },
    _handleClick: function () {
        "use strict";
        if (this.state.open) {
            this.setState({
                open: false
            });
        } else {
            this.setState({
                open: true
            });
        }
    },
    _elementClick: function (event) {
        "use strict";
        event.stopPropagation();
    },
    _updateTaskActivityId: function (event) {
        "use strict";
        var activityId = this.refs.activity.getValue();
        AppActions.updateTaskActivityId(this.props.item.id, activityId);
        event.stopPropagation();
    },
    _updateTaskComments: function (comment) {
        "use strict";
        AppActions.updateTaskComments(this.props.item.id, comment);
    },
    _updateTaskHours: function (event) {
        "use strict";
        var spentHours = this.refs.spentHours.getValue();
        AppActions.updateTaskHours(this.props.item.id, spentHours);
    },
    _remove: function (event) {
        "use strict";
        AppActions.removeTimeEntry(this.props.item.id);
        event.nativeEvent.stopImmediatePropagation();
    },
    _openExternalUrl: function (event) {
        "use strict";
        openExternalUrl(this.props.item.taskUrl);
        minimizeWindow();
        event.nativeEvent.stopImmediatePropagation();
    },
    render : function () {
        "use strict";
        var activities = this.props.activities,
            item = this.props.item,
            tileClass = "tile tile-collapse",
            hoursText = "",
            iconText,
            dataTarget;

        if (item.updated) {
            tileClass = "tile tile-collapse selected";
            hoursText = "[" + parseFloat(item.hours).toFixed(2) + " Hours]";
        }

        // Just get the first proper letter of the project
        iconText = this.props.item.projectName.replace(/\W/g, '').charAt(0);
        dataTarget = "tile-collapse-" + item.id;

        return (

                            {iconText}

                                IssueID

                                Delete

                                {hoursText}

{item.issueName}

                                <TextField ref="comment" label = "Comment" value={item.comments} keyUp={this._updateTaskComments}/>

                                <DropDown ref="activity" data={activities} initialValue={item.activityId} onChange={this._updateTaskActivityId}/>

                                <TextField ref="spentHours" label = "Hours" value={item.hours} keyUp={this._updateTaskHours} isNumeric={true} setFixedFloatingZeros={true}/>

        );
    }
});

module.exports = Task;
<commit_msg>Updated title text<commit_after>/*global require, module, openExternalUrl, minimizeWindow*/
/** @jsx React.DOM */
var React = require('react'),
    AppActions = require('../actions/app-actions'),
    TextField = require('../components/form/app-TextField'),
    DropDown = require('../components/form/app-Dropdown');

var Task = React.createClass({
    getInitialState: function () {
        "use strict";
        return {
            open: false
        };
    },
    _handleClick: function () {
        "use strict";
        if (this.state.open) {
            this.setState({
                open: false
            });
        } else {
            this.setState({
                open: true
            });
        }
    },
    _elementClick: function (event) {
        "use strict";
        event.stopPropagation();
    },
    _updateTaskActivityId: function (event) {
        "use strict";
        var activityId = this.refs.activity.getValue();
        AppActions.updateTaskActivityId(this.props.item.id, activityId);
        event.stopPropagation();
    },
    _updateTaskComments: function (comment) {
        "use strict";
        AppActions.updateTaskComments(this.props.item.id, comment);
    },
    _updateTaskHours: function (event) {
        "use strict";
        var spentHours = this.refs.spentHours.getValue();
        AppActions.updateTaskHours(this.props.item.id, spentHours);
    },
    _remove: function (event) {
        "use strict";
        AppActions.removeTimeEntry(this.props.item.id);
        event.nativeEvent.stopImmediatePropagation();
    },
    _openExternalUrl: function (event) {
        "use strict";
        openExternalUrl(this.props.item.taskUrl);
        minimizeWindow();
        event.nativeEvent.stopImmediatePropagation();
    },
    render : function () {
        "use strict";
        var activities = this.props.activities,
            item = this.props.item,
            tileClass = "tile tile-collapse",
            hoursText = "",
            iconText,
            dataTarget;

        if (item.updated) {
            tileClass = "tile tile-collapse selected";
            hoursText = "[" + parseFloat(item.hours).toFixed(2) + " Hours]";
        }

        // Just get the first proper letter of the project
        iconText = this.props.item.projectName.replace(/\W/g, '').charAt(0);
        dataTarget = "tile-collapse-" + item.id;

        return (

                            {iconText}

                                IssueID

                                Delete

                                {hoursText}

{item.issueName}

                                <TextField ref="comment" label = "Comment" value={item.comments} keyUp={this._updateTaskComments}/>

                                <DropDown ref="activity" data={activities} initialValue={item.activityId} onChange={this._updateTaskActivityId}/>

                                <TextField ref="spentHours" label = "Hours" value={item.hours} keyUp={this._updateTaskHours} isNumeric={true} setFixedFloatingZeros={true}/>

        );
    }
});

module.exports = Task;
<|endoftext|>