<commit_before>// This [jQuery](http://jquery.com/) plugin implements an `<iframe>`
// [transport](http://api.jquery.com/extending-ajax/#Transports) so that
// `$.ajax()` calls support the uploading of files using standard HTML file
// input fields. This is done by switching the exchange from `XMLHttpRequest`
// to a hidden `iframe` element containing a form that is submitted.

// The [source for the plugin](http://github.com/cmlenz/jquery-iframe-transport)
// is available on [Github](http://github.com/) and dual licensed under the MIT
// or GPL Version 2 licenses.

// ## Usage

// To use this plugin, you simply add an `iframe` option with the value `true`
// to the Ajax settings an `$.ajax()` call, and specify the file fields to
// include in the submssion using the `files` option, which can be a selector,
// jQuery object, or a list of DOM elements containing one or more
// `<input type="file">` elements:

//     $("#myform").submit(function() {
//         $.ajax(this.action, {
//             files: $(":file", this),
//             iframe: true
//         }).complete(function(data) {
//             console.log(data);
//         });
//     });

// The plugin will construct hidden `<iframe>` and `<form>` elements, add the
// file field(s) to that form, submit the form, and process the response.

// If you want to include other form fields in the form submission, include
// them in the `data` option, and set the `processData` option to `false`:

//     $("#myform").submit(function() {
//         $.ajax(this.action, {
//             data: $(":text", this).serializeArray(),
//             files: $(":file", this),
//             iframe: true,
//             processData: false
//         }).complete(function(data) {
//             console.log(data);
//         });
//     });

// ### Response Data Types

// As the transport does not have access to the HTTP headers of the server
// response, it is not as simple to make use of the automatic content type
// detection provided by jQuery as with regular XHR. If you can't set the
// expected response data type (for example because it may vary depending on
// the outcome of processing by the server), you will need to employ a
// workaround on the server side: Send back an HTML document containing just a
// `<textarea>` element with a `data-type` attribute that specifies the MIME
// type, and put the actual payload in the textarea:

//     <textarea data-type="application/json">
//       {"ok": true, "message": "Thanks so much"}
//     </textarea>

// The iframe transport plugin will detect this and pass the value of the
// `data-type` attribute on to jQuery as if it was the "Content-Type" response
// header, thereby enabling the same kind of conversions that jQuery applies
// to regular responses. For the example above you should get a Javascript
// object as the `data` parameter of the `complete` callback, with the
// properties `ok: true` and `message: "Thanks so much"`.

// ### Handling Server Errors

// Another problem with using an `iframe` for file uploads is that it is
// impossible for the javascript code to determine the HTTP status code of the
// servers response. Effectively, all of the calls you make will look like they
// are getting successful responses, and thus invoke the `done()` or
// `complete()` callbacks. You can only determine communicate problems using
// the content of the response payload. For example, consider using a JSON
// response such as the following to indicate a problem with an uploaded file:

//     <textarea data-type="application/json">
//       {"ok": false, "message": "Please only upload reasonably sized files."}
//     </textarea>

// ### Compatibility

// This plugin has primarily been tested on Safari 5 (or later), Firefox 4 (or
// later), and Internet Explorer (all the way back to version 6). While I
// haven't found any issues with it so far, I'm fairly sure it still doesn't
// work around all the quirks in all different browsers. But the code is still
// pretty simple overall, so you should be able to fix it and contribute a
// patch :)

// ## Annotated Source

(function($, undefined) {
  "use strict";

  // Register a prefilter that checks whether the `iframe` option is set, and
  // switches to the "iframe" data type if it is `true`.
  $.ajaxPrefilter(function(options, origOptions, jqXHR) {
    if (options.iframe) {
      return "iframe";
    }
  });

  // Register a transport for the "iframe" data type. It will only activate
  // when the "files" option has been set to a non-empty list of enabled file
  // inputs.
  $.ajaxTransport("iframe", function(options, origOptions, jqXHR) {
    var form = null,
        iframe = null,
        name = "iframe-" + $.now(),
        files = $(options.files).filter(":file:enabled"),
        markers = null,
        accepts;

    // This function gets called after a successful submission or an abortion
    // and should revert all changes made to the page to enable the
    // submission via this transport.
    function cleanUp() {
      markers.prop('disabled', false);
      form.remove();
      iframe.bind("load", function() { iframe.remove(); });
      iframe.attr("src", "javascript:false;");
    }

    // Remove "iframe" from the data types list so that further processing is
    // based on the content type returned by the server, without attempting an
    // (unsupported) conversion from "iframe" to the actual type.
    options.dataTypes.shift();

    if (files.length) {
      form = $("<form enctype='multipart/form-data' method='post'></form>").
        hide().attr({action: options.url, target: name});

      // If there is any additional data specified via the `data` option,
      // we add it as hidden fields to the form. This (currently) requires
      // the `processData` option to be set to false so that the data doesn't
      // get serialized to a string.
      if (typeof(options.data) === "string" && options.data.length > 0) {
        $.error("data must not be serialized");
      }
      $.each(options.data || {}, function(name, value) {
        if ($.isPlainObject(value)) {
          name = value.name;
          value = value.value;
        }
        $("<input type='hidden' />").attr({name:  name, value: value}).
          appendTo(form);
      });

      // Add a hidden `X-Requested-With` field with the value `IFrame` to the
      // field, to help server-side code to determine that the upload happened
      // through this transport.
      $("<input type='hidden' value='IFrame' name='X-Requested-With' />").
        appendTo(form);

      // Borrowed straight from the JQuery source
      // Provides a way of specifying the accepted data type similar to HTTP_ACCEPTS
      accepts = options.dataTypes[ 0 ] && options.accepts[ options.dataTypes[0] ] ?
        options.accepts[ options.dataTypes[0] ] + ( options.dataTypes[ 0 ] !== "*" ? ", */*; q=0.01" : "" ) :
        options.accepts[ "*" ]

      $("<input type='hidden' name='X-Http-Accept'>")
        .attr("value", accepts).appendTo(form);

      // Move the file fields into the hidden form, but first remember their
      // original locations in the document by replacing them with disabled
      // clones. This should also avoid introducing unwanted changes to the
      // page layout during submission.
      markers = files.after(function(idx) {
        var $el = $(this);
        var clone = $el.clone();
        clone[0].files = $el[0].files;
        return clone.prop("disabled", true);
      }).next();
      files.appendTo(form);

      return {

        // The `send` function is called by jQuery when the request should be
        // sent.
        send: function(headers, completeCallback) {
          iframe = $("");

          // The first load event gets fired after the iframe has been injected
          // into the DOM, and is used to prepare the actual submission.
          iframe.bind("load", function() {

            // The second load event gets fired when the response to the form
            // submission is received. The implementation detects whether the
            // actual payload is embedded in a `<textarea>` element, and
            // prepares the required conversions to be made in that case.
            iframe.unbind("load").bind("load", function() {
              var doc = this.contentWindow ? this.contentWindow.document :
                (this.contentDocument ? this.contentDocument : this.document),
                root = doc.documentElement ? doc.documentElement : doc.body,
                textarea = root.getElementsByTagName("textarea")[0],
                type = textarea && textarea.getAttribute("data-type") || null,
                status = textarea && textarea.getAttribute("data-status") || 200,
                statusText = textarea && textarea.getAttribute("data-statusText") || "OK",
                content = {
                  html: root.innerHTML,
                  text: type ?
                    textarea.value :
                    root ? (root.textContent || root.innerText) : null
                };
              cleanUp();
              if (!jqXHR.responseText) {
                jqXHR.responseText = content.text;
              }
              completeCallback(status, statusText, content, type ?
                ("Content-Type: " + type) :
                null);
            });

            // Now that the load handler has been set up, submit the form.
            form[0].submit();
          });

          // After everything has been set up correctly, the form and iframe
          // get injected into the DOM so that the submission can be
          // initiated.
          $("body").append(form, iframe);
        },

        // The `abort` function is called by jQuery when the request should be
        // aborted.
        abort: function() {
          if (iframe !== null) {
            iframe.unbind("load").attr("src", "javascript:false;");
            cleanUp();
          }
        }

      };
    }
  });

})(jQuery);
<commit_msg>firefox support<commit_after>// This [jQuery](http://jquery.com/) plugin implements an `<iframe>`
// [transport](http://api.jquery.com/extending-ajax/#Transports) so that
// `$.ajax()` calls support the uploading of files using standard HTML file
// input fields. This is done by switching the exchange from `XMLHttpRequest`
// to a hidden `iframe` element containing a form that is submitted.

// The [source for the plugin](http://github.com/cmlenz/jquery-iframe-transport)
// is available on [Github](http://github.com/) and dual licensed under the MIT
// or GPL Version 2 licenses.

// ## Usage

// To use this plugin, you simply add an `iframe` option with the value `true`
// to the Ajax settings an `$.ajax()` call, and specify the file fields to
// include in the submssion using the `files` option, which can be a selector,
// jQuery object, or a list of DOM elements containing one or more
// `<input type="file">` elements:

//     $("#myform").submit(function() {
//         $.ajax(this.action, {
//             files: $(":file", this),
//             iframe: true
//         }).complete(function(data) {
//             console.log(data);
//         });
//     });

// The plugin will construct hidden `<iframe>` and `<form>` elements, add the
// file field(s) to that form, submit the form, and process the response.

// If you want to include other form fields in the form submission, include
// them in the `data` option, and set the `processData` option to `false`:

//     $("#myform").submit(function() {
//         $.ajax(this.action, {
//             data: $(":text", this).serializeArray(),
//             files: $(":file", this),
//             iframe: true,
//             processData: false
//         }).complete(function(data) {
//             console.log(data);
//         });
//     });

// ### Response Data Types

// As the transport does not have access to the HTTP headers of the server
// response, it is not as simple to make use of the automatic content type
// detection provided by jQuery as with regular XHR. If you can't set the
// expected response data type (for example because it may vary depending on
// the outcome of processing by the server), you will need to employ a
// workaround on the server side: Send back an HTML document containing just a
// `<textarea>` element with a `data-type` attribute that specifies the MIME
// type, and put the actual payload in the textarea:

//     <textarea data-type="application/json">
//       {"ok": true, "message": "Thanks so much"}
//     </textarea>

// The iframe transport plugin will detect this and pass the value of the
// `data-type` attribute on to jQuery as if it was the "Content-Type" response
// header, thereby enabling the same kind of conversions that jQuery applies
// to regular responses. For the example above you should get a Javascript
// object as the `data` parameter of the `complete` callback, with the
// properties `ok: true` and `message: "Thanks so much"`.

// ### Handling Server Errors

// Another problem with using an `iframe` for file uploads is that it is
// impossible for the javascript code to determine the HTTP status code of the
// servers response. Effectively, all of the calls you make will look like they
// are getting successful responses, and thus invoke the `done()` or
// `complete()` callbacks. You can only determine communicate problems using
// the content of the response payload. For example, consider using a JSON
// response such as the following to indicate a problem with an uploaded file:

//     <textarea data-type="application/json">
//       {"ok": false, "message": "Please only upload reasonably sized files."}
//     </textarea>

// ### Compatibility

// This plugin has primarily been tested on Safari 5 (or later), Firefox 4 (or
// later), and Internet Explorer (all the way back to version 6). While I
// haven't found any issues with it so far, I'm fairly sure it still doesn't
// work around all the quirks in all different browsers. But the code is still
// pretty simple overall, so you should be able to fix it and contribute a
// patch :)

// ## Annotated Source

(function($, undefined) {
  "use strict";

  // Register a prefilter that checks whether the `iframe` option is set, and
  // switches to the "iframe" data type if it is `true`.
  $.ajaxPrefilter(function(options, origOptions, jqXHR) {
    if (options.iframe) {
      return "iframe";
    }
  });

  // Register a transport for the "iframe" data type. It will only activate
  // when the "files" option has been set to a non-empty list of enabled file
  // inputs.
  $.ajaxTransport("iframe", function(options, origOptions, jqXHR) {
    var form = null,
        iframe = null,
        name = "iframe-" + $.now(),
        files = $(options.files).filter(":file:enabled"),
        markers = null,
        accepts;

    // This function gets called after a successful submission or an abortion
    // and should revert all changes made to the page to enable the
    // submission via this transport.
    function cleanUp() {
      markers.prop('disabled', false);
      form.remove();
      iframe.bind("load", function() { iframe.remove(); });
      iframe.attr("src", "javascript:false;");
    }

    // Remove "iframe" from the data types list so that further processing is
    // based on the content type returned by the server, without attempting an
    // (unsupported) conversion from "iframe" to the actual type.
    options.dataTypes.shift();

    if (files.length) {
      form = $("<form enctype='multipart/form-data' method='post'></form>").
        hide().attr({action: options.url, target: name});

      // If there is any additional data specified via the `data` option,
      // we add it as hidden fields to the form. This (currently) requires
      // the `processData` option to be set to false so that the data doesn't
      // get serialized to a string.
      if (typeof(options.data) === "string" && options.data.length > 0) {
        $.error("data must not be serialized");
      }
      $.each(options.data || {}, function(name, value) {
        if ($.isPlainObject(value)) {
          name = value.name;
          value = value.value;
        }
        $("<input type='hidden' />").attr({name:  name, value: value}).
          appendTo(form);
      });

      // Add a hidden `X-Requested-With` field with the value `IFrame` to the
      // field, to help server-side code to determine that the upload happened
      // through this transport.
      $("<input type='hidden' value='IFrame' name='X-Requested-With' />").
        appendTo(form);

      // Borrowed straight from the JQuery source
      // Provides a way of specifying the accepted data type similar to HTTP_ACCEPTS
      accepts = options.dataTypes[ 0 ] && options.accepts[ options.dataTypes[0] ] ?
        options.accepts[ options.dataTypes[0] ] + ( options.dataTypes[ 0 ] !== "*" ? ", */*; q=0.01" : "" ) :
        options.accepts[ "*" ]

      $("<input type='hidden' name='X-Http-Accept'>")
        .attr("value", accepts).appendTo(form);

      // Move the file fields into the hidden form, but first remember their
      // original locations in the document by replacing them with disabled
      // clones. This should also avoid introducing unwanted changes to the
      // page layout during submission.
      markers = files.after(function(idx) {
        var $el = $(this);
        var clone = $el.clone();
        clone.value = $el[0].files;
        return clone.prop("disabled", true);
      }).next();
      files.appendTo(form);

      return {

        // The `send` function is called by jQuery when the request should be
        // sent.
        send: function(headers, completeCallback) {
          iframe = $("");

          // The first load event gets fired after the iframe has been injected
          // into the DOM, and is used to prepare the actual submission.
          iframe.bind("load", function() {

            // The second load event gets fired when the response to the form
            // submission is received. The implementation detects whether the
            // actual payload is embedded in a `<textarea>` element, and
            // prepares the required conversions to be made in that case.
            iframe.unbind("load").bind("load", function() {
              var doc = this.contentWindow ? this.contentWindow.document :
                (this.contentDocument ? this.contentDocument : this.document),
                root = doc.documentElement ? doc.documentElement : doc.body,
                textarea = root.getElementsByTagName("textarea")[0],
                type = textarea && textarea.getAttribute("data-type") || null,
                status = textarea && textarea.getAttribute("data-status") || 200,
                statusText = textarea && textarea.getAttribute("data-statusText") || "OK",
                content = {
                  html: root.innerHTML,
                  text: type ?
                    textarea.value :
                    root ? (root.textContent || root.innerText) : null
                };
              cleanUp();
              if (!jqXHR.responseText) {
                jqXHR.responseText = content.text;
              }
              completeCallback(status, statusText, content, type ?
                ("Content-Type: " + type) :
                null);
            });

            // Now that the load handler has been set up, submit the form.
            form[0].submit();
          });

          // After everything has been set up correctly, the form and iframe
          // get injected into the DOM so that the submission can be
          // initiated.
          $("body").append(form, iframe);
        },

        // The `abort` function is called by jQuery when the request should be
        // aborted.
        abort: function() {
          if (iframe !== null) {
            iframe.unbind("load").attr("src", "javascript:false;");
            cleanUp();
          }
        }

      };
    }
  });

})(jQuery);
<|endoftext|>


<commit_before>var gzip = require('zlib').gzip;
var M = process.mono;
var client;
var resHeaders = {
    'content-type': 'text/html; charset=utf-8',
    'access-control-allow-origin': 'http://jipics.net',
    'content-encoding': 'gzip'
};

function sendClient (res) {

    if (client) {
        res.writeHead(200, resHeaders);
        return res.end(client);
    }

    var libs = '';
    if (M.config.lib) {
        for (var i = 0; i < M.config.lib.length; ++i) {
            libs += "\n";
        }
    }

    gzip(
        "<!DOCTYPE html>\n" +
            "<link rel='icon' href='/favicon.ico'/>\n" +
            "<meta http-equiv='content-type' content='text/html; charset=utf-8'/>\n" +
            "<meta http-equiv='X-UA-Compatible' content='IE=edge'>\n" +
            "\n" +
            libs +
            "\n" +
            "\n" +
        "",
        function (err, data) {

            client = data;
            resHeaders['content-length'] = client.length;
            res.writeHead(200, resHeaders);
            res.end(client);
        }
    );
}

function route (pathname, req, res) {
    var self = this;

    // send client
    if (pathname === '/') {
        return sendClient(res);
    }

    // file server
    M.file.public.serve(req, res, function (err) {
        if (err) {
            // send client when file don't exists
            sendClient(res);
        }
    });
}

module.exports = route;
<commit_msg>dont load < IE10 scripts<commit_after>var gzip = require('zlib').gzip;
var M = process.mono;
var client;
var resHeaders = {
    'content-type': 'text/html; charset=utf-8',
    //'access-control-allow-origin': 'http://jipics.net',
    'content-encoding': 'gzip'
};

function sendClient (res) {

    if (client) {
        res.writeHead(200, resHeaders);
        return res.end(client);
    }

    var libs = '';
    if (M.config.lib) {
        for (var i = 0; i < M.config.lib.length; ++i) {
            libs += "\n";
        }
    }

    gzip(
        "<!DOCTYPE html><link rel='icon' href='/favicon.ico'/>\n" +
            //"\n" +
            libs +
            "\n" +
        "",
        function (err, data) {

            client = data;
            resHeaders['content-length'] = client.length;
            res.writeHead(200, resHeaders);
            res.end(client);
        }
    );
}

function route (pathname, req, res) {
    var self = this;

    // send client
    if (pathname === '/') {
        return sendClient(res);
    }

    // file server
    M.file.public.serve(req, res, function (err) {
        if (err) {
            // send client when file don't exists
            sendClient(res);
        }
    });
}

module.exports = route;
<|endoftext|>


<commit_before>'use strict';

import $ from 'jquery';
import { GetYoDigits } from './foundation.util.core';
import { Plugin } from './foundation.plugin';
import { SmoothScroll } from './foundation.smoothScroll';

/**
 * Magellan module.
 * @module foundation.magellan
 * @requires foundation.smoothScroll
 */

class Magellan extends Plugin {
  /**
   * Creates a new instance of Magellan.
   * @class
   * @fires Magellan#init
   * @param {Object} element - jQuery object to add the trigger to.
   * @param {Object} options - Overrides to the default plugin settings.
   */
  _setup(element, options) {
    this.$element = element;
    this.options  = $.extend({}, Magellan.defaults, this.$element.data(), options);

    this._init();
    this.calcPoints();
  }

  /**
   * Initializes the Magellan plugin and calls functions to get equalizer functioning on load.
   * @private
   */
  _init() {
    var id = this.$element[0].id || GetYoDigits(6, 'magellan');
    var _this = this;
    this.$targets = $('[data-magellan-target]');
    this.$links = this.$element.find('a');
    this.$element.attr({
      'data-resize': id,
      'data-scroll': id,
      'id': id
    });
    this.$active = $();
    this.scrollPos = parseInt(window.pageYOffset, 10);

    this._events();
  }

  /**
   * Calculates an array of pixel values that are the demarcation lines between locations on the page.
   * Can be invoked if new elements are added or the size of a location changes.
   * @function
   */
  calcPoints() {
    var _this = this,
        body = document.body,
        html = document.documentElement;

    this.points = [];
    this.winHeight = Math.round(Math.max(window.innerHeight, html.clientHeight));
    this.docHeight = Math.round(Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight));

    this.$targets.each(function(){
      var $tar = $(this),
          pt = Math.round($tar.offset().top - _this.options.threshold);
      $tar.targetPoint = pt;
      _this.points.push(pt);
    });
  }

  /**
   * Initializes events for Magellan.
   * @private
   */
  _events() {
    var _this = this,
        $body = $('html, body'),
        opts = {
          duration: _this.options.animationDuration,
          easing:   _this.options.animationEasing
        };
    $(window).one('load', function(){
      if(_this.options.deepLinking){
        if(location.hash){
          _this.scrollToLoc(location.hash);
        }
      }
      _this.calcPoints();
      _this._updateActive();
    });

    this.$element.on({
      'resizeme.zf.trigger': this.reflow.bind(this),
      'scrollme.zf.trigger': this._updateActive.bind(this)
    }).on('click.zf.magellan', 'a[href^="#"]', function(e) {
        e.preventDefault();
        var arrival   = this.getAttribute('href');
        _this.scrollToLoc(arrival);
      });
    $(window).on('popstate', function(e) {
      if(_this.options.deepLinking) {
        _this.scrollToLoc(window.location.hash);
      }
    });
  }

  /**
   * Function to scroll to a given location on the page.
   * @param {String} loc - a properly formatted jQuery id selector. Example: '#foo'
   * @function
   */
  scrollToLoc(loc) {
    this._inTransition = true;
    var _this = this;

    var options = {
      animationEasing: this.options.animationEasing,
      animationDuration: this.options.animationDuration,
      threshold: this.options.threshold,
      offset: this.options.offset
    };

    SmoothScroll.scrollToLoc(loc, options, function() {
      _this._inTransition = false;
      _this._updateActive();
    })
  }

  /**
   * Calls necessary functions to update Magellan upon DOM change
   * @function
   */
  reflow() {
    this.calcPoints();
    this._updateActive();
  }

  /**
   * Updates the visibility of an active location link, and updates the url hash for the page, if deepLinking enabled.
   * @private
   * @function
   * @fires Magellan#update
   */
  _updateActive(/*evt, elem, scrollPos*/) {
    if(this._inTransition) {return;}
    var winPos = /*scrollPos ||*/ parseInt(window.pageYOffset, 10),
        curIdx;

    if(winPos + this.winHeight === this.docHeight){ curIdx = this.points.length - 1; }
    else if(winPos < this.points[0]){ curIdx = undefined; }
    else{
      var isDown = this.scrollPos < winPos,
          _this = this,
          curVisible = this.points.filter(function(p, i){
            return isDown ? p - _this.options.offset <= winPos : p - _this.options.offset - _this.options.threshold <= winPos;
          });
      curIdx = curVisible.length ? curVisible.length - 1 : 0;
    }

    this.$active.removeClass(this.options.activeClass);
    this.$active = this.$links.filter('[href="#' + this.$targets.eq(curIdx).data('magellan-target') + '"]').addClass(this.options.activeClass);

    if(this.options.deepLinking){
      var hash = "";
      if(curIdx != undefined){
        hash = this.$active[0].getAttribute('href');
      }
      if(hash !== window.location.hash) {
        if(window.history.pushState){
          window.history.pushState(null, null, hash);
        }else{
          window.location.hash = hash;
        }
      }
    }

    this.scrollPos = winPos;
    /**
     * Fires when magellan is finished updating to the new active element.
     * @event Magellan#update
     */
    this.$element.trigger('update.zf.magellan', [this.$active]);
  }

  /**
   * Destroys an instance of Magellan and resets the url of the window.
   * @function
   */
  _destroy() {
    this.$element.off('.zf.trigger .zf.magellan')
        .find(`.${this.options.activeClass}`).removeClass(this.options.activeClass);

    if(this.options.deepLinking){
      var hash = this.$active[0].getAttribute('href');
      window.location.hash.replace(hash, '');
    }
  }
}

/**
 * Default settings for plugin
 */
Magellan.defaults = {
  /**
   * Amount of time, in ms, the animated scrolling should take between locations.
   * @option
   * @type {number}
   * @default 500
   */
  animationDuration: 500,
  /**
   * Animation style to use when scrolling between locations. Can be `'swing'` or `'linear'`.
   * @option
   * @type {string}
   * @default 'linear'
   * @see {@link https://api.jquery.com/animate|Jquery animate}
   */
  animationEasing: 'linear',
  /**
   * Number of pixels to use as a marker for location changes.
   * @option
   * @type {number}
   * @default 50
   */
  threshold: 50,
  /**
   * Class applied to the active locations link on the magellan container.
   * @option
   * @type {string}
   * @default 'is-active'
   */
  activeClass: 'is-active',
  /**
   * Allows the script to manipulate the url of the current page, and if supported, alter the history.
   * @option
   * @type {boolean}
   * @default false
   */
  deepLinking: false,
  /**
   * Number of pixels to offset the scroll of the page on item click if using a sticky nav bar.
   * @option
   * @type {number}
   * @default 0
   */
  offset: 0
}

export {Magellan};
<commit_msg>Fix issue #10020<commit_after>'use strict';

import $ from 'jquery';
import { GetYoDigits } from './foundation.util.core';
import { Plugin } from './foundation.plugin';
import { SmoothScroll } from './foundation.smoothScroll';

/**
 * Magellan module.
 * @module foundation.magellan
 * @requires foundation.smoothScroll
 */

class Magellan extends Plugin {
  /**
   * Creates a new instance of Magellan.
   * @class
   * @fires Magellan#init
   * @param {Object} element - jQuery object to add the trigger to.
   * @param {Object} options - Overrides to the default plugin settings.
   */
  _setup(element, options) {
    this.$element = element;
    this.options  = $.extend({}, Magellan.defaults, this.$element.data(), options);

    this._init();
    this.calcPoints();
  }

  /**
   * Initializes the Magellan plugin and calls functions to get equalizer functioning on load.
   * @private
   */
  _init() {
    var id = this.$element[0].id || GetYoDigits(6, 'magellan');
    var _this = this;
    this.$targets = $('[data-magellan-target]');
    this.$links = this.$element.find('a');
    this.$element.attr({
      'data-resize': id,
      'data-scroll': id,
      'id': id
    });
    this.$active = $();
    this.scrollPos = parseInt(window.pageYOffset, 10);

    this._events();
  }

  /**
   * Calculates an array of pixel values that are the demarcation lines between locations on the page.
   * Can be invoked if new elements are added or the size of a location changes.
   * @function
   */
  calcPoints() {
    var _this = this,
        body = document.body,
        html = document.documentElement;

    this.points = [];
    this.winHeight = Math.round(Math.max(window.innerHeight, html.clientHeight));
    this.docHeight = Math.round(Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight));

    this.$targets.each(function(){
      var $tar = $(this),
          pt = Math.round($tar.offset().top - _this.options.threshold);
      $tar.targetPoint = pt;
      _this.points.push(pt);
    });
  }

  /**
   * Initializes events for Magellan.
   * @private
   */
  _events() {
    var _this = this,
        $body = $('html, body'),
        opts = {
          duration: _this.options.animationDuration,
          easing:   _this.options.animationEasing
        };
    $(window).one('load', function(){
      if(_this.options.deepLinking){
        if(location.hash){
          _this.scrollToLoc(location.hash);
        }
      }
      _this.calcPoints();
      _this._updateActive();
    });

    this.$element.on({
      'resizeme.zf.trigger': this.reflow.bind(this),
      'scrollme.zf.trigger': this._updateActive.bind(this)
    }).on('click.zf.magellan', 'a[href^="#"]', function(e) {
        e.preventDefault();
        var arrival   = this.getAttribute('href');
        _this.scrollToLoc(arrival);
      });

    this._deepLinkScroll = function(e) {
      if(_this.options.deepLinking) {
        _this.scrollToLoc(window.location.hash);
      }
    };

    $(window).on('popstate', this._deepLinkScroll);
  }

  /**
   * Function to scroll to a given location on the page.
   * @param {String} loc - a properly formatted jQuery id selector. Example: '#foo'
   * @function
   */
  scrollToLoc(loc) {
    this._inTransition = true;
    var _this = this;

    var options = {
      animationEasing: this.options.animationEasing,
      animationDuration: this.options.animationDuration,
      threshold: this.options.threshold,
      offset: this.options.offset
    };

    SmoothScroll.scrollToLoc(loc, options, function() {
      _this._inTransition = false;
      _this._updateActive();
    })
  }

  /**
   * Calls necessary functions to update Magellan upon DOM change
   * @function
   */
  reflow() {
    this.calcPoints();
    this._updateActive();
  }

  /**
   * Updates the visibility of an active location link, and updates the url hash for the page, if deepLinking enabled.
   * @private
   * @function
   * @fires Magellan#update
   */
  _updateActive(/*evt, elem, scrollPos*/) {
    if(this._inTransition) {return;}
    var winPos = /*scrollPos ||*/ parseInt(window.pageYOffset, 10),
        curIdx;

    if(winPos + this.winHeight === this.docHeight){ curIdx = this.points.length - 1; }
    else if(winPos < this.points[0]){ curIdx = undefined; }
    else{
      var isDown = this.scrollPos < winPos,
          _this = this,
          curVisible = this.points.filter(function(p, i){
            return isDown ? p - _this.options.offset <= winPos : p - _this.options.offset - _this.options.threshold <= winPos;
          });
      curIdx = curVisible.length ? curVisible.length - 1 : 0;
    }

    this.$active.removeClass(this.options.activeClass);
    this.$active = this.$links.filter('[href="#' + this.$targets.eq(curIdx).data('magellan-target') + '"]').addClass(this.options.activeClass);

    if(this.options.deepLinking){
      var hash = "";
      if(curIdx != undefined){
        hash = this.$active[0].getAttribute('href');
      }
      if(hash !== window.location.hash) {
        if(window.history.pushState){
          window.history.pushState(null, null, hash);
        }else{
          window.location.hash = hash;
        }
      }
    }

    this.scrollPos = winPos;
    /**
     * Fires when magellan is finished updating to the new active element.
     * @event Magellan#update
     */
    this.$element.trigger('update.zf.magellan', [this.$active]);
  }

  /**
   * Destroys an instance of Magellan and resets the url of the window.
   * @function
   */
  _destroy() {
    this.$element.off('.zf.trigger .zf.magellan')
        .find(`.${this.options.activeClass}`).removeClass(this.options.activeClass);

    if(this.options.deepLinking){
      var hash = this.$active[0].getAttribute('href');
      window.location.hash.replace(hash, '');
    }
    $(window).off('popstate', this._deepLinkScroll);
  }
}

/**
 * Default settings for plugin
 */
Magellan.defaults = {
  /**
   * Amount of time, in ms, the animated scrolling should take between locations.
   * @option
   * @type {number}
   * @default 500
   */
  animationDuration: 500,
  /**
   * Animation style to use when scrolling between locations. Can be `'swing'` or `'linear'`.
   * @option
   * @type {string}
   * @default 'linear'
   * @see {@link https://api.jquery.com/animate|Jquery animate}
   */
  animationEasing: 'linear',
  /**
   * Number of pixels to use as a marker for location changes.
   * @option
   * @type {number}
   * @default 50
   */
  threshold: 50,
  /**
   * Class applied to the active locations link on the magellan container.
   * @option
   * @type {string}
   * @default 'is-active'
   */
  activeClass: 'is-active',
  /**
   * Allows the script to manipulate the url of the current page, and if supported, alter the history.
   * @option
   * @type {boolean}
   * @default false
   */
  deepLinking: false,
  /**
   * Number of pixels to offset the scroll of the page on item click if using a sticky nav bar.
   * @option
   * @type {number}
   * @default 0
   */
  offset: 0
}

export {Magellan};
<|endoftext|>


<commit_before>var window = require("global/window")
var test = require("tape")
var forEach = require("for-each")

var xhr = require("../index.js")

test("constructs and calls callback without throwing", { timeout: 500 }, function(assert) {
    xhr({}, function(err, resp, body) {
        assert.ok(true, "got here")
        assert.end()
    })
})

test("[func] Can GET a url (cross-domain)", { timeout: 2000 }, function(assert) {
    xhr({
        uri: "http://www.mocky.io/v2/55a02cb72651260b1a94f024",
        useXDR: true
    }, function(err, resp, body) {
        assert.ifError(err, "no err")
        assert.equal(resp.statusCode, 200)
        assert.equal(typeof resp.rawRequest, "object")
        assert.notEqual(resp.body.length, 0)
        assert.equal(resp.body, '{"a":1}')
        assert.notEqual(body.length, 0)
        assert.end()
    })
})

test("[func] Returns http error responses like npm's request (cross-domain)", { timeout: 2000 }, function(assert) {
    if (!window.XDomainRequest) {
        xhr({
            uri: "http://www.mocky.io/v2/55a02d63265126221a94f025",
        }, function(err, resp, body) {
            assert.ifError(err, "no err")
            assert.equal(resp.statusCode, 404)
            assert.equal(typeof resp.rawRequest, "object")
            assert.end()
        })
    } else {
        assert.end();
    }
})

test("[func] Request to domain with not allowed cross-domain", { timeout: 2000 }, function(assert) {
    xhr({
        uri: "http://www.mocky.io/v2/57bb70c21000002f175850bd",
    }, function(err, resp, body) {
        assert.ok(err instanceof Error, "should return error")
        assert.equal(resp.statusCode, 0)
        assert.equal(typeof resp.rawRequest, "object")
        assert.end()
    })
})

test("[func] Returns a falsy body for 2xx responses", { timeout: 500 }, function(assert) {
  assert.plan(8)
    xhr({
        uri: "/mock/no-content/200"
    }, function(err, resp, body) {
        assert.notOk(body, "body should be falsy")
        assert.equal(resp.statusCode, 200)
    })
    xhr({
        uri: "/mock/no-content/201"
    }, function(err, resp, body) {
        assert.notOk(body, "body should be falsy")
        assert.equal(resp.statusCode, 201)
    })
    xhr({
        uri: "/mock/no-content/204"
    }, function(err, resp, body) {
        assert.notOk(body, "body should be falsy")
        assert.equal(resp.statusCode, 204)
    })
    xhr({
        uri: "/mock/no-content/205"
    }, function(err, resp, body) {
        assert.notOk(body, "body should be falsy")
        assert.equal(resp.statusCode, 205)
    })

})

test("[func] Calls the callback at most once even if error is thrown issue #127", { timeout: 500 }, function(assert) {
    //double call happened in chrome
    var count = 0;
    setTimeout(function() {
        assert.ok(count <= 1, "expected at most one call")
        assert.end()
    }, 100)
    try {
        xhr({
            uri: "instanterror://foo"
        }, function(err, resp, body) {
            count++;
            throw Error("dummy error")
        })
    } catch(e){}
})

test("[func] Times out to an error ", { timeout: 500 }, function(assert) {
    xhr({
        timeout: 1,
        uri: "/mock/timeout"
    }, function(err, resp, body) {
        assert.ok(err instanceof Error, "should return error")
        assert.equal(err.message, "XMLHttpRequest timeout")
        assert.equal(err.code, "ETIMEDOUT")
        assert.equal(resp.statusCode, 0)
        assert.end()
    })
})

test("withCredentials option", { timeout: 500 }, function(assert) {
    if (!window.XDomainRequest) {
        var req = xhr({}, function() {})
        assert.ok(!req.withCredentials,
            "withCredentials not true"
        )
        req = xhr({
            withCredentials: true
        }, function() {})
        assert.ok(
            req.withCredentials,
            "withCredentials set to true"
        )
    }
    assert.end()
})

test("withCredentials ignored when using synchronous requests", { timeout: 500 }, function(assert) {
    if (!window.XDomainRequest) {
        var req = xhr({
            withCredentials: true,
            sync: true
        }, function() {})
        assert.ok(!req.withCredentials,
            "sync overrides withCredentials"
        )
    }
    assert.end()
})

test("XDR usage (run on IE8 or 9)", { timeout: 500 }, function(assert) {
    var req = xhr({
        useXDR: true,
        uri: window.location.href,
    }, function() {})

    assert.ok(!window.XDomainRequest || window.XDomainRequest === req.constructor,
        "Uses XDR when told to"
    )

    if (!!window.XDomainRequest) {
        assert.throws(function() {
            xhr({
                useXDR: true,
                uri: window.location.href,
                headers: {
                    "foo": "bar"
                }
            }, function() {})
        }, true, "Throws when trying to send headers with XDR")
    }
    assert.end()
})

test("handles errorFunc call with no arguments provided", { timeout: 500 }, function(assert) {
    var req = xhr({}, function(err) {
        assert.ok(err instanceof Error, "callback should get an error")
        assert.equal(err.message, "Unknown XMLHttpRequest Error", "error message incorrect")
    })
    assert.doesNotThrow(function() {
        req.onerror()
    }, "should not throw when error handler called without arguments")
    assert.end()

})

test("constructs and calls callback without throwing", { timeout: 500 }, function(assert) {
    assert.throws(function() {
        xhr({})
    }, "callback is not optional")
    assert.end()
})

if (!window.XDomainRequest) {
    var methods = ["get", "put", "post", "patch"]
} else {
    var methods = ["get", "post"]
}

test("[func] xhr[method] get, put, post, patch", { timeout: 500 }, function(assert) {
    var i = 0

    forEach(methods, function(method) {
        xhr[method]({
            uri: "/mock/200ok"
        }, function(err, resp, body) {
            i++
            assert.ifError(err, "no err")
            assert.equal(resp.statusCode, 200)
            assert.equal(resp.method, method.toUpperCase())
            if (i === methods.length) assert.end()
        })
    })
})

test("xhr[method] get, put, post, patch with url shorthands", { timeout: 500 }, function(assert) {
    var i = 0
    forEach(methods, function(method) {
        var req = xhr[method]("/some-test", { timeout: 500 }, function() {})
        i++
        assert.equal(req.method, method.toUpperCase())

        if (i === methods.length) assert.end()
    })
})

test("[func] sends options.body as json body when options.json === true", { timeout: 500 }, function(assert) {
    xhr.post("/mock/echo", {
        json: true,
        body: {
            foo: "bar"
        }
    }, function(err, resp, body) {
        assert.equal(resp.rawRequest.headers["Content-Type"], "application/json")
        assert.deepEqual(body, {
            foo: "bar"
        })
        assert.end()
    })
})

test("[func] doesn't freak out when json option is false", { timeout: 500 }, function(assert) {
    xhr.post("/mock/echo", {
        json: false,
        body: "{\"a\":1}"
    }, function(err, resp, body) {
        assert.notEqual(resp.rawRequest.headers["Content-Type"], "application/json")
        assert.equal(body, "{\"a\":1}")
        assert.end()
    })
})

test("[func] sends options.json as body when it's not a boolean", { timeout: 500 }, function(assert) {
    xhr.post("/mock/echo", {
        json: {
            foo: "bar"
        }
    }, function(err, resp, body) {
        assert.equal(resp.rawRequest.headers["Content-Type"], "application/json")
        assert.deepEqual(body, {
            foo: "bar"
        })
        assert.end()
    })
})

test("xhr[method] get, put, post, patch with url shorthands and options", { timeout: 500 }, function(assert) {
    var i = 0
    forEach(methods, function(method) {
        var req = xhr[method]("/some-test", {
            headers: {
                foo: 'bar'
            }
        }, function(err, resp, body) {
            i++
            assert.equal(resp.rawRequest.headers.foo, 'bar')
            assert.equal(resp.method, method.toUpperCase())

            if (i === methods.length) assert.end()
        })
    })
})
if (!window.XDomainRequest) {
    test("[func] xhr.head", { timeout: 500 }, function(assert) {
        xhr.head({
            uri: "/mock/200ok",
        }, function(err, resp, body) {
            assert.ifError(err, "no err")
            assert.equal(resp.statusCode, 200)
            assert.equal(resp.method, "HEAD")
            assert.notOk(resp.body)
            assert.end()
        })
    })

    test("xhr.head url shorthand", { timeout: 500 }, function(assert) {
        xhr.head("/mock/200ok", { timeout: 500 }, function(err, resp, body) {
            assert.equal(resp.method, "HEAD")
            assert.end()
        })
    })

    test("[func] xhr.del", { timeout: 500 }, function(assert) {
        xhr.del({
            uri: "/mock/200ok"
        }, function(err, resp, body) {
            assert.ifError(err, "no err")
            assert.equal(resp.statusCode, 200)
            assert.equal(resp.method, "DELETE")
            assert.end()
        })
    })

    test("xhr.del url shorthand", { timeout: 500 }, function(assert) {
        xhr.del("/mock/200ok", { timeout: 500 }, function(err, resp, body) {
            assert.equal(resp.method, "DELETE")
            assert.end()
        })
    })
}
test("url signature without object", { timeout: 500 }, function(assert) {
    xhr("/some-test", { timeout: 500 }, function(err, resp, body) {
        assert.equal(resp.url, '/some-test')
        assert.end()
    })
})

test("url signature with object", { timeout: 500 }, function(assert) {
    xhr("/some-test", {
        headers: {
            "foo": "bar"
        }
    }, function(err, resp, body) {
        assert.equal(resp.url, '/some-test')
        assert.equal(resp.rawRequest.headers.foo, 'bar')
        assert.end()
    })
})

test("aborting XHR immediately prevents callback from being called", { timeout: 500 }, function(assert) {
    var req = xhr({ uri: "/mock/200ok" }, function(err, response) {
        assert.fail('this callback should not be called');
    });
    req.abort();
    setTimeout(function() {
        assert.end()
    }, 2)
})

test("aborting XHR asynchronously still prevents callback from being called", { timeout: 500 }, function(assert) {
    var req = xhr({ uri: "/mock/timeout" }, function(err, response) {
        assert.fail('this callback should not be called');
    });
    setTimeout(function() {
        req.abort();
    }, 0)
    setTimeout(function() {
        assert.end()
    }, 2)
})

test("XHR can be overridden", { timeout: 500 }, function(assert) {
    var xhrs = 0
    var noop = function() {}
    var fakeXHR = function() {
        xhrs++
        this.open = this.send = noop
    }
    var xdrs = 0
    var fakeXDR = function() {
        xdrs++
        this.open = this.send = noop
    }
    xhr.XMLHttpRequest = fakeXHR
    xhr({}, function() {})
    assert.equal(xhrs, 1, "created the custom XHR")

    xhr.XDomainRequest = fakeXDR
    xhr({
        useXDR: true
    }, function() {});
    assert.equal(xdrs, 1, "created the custom XDR")
    assert.end()
})
<commit_msg>remove accidental timeouts in tests<commit_after>var window = require("global/window")
var test = require("tape")
var forEach = require("for-each")

var xhr = require("../index.js")

test("constructs and calls callback without throwing", { timeout: 500 }, function(assert) {
    xhr({}, function(err, resp, body) {
        assert.ok(true, "got here")
        assert.end()
    })
})

test("[func] Can GET a url (cross-domain)", { timeout: 2000 }, function(assert) {
    xhr({
        uri: "http://www.mocky.io/v2/55a02cb72651260b1a94f024",
        useXDR: true
    }, function(err, resp, body) {
        assert.ifError(err, "no err")
        assert.equal(resp.statusCode, 200)
        assert.equal(typeof resp.rawRequest, "object")
        assert.notEqual(resp.body.length, 0)
        assert.equal(resp.body, '{"a":1}')
        assert.notEqual(body.length, 0)
        assert.end()
    })
})

test("[func] Returns http error responses like npm's request (cross-domain)", { timeout: 2000 }, function(assert) {
    if (!window.XDomainRequest) {
        xhr({
            uri: "http://www.mocky.io/v2/55a02d63265126221a94f025",
        }, function(err, resp, body) {
            assert.ifError(err, "no err")
            assert.equal(resp.statusCode, 404)
            assert.equal(typeof resp.rawRequest, "object")
            assert.end()
        })
    } else {
        assert.end();
    }
})

test("[func] Request to domain with not allowed cross-domain", { timeout: 2000 }, function(assert) {
    xhr({
        uri: "http://www.mocky.io/v2/57bb70c21000002f175850bd",
    }, function(err, resp, body) {
        assert.ok(err instanceof Error, "should return error")
        assert.equal(resp.statusCode, 0)
        assert.equal(typeof resp.rawRequest, "object")
        assert.end()
    })
})

test("[func] Returns a falsy body for 2xx responses", { timeout: 500 }, function(assert) {
  assert.plan(8)
    xhr({
        uri: "/mock/no-content/200"
    }, function(err, resp, body) {
        assert.notOk(body, "body should be falsy")
        assert.equal(resp.statusCode, 200)
    })
    xhr({
        uri: "/mock/no-content/201"
    }, function(err, resp, body) {
        assert.notOk(body, "body should be falsy")
        assert.equal(resp.statusCode, 201)
    })
    xhr({
        uri: "/mock/no-content/204"
    }, function(err, resp, body) {
        assert.notOk(body, "body should be falsy")
        assert.equal(resp.statusCode, 204)
    })
    xhr({
        uri: "/mock/no-content/205"
    }, function(err, resp, body) {
        assert.notOk(body, "body should be falsy")
        assert.equal(resp.statusCode, 205)
    })

})

test("[func] Calls the callback at most once even if error is thrown issue #127", { timeout: 500 }, function(assert) {
    //double call happened in chrome
    var count = 0;
    setTimeout(function() {
        assert.ok(count <= 1, "expected at most one call")
        assert.end()
    }, 100)
    try {
        xhr({
            uri: "instanterror://foo"
        }, function(err, resp, body) {
            count++;
            throw Error("dummy error")
        })
    } catch(e){}
})

test("[func] Times out to an error ", { timeout: 500 }, function(assert) {
    xhr({
        timeout: 1,
        uri: "/mock/timeout"
    }, function(err, resp, body) {
        assert.ok(err instanceof Error, "should return error")
        assert.equal(err.message, "XMLHttpRequest timeout")
        assert.equal(err.code, "ETIMEDOUT")
        assert.equal(resp.statusCode, 0)
        assert.end()
    })
})

test("withCredentials option", { timeout: 500 }, function(assert) {
    if (!window.XDomainRequest) {
        var req = xhr({}, function() {})
        assert.ok(!req.withCredentials,
            "withCredentials not true"
        )
        req = xhr({
            withCredentials: true
        }, function() {})
        assert.ok(
            req.withCredentials,
            "withCredentials set to true"
        )
    }
    assert.end()
})

test("withCredentials ignored when using synchronous requests", { timeout: 500 }, function(assert) {
    if (!window.XDomainRequest) {
        var req = xhr({
            withCredentials: true,
            sync: true
        }, function() {})
        assert.ok(!req.withCredentials,
            "sync overrides withCredentials"
        )
    }
    assert.end()
})

test("XDR usage (run on IE8 or 9)", { timeout: 500 }, function(assert) {
    var req = xhr({
        useXDR: true,
        uri: window.location.href,
    }, function() {})

    assert.ok(!window.XDomainRequest || window.XDomainRequest === req.constructor,
        "Uses XDR when told to"
    )

    if (!!window.XDomainRequest) {
        assert.throws(function() {
            xhr({
                useXDR: true,
                uri: window.location.href,
                headers: {
                    "foo": "bar"
                }
            }, function() {})
        }, true, "Throws when trying to send headers with XDR")
    }
    assert.end()
})

test("handles errorFunc call with no arguments provided", { timeout: 500 }, function(assert) {
    var req = xhr({}, function(err) {
        assert.ok(err instanceof Error, "callback should get an error")
        assert.equal(err.message, "Unknown XMLHttpRequest Error", "error message incorrect")
    })
    assert.doesNotThrow(function() {
        req.onerror()
    }, "should not throw when error handler called without arguments")
    assert.end()

})

test("constructs and calls callback without throwing", { timeout: 500 }, function(assert) {
    assert.throws(function() {
        xhr({})
    }, "callback is not optional")
    assert.end()
})

if (!window.XDomainRequest) {
    var methods = ["get", "put", "post", "patch"]
} else {
    var methods = ["get", "post"]
}

test("[func] xhr[method] get, put, post, patch", { timeout: 500 }, function(assert) {
    var i = 0

    forEach(methods, function(method) {
        xhr[method]({
            uri: "/mock/200ok"
        }, function(err, resp, body) {
            i++
            assert.ifError(err, "no err")
            assert.equal(resp.statusCode, 200)
            assert.equal(resp.method, method.toUpperCase())
            if (i === methods.length) assert.end()
        })
    })
})

test("xhr[method] get, put, post, patch with url shorthands", { timeout: 500 }, function(assert) {
    var i = 0
    forEach(methods, function(method) {
        var req = xhr[method]("/some-test", function() {})
        i++
        assert.equal(req.method, method.toUpperCase())

        if (i === methods.length) assert.end()
    })
})

test("[func] sends options.body as json body when options.json === true", { timeout: 500 }, function(assert) {
    xhr.post("/mock/echo", {
        json: true,
        body: {
            foo: "bar"
        }
    }, function(err, resp, body) {
        assert.equal(resp.rawRequest.headers["Content-Type"], "application/json")
        assert.deepEqual(body, {
            foo: "bar"
        })
        assert.end()
    })
})

test("[func] doesn't freak out when json option is false", { timeout: 500 }, function(assert) {
    xhr.post("/mock/echo", {
        json: false,
        body: "{\"a\":1}"
    }, function(err, resp, body) {
        assert.notEqual(resp.rawRequest.headers["Content-Type"], "application/json")
        assert.equal(body, "{\"a\":1}")
        assert.end()
    })
})

test("[func] sends options.json as body when it's not a boolean", { timeout: 500 }, function(assert) {
    xhr.post("/mock/echo", {
        json: {
            foo: "bar"
        }
    }, function(err, resp, body) {
        assert.equal(resp.rawRequest.headers["Content-Type"], "application/json")
        assert.deepEqual(body, {
            foo: "bar"
        })
        assert.end()
    })
})

test("xhr[method] get, put, post, patch with url shorthands and options", { timeout: 500 }, function(assert) {
    var i = 0
    forEach(methods, function(method) {
        var req = xhr[method]("/some-test", {
            headers: {
                foo: 'bar'
            }
        }, function(err, resp, body) {
            i++
            assert.equal(resp.rawRequest.headers.foo, 'bar')
            assert.equal(resp.method, method.toUpperCase())

            if (i === methods.length) assert.end()
        })
    })
})
if (!window.XDomainRequest) {
    test("[func] xhr.head", function(assert) {
        xhr.head({
            uri: "/mock/200ok",
        }, function(err, resp, body) {
            assert.ifError(err, "no err")
            assert.equal(resp.statusCode, 200)
            assert.equal(resp.method, "HEAD")
            assert.notOk(resp.body)
            assert.end()
        })
    })

    test("xhr.head url shorthand", { timeout: 500 }, function(assert) {
        xhr.head("/mock/200ok", function(err, resp, body) {
            assert.equal(resp.method, "HEAD")
            assert.end()
        })
    })

    test("[func] xhr.del", { timeout: 500 }, function(assert) {
        xhr.del({
            uri: "/mock/200ok"
        }, function(err, resp, body) {
            assert.ifError(err, "no err")
            assert.equal(resp.statusCode, 200)
            assert.equal(resp.method, "DELETE")
            assert.end()
        })
    })

    test("xhr.del url shorthand", { timeout: 500 }, function(assert) {
        xhr.del("/mock/200ok", function(err, resp, body) {
            assert.equal(resp.method, "DELETE")
            assert.end()
        })
    })
}
test("url signature without object", { timeout: 500 }, function(assert) {
    xhr("/some-test", function(err, resp, body) {
        assert.equal(resp.url, '/some-test')
        assert.end()
    })
})

test("url signature with object", { timeout: 500 }, function(assert) {
    xhr("/some-test", {
        headers: {
            "foo": "bar"
        }
    }, function(err, resp, body) {
        assert.equal(resp.url, '/some-test')
        assert.equal(resp.rawRequest.headers.foo, 'bar')
        assert.end()
    })
})

test("aborting XHR immediately prevents callback from being called", { timeout: 500 }, function(assert) {
    var req = xhr({ uri: "/mock/200ok" }, function(err, response) {
        assert.fail('this callback should not be called');
    });
    req.abort();
    setTimeout(function() {
        assert.end()
    }, 2)
})

test("aborting XHR asynchronously still prevents callback from being called", { timeout: 500 }, function(assert) {
    var req = xhr({ uri: "/mock/timeout" }, function(err, response) {
        assert.fail('this callback should not be called');
    });
    setTimeout(function() {
        req.abort();
    }, 0)
    setTimeout(function() {
        assert.end()
    }, 2)
})

test("XHR can be overridden", { timeout: 500 }, function(assert) {
    var xhrs = 0
    var noop = function() {}
    var fakeXHR = function() {
        xhrs++
        this.open = this.send = noop
    }
    var xdrs = 0
    var fakeXDR = function() {
        xdrs++
        this.open = this.send = noop
    }
    xhr.XMLHttpRequest = fakeXHR
    xhr({}, function() {})
    assert.equal(xhrs, 1, "created the custom XHR")

    xhr.XDomainRequest = fakeXDR
    xhr({
        useXDR: true
    }, function() {});
    assert.equal(xdrs, 1, "created the custom XDR")
    assert.end()
})
<|endoftext|>


<commit_before>var S	= {
	cssAnimation												: 'webkitTransitionEnd transitionend oTransitionEnd',
	months														: [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sept', 'Oct', 'Nov', 'Dec' ],

	ready														: function()
	{
		var h	= document.getElementsByTagName( 'html' )[ 0 ].className	= '';

		S.findTooltips();
		S.loadPosts();
		S.loadTweets();
	},

	findTooltips												: function()
	{
		$( '.tooltip:not(.found)' ).each( function()
		{
			var t	= $( this );
			var p	= t.parent();

			t.addClass( 'found' )
			.prepend( '' )
			.css({
				'margin-left'	: ( p.outerWidth() - t.outerWidth() ) * .5 + 'px'
			});
		});
	},

	loadPosts													: function()
	{
		$.getJSON( 'http://ahmednuaman.tumblr.com/api/read/json?type=text&filter=text&num=5&callback=?', function(d)
		{
			$( '#posts' ).bind( S.cssAnimation, function()
			{
				var l	= Number( d[ 'posts-total' ] );
				var ul	= $( this );
				var i;

				ul.unbind( S.cssAnimation ).empty();

				for ( i = 0; i < l; i++ )
				{
					ul.append( S.formatPost( d.posts[ i ] ) );
				}

				S.findTooltips();

				ul.removeClass( 'fadeOut' );
			}).addClass( 'fadeOut' );
		});
	},

	formatPost													: function(s)
	{
		var d	= new Date( s[ 'date-gmt' ] );

		return '
→ ' + s[ 'regular-title' ] + ' ~ ' + S.truncate( s[ 'regular-body' ], 40, ' ...' ) + 'Posted at ' + d.getHours() + ':' + d.getMinutes() + ' on ' + d.getDate() + ' ' + S.months[ d.getMonth() ] + '
';
	},

	truncate													: function(s, l, a)
	{
		return s.length > l ? s.substr( 0, l ) + a : s;
	},

	loadTweets													: function()
	{
		$.getJSON( 'https://api.twitter.com/1/statuses/user_timeline.json?screen_name=ahmednuaman&count=5&callback=?', function(d)
		{
			$( '#tweets' ).bind( S.cssAnimation, function()
			{
				var l	= d.length;
				var ul	= $( this );
				var i;

				ul.unbind( S.cssAnimation ).empty();

				for ( i = 0; i < l; i++ )
				{
					ul.append( S.formatTweet( d[ i ] ) );
				}

				S.findTooltips();

				ul.removeClass( 'fadeOut' );
			}).addClass( 'fadeOut' );
		});
	},

	formatTweet													: function(s)
	{
		var d	= new Date( s.created_at );

		return '
→ ' + S.prepareLinks( s.text ) + 'Posted at ' + d.getHours() + ':' + d.getMinutes() + ' on ' + d.getDate() + ' ' + S.months[ d.getMonth() ] + '
';
	},

	prepareLinks												: function(t, i)
	{
		t	= t.replace( /&/gim, '&' ).replace( /</gim, '<' ).replace( />/gim, '>' );

		t	= t.replace( /((https?:\/\/|www\.)[^\s]+)/gim, function(m)
		{
			var l	= ( m.indexOf( 'http' ) === -1 ? 'http://' : '' ) + m;

			return '' + m + '';
		});

		t	= t.replace( /\s?(\@[^\s]+)\s?/gim, function(m)
		{
			m		= m.replace( /\s/gim, '' );

			var l	= 'http://twitter.com/' + m;

			return ' ' + m + ' ';
		});

		t	= t.replace( /\s?(\#[^\s]+)\s?/gim, function(m)
		{
			m		= m.replace( /\s/gim, '' );

			var l	= 'http://twitter.com/search?q=' + m;

			return ' ' + m + ' ';
		});

		return t;
	}
};

// var _gaq=[['_setAccount','UA-352545-12'],['_trackPageview'],['_trackPageLoadTime']];
// (function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];g.async=1;
// g.src=('https:'==location.protocol?'//ssl':'//www')+'.google-analytics.com/ga.js';
// s.parentNode.insertBefore(g,s)}(document,'script'));

$( document ).ready( S.ready );<commit_msg>tidied up some js<commit_after>var S	= {
	cssAnimation												: 'webkitTransitionEnd transitionend oTransitionEnd',
	months														: [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sept', 'Oct', 'Nov', 'Dec' ],
	slowLoad													: 5000,

	ready														: function()
	{
		var h	= document.getElementsByTagName( 'html' )[ 0 ].className	= '';

		S.findTooltips();
		S.loadPosts();
		S.loadTweets();
	},

	findTooltips												: function()
	{
		$( '.tooltip:not(.found)' ).each( function()
		{
			var t	= $( this );
			var p	= t.parent();

			t.addClass( 'found' )
			.prepend( '' )
			.css({
				'margin-left'	: ( p.outerWidth() - t.outerWidth() ) * .5 + 'px'
			});
		});
	},

	loadPosts													: function()
	{
		var ul	= $( '#posts' );
		var t	= setTimeout( function()
		{
			$( 'li', ul ).append( ' Well, this is magical...' );
		}, S.slowLoad );

		$.getJSON( 'http://ahmednuaman.tumblr.com/api/read/json?type=text&filter=text&num=5&callback=?', function(d)
		{
			clearTimeout( t );

			ul.bind( S.cssAnimation, function()
			{
				var l	= Number( d[ 'posts-total' ] );
				var i;

				ul.unbind( S.cssAnimation ).empty();

				for ( i = 0; i < l; i++ )
				{
					ul.append( S.formatPost( d.posts[ i ] ) );
				}

				S.findTooltips();

				ul.removeClass( 'fadeOut' );
			}).addClass( 'fadeOut' );
		});
	},

	formatPost													: function(s)
	{
		var d	= new Date( s[ 'date-gmt' ] );

		return '
→ ' + s[ 'regular-title' ] + ' ~ ' + S.truncate( s[ 'regular-body' ], 40, ' ...' ) + 'Posted at ' + d.getHours() + ':' + d.getMinutes() + ' on ' + d.getDate() + ' ' + S.months[ d.getMonth() ] + '
';
	},

	truncate													: function(s, l, a)
	{
		return s.length > l ? s.substr( 0, l ) + a : s;
	},

	loadTweets													: function()
	{
		var ul	= $( '#tweets' );
		var t	= setTimeout( function()
		{
			$( 'li', ul ).append( ' Well, this is magical...' );
		}, S.slowLoad );

		$.getJSON( 'https://api.twitter.com/1/statuses/user_timeline.json?screen_name=ahmednuaman&count=5&callback=?', function(d)
		{
			clearTimeout( t );

			ul.bind( S.cssAnimation, function()
			{
				var l	= d.length;
				var i;

				ul.unbind( S.cssAnimation ).empty();

				for ( i = 0; i < l; i++ )
				{
					ul.append( S.formatTweet( d[ i ] ) );
				}

				S.findTooltips();

				ul.removeClass( 'fadeOut' );
			}).addClass( 'fadeOut' );
		});
	},

	formatTweet													: function(s)
	{
		var d	= new Date( s.created_at );

		return '
→ ' + S.prepareLinks( s.text ) + 'Posted at ' + d.getHours() + ':' + d.getMinutes() + ' on ' + d.getDate() + ' ' + S.months[ d.getMonth() ] + '
';
	},

	prepareLinks												: function(t, i)
	{
		//t	= t.replace( /&/gim, '&' ).replace( /</gim, '<' ).replace( />/gim, '>' );

		t	= t.replace( /((https?:\/\/|www\.)[^\s]+)/gim, function(m)
		{
			var l	= ( m.indexOf( 'http' ) === -1 ? 'http://' : '' ) + m;

			return '' + m + '';
		});

		t	= t.replace( /\s?(\@[^\s]+)\s?/gim, function(m)
		{
			m		= m.replace( /\s/gim, '' );

			var l	= 'http://twitter.com/' + m;

			return ' ' + m + ' ';
		});

		t	= t.replace( /\s?(\#[^\s]+)\s?/gim, function(m)
		{
			m		= m.replace( /\s/gim, '' );

			var l	= 'http://twitter.com/search?q=' + m;

			return ' ' + m + ' ';
		});

		return t;
	}
};

// var _gaq=[['_setAccount','UA-352545-12'],['_trackPageview'],['_trackPageLoadTime']];
// (function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];g.async=1;
// g.src=('https:'==location.protocol?'//ssl':'//www')+'.google-analytics.com/ga.js';
// s.parentNode.insertBefore(g,s)}(document,'script'));

$( document ).ready( S.ready );<|endoftext|>


<commit_before>var protected_links = "";
var a_to_va = 0;
var a_to_vb = 0;
var a_to_vc = "";
function auto_anonymize()
{
	auto_anonyminize();
}
function auto_anonyminize()
{
	var a_to_vd = window.location.hostname;
	if(protected_links != "" && !protected_links.match(a_to_vd))
	{
		protected_links += ", " + a_to_vd;
	}
	else if(protected_links == "")
	{
		protected_links = a_to_vd;
	}
	var a_to_ve = "";
	var a_to_vf = new Array();
	var a_to_vg = 0;
	a_to_ve = document.getElementsByTagName("a");
	a_to_va = a_to_ve.length;
	a_to_vf = a_to_fa();
	a_to_vg = a_to_vf.length;
	var a_to_vh = false;
	var j = 0;
	var a_to_vi = "";
	for(var i = 0; i < a_to_va; i++)
	{
		a_to_vh = false;
		j = 0;
		while(a_to_vh == false && j < a_to_vg)
		{
			a_to_vi = a_to_ve[i].href;
			if(a_to_vi.match(a_to_vf[j]) || !a_to_vi)
			{
				a_to_vh = true;
			}
			j++;
		}

		if(a_to_vh == false)
		{
			a_to_ve[i].href = "http://anonym.to?" + a_to_vi;
			a_to_vb++;
			a_to_vc += i + ":::" + a_to_ve[i].href + "\n" ;
		}
	}
	var a_to_vj = document.getElementById("anonyminized");
	var a_to_vk = document.getElementById("found_links");
	if(a_to_vj)
	{
		a_to_vj.innerHTML += a_to_vb;
	}
	if(a_to_vk)
	{
		a_to_vk.innerHTML += a_to_va;
	}
}
function a_to_fa()
{
	var a_to_vf = new Array();
	protected_links = protected_links.replace(" ", "");
	a_to_vf = protected_links.split(",");
	return a_to_vf;
}

auto_anonymize();
<commit_msg>Remove unneccesary function<commit_after>var protected_links = "";
var a_to_va = 0;
var a_to_vb = 0;
var a_to_vc = "";
function auto_anonymize()
{
	var a_to_vd = window.location.hostname;
	if(protected_links != "" && !protected_links.match(a_to_vd))
	{
		protected_links += ", " + a_to_vd;
	}
	else if(protected_links == "")
	{
		protected_links = a_to_vd;
	}
	var a_to_ve = "";
	var a_to_vf = new Array();
	var a_to_vg = 0;
	a_to_ve = document.getElementsByTagName("a");
	a_to_va = a_to_ve.length;
	a_to_vf = a_to_fa();
	a_to_vg = a_to_vf.length;
	var a_to_vh = false;
	var j = 0;
	var a_to_vi = "";
	for(var i = 0; i < a_to_va; i++)
	{
		a_to_vh = false;
		j = 0;
		while(a_to_vh == false && j < a_to_vg)
		{
			a_to_vi = a_to_ve[i].href;
			if(a_to_vi.match(a_to_vf[j]) || !a_to_vi)
			{
				a_to_vh = true;
			}
			j++;
		}

		if(a_to_vh == false)
		{
			a_to_ve[i].href = "http://anonym.to?" + a_to_vi;
			a_to_vb++;
			a_to_vc += i + ":::" + a_to_ve[i].href + "\n" ;
		}
	}
	var a_to_vj = document.getElementById("anonyminized");
	var a_to_vk = document.getElementById("found_links");
	if(a_to_vj)
	{
		a_to_vj.innerHTML += a_to_vb;
	}
	if(a_to_vk)
	{
		a_to_vk.innerHTML += a_to_va;
	}
}
function a_to_fa()
{
	var a_to_vf = new Array();
	protected_links = protected_links.replace(" ", "");
	a_to_vf = protected_links.split(",");
	return a_to_vf;
}

auto_anonymize();
<|endoftext|>