<commit_before>/*   File: tooltip.js
 * Author: Jin Savage ("spynix")
 *
 *
 * License - 2-clause ("simplified") BSD
 * ----------------------------------------------------------------------------
 *
 * Copyright (c) 2015, Jin Savage ("spynix")
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *
 * Structure
 * ----------------------------------------------------------------------------
 *   element: <dom element> (the element to receive the tooltip)
 *   config {
 *     title: <displayed title> (defaults to null and not added to the tooltip)
 *     content: <displayed text>
 *     vector: <directionality> (either an angle or a cardinal direction)
 *     distance: <integer>
 *     connector: <none, line, arrow> (sometimes called a stem)
 *     show_delay: <integer in ms> (wait period before beginning show animation)
 *     show_transition: <integer in ms> (duration of show animation)
 *     hide_delay: <integer in ms> (wait period before beginning hide animation)
 *     hide_transition: <integer in ms> (duration of hide animation)
 *   }
 *
 *
 * Notes
 * ----------------------------------------------------------------------------
 *   hook: this is a container div wrapped around the selected element so that
 *         all selected element functionality remains untouched and all event
 *         handlers can be attached here
 *
 *   vector: in the future i'd like a more geometrically accurate result here
 *         by using any valid angle, but for now it simply takes the angle
 *         and converts it to a cardinal vector, or you can use an explicit
 *         cardinal vector string
 *
 *         right now this works somewhat unintuitively though, and may need
 *         redesigning because of that, but it collectively handles both
 *         sides of the connection between the tooltip and the hook
 *
 *   removing tooltips: currently not available.  in the future i want to make
 *         it so each module manhandles its own respective fields, but at the
 *         same time not replicate code across each created object, so i'll be
 *         spending more time deciding how i want to accomplish that
 *
 */

define(["jquery"], function($) {
  var tooltip_module = (function() {
    var top_tooltip_id = 0;
    var vectors = ["n", "ne", "e", "se", "s", "sw", "w", "nw"];
    var connectors = ["arrow", "line", "none"];

    var defaults = {
      id: -1,                         /* unique id for every tooltip */
      active: true,                   /* is this tooltip on or off (not related to showing or not) */
      visible: false,                 /* is the tooltip currently being displayed */
      element: null,                  /* the parent element this tooltip is attached to */
      container: null,                /* reference for the generated tooltip element */
      hook: null,                     /* see devnotes->hook */
      title: null,                    /* if a title is specified, creates a dialogue modal style header */
      content: "This is a tooltip.",  /* innerHTML of the tooltip's body */
      vector: "n",                    /* see devnotes->vector */
      distance: 16,                   /* distance in pixels the tooltip will appear from the element */
      connector: "line",              /* the graphical connector made between the tooltip and the element */
      show_delay: 400,                /* wait period before showing the tooltip */
      show_timeout: null,             /* reference to the timeout function for show */
      show_transition: 250,           /* transition time from transparent to opaque */
      hide_delay: 400,                /* wait period before hiding the tooltip */
      hide_timeout: null,             /* reference to the timeout function for hide */
      hide_transition: 250            /* transition time from opaque to transparent */
    };

    /* create():
     *   creates the tooltip element itself
     */
    var create = function(config) {
      var container = document.createElement("div");
      var title = config.title !== null ? document.createElement("div") : false;
      var content = document.createElement("div");

      container.id = "tooltip_" + config.id.toString();
      container.className = "tooltip";

      if (title) {
        title.className = "tooltip-title";
        title.innerHTML = config.title;
        container.appendChild(title);
      }

      content.className = "tooltip-content";
      content.innerHTML = config.content;
      container.appendChild(content);

      document.body.appendChild(container);

      return container;
    };

    var position = function(hook, container, vector, distance) {
      var body_bounds, hook_bounds, container_bounds;
      var hook_center, hook_middle;
      var container_top, container_left;
      var hook_width, hook_height, container_width, container_height;

      body_bounds = document.body.getBoundingClientRect();
      hook_bounds = hook.getBoundingClientRect();
      container_bounds = container.getBoundingClientRect();

      hook_width = hook_bounds.right - hook_bounds.left;
      hook_height = hook_bounds.bottom - hook_bounds.top;

      container_width = container_bounds.right - container_bounds.left;
      container_height = container_bounds.bottom - container_bounds.top;

      hook_center = Math.round(hook_bounds.left + Math.round(hook_width / 2)); /* vertical plane */
      hook_middle = Math.round(hook_bounds.top + Math.round(hook_height / 2)); /* horizontal plane */

      switch (vector) {
        case "n": /* fall through */
        default:
          container_top = hook_bounds.top - distance - container_height;
          container_top += window.scrollY;

          container_left = Math.round(hook_center - Math.round(container_width / 2));
          container_left += window.scrollX;

          break;
        case "ne":
          break;
        case "e":
          container_top = Math.round(hook_middle - Math.round(container_height / 2));
          container_top += window.scrollY;

          container_left = hook_bounds.right + distance;
          container_left += distance;

          break;
        case "se":
          break;
        case "s":
          container_top = hook_bounds.bottom + distance;
          container_top += window.scrollY;

          container_left = Math.round(hook_center - Math.round(container_width / 2));
          container_left += window.scrollX;

          break;
        case "sw":
          break;
        case "w":
          container_top = Math.round(hook_middle - Math.round(container_height / 2));
          container_top += window.scrollY;

          container_left = hook_bounds.left - distance - container_width;
          container_left += window.scrollX;

          break;
        case "nw":
          break;
      }

      container.style.position = "absolute";
      container.style.top = container_top + "px";
      container.style.left = container_left + "px";
    };

    /* attach():
     *   performs dom element<->tooltip linking
     */
    var attach = function(element, config) {
//      var i = 0, l = 0;
//      var event_handles = [];
      var container, hook;

      if (!element || !config)
        return false;

      container = create(config);

      $(element).wrap('

');
      hook = element.parentElement;

      /* can probably just set display: hidden here and save some cycles */
      $(container).fadeOut({ duration: 0 });

      $(hook).on("mouseenter", (function(hook, container, vector, duration, transition, distance) {
        var timeout = false;

        return function() {
          if (timeout !== false) {
            clearTimeout(timeout);
            timeout = false;
          }

          if (!isNaN(duration) && (duration >= 1) && (duration <= 5000))
            timeout = setTimeout((function(hook, container, vector, distance) {
              return function() {
                $(container).fadeIn({
                  duration: transition,
                  start: function() { position(hook, container, vector, distance); },
                  complete: function() {
                  }
                });
              };
            })(hook, container, vector, distance), duration);
          else {
            $(container).fadeIn({
              duration: transition,
              start: function() { position(hook, container, vector, distance); },
              complete: function() {
              }
            });
          }
        };
      }(hook, container, config.vector, config.show_delay, config.show_transition, config.distance)));

      $(hook).on("mouseleave", (function(hook, container, vector, duration, transition) {
        var timeout = false;

        return function() {
          if (timeout !== false) {
            clearTimeout(timeout);
            timeout = false;
          }

          if (!isNaN(duration) && (duration >= 1) && (duration <= 5000))
            timeout = setTimeout(function() {
              $(container).fadeOut({
                duration: transition,
                complete: function() {
                }
              });
            }, duration);
          else {
            $(container).fadeOut({
              duration: transition,
              complete: function() {
              }
            });
          }
        };
      } (hook, container, config.vector, config.hide_delay, config.hide_transition)));

      /* get the triggers for everything in tooltip.events and generate the
       * corresponding handlers for them all
       */
//      event_handles = Object.keys(config.events);
//
//      for (i = 0, l = event_handles.length; i < l; i++)
//        $(config.hook).on(event_handles[i], config.events[event_handles[i]]);
    };

    /* nearest_vector():
     *   if an actual angle is used, this will determine which vector to use
     *   based on that angle.  rotation is clockwise beginning at 0-deg = north.
     */
    var nearest_vector = function(angle) {
      if (angle <= -1)
        angle *= -1;

      return (vectors[Math.round(angle / 45) % 8]);
    };

    /* tooltip():
     *   module entry point.  for now rather than returning a group of closed
     *   functions it simply pipes a single function -- the one to actually
     *   produce the tooltip -- instead.  once i decide how i want to handle
     *   removing an existing tooltip this may change.
     */
    var tooltip = function(element, config) {
      var options = {};

      if (!element)
        return false;

      /* if there's already a tooltip attached to this element... */
      if ($(element).parent().is('div[class="tooltip"]'))
        return false;

      $.extend(true, options, defaults, config);

      /* if the vector is a mathematical angle, transform it to a directional
       * vector relative to the element */
      if (!isNaN(options.vector))
        options.vector = nearest_vector(options.vector);

      options.id = top_tooltip_id;
      top_tooltip_id++;

      attach(element, options);

      return true;
    };

    return tooltip;
  })();

  return tooltip_module;
});<commit_msg>Debugging<commit_after>/*   File: tooltip.js
 * Author: Jin Savage ("spynix")
 *
 *
 * License - 2-clause ("simplified") BSD
 * ----------------------------------------------------------------------------
 *
 * Copyright (c) 2015, Jin Savage ("spynix")
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *
 * Structure
 * ----------------------------------------------------------------------------
 *   element: <dom element> (the element to receive the tooltip)
 *   config {
 *     title: <displayed title> (defaults to null and not added to the tooltip)
 *     content: <displayed text>
 *     vector: <directionality> (either an angle or a cardinal direction)
 *     distance: <integer>
 *     connector: <none, line, arrow> (sometimes called a stem)
 *     show_delay: <integer in ms> (wait period before beginning show animation)
 *     show_transition: <integer in ms> (duration of show animation)
 *     hide_delay: <integer in ms> (wait period before beginning hide animation)
 *     hide_transition: <integer in ms> (duration of hide animation)
 *   }
 *
 *
 * Notes
 * ----------------------------------------------------------------------------
 *   hook: this is a container div wrapped around the selected element so that
 *         all selected element functionality remains untouched and all event
 *         handlers can be attached here
 *
 *   vector: in the future i'd like a more geometrically accurate result here
 *         by using any valid angle, but for now it simply takes the angle
 *         and converts it to a cardinal vector, or you can use an explicit
 *         cardinal vector string
 *
 *         right now this works somewhat unintuitively though, and may need
 *         redesigning because of that, but it collectively handles both
 *         sides of the connection between the tooltip and the hook
 *
 *   removing tooltips: currently not available.  in the future i want to make
 *         it so each module manhandles its own respective fields, but at the
 *         same time not replicate code across each created object, so i'll be
 *         spending more time deciding how i want to accomplish that
 *
 */

define(["jquery"], function ($) {
  var tooltip_module = (function () {
    var top_tooltip_id = 0;
    var vectors = ["n", "ne", "e", "se", "s", "sw", "w", "nw"];
    var connectors = ["arrow", "line", "none"];

    var defaults = {
      id: -1,                        /* unique id for every tooltip */
      active: true,                  /* is this tooltip on or off (not related to showing or not) */
      visible: false,                /* is the tooltip currently being displayed */
      element: null,                 /* the parent element this tooltip is attached to */
      container: null,               /* reference for the generated tooltip element */
      hook: null,                    /* see devnotes->hook */
      title: null,                   /* if a title is specified, creates a dialogue modal style header */
      content: "This is a tooltip.", /* innerHTML of the tooltip's body */
      vector: "n",                   /* see devnotes->vector */
      distance: 16,                  /* distance in pixels the tooltip will appear from the element */
      connector: "line",             /* the graphical connector made between the tooltip and the element */
      show_delay: 400,               /* wait period before showing the tooltip */
      show_timeout: null,            /* reference to the timeout function for show */
      show_transition: 250,          /* transition time from transparent to opaque */
      hide_delay: 400,               /* wait period before hiding the tooltip */
      hide_timeout: null,            /* reference to the timeout function for hide */
      hide_transition: 250           /* transition time from opaque to transparent */
    };

    /* create():
     *   creates the tooltip element itself
     */
    var create = function (config) {
      var container = document.createElement("div");
      var title = config.title !== null ? document.createElement("div") : false;
      var content = document.createElement("div");

      container.id = "tooltip_" + config.id.toString();
      container.className = "tooltip";

      if (title) {
        title.className = "tooltip-title";
        title.innerHTML = config.title;
        container.appendChild(title);
      }

      content.className = "tooltip-content";
      content.innerHTML = config.content;
      container.appendChild(content);

      document.body.appendChild(container);

      return container;
    };

    var position = function (hook, container, vector, distance) {
      var body_bounds, hook_bounds, container_bounds;
      var hook_center, hook_middle;
      var container_top, container_left;
      var hook_width, hook_height, container_width, container_height;

      body_bounds = document.body.getBoundingClientRect();
      hook_bounds = hook.getBoundingClientRect();
      container_bounds = container.getBoundingClientRect();

      hook_width = hook_bounds.right - hook_bounds.left;
      hook_height = hook_bounds.bottom - hook_bounds.top;

      container_width = container_bounds.right - container_bounds.left;
      container_height = container_bounds.bottom - container_bounds.top;

      hook_center = Math.round(hook_bounds.left + Math.round(hook_width / 2)); /* vertical plane */
      hook_middle = Math.round(hook_bounds.top + Math.round(hook_height / 2)); /* horizontal plane */

      switch (vector) {
        case "n": /* fall through */
        default:
          container_top = hook_bounds.top - distance - container_height;
          container_top += window.scrollY;

          container_left = Math.round(hook_center - Math.round(container_width / 2));
          container_left += window.scrollX;

          break;
        case "ne":
          break;
        case "e":
          container_top = Math.round(hook_middle - Math.round(container_height / 2));
          container_top += window.scrollY;

          container_left = hook_bounds.right + distance;
          container_left += distance;

          break;
        case "se":
          break;
        case "s":
          container_top = hook_bounds.bottom + distance;
          container_top += window.scrollY;

          container_left = Math.round(hook_center - Math.round(container_width / 2));
          container_left += window.scrollX;

          break;
        case "sw":
          break;
        case "w":
          container_top = Math.round(hook_middle - Math.round(container_height / 2));
          container_top += window.scrollY;

          container_left = hook_bounds.left - distance - container_width;
          container_left += window.scrollX;

          break;
        case "nw":
          break;
      }

      container.style.position = "absolute";
      container.style.top = container_top + "px";
      container.style.left = container_left + "px";
    };

    /* attach():
     *   performs dom element<->tooltip linking
     */
    var attach = function (element, config) {
//      var i = 0, l = 0;
//      var event_handles = [];
      var container, hook;

      if (!element || !config)
        return false;

      container = create(config);

      $(element).wrap('

');
      hook = element.parentElement;

      /* can probably just set display: hidden here and save some cycles */
      $(container).fadeOut({duration: 0});

      $(hook).on("mouseenter", (function (hook, container, vector, duration, transition, distance) {
        var timeout = false;

        return function () {
          if (timeout !== false) {
            clearTimeout(timeout);
            timeout = false;
          }

          if (!isNaN(duration) && (duration >= 1) && (duration <= 5000))
            timeout = setTimeout((function (hook, container, vector, distance) {
              return function () {
                $(container).fadeIn({
                  duration: transition,
                  start: function () {
                    position(hook, container, vector, distance);
                  },
                  complete: function () {
                  }
                });
              };
            })(hook, container, vector, distance), duration);
          else {
            $(container).fadeIn({
              duration: transition,
              start: function () {
                position(hook, container, vector, distance);
              },
              complete: function () {
              }
            });
          }
        };
      }(hook, container, config.vector, config.show_delay, config.show_transition, config.distance)));

      $(hook).on("mouseleave", (function (hook, container, vector, duration, transition) {
        var timeout = false;

        return function () {
          if (timeout !== false) {
            clearTimeout(timeout);
            timeout = false;
          }

          if (!isNaN(duration) && (duration >= 1) && (duration <= 5000))
            timeout = setTimeout(function () {
              $(container).fadeOut({
                duration: transition,
                complete: function () {
                }
              });
            }, duration);
          else {
            $(container).fadeOut({
              duration: transition,
              complete: function () {
              }
            });
          }
        };
      }(hook, container, config.vector, config.hide_delay, config.hide_transition)));

      /* get the triggers for everything in tooltip.events and generate the
       * corresponding handlers for them all
       */
//      event_handles = Object.keys(config.events);
//
//      for (i = 0, l = event_handles.length; i < l; i++)
//        $(config.hook).on(event_handles[i], config.events[event_handles[i]]);
    };

    /* nearest_vector():
     *   if an actual angle is used, this will determine which vector to use
     *   based on that angle.  rotation is clockwise beginning at 0-deg = north.
     */
    var nearest_vector = function (angle) {
      if (angle <= -1)
        angle *= -1;

      return (vectors[Math.round(angle / 45) % 8]);
    };

    /* tooltip():
     *   module entry point.  for now rather than returning a group of closed
     *   functions it simply pipes a single function -- the one to actually
     *   produce the tooltip -- instead.  once i decide how i want to handle
     *   removing an existing tooltip this may change.
     */
    var tooltip = function (element, config) {
      var options = {};

      if (!element)
        return false;

      /* if there's already a tooltip attached to this element... */
      if ($(element).parent().is('div[class="tooltip"]'))
        return false;

      $.extend(true, options, defaults, config);

      /* if the vector is a mathematical angle, transform it to a directional
       * vector relative to the element */
      if (!isNaN(options.vector))
        options.vector = nearest_vector(options.vector);

      options.id = top_tooltip_id;
      top_tooltip_id++;

      attach(element, options);

      return true;
    };

    return tooltip;
  })();

  return tooltip_module;
});<|endoftext|>


<commit_before>/* ===========================================================
 * bootstrap-tooltip.js v2.3.2
 * http://getbootstrap.com/2.3.2/javascript.html#tooltips
 * Inspired by the original jQuery.tipsy by Jason Frame
 * ===========================================================
 * Copyright 2013 Twitter, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * ========================================================== */

!function ($) {

  "use strict";

 /* TOOLTIP PUBLIC CLASS DEFINITION
  * =============================== */

  //element为触发元素，如标识文字链
  var Tooltip = function (element, options) {
    this.init('tooltip', element, options)
  }

  Tooltip.prototype = {

    constructor: Tooltip

  , init: function (type, element, options) {
      var eventIn
        , eventOut
        , triggers
        , trigger
        , i

      this.type = type
      this.$element = $(element)
      this.options = this.getOptions(options)
      this.enabled = true
      this.hoverState = 'out'

      triggers = this.options.trigger.split(' ')

      for (i = triggers.length; i--;) {
        trigger = triggers[i]
        if (trigger == 'click') {
          this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))

        } else if (trigger != 'manual') {
          eventIn = trigger == 'hover' ? 'mouseenter' : 'focus'
          eventOut = trigger == 'hover' ? 'mouseleave' : 'blur'
          this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
          this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
        }
      }

      //为confirm类型tooltip增加取消按钮设置默认逻辑
      if (this.options.type == 'confirm') {
        this.$element.parent().on('click', '[data-dismiss=tooltip]', function(e){
          $(this).parents('.sui-tooltip').prev().trigger('click')
        })
        this.$element.parent().on('click', '[data-ok=tooltip]', $.proxy(this.options.okHide, this))

      }

      this.options.selector ?
        (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
        this.fixTitle()
    }

  , getOptions: function (options) {
      options = $.extend({}, $.fn[this.type].defaults, this.$element.data(), options)

      var foot = options.type == 'confirm' ? '
<button class="sui-btn btn-primary" data-ok="tooltip">确定</button><button class="sui-btn btn-default" data-dismiss="tooltip">取消</button>
' : ''
      //根据tooltip的type类型构造tip模版
      options.template = '

' + foot + '
'
      options.type == 'confirm' && (options.html = true)

      if (options.delay && typeof options.delay == 'number') {
        options.delay = {
          show: options.delay
        , hide: options.delay
        }
      }

      return options
    }

  , enter: function (e) {
      var defaults = $.fn[this.type].defaults
        , options = {}
        , self

      this._options && $.each(this._options, function (key, value) {
        if (defaults[key] != value) options[key] = value
      }, this)

      self = $(e.currentTarget)[this.type](options).data(this.type)

      clearTimeout(this.timeout)
      if (this.hoverState == 'out') {
        this.hoverState = 'in'
        this.tip().off($.support.transition.end)
        if (!this.options.delay || !this.options.delay.show) return this.show()
        this.timeout = setTimeout(function() {
          if (self.hoverState == 'in') self.show()
        }, self.options.delay.show)
      }
    }

  , leave: function (e) {
      var self = $(e.currentTarget)[this.type](this._options).data(this.type)
      if (this.timeout) clearTimeout(this.timeout)
      if (!self.options.delay || !self.options.delay.hide) return self.hide()

      this.timeout = setTimeout(function() {
        //isHover 为0或undefined，undefined:没有移到tip上过
        if (!self.isTipHover) {
          self.hoverState = 'out'
        }
        if (self.hoverState == 'out') self.hide()
      }, self.options.delay.hide)
    }

  , show: function () {
      var $tip
        , pos
        , actualWidth
        , actualHeight
        , placement
        , tp
        , e = $.Event('show')
        , opt = this.options
        , widthLimit = opt.widthlimit
        , self = this

      if (this.hasContent() && this.enabled) {
        this.$element.trigger(e)
        if (e.isDefaultPrevented()) return
        $tip = this.tip()
        this.setContent()

        if (opt.animation) {
          $tip.addClass('fade')
        }

        placement = typeof opt.placement == 'function' ?
          opt.placement.call(this, $tip[0], this.$element[0]) :
          opt.placement

        $tip
          .detach()
          .css({ top: 0, left: 0, display: 'block' })

        opt.container ? $tip.appendTo(opt.container) : $tip.insertAfter(this.$element)
        if (opt.trigger !== 'click') {
          $tip.hover(function(){
            self.isTipHover = 1;
          }, function(){
            self.isTipHover = 0;
            self.hide()
          })
        }

        //宽度限制逻辑
        if (widthLimit !== true) {
          var val
          widthLimit === false && (val = 'none')
          typeof opt.widthlimit == 'string' && (val = widthLimit)
          $tip.css('max-width', val)
        }
        pos = this.getPosition()

        actualWidth = $tip[0].offsetWidth
        actualHeight = $tip[0].offsetHeight

        //+ - 7修正，和css对应，勿单独修改
        var d = opt.type == 'attention' ? 5 : 7
        switch (placement) {
          case 'bottom':
            tp = {top: pos.top + pos.height + d, left: pos.left + pos.width / 2 - actualWidth / 2}
            break
          case 'top':
            tp = {top: pos.top - actualHeight - d, left: pos.left + pos.width / 2 - actualWidth / 2}
            break
          case 'left':
            tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth - d}
            break
          case 'right':
            tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width + d}
            break
        }

        this.applyPlacement(tp, placement)
        this.$element.trigger('shown')
      }
    }

  , applyPlacement: function(offset, placement){
      var $tip = this.tip()
        , width = $tip[0].offsetWidth
        , height = $tip[0].offsetHeight
        , actualWidth
        , actualHeight
        , delta
        , replace

      $tip
        .offset(offset)
        .addClass(placement)
        .addClass('in')

      actualWidth = $tip[0].offsetWidth
      actualHeight = $tip[0].offsetHeight

      if (placement == 'top' && actualHeight != height) {
        offset.top = offset.top + height - actualHeight
        replace = true
      }

      if (placement == 'bottom' || placement == 'top') {
        delta = 0

        if (offset.left < 0){
          delta = offset.left * -2
          offset.left = 0
          $tip.offset(offset)
          actualWidth = $tip[0].offsetWidth
          actualHeight = $tip[0].offsetHeight
        }

        this.replaceArrow(delta - width + actualWidth, actualWidth, 'left')
      } else {
        this.replaceArrow(actualHeight - height, actualHeight, 'top')
      }

      if (replace) $tip.offset(offset)
    }

  , replaceArrow: function(delta, dimension, position){
      this
        .arrow()
        .css(position, delta ? (50 * (1 - delta / dimension) + "%") : '')
    }

  , setContent: function () {
      var $tip = this.tip()
        , title = this.getTitle()

      $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
      $tip.removeClass('fade in top bottom left right')
    }

  , hide: function () {
      var $tip = this.tip()
        , e = $.Event('hide')
        , self = this

      this.$element.trigger(e)
      if (e.isDefaultPrevented()) return

      $tip.removeClass('in')

      function removeWithAnimation() {
        self.timeout = setTimeout(function () {
          $tip.off($.support.transition.end).detach()
        }, 500)

        $tip.one($.support.transition.end, function () {
          clearTimeout(self.timeout)
          $tip.detach()
        })
      }

      $.support.transition && this.$tip.hasClass('fade') ?
        removeWithAnimation() :
        ($tip.detach())
      this.$element.trigger('hidden')

      return this
    }

  , fixTitle: function () {
      var $e = this.$element
      if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
        $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
      }
    }

  , hasContent: function () {
      return this.getTitle()
    }

  , getPosition: function () {
      var el = this.$element[0]
      return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : {
        width: el.offsetWidth
      , height: el.offsetHeight
      }, this.$element.offset())
    }

  , getTitle: function () {
      var title
        , $e = this.$element
        , o = this.options

      title = $e.attr('data-original-title')
        || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)
      return title
    }

  , tip: function () {
      return this.$tip = this.$tip || $(this.options.template)
    }

  , arrow: function(){
      return this.$arrow = this.$arrow || this.tip().find(".tooltip-arrow")
    }

  , validate: function () {
      if (!this.$element[0].parentNode) {
        this.hide()
        this.$element = null
        this.options = null
      }
    }

  , enable: function () {
      this.enabled = true
    }

  , disable: function () {
      this.enabled = false
    }

  , toggleEnabled: function () {
      this.enabled = !this.enabled
    }

  , toggle: function (e) {
      var self = e ? $(e.currentTarget)[this.type](this._options).data(this.type) : this
      self.tip().hasClass('in') ? self.hide() : self.show()
    }

  , destroy: function () {
      this.hide().$element.off('.' + this.type).removeData(this.type)
    }

  }

 /* TOOLTIP PLUGIN DEFINITION
  * ========================= */

  var old = $.fn.tooltip

  $.fn.tooltip = function ( option ) {

    return this.each(function () {
      var $this = $(this)
        , data = $this.data('tooltip')
        , options = typeof option == 'object' && option
      if (!data) $this.data('tooltip', (data = new Tooltip(this, options)))
      if (typeof option == 'string') data[option]()
    })
  }

  $.fn.tooltip.Constructor = Tooltip

  $.fn.tooltip.defaults = {
    animation: true
  , type: 'default'   //tip 类型 {string} 'default'|'attention'|'confirm' ,区别见demo
  , placement: 'top'
  , selector: false  //通常要配合调用方法使用，如果tooltip元素很多，用此途径进行事件委托减少事件监听数量: $('body').tooltip({selector: '.tips'})
  , trigger: 'hover focus'   //触发方式，多选：click hover focus，如果希望手动触发，则传入'manual'
  , title: 'it is default title'  //默认tooltip的内容，如果给html元素添加了title属性则使用该html属性替代此属性
  , delay: {show:0, hide: 200}   //如果只传number，则show、hide时都会使用这个延时，若想差异化则传入形如{show:400, hide: 600} 的对象   注：delay参数对manual触发方式的tooltip无效
  , html: true  //决定是html()还是text()
  , container: false  //将tooltip与输入框组一同使用时，为了避免不必要的影响，需要设置container.他用来将tooltip的dom节点插入到container指定的元素内的最后，可理解为 container.append(tooltipDom)。
  , widthlimit: true  // {Boolean|string} tooltip元素最大宽度限制，false不限宽，true限宽300px，也可传入"500px",人工限制宽度
  }

 /* TOOLTIP NO CONFLICT
  * =================== */

  $.fn.tooltip.noConflict = function () {
    $.fn.tooltip = old
    return this
  }

  //document ready init
  $(function(){
    $('[data-toggle="tooltip"]').tooltip()

    //点击外部可消失tooltip
    $(document).on('mousedown', function(e){
      var tgt = $(e.target)
        , tip = $('.sui-tooltip')
        , switchTgt = tip.prev()
        , tipContainer = tgt.parents('.sui-tooltip')
      if (tip.length && !tipContainer.length && tgt[0] != switchTgt[0]) {
        switchTgt.trigger('click.tooltip')
      }
    })

  })

}(window.jQuery);
<commit_msg>tooltip in ie8 cancel animation<commit_after>/* ===========================================================
 * bootstrap-tooltip.js v2.3.2
 * http://getbootstrap.com/2.3.2/javascript.html#tooltips
 * Inspired by the original jQuery.tipsy by Jason Frame
 * ===========================================================
 * Copyright 2013 Twitter, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * ========================================================== */

!function ($) {

  "use strict";

 /* TOOLTIP PUBLIC CLASS DEFINITION
  * =============================== */

  //element为触发元素，如标识文字链
  var Tooltip = function (element, options) {
    this.init('tooltip', element, options)
  }

  Tooltip.prototype = {

    constructor: Tooltip

  , init: function (type, element, options) {
      var eventIn
        , eventOut
        , triggers
        , trigger
        , i

      this.type = type
      this.$element = $(element)
      this.options = this.getOptions(options)
      this.enabled = true
      this.hoverState = 'out'

      triggers = this.options.trigger.split(' ')

      for (i = triggers.length; i--;) {
        trigger = triggers[i]
        if (trigger == 'click') {
          this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))

        } else if (trigger != 'manual') {
          eventIn = trigger == 'hover' ? 'mouseenter' : 'focus'
          eventOut = trigger == 'hover' ? 'mouseleave' : 'blur'
          this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
          this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
        }
      }

      //为confirm类型tooltip增加取消按钮设置默认逻辑
      if (this.options.type == 'confirm') {
        this.$element.parent().on('click', '[data-dismiss=tooltip]', function(e){
          $(this).parents('.sui-tooltip').prev().trigger('click')
        })
        this.$element.parent().on('click', '[data-ok=tooltip]', $.proxy(this.options.okHide, this))

      }

      this.options.selector ?
        (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
        this.fixTitle()
    }

  , getOptions: function (options) {
      options = $.extend({}, $.fn[this.type].defaults, this.$element.data(), options)

      var foot = options.type == 'confirm' ? '
<button class="sui-btn btn-primary" data-ok="tooltip">确定</button><button class="sui-btn btn-default" data-dismiss="tooltip">取消</button>
' : ''
      //根据tooltip的type类型构造tip模版
      options.template = '

' + foot + '
'
      options.type == 'confirm' && (options.html = true)

      if (options.delay && typeof options.delay == 'number') {
        options.delay = {
          show: options.delay
        , hide: options.delay
        }
      }

      return options
    }

  , enter: function (e) {
      var defaults = $.fn[this.type].defaults
        , options = {}
        , self

      this._options && $.each(this._options, function (key, value) {
        if (defaults[key] != value) options[key] = value
      }, this)

      self = $(e.currentTarget)[this.type](options).data(this.type)

      clearTimeout(this.timeout)
      if (this.hoverState == 'out') {
        this.hoverState = 'in'
        this.tip().off($.support.transition && $.support.transition.end)
        if (!this.options.delay || !this.options.delay.show) return this.show()
        this.timeout = setTimeout(function() {
          if (self.hoverState == 'in') self.show()
        }, self.options.delay.show)
      }
    }

  , leave: function (e) {
      var self = $(e.currentTarget)[this.type](this._options).data(this.type)
      if (this.timeout) clearTimeout(this.timeout)
      if (!self.options.delay || !self.options.delay.hide) return self.hide()

      this.timeout = setTimeout(function() {
        //isHover 为0或undefined，undefined:没有移到tip上过
        if (!self.isTipHover) {
          self.hoverState = 'out'
        }
        if (self.hoverState == 'out') self.hide()
      }, self.options.delay.hide)
    }

  , show: function () {
      var $tip
        , pos
        , actualWidth
        , actualHeight
        , placement
        , tp
        , e = $.Event('show')
        , opt = this.options
        , widthLimit = opt.widthlimit
        , self = this

      if (this.hasContent() && this.enabled) {
        this.$element.trigger(e)
        if (e.isDefaultPrevented()) return
        $tip = this.tip()
        this.setContent()

        if (opt.animation) {
          $tip.addClass('fade')
        }

        placement = typeof opt.placement == 'function' ?
          opt.placement.call(this, $tip[0], this.$element[0]) :
          opt.placement

        $tip
          .detach()
          .css({ top: 0, left: 0, display: 'block' })

        opt.container ? $tip.appendTo(opt.container) : $tip.insertAfter(this.$element)
        if (opt.trigger !== 'click') {
          $tip.hover(function(){
            self.isTipHover = 1;
          }, function(){
            self.isTipHover = 0;
            self.hide()
          })
        }

        //宽度限制逻辑
        if (widthLimit !== true) {
          var val
          widthLimit === false && (val = 'none')
          typeof opt.widthlimit == 'string' && (val = widthLimit)
          $tip.css('max-width', val)
        }
        pos = this.getPosition()

        actualWidth = $tip[0].offsetWidth
        actualHeight = $tip[0].offsetHeight

        //+ - 7修正，和css对应，勿单独修改
        var d = opt.type == 'attention' ? 5 : 7
        switch (placement) {
          case 'bottom':
            tp = {top: pos.top + pos.height + d, left: pos.left + pos.width / 2 - actualWidth / 2}
            break
          case 'top':
            tp = {top: pos.top - actualHeight - d, left: pos.left + pos.width / 2 - actualWidth / 2}
            break
          case 'left':
            tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth - d}
            break
          case 'right':
            tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width + d}
            break
        }

        this.applyPlacement(tp, placement)
        this.$element.trigger('shown')
      }
    }

  , applyPlacement: function(offset, placement){
      var $tip = this.tip()
        , width = $tip[0].offsetWidth
        , height = $tip[0].offsetHeight
        , actualWidth
        , actualHeight
        , delta
        , replace

      $tip
        .offset(offset)
        .addClass(placement)
        .addClass('in')

      actualWidth = $tip[0].offsetWidth
      actualHeight = $tip[0].offsetHeight

      if (placement == 'top' && actualHeight != height) {
        offset.top = offset.top + height - actualHeight
        replace = true
      }

      if (placement == 'bottom' || placement == 'top') {
        delta = 0

        if (offset.left < 0){
          delta = offset.left * -2
          offset.left = 0
          $tip.offset(offset)
          actualWidth = $tip[0].offsetWidth
          actualHeight = $tip[0].offsetHeight
        }

        this.replaceArrow(delta - width + actualWidth, actualWidth, 'left')
      } else {
        this.replaceArrow(actualHeight - height, actualHeight, 'top')
      }

      if (replace) $tip.offset(offset)
    }

  , replaceArrow: function(delta, dimension, position){
      this
        .arrow()
        .css(position, delta ? (50 * (1 - delta / dimension) + "%") : '')
    }

  , setContent: function () {
      var $tip = this.tip()
        , title = this.getTitle()

      $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
      $tip.removeClass('fade in top bottom left right')
    }

  , hide: function () {
      var $tip = this.tip()
        , e = $.Event('hide')
        , self = this

      this.$element.trigger(e)
      if (e.isDefaultPrevented()) return

      $tip.removeClass('in')

      function removeWithAnimation() {
        self.timeout = setTimeout(function () {
          $tip.off($.support.transition.end).detach()
        }, 500)

        $tip.one($.support.transition.end, function () {
          clearTimeout(self.timeout)
          $tip.detach()
        })
      }

      $.support.transition && this.$tip.hasClass('fade') ?
        removeWithAnimation() :
        ($tip.detach())
      this.$element.trigger('hidden')

      return this
    }

  , fixTitle: function () {
      var $e = this.$element
      if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
        $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
      }
    }

  , hasContent: function () {
      return this.getTitle()
    }

  , getPosition: function () {
      var el = this.$element[0]
      return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : {
        width: el.offsetWidth
      , height: el.offsetHeight
      }, this.$element.offset())
    }

  , getTitle: function () {
      var title
        , $e = this.$element
        , o = this.options

      title = $e.attr('data-original-title')
        || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)
      return title
    }

  , tip: function () {
      return this.$tip = this.$tip || $(this.options.template)
    }

  , arrow: function(){
      return this.$arrow = this.$arrow || this.tip().find(".tooltip-arrow")
    }

  , validate: function () {
      if (!this.$element[0].parentNode) {
        this.hide()
        this.$element = null
        this.options = null
      }
    }

  , enable: function () {
      this.enabled = true
    }

  , disable: function () {
      this.enabled = false
    }

  , toggleEnabled: function () {
      this.enabled = !this.enabled
    }

  , toggle: function (e) {
      var self = e ? $(e.currentTarget)[this.type](this._options).data(this.type) : this
      self.tip().hasClass('in') ? self.hide() : self.show()
    }

  , destroy: function () {
      this.hide().$element.off('.' + this.type).removeData(this.type)
    }

  }

 /* TOOLTIP PLUGIN DEFINITION
  * ========================= */

  var old = $.fn.tooltip

  $.fn.tooltip = function ( option ) {

    return this.each(function () {
      var $this = $(this)
        , data = $this.data('tooltip')
        , options = typeof option == 'object' && option
      if (!data) $this.data('tooltip', (data = new Tooltip(this, options)))
      if (typeof option == 'string') data[option]()
    })
  }

  $.fn.tooltip.Constructor = Tooltip

  $.fn.tooltip.defaults = {
    animation: true
  , type: 'default'   //tip 类型 {string} 'default'|'attention'|'confirm' ,区别见demo
  , placement: 'top'
  , selector: false  //通常要配合调用方法使用，如果tooltip元素很多，用此途径进行事件委托减少事件监听数量: $('body').tooltip({selector: '.tips'})
  , trigger: 'hover focus'   //触发方式，多选：click hover focus，如果希望手动触发，则传入'manual'
  , title: 'it is default title'  //默认tooltip的内容，如果给html元素添加了title属性则使用该html属性替代此属性
  , delay: {show:0, hide: 200}   //如果只传number，则show、hide时都会使用这个延时，若想差异化则传入形如{show:400, hide: 600} 的对象   注：delay参数对manual触发方式的tooltip无效
  , html: true  //决定是html()还是text()
  , container: false  //将tooltip与输入框组一同使用时，为了避免不必要的影响，需要设置container.他用来将tooltip的dom节点插入到container指定的元素内的最后，可理解为 container.append(tooltipDom)。
  , widthlimit: true  // {Boolean|string} tooltip元素最大宽度限制，false不限宽，true限宽300px，也可传入"500px",人工限制宽度
  }

 /* TOOLTIP NO CONFLICT
  * =================== */

  $.fn.tooltip.noConflict = function () {
    $.fn.tooltip = old
    return this
  }

  //document ready init
  $(function(){
    $('[data-toggle="tooltip"]').tooltip()

    //点击外部可消失tooltip
    $(document).on('mousedown', function(e){
      var tgt = $(e.target)
        , tip = $('.sui-tooltip')
        , switchTgt = tip.prev()
        , tipContainer = tgt.parents('.sui-tooltip')
      if (tip.length && !tipContainer.length && tgt[0] != switchTgt[0]) {
        switchTgt.trigger('click.tooltip')
      }
    })

  })

}(window.jQuery);
<|endoftext|>


<commit_before>
let zip = [];
let completezip = [];
let errorzip = [];
let all_url_stack = "";//lock
let datalockcount = 0;
const subDomainList = ["la","aa","ba"];
const callPerServer = 2;
const download_array = [];

let a = "";
a.on
download_array[0] = function download_html(zipnumber , passlockcount) {
    download_hitomi_html(zipnumber , passlockcount);
}

download_array[1] = function download_hitomi_js(zipnumber , passlockcount ) {
    $.ajax({
        url: 'http://localhost:443/https://hitomi.la/galleries/'+ zip[zipnumber].filenumber +'.js',
        //async:false,
        success: function() {
            $.each(galleryinfo, function(i, image) {
                zip[zipnumber].pushimageurl(url_from_url(zip[zipnumber].filenumber + "/" +image.name , i));
                zip[zipnumber].pushimagename(image.name);
            });
            returnlock(passlockcount).then(isworking() , thenerror());

        },
        error: function() {
            zip[zipnumber].imageurl = ["error"];
            zip[zipnumber].imagename = ["error"];
            returnlock(passlockcount).then(isworking() , thenerror());
        }
    });
}

class zipmember{
    constructor()
    {
        this.filename = "";//for save file
        this.fileurl = "";//for save original url
        this.filenumber = "";//for download
        this.imagename = [];//for save imagefile
        this.imageurl = [];//for download
        this.jszip = new JSZip();
        this.threadcount = 0;
    }

    get filename() {return this._filename; }
    get fileurl() {return this._fileurl; }
    get filenumber() {return this._filenumber; }
    get imagename() {return this._imagename; }
    get imageurl() {return this._imageurl; }
    get jszip() {return this._jszip; }
    get threadcount() {return this._threadcount; }

    set filename(stri) {this._filename = stri; }
    set fileurl(stri) {this._fileurl = stri; this.setfilenumber(stri);}
    set filenumber(stri) { }
    set imagename(arra) { if(Array.isArray(arra)){this._imagename = arra;} }
    set imageurl(arra) {if(Array.isArray(arra)){this._imageurl = arra;}}
    set jszip(jszi) {this._jszip = jszi;}//need block if not JSzip
    set threadcount(inte) {this._threadcount = inte; }

    pushimagename(stri){
        this._imagename.push(stri);
    };
    pushimageurl(stri){
        this._imageurl.push(stri);
    };
    unlockthread(){
        this._threadcount = this._threadcount -1;
    };
    setfilenumber(inputurl){
        let urltext = inputurl.split("/");
        let linkid = "";
        if(urltext[0] == "e-hentai.org" || urltext[0] == "exhentai.org") {
            if(urltext[1] == "g") {
                linkid = urltext[urltext.length-3];
            }
            else if(urltext == "s") {
                linkid = urltext[urltext.length-1].split("-")[0];
            }
        }
        else if(urltext[0] == "hitomi.la"){
            linkid = urltext[urltext.length-1].split(".")[0];
        }
        else{
            linkid = "error";
        }
        this._filenumber = linkid;
    }
}

function  initzipnumber(zipnumber) {
    zip[zipnumber] = new zipmember();
}

$(document).ready(function() {
    $('#getData').click(function () {
        if (datalockcount == 0 && zip.length == 0) {
            //need disable button
            printwithTime("start------------");
            download_get(all_url_stack + $('#input_url').val(), $('#input_fileName').val());
            all_url_stack = "";
        }
        else {
            all_url_stack = all_url_stack + $('#input_url').val() , $('#input_fileName').val();
            printwithTime("ready for add download url-----------");
        }
    });
});

function download_get(galleryhtml) {
        let inputurl = galleryhtml.split("https://");
        inputurl.shift();
        getfiledata(inputurl);
}

function getfiledata(inputurl){
    let linkid = 0;
    let pushnumber = zip.length;
    let inputurllength = inputurl.length;
    let passlockcount = datalockcount;
    let download_arraylength = download_array.length;

    setthreadlock(inputurllength * download_arraylength);

    for(let zipnumber = 0; zipnumber < inputurllength ; zipnumber++) {
        initzipnumber(zipnumber+ pushnumber);

        zip[zipnumber+ pushnumber].fileurl = inputurl[zipnumber];

        for(let i = 0 ; i < download_arraylength ; i++)
        {
            download_array[i](zipnumber+ pushnumber , passlockcount);
        }
    }
}

function setthreadlock(number) {
    datalockcount = datalockcount + number;
    return new Promise(function (resolve, reject) {
        if (datalockcount >= 0) {
            resolve();
        }
        else {
            reject();
        }
    });
};

function returnlock(passlockcount) {
    datalockcount = datalockcount -1;
    return new Promise(function (resolve, reject) {
        if (  !  (datalockcount < passlockcount)) {
            resolve();
        }
        else {
            reject();
        }
    });
}

function download_html(zipnumber , passlockcount) {
    download_hitomi_html(zipnumber , passlockcount);
}

function download_hitomi_html(zipnumber , passlockcount)
{
        $.ajax({
            url: 'http://localhost:443/https://hitomi.la/galleries/' + zip[zipnumber].filenumber + '.html',
            //async:false,
            success: function (data) {
                let text1 = textsplit(data , "-gallery" , "gallery-info");

                let datatext = textsplit(text1 , "h1>" , "</h1");
                datatext = textsplit(datatext , ".html\">" , "</a");

                let creatertext = textsplit(text1 , "h2>" , "</h2");
                creatertext = textsplit(creatertext , ".html\">" , "</a");

                if(datatext == ""){
                    datatext = zip[zipnumber].filenumber ;
                }

                if(creatertext == ""){
                    creatertext = "N_A";
                }

                zip[zipnumber].filename = creatertext + "__" + datatext;
                returnlock(passlockcount).then(isworking() , thenerror());
            },
            error: function() {
                zip[zipnumber].filename = zip[zipnumber].filenumber;
                returnlock(passlockcount).then(isworking() , thenerror());
            }
        });
}

function textsplit(data , sp1 , sp2)
{
    if(data.indexOf(sp1) != -1 && data.indexOf(sp2) != -1){
        let text = data.split(sp1)[1].split(sp2)[0];
        return text;
    }
    else{
        return "";
    }
}

function download_hitomi_js(zipnumber , passlockcount ) {
    $.ajax({
        url: 'http://localhost:443/https://hitomi.la/galleries/'+ zip[zipnumber][1] +'.js',
        //async:false,
        success: function() {
            $.each(galleryinfo, function(i, image) {
                zip[zipnumber].pushimageurl(url_from_url(zip[zipnumber].filenumber + "/" +image.name , i));
                zip[zipnumber].pushimagename(image.name);
                //zip[zipnumber].lockthread(); i try set thread lock here. but fail. why?
            });
            returnlock(passlockcount).then(isworking() , thenerror());

        },
        error: function() {
            //zip[zipnumber].pushimageurl(url_from_url(zip[zipnumber].filenumber + "/" +image.name , i));
            //zip[zipnumber].pushimagename(image.name);
            zip[zipnumber].threadcount = 0;//is this really work?
            returnlock(passlockcount).then(isworking() , thenerror());
        }
    });
}

function url_from_url(url , i) {
    return "http://localhost:443/https://" + subdomain_from_url(i) + ".hitomi.la/galleries/"+ url;
}

function subdomain_from_url(i) {
    let retval = subDomainList[i%subDomainList.length];
    return retval;
}

function isworking()
{
    if(all_url_stack != "")
    {
        download_get(all_url_stack);
        all_url_stack = "";
    }
    else if(datalockcount == 0 && (zip.length > 0))
    {
        if(zip[0].imageurl[0] == "error")
        {
            errorzip.push(zip.shift());
            isworking();
        }
        else
        {
            getimagedata(0);
        }
    }
    else if(datalockcount == 0 && zip.length == 0 )
    {
        printwithTime("finish------");
    }
    else if(datalockcount > 0 && zip.length > 0)
    {

    }
    else
    {
        printwithTime("error in isworking - " + zip[0].fileurl + "\ndatalockcount = " + datalockcount + "\nzip.length = " + zip.length);
    }
}

function getimagedata(zipnumber) {
    let imageurllength = zip[zipnumber].imageurl.length -1;
    zip[zipnumber]._threadcount = imageurllength +1;
    let maxthread = subDomainList.length * callPerServer;
    for(let i = 0 ; (i < subDomainList.length * callPerServer) && (i < imageurllength) ; i ++){
        download_next_image(imageurllength -i, zipnumber , maxthread);
    }
}

function download_next_image(index , zipnumber , maxthread) {
    if(index >= 0)
    {
        ajax_download_blob(index, zipnumber , 0 , maxthread);
    }
}

function ajax_download_blob(index, zipnumber , count , maxthread) {
    let xhr = new XMLHttpRequest();

    xhr.onreadystatechange = function() {
        if(this.readyState == 4) {
            if( this.status == 200 || this.status == 304) {
                image_downloaded(this.response , index, zipnumber , maxthread);
            }

            else {
                if(count < 10) {
                    ajax_download_blob(index, zipnumber, count + 1);
                }
                else {
                    alert("error on picture number" + index +"-- error " + this.status);
                    //need whar file
                }
            }
        }
    }
    xhr.open('GET', zip[zipnumber].imageurl[index]);
    xhr.responseType = 'arraybuffer';
    xhr.send();
}

function image_downloaded(imgData , index, zipnumber , maxthread) {
    zip[zipnumber].jszip.file(zip[zipnumber].imagename[index], imgData, {base64: true});
    zip[zipnumber].unlockthread();
        // > maybe wrong
    if (zip[zipnumber].threadcount == 0) {// need check error when threadcount < 0 ;
        let content = zip[zipnumber].jszip.generateAsync({type:"blob"})
        .then(function (blob) {
            saveAs(blob, zip[zipnumber].filename+".zip")
                .then(nextcontent(blob , zipnumber) , thenerror());
        }  , thenerror());
    }
    else{
        download_next_image(index - maxthread , zipnumber , maxthread);
    }
}

function thenerror(){}

function nextcontent(blob , zipnumber){
    var completeziplength = completezip.length
    completezip.push(zip.shift());
    //completezip[completeziplength].jszip = "";
    //completezip[completeziplength].imageurl = [""];
    //completezip[completeziplength].imagename = [""];
    printwithTime(completezip[completeziplength].filename+".zip finish");
    //blob.close();
    isworking()
}

function printwithTime(str) {
    $('#finished_list').val( new Date().toLocaleTimeString() + ":\n " + str + "\n\n" + $('#finished_list').val());
}

<commit_msg>Remove // for free memory<commit_after>
let zip = [];
let completezip = [];
let errorzip = [];
let all_url_stack = "";//lock
let datalockcount = 0;
const subDomainList = ["la","aa","ba"];
const callPerServer = 2;
const download_array = [];

let a = "";
a.on
download_array[0] = function download_html(zipnumber , passlockcount) {
    download_hitomi_html(zipnumber , passlockcount);
}

download_array[1] = function download_hitomi_js(zipnumber , passlockcount ) {
    $.ajax({
        url: 'http://localhost:443/https://hitomi.la/galleries/'+ zip[zipnumber].filenumber +'.js',
        //async:false,
        success: function() {
            $.each(galleryinfo, function(i, image) {
                zip[zipnumber].pushimageurl(url_from_url(zip[zipnumber].filenumber + "/" +image.name , i));
                zip[zipnumber].pushimagename(image.name);
            });
            returnlock(passlockcount).then(isworking() , thenerror());

        },
        error: function() {
            zip[zipnumber].imageurl = ["error"];
            zip[zipnumber].imagename = ["error"];
            returnlock(passlockcount).then(isworking() , thenerror());
        }
    });
}

class zipmember{
    constructor()
    {
        this.filename = "";//for save file
        this.fileurl = "";//for save original url
        this.filenumber = "";//for download
        this.imagename = [];//for save imagefile
        this.imageurl = [];//for download
        this.jszip = new JSZip();
        this.threadcount = 0;
    }

    get filename() {return this._filename; }
    get fileurl() {return this._fileurl; }
    get filenumber() {return this._filenumber; }
    get imagename() {return this._imagename; }
    get imageurl() {return this._imageurl; }
    get jszip() {return this._jszip; }
    get threadcount() {return this._threadcount; }

    set filename(stri) {this._filename = stri; }
    set fileurl(stri) {this._fileurl = stri; this.setfilenumber(stri);}
    set filenumber(stri) { }
    set imagename(arra) { if(Array.isArray(arra)){this._imagename = arra;} }
    set imageurl(arra) {if(Array.isArray(arra)){this._imageurl = arra;}}
    set jszip(jszi) {this._jszip = jszi;}//need block if not JSzip
    set threadcount(inte) {this._threadcount = inte; }

    pushimagename(stri){
        this._imagename.push(stri);
    };
    pushimageurl(stri){
        this._imageurl.push(stri);
    };
    unlockthread(){
        this._threadcount = this._threadcount -1;
    };
    setfilenumber(inputurl){
        let urltext = inputurl.split("/");
        let linkid = "";
        if(urltext[0] == "e-hentai.org" || urltext[0] == "exhentai.org") {
            if(urltext[1] == "g") {
                linkid = urltext[urltext.length-3];
            }
            else if(urltext == "s") {
                linkid = urltext[urltext.length-1].split("-")[0];
            }
        }
        else if(urltext[0] == "hitomi.la"){
            linkid = urltext[urltext.length-1].split(".")[0];
        }
        else{
            linkid = "error";
        }
        this._filenumber = linkid;
    }
}

function  initzipnumber(zipnumber) {
    zip[zipnumber] = new zipmember();
}

$(document).ready(function() {
    $('#getData').click(function () {
        if (datalockcount == 0 && zip.length == 0) {
            //need disable button
            printwithTime("start------------");
            download_get(all_url_stack + $('#input_url').val(), $('#input_fileName').val());
            all_url_stack = "";
        }
        else {
            all_url_stack = all_url_stack + $('#input_url').val() , $('#input_fileName').val();
            printwithTime("ready for add download url-----------");
        }
    });
});

function download_get(galleryhtml) {
        let inputurl = galleryhtml.split("https://");
        inputurl.shift();
        getfiledata(inputurl);
}

function getfiledata(inputurl){
    let linkid = 0;
    let pushnumber = zip.length;
    let inputurllength = inputurl.length;
    let passlockcount = datalockcount;
    let download_arraylength = download_array.length;

    setthreadlock(inputurllength * download_arraylength);

    for(let zipnumber = 0; zipnumber < inputurllength ; zipnumber++) {
        initzipnumber(zipnumber+ pushnumber);

        zip[zipnumber+ pushnumber].fileurl = inputurl[zipnumber];

        for(let i = 0 ; i < download_arraylength ; i++)
        {
            download_array[i](zipnumber+ pushnumber , passlockcount);
        }
    }
}

function setthreadlock(number) {
    datalockcount = datalockcount + number;
    return new Promise(function (resolve, reject) {
        if (datalockcount >= 0) {
            resolve();
        }
        else {
            reject();
        }
    });
};

function returnlock(passlockcount) {
    datalockcount = datalockcount -1;
    return new Promise(function (resolve, reject) {
        if (  !  (datalockcount < passlockcount)) {
            resolve();
        }
        else {
            reject();
        }
    });
}

function download_html(zipnumber , passlockcount) {
    download_hitomi_html(zipnumber , passlockcount);
}

function download_hitomi_html(zipnumber , passlockcount)
{
        $.ajax({
            url: 'http://localhost:443/https://hitomi.la/galleries/' + zip[zipnumber].filenumber + '.html',
            //async:false,
            success: function (data) {
                let text1 = textsplit(data , "-gallery" , "gallery-info");

                let datatext = textsplit(text1 , "h1>" , "</h1");
                datatext = textsplit(datatext , ".html\">" , "</a");

                let creatertext = textsplit(text1 , "h2>" , "</h2");
                creatertext = textsplit(creatertext , ".html\">" , "</a");

                if(datatext == ""){
                    datatext = zip[zipnumber].filenumber ;
                }

                if(creatertext == ""){
                    creatertext = "N_A";
                }

                zip[zipnumber].filename = creatertext + "__" + datatext;
                returnlock(passlockcount).then(isworking() , thenerror());
            },
            error: function() {
                zip[zipnumber].filename = zip[zipnumber].filenumber;
                returnlock(passlockcount).then(isworking() , thenerror());
            }
        });
}

function textsplit(data , sp1 , sp2)
{
    if(data.indexOf(sp1) != -1 && data.indexOf(sp2) != -1){
        let text = data.split(sp1)[1].split(sp2)[0];
        return text;
    }
    else{
        return "";
    }
}

function download_hitomi_js(zipnumber , passlockcount ) {
    $.ajax({
        url: 'http://localhost:443/https://hitomi.la/galleries/'+ zip[zipnumber][1] +'.js',
        //async:false,
        success: function() {
            $.each(galleryinfo, function(i, image) {
                zip[zipnumber].pushimageurl(url_from_url(zip[zipnumber].filenumber + "/" +image.name , i));
                zip[zipnumber].pushimagename(image.name);
                //zip[zipnumber].lockthread(); i try set thread lock here. but fail. why?
            });
            returnlock(passlockcount).then(isworking() , thenerror());

        },
        error: function() {
            //zip[zipnumber].pushimageurl(url_from_url(zip[zipnumber].filenumber + "/" +image.name , i));
            //zip[zipnumber].pushimagename(image.name);
            zip[zipnumber].threadcount = 0;//is this really work?
            returnlock(passlockcount).then(isworking() , thenerror());
        }
    });
}

function url_from_url(url , i) {
    return "http://localhost:443/https://" + subdomain_from_url(i) + ".hitomi.la/galleries/"+ url;
}

function subdomain_from_url(i) {
    let retval = subDomainList[i%subDomainList.length];
    return retval;
}

function isworking()
{
    if(all_url_stack != "")
    {
        download_get(all_url_stack);
        all_url_stack = "";
    }
    else if(datalockcount == 0 && (zip.length > 0))
    {
        if(zip[0].imageurl[0] == "error")
        {
            errorzip.push(zip.shift());
            isworking();
        }
        else
        {
            getimagedata(0);
        }
    }
    else if(datalockcount == 0 && zip.length == 0 )
    {
        printwithTime("finish------");
    }
    else if(datalockcount > 0 && zip.length > 0)
    {

    }
    else
    {
        printwithTime("error in isworking - " + zip[0].fileurl + "\ndatalockcount = " + datalockcount + "\nzip.length = " + zip.length);
    }
}

function getimagedata(zipnumber) {
    let imageurllength = zip[zipnumber].imageurl.length -1;
    zip[zipnumber]._threadcount = imageurllength +1;
    let maxthread = subDomainList.length * callPerServer;
    for(let i = 0 ; (i < subDomainList.length * callPerServer) && (i < imageurllength) ; i ++){
        download_next_image(imageurllength -i, zipnumber , maxthread);
    }
}

function download_next_image(index , zipnumber , maxthread) {
    if(index >= 0)
    {
        ajax_download_blob(index, zipnumber , 0 , maxthread);
    }
}

function ajax_download_blob(index, zipnumber , count , maxthread) {
    let xhr = new XMLHttpRequest();

    xhr.onreadystatechange = function() {
        if(this.readyState == 4) {
            if( this.status == 200 || this.status == 304) {
                image_downloaded(this.response , index, zipnumber , maxthread);
            }

            else {
                if(count < 10) {
                    ajax_download_blob(index, zipnumber, count + 1);
                }
                else {
                    alert("error on picture number" + index +"-- error " + this.status);
                    //need whar file
                }
            }
        }
    }
    xhr.open('GET', zip[zipnumber].imageurl[index]);
    xhr.responseType = 'arraybuffer';
    xhr.send();
}

function image_downloaded(imgData , index, zipnumber , maxthread) {
    zip[zipnumber].jszip.file(zip[zipnumber].imagename[index], imgData, {base64: true});
    zip[zipnumber].unlockthread();
        // > maybe wrong
    if (zip[zipnumber].threadcount == 0) {// need check error when threadcount < 0 ;
        let content = zip[zipnumber].jszip.generateAsync({type:"blob"})
        .then(function (blob) {
            saveAs(blob, zip[zipnumber].filename+".zip")
                .then(nextcontent(blob , zipnumber) , thenerror());
        }  , thenerror());
    }
    else{
        download_next_image(index - maxthread , zipnumber , maxthread);
    }
}

function thenerror(){}

function nextcontent(blob , zipnumber){
    var completeziplength = completezip.length
    completezip.push(zip.shift());
    completezip[completeziplength].jszip = "";
    completezip[completeziplength].imageurl = [""];
    completezip[completeziplength].imagename = [""];
    printwithTime(completezip[completeziplength].filename+".zip finish");
    //blob.close();
    isworking()
}

function printwithTime(str) {
    $('#finished_list').val( new Date().toLocaleTimeString() + ":\n " + str + "\n\n" + $('#finished_list').val());
}

<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
*/

var KEY_FIRST_NAME = "firstName";
var KEY_LAST_NAME = "lastName";
var KEY_ADDRESS = "address";
var KEY_CITY = "city";
var KEY_STATE = "state";
var KEY_COUNTRY = "country";
var KEY_POSTAL_CODE = "postalCode";
var KEY_GENDER = "gender";
var KEY_EMAIL = "email";
var KEY_TWITTER = "twitterId";
var KEY_FACEBOOK = "facebookId";
var KEY_LINKEDIN = "linkedinId";
var KEY_LEAD_SOURCE = "leadSource";
var KEY_BIRTHDAY = "dateOfBirth";
var KEY_FACEBOOK_PROFILE_URL = "facebookProfileURL";
var KEY_FACEBOOK_PROFILE_PIC = "facebookPhotoURL";

var marketo = {
  /**
   * Call this method when user wants to initialize marketo application
   * Action name should be
   *
   * @param success the message if successful
   * @param fail the message if the action fails
   * @param secret_key provided by Marketo
   * @param muchkin_id provided by Marketo
   */
    initialize: function (success, fail, muchkin_id, secret_key) {
        return cordova.exec( success, fail,
            "MarketoPlugin",
            "initialize", [muchkin_id, secret_key]);
    },

    /**
     * Call this method when user wants to add support to the push notification
     *
     * @param success the message if successful
     * @param fail the message if the action fails
     * @param project_id represents the applications Google Developers Console's project id
     */
    initializeMarketoPush: function (success, fail, project_id) {
        return cordova.exec( success, fail,
            "MarketoPlugin",
            "initializeMarketoPush", [project_id]);
    },

    /**
     * Call this method when user wants to create a lead.
     *
     * @param success the message if successful
     * @param fail the message if the action fails
     * @param lead_data represents the lead data in Json format
     */
    associateLead: function (success, fail, lead_data) {
        return cordova.exec( success, fail,
            "MarketoPlugin",
            "associateLead", [lead_data]);
    },

    /**
     * Call this method when user wants to log users activity in his application.
     *
     * @param success the message if successful
     * @param fail the message if the action fails
     */
    onStop: function (success, fail) {
        return cordova.exec( success, fail,
            "MarketoPlugin",
            "onStop", []);
    },

    /**
     *  Call this method when user wants to log users activity in his application.
     *
     * @param success the message if successful
     * @param fail the message if the action fails
     */
    onStart: function (success, fail) {
        return cordova.exec( success, fail,
            "MarketoPlugin",
            "onStart", []);
    },

    /**
     * Call this method when user hits the reportAction .
     * Action name should be
     *
     * @param success the message if successful
     * @param fail the message if the action fails
     * @param action represents the action name in string format
     * @param action_metadata represents the actions data in Json format.
     */
    reportaction: function (success, fail, reportAction, action_metadata) {
        return cordova.exec( success, fail,
            "MarketoPlugin",
            "reportaction", [reportAction, action_metadata]);
    },

    /**
     * Call this method when user wants to remove secure signature
     *
     * @param success the message if successful
     * @param fail the message if the action fails
     */
    removeSecureSignature: function (success, fail) {
        return cordova.exec( success, fail,
            "MarketoPlugin",
            "removeSecureSignature", []);
    },

    /**
     * Call this method when user wants to set the request's timeout
     *
     * @param success the message if successful
     * @param fail the message if the action fails
     * @param secureMode represents the secure signature information in Json format
     */
     setSecureSignature: function (success, fail, accessKey, signature, email, timestamp) {
      return cordova.exec(success, fail,
        "MarketoPlugin",
        "setSecureSignature", [accessKey, signature, email, timestamp]);
    },

    /**
     * Call this method when user wants to check the status of secure mode
     *
     * @param success contains the boolean flag to check whether secure mode is on or off.
     * @param fail the message if the action fails
     */
    isSecureModeEnabled: function (success, fail) {
     return cordova.exec(success, fail,
       "MarketoPlugin",
       "isSecureModeEnabled",[]);
   },

    /**
     * Helper method to get DeviceId.
     * @param success should be the function which takes device id as a parameter ex. function(deviceid){ ... }
     * @param fail the message if the action fails
     * @return This method will return device ID if the MarketoSDK is initialized, otherwise will return null
     */
     getDeviceId: function (success, fail) {
      return cordova.exec(success, fail,
        "MarketoPlugin",
        "getDeviceId", []);
     },

     /**
      * Helper method to set notification configeration.
      * @param success the message if successful
      * @param fail the message if the action fails
      * @param image path for large notification icon. Available only Android Honeycomb and Above
      * @param resourceName should be the name of the resource for the small notification icon
      */
      setNotificationConfig: function (success, fail, imagePath, resourceName) {
       return cordova.exec(success, fail,
         "MarketoPlugin",
         "setNotificationConfig", [imagePath, resourceName]);
      },

      /**
       * Helper method to get DeviceId.
       * @param success should be the function which takes JSONArray as a parameter ex. function(config){ ... }
       * @param fail the message if the action fails
       * @return This method will return the notification configerations
       */
       getNotificationConfig: function (success, fail) {
        return cordova.exec(success, fail,
          "MarketoPlugin",
          "getNotificationConfig", []);
       },

    /**
     * Call this method when user wants to set the request's timeout
     *
     * @param success the message if successful
     * @param fail the message if the action fails
     * @param timeout represents the time in integer.
     */
    settimeout: function (success, fail, timeout){
      return cordova.exec(success, fail,
        "MarketoPlugin",
        "settimeout", [timeout]);
    }
}
module.exports = marketo;
<commit_msg>Bug Fix<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
*/

var marketo = {
  'KEY_FIRST_NAME' = "firstName";
  'KEY_LAST_NAME' = "lastName";
  'KEY_ADDRESS' = "address";
  'KEY_CITY' = "city";
  'KEY_STATE' = "state";
  'KEY_COUNTRY' = "country";
  'KEY_POSTAL_CODE' = "postalCode";
  'KEY_GENDER' = "gender";
  'KEY_EMAIL' = "email";
  'KEY_TWITTER' = "twitterId";
  'KEY_FACEBOOK' = "facebookId";
  'KEY_LINKEDIN' = "linkedinId";
  'KEY_LEAD_SOURCE' = "leadSource";
  'KEY_BIRTHDAY' = "dateOfBirth";
  'KEY_FACEBOOK_PROFILE_URL' = "facebookProfileURL";
  'KEY_FACEBOOK_PROFILE_PIC' = "facebookPhotoURL";

  /**
   * Call this method when user wants to initialize marketo application
   * Action name should be
   *
   * @param success the message if successful
   * @param fail the message if the action fails
   * @param secret_key provided by Marketo
   * @param muchkin_id provided by Marketo
   */
    initialize: function (success, fail, muchkin_id, secret_key) {
        return cordova.exec( success, fail,
            "MarketoPlugin",
            "initialize", [muchkin_id, secret_key]);
    },

    /**
     * Call this method when user wants to add support to the push notification
     *
     * @param success the message if successful
     * @param fail the message if the action fails
     * @param project_id represents the applications Google Developers Console's project id
     */
    initializeMarketoPush: function (success, fail, project_id) {
        return cordova.exec( success, fail,
            "MarketoPlugin",
            "initializeMarketoPush", [project_id]);
    },

    /**
     * Call this method when user wants to create a lead.
     *
     * @param success the message if successful
     * @param fail the message if the action fails
     * @param lead_data represents the lead data in Json format
     */
    associateLead: function (success, fail, lead_data) {
        return cordova.exec( success, fail,
            "MarketoPlugin",
            "associateLead", [lead_data]);
    },

    /**
     * Call this method when user wants to log users activity in his application.
     *
     * @param success the message if successful
     * @param fail the message if the action fails
     */
    onStop: function (success, fail) {
        return cordova.exec( success, fail,
            "MarketoPlugin",
            "onStop", []);
    },

    /**
     *  Call this method when user wants to log users activity in his application.
     *
     * @param success the message if successful
     * @param fail the message if the action fails
     */
    onStart: function (success, fail) {
        return cordova.exec( success, fail,
            "MarketoPlugin",
            "onStart", []);
    },

    /**
     * Call this method when user hits the reportAction .
     * Action name should be
     *
     * @param success the message if successful
     * @param fail the message if the action fails
     * @param action represents the action name in string format
     * @param action_metadata represents the actions data in Json format.
     */
    reportaction: function (success, fail, reportAction, action_metadata) {
        return cordova.exec( success, fail,
            "MarketoPlugin",
            "reportaction", [reportAction, action_metadata]);
    },

    /**
     * Call this method when user wants to remove secure signature
     *
     * @param success the message if successful
     * @param fail the message if the action fails
     */
    removeSecureSignature: function (success, fail) {
        return cordova.exec( success, fail,
            "MarketoPlugin",
            "removeSecureSignature", []);
    },

    /**
     * Call this method when user wants to set the request's timeout
     *
     * @param success the message if successful
     * @param fail the message if the action fails
     * @param secureMode represents the secure signature information in Json format
     */
     setSecureSignature: function (success, fail, accessKey, signature, email, timestamp) {
      return cordova.exec(success, fail,
        "MarketoPlugin",
        "setSecureSignature", [accessKey, signature, email, timestamp]);
    },

    /**
     * Call this method when user wants to check the status of secure mode
     *
     * @param success contains the boolean flag to check whether secure mode is on or off.
     * @param fail the message if the action fails
     */
    isSecureModeEnabled: function (success, fail) {
     return cordova.exec(success, fail,
       "MarketoPlugin",
       "isSecureModeEnabled",[]);
   },

    /**
     * Helper method to get DeviceId.
     * @param success should be the function which takes device id as a parameter ex. function(deviceid){ ... }
     * @param fail the message if the action fails
     * @return This method will return device ID if the MarketoSDK is initialized, otherwise will return null
     */
     getDeviceId: function (success, fail) {
      return cordova.exec(success, fail,
        "MarketoPlugin",
        "getDeviceId", []);
     },

     /**
      * Helper method to set notification configeration.
      * @param success the message if successful
      * @param fail the message if the action fails
      * @param image path for large notification icon. Available only Android Honeycomb and Above
      * @param resourceName should be the name of the resource for the small notification icon
      */
      setNotificationConfig: function (success, fail, imagePath, resourceName) {
       return cordova.exec(success, fail,
         "MarketoPlugin",
         "setNotificationConfig", [imagePath, resourceName]);
      },

      /**
       * Helper method to get DeviceId.
       * @param success should be the function which takes JSONArray as a parameter ex. function(config){ ... }
       * @param fail the message if the action fails
       * @return This method will return the notification configerations
       */
       getNotificationConfig: function (success, fail) {
        return cordova.exec(success, fail,
          "MarketoPlugin",
          "getNotificationConfig", []);
       },

    /**
     * Call this method when user wants to set the request's timeout
     *
     * @param success the message if successful
     * @param fail the message if the action fails
     * @param timeout represents the time in integer.
     */
    settimeout: function (success, fail, timeout){
      return cordova.exec(success, fail,
        "MarketoPlugin",
        "settimeout", [timeout]);
    }
}
module.exports = marketo;
<|endoftext|>