<commit_before>var path = require('path'),
    fs = require('fs'),
    jsdom = require('jsdom'),
    Script = require('./script.js'),
    File = require('./file.js'),
    Stylesheet = require('./stylesheet.js');

/**
 * @constructor
 * @param {String} file_path
 * @param mount_path
 */
function Template(file_path, mount_path) {
   this.path = file_path;
   this._base_path = path.dirname(file_path);
   this._mount_path = mount_path;
}

require('util').inherits(Template, File);

Template.prototype._base_path = null;

Template.prototype._mount_path = null;

/**
 * The file path
 * @type {String}
 */
Template.prototype.path = null;

/**
 * A map of all the stylesheets
 * @type {Object}
 */
Template.prototype.stylesheets = null;

/**
 * A map of all the scripts
 * @param {Object}
 */
Template.prototype.scripts = null;

/**
 * A list of scripts that run only on the server
 * @param script
 */
Template.prototype.server_scripts = null;

/**
 * A list of scripts that run only on the client
 * @param script
 */
Template.prototype.client_scripts = null;

Template.prototype._window = null;

/**
 * Registers a script on the template
 * @param {Script} script
 */
Template.prototype.add_script = function(script) {

   this.scripts[script.id] = script;

   if (script.target == Script.SERVER || script.target == Script.BOTH) {
      this.server_scripts.push(script);
   }

   if (script.target == Script.CLIENT || script.target == Script.BOTH) {
      if (!script.tag) {
         this._add_script_tag(script);
      }
      this.client_scripts.push(script);
   }

};

/**
 * Creates a document from the source
 */
Template.prototype.create_document = function() {
   return jsdom.jsdom(this.source/*''*/, null, {
      features: {
         FetchExternalResources: false,
         ProcessExternalResources: false,
         MutationEvents: '2.0',
         QuerySelector: true
      }
   });
};

/**
 * Creates a document and window from the source
 * Used by dommr.process_request
 */
Template.prototype.create_window = function() {
   return this.create_document().createWindow();
};

Template.prototype._add_script_tag = function(script) {
   var document = this._window.document,
       tag = script.tag = document.createElement('script'),
       last_tag, first_tag;

   tag.type = 'text/javascript';
   tag.charset = 'utf-8';
   tag.src = this._mount_path + '/script/' + script.id + '.js';

   if (this.client_scripts.length > 0) {
      last_tag = this.client_scripts[this.client_scripts.length - 1].tag;

      if (last_tag.nextSibling) {
         last_tag.parentNode.insertBefore(tag, last_tag.nextSibling);
      } else {
         last_tag.parentNode.appendChild(tag);
      }
   } else if (first_tag = document.getElementsByTagName('script')[0]) {
      first_tag.parentNode.insertBefore(tag, first_tag);
   } else {
      document.body.appendChild(tag);
   }

   this.source = document.innerHTML;

};

/**
 * Called when the file is ready. Loads all the scripts and style sheets
 * and stores them as instances.
 */
Template.prototype._process_source = function() {

   var document = this.create_document(),
       script_tags, link_tags, stylesheet, scripts = [ ];

   this._window = document.createWindow();
   this.stylesheets = { };
   this.scripts = { };
   this.client_scripts = [ ];
   this.server_scripts = [ ];

   script_tags = document.getElementsByTagName('script');

   this.emit('scripts:pre', this);

   for (var i = 0, len = script_tags.length; i < len; i++) {
      this.add_script(Script.create_from_tag(script_tags[i], this._base_path));
   }

   this.emit('scripts:post', this);

   link_tags = document.getElementsByTagName('link');

   for (i = 0,len = link_tags.length; i < len; i++) {
      // TODO: move to Stylesheet.js
      if (link_tags.rel = 'stylesheet') {
         stylesheet = new Stylesheet(link_tags[i], this._base_path);
         this.stylesheets[stylesheet.id] = stylesheet;
      }
   }

   // extensions may have manipulated the source so update it
   this.source = document.innerHTML;

};

module.exports = Template;

<commit_msg>Unwatch any watched files before reprocessing template<commit_after>var path = require('path'),
    fs = require('fs'),
    jsdom = require('jsdom'),
    Script = require('./script.js'),
    File = require('./file.js'),
    Stylesheet = require('./stylesheet.js');

/**
 * @constructor
 * @param {String} file_path
 * @param mount_path
 */
function Template(file_path, mount_path) {
   this.path = file_path;
   this._base_path = path.dirname(file_path);
   this._mount_path = mount_path;
}

require('util').inherits(Template, File);

Template.prototype._base_path = null;

Template.prototype._mount_path = null;

/**
 * The file path
 * @type {String}
 */
Template.prototype.path = null;

/**
 * A map of all the stylesheets
 * @type {Object}
 */
Template.prototype.stylesheets = null;

/**
 * A map of all the scripts
 * @param {Object}
 */
Template.prototype.scripts = null;

/**
 * A list of scripts that run only on the server
 * @param script
 */
Template.prototype.server_scripts = null;

/**
 * A list of scripts that run only on the client
 * @param script
 */
Template.prototype.client_scripts = null;

Template.prototype._window = null;

/**
 * Registers a script on the template
 * @param {Script} script
 */
Template.prototype.add_script = function(script) {

   this.scripts[script.id] = script;

   if (script.target == Script.SERVER || script.target == Script.BOTH) {
      this.server_scripts.push(script);
   }

   if (script.target == Script.CLIENT || script.target == Script.BOTH) {
      if (!script.tag) {
         this._add_script_tag(script);
      }
      this.client_scripts.push(script);
   }

};

/**
 * Creates a document from the source
 */
Template.prototype.create_document = function() {
   return jsdom.jsdom(this.source/*''*/, null, {
      features: {
         FetchExternalResources: false,
         ProcessExternalResources: false,
         MutationEvents: '2.0',
         QuerySelector: true
      }
   });
};

/**
 * Creates a document and window from the source
 * Used by dommr.process_request
 */
Template.prototype.create_window = function() {
   return this.create_document().createWindow();
};

Template.prototype._add_script_tag = function(script) {
   var document = this._window.document,
       tag = script.tag = document.createElement('script'),
       last_tag, first_tag;

   tag.type = 'text/javascript';
   tag.charset = 'utf-8';
   tag.src = this._mount_path + '/script/' + script.id + '.js';

   if (this.client_scripts.length > 0) {
      last_tag = this.client_scripts[this.client_scripts.length - 1].tag;

      if (last_tag.nextSibling) {
         last_tag.parentNode.insertBefore(tag, last_tag.nextSibling);
      } else {
         last_tag.parentNode.appendChild(tag);
      }
   } else if (first_tag = document.getElementsByTagName('script')[0]) {
      first_tag.parentNode.insertBefore(tag, first_tag);
   } else {
      document.body.appendChild(tag);
   }

   this.source = document.innerHTML;

};

/**
 * Given an object mapping ids to files (such as this.stylesheet/script)
 * unwatches all the files mapped
 * @private
 * @param [Object] file_object Object with a id->file mapping
 */
Template.prototype._unwatch_all = function(file_object) {

   if (file_object) {
      Object.keys(file_object).forEach(function(id) { file_object[id].unwatch(); });
   }

};

/**
 * Called when the file is ready. Loads all the scripts and style sheets
 * and stores them as instances.
 */
Template.prototype._process_source = function() {

   var document = this.create_document(),
       script_tags, link_tags, stylesheet, scripts = [ ];

   // if scripts and style sheets have already been loaded then unwatch all the files
   this._unwatch_all(this.stylesheets);
   this._unwatch_all(this.scripts);

   this._window = document.createWindow();
   this.stylesheets = { };
   this.scripts = { };
   this.client_scripts = [ ];
   this.server_scripts = [ ];

   script_tags = document.getElementsByTagName('script');

   this.emit('scripts:pre', this);

   for (var i = 0, len = script_tags.length; i < len; i++) {
      this.add_script(Script.create_from_tag(script_tags[i], this._base_path));
   }

   this.emit('scripts:post', this);

   link_tags = document.getElementsByTagName('link');

   for (i = 0,len = link_tags.length; i < len; i++) {
      // TODO: move to Stylesheet.js
      if (link_tags.rel = 'stylesheet') {
         stylesheet = new Stylesheet(link_tags[i], this._base_path);
         this.stylesheets[stylesheet.id] = stylesheet;
      }
   }

   // extensions may have manipulated the source so update it
   this.source = document.innerHTML;

};

module.exports = Template;

<|endoftext|>


<commit_before>var Economy = require('./economy');
var Q = require('q');
var User = require('./mongo').userModel;
var color = require('./color');
var moment = require('moment');

module.exports = Profile;

var BR = '
';
var SPACE = ' ';
var profileColor = '#24678d';
var trainersprites = [1, 2, 101, 102, 169, 170, 265, 266, 168];

/**
 * Profile constructor.
 *
 * @param {Boolean} isOnline
 * @param {Object|String} user - if isOnline then Object else String
 * @param {String} image
 */

function Profile(isOnline, user, image) {
   this.isOnline = isOnline || false;
   this.user = user || null;
   this.image = image;

   this.username = this.isOnline ? this.user.name : this.user;
   this.url = Config.avatarurl || '';
}

/**
 * Create an bold html tag element.
 *
 * Example:
 * createFont('Hello World!');
 * => 'Hello World!'
 *
 * @param {String} color
 * @param {String} text
 * @return {String}
 */

function bold(text) {
    return '' + text + '';
}

/**
 * Create an font html tag element.
 *
 * Example:
 * createFont('Hello World!', 'blue');
 * => 'Hello World!'
 *
 * @param {String} color
 * @param {String} text
 * @return {String}
 */

function font(color, text) {
    return '' + text + '';
}

/**
 * Create an img tag element.
 *
 * Example:
 * createImg('phil.png');
 * => ''
 *
 * @param {String} link
 * @return {String}
 */

function img(link) {
    return '';
}

/**
 * Create a font html element wrap around by a bold html element.
 * Uses to `profileColor` as a color.
 * Adds a colon at the end of the text and a SPACE at the end of the element.
 *
 * @param {String} text
 * @return {String}
 */

function label(text) {
    return bold(font(profileColor, text + ':')) + SPACE;
}

/**
 * Q Wrapper for getting when a user was last seen in the
 * MongoDB database.
 *
 * @param {String} name
 * @return {Promise}
 */

function seen(name) {
    var deferred = Q.defer();
    User.findOne({name: toId(name)}, function(err, user) {
        if (err) return deferred.reject(new Error(err));
        if (!user || !user.seen) return deferred.resolve(false);
        return deferred.resolve(moment(user.seen).fromNow());
    });
    return deferred.promise;
}

Profile.prototype.avatar = function() {
    if (this.isOnline) {
        if (typeof this.image === 'string') return img(this.url + '/avatars/' + this.image);
        return img('http://play.pokemonshowdown.com/sprites/trainers/' + this.image + '.png');
    }
    for (var name in Config.customAvatars) {
        if (this.username === name) {
            return img(this.url + '/avatars/' + Config.customAvatars[name]);
        }
    }
    var selectedSprite = trainersprites[Math.floor(Math.random() * trainersprites.length)];
    return img('http://play.pokemonshowdown.com/sprites/trainers/' + selectedSprite + '.png');
};

Profile.prototype.group = function() {
    if (this.isOnline && this.user.group === ' ') return label('Group') + 'Regular User';
    if (this.isOnline) return label('Group') + Config.groups[this.user.group].name;
    for (var name in Users.usergroups) {
        if (toId(this.username) === name) {
            return label('Group') + Config.groups[Users.usergroups[name].charAt(0)].name;
        }
    }
    return label('Group') + 'Regular User';
};

Profile.prototype.money = function(amount) {
    return label('Money') + amount + Economy.currency(amount);
};

Profile.prototype.name = function() {
    return label('Name') + bold(font(color(toId(this.username)), this.username));
};

Profile.prototype.seen = function(timeAgo) {
    if (this.isOnline) return label('Last Seen') + font('#2ECC40', 'Currently Online');
    if (!timeAgo) return label('Last Seen') + 'Never';
    return label('Last Seen') + timeAgo;
};

Profile.prototype.show = function(callback) {
    Q.all([Economy.get(this.username), seen(this.username)])
     .spread(function(amount, lastSeen) {
        callback(this.avatar() +
            SPACE + this.name() + BR +
            SPACE + this.group() + BR +
            SPACE + this.money(amount) + BR +
            SPACE + this.seen(lastSeen) +
            '
');
     }.bind(this), function(err) {
        if (err) throw new Error(err);
     }).done();
};
<commit_msg>Add example doc to label<commit_after>var Economy = require('./economy');
var Q = require('q');
var User = require('./mongo').userModel;
var color = require('./color');
var moment = require('moment');

module.exports = Profile;

var BR = '
';
var SPACE = ' ';
var profileColor = '#24678d';
var trainersprites = [1, 2, 101, 102, 169, 170, 265, 266, 168];

/**
 * Profile constructor.
 *
 * @param {Boolean} isOnline
 * @param {Object|String} user - if isOnline then Object else String
 * @param {String} image
 */

function Profile(isOnline, user, image) {
   this.isOnline = isOnline || false;
   this.user = user || null;
   this.image = image;

   this.username = this.isOnline ? this.user.name : this.user;
   this.url = Config.avatarurl || '';
}

/**
 * Create an bold html tag element.
 *
 * Example:
 * createFont('Hello World!');
 * => 'Hello World!'
 *
 * @param {String} color
 * @param {String} text
 * @return {String}
 */

function bold(text) {
    return '' + text + '';
}

/**
 * Create an font html tag element.
 *
 * Example:
 * createFont('Hello World!', 'blue');
 * => 'Hello World!'
 *
 * @param {String} color
 * @param {String} text
 * @return {String}
 */

function font(color, text) {
    return '' + text + '';
}

/**
 * Create an img tag element.
 *
 * Example:
 * createImg('phil.png');
 * => ''
 *
 * @param {String} link
 * @return {String}
 */

function img(link) {
    return '';
}

/**
 * Create a font html element wrap around by a bold html element.
 * Uses to `profileColor` as a color.
 * Adds a colon at the end of the text and a SPACE at the end of the element.
 *
 * Example:
 * label('Name');
 * => 'Name:'
 *
 * @param {String} text
 * @return {String}
 */

function label(text) {
    return bold(font(profileColor, text + ':')) + SPACE;
}

/**
 * Q Wrapper for getting when a user was last seen in the
 * MongoDB database.
 *
 * @param {String} name
 * @return {Promise}
 */

function seen(name) {
    var deferred = Q.defer();
    User.findOne({name: toId(name)}, function(err, user) {
        if (err) return deferred.reject(new Error(err));
        if (!user || !user.seen) return deferred.resolve(false);
        return deferred.resolve(moment(user.seen).fromNow());
    });
    return deferred.promise;
}

Profile.prototype.avatar = function() {
    if (this.isOnline) {
        if (typeof this.image === 'string') return img(this.url + '/avatars/' + this.image);
        return img('http://play.pokemonshowdown.com/sprites/trainers/' + this.image + '.png');
    }
    for (var name in Config.customAvatars) {
        if (this.username === name) {
            return img(this.url + '/avatars/' + Config.customAvatars[name]);
        }
    }
    var selectedSprite = trainersprites[Math.floor(Math.random() * trainersprites.length)];
    return img('http://play.pokemonshowdown.com/sprites/trainers/' + selectedSprite + '.png');
};

Profile.prototype.group = function() {
    if (this.isOnline && this.user.group === ' ') return label('Group') + 'Regular User';
    if (this.isOnline) return label('Group') + Config.groups[this.user.group].name;
    for (var name in Users.usergroups) {
        if (toId(this.username) === name) {
            return label('Group') + Config.groups[Users.usergroups[name].charAt(0)].name;
        }
    }
    return label('Group') + 'Regular User';
};

Profile.prototype.money = function(amount) {
    return label('Money') + amount + Economy.currency(amount);
};

Profile.prototype.name = function() {
    return label('Name') + bold(font(color(toId(this.username)), this.username));
};

Profile.prototype.seen = function(timeAgo) {
    if (this.isOnline) return label('Last Seen') + font('#2ECC40', 'Currently Online');
    if (!timeAgo) return label('Last Seen') + 'Never';
    return label('Last Seen') + timeAgo;
};

Profile.prototype.show = function(callback) {
    Q.all([Economy.get(this.username), seen(this.username)])
     .spread(function(amount, lastSeen) {
        callback(this.avatar() +
            SPACE + this.name() + BR +
            SPACE + this.group() + BR +
            SPACE + this.money(amount) + BR +
            SPACE + this.seen(lastSeen) +
            '
');
     }.bind(this), function(err) {
        if (err) throw new Error(err);
     }).done();
};
<|endoftext|>


<commit_before>const awaitMethodName = 'await';
const renderMethodName = 'render';

class Engine {
    constructor(container = {}) {
        this.container = container;
    }

    register(...types) {
        types.forEach(type => this.container[type.name] = type);
        return this;
    }

    instantiate(component) {
        return new component({
            render: params => this.render(params),
            components: this.container
        });
    }

    render(component, params) {
        return new Promise((resolve, reject) => {
            let instance = this.instantiate(component),
                instanceRender = () => resolve(instance[renderMethodName](params));

            if (instance[awaitMethodName] !== undefined) {
                new Promise((awaitResolve, awaitReject) =>
                    instance[awaitMethodName](awaitResolve, awaitReject))
                .then(instanceRender)
                .catch(reject);
            } else {
                try {
                    resolve(instanceRender());
                } catch(error) {
                    reject(error);
                }
            }
        });
    }
}

class Home {
    render() {
        return `This is the home page!`;
    }
}

class Component {
    constructor({ render, components }) {
        this.compRender = render;
        this.components = components;
        this.title = 'Hello world';
    }

    await(resolve) {
        setTimeout(() => this.compRender(this.components.Home)
            .then(homeHtml => resolve(this.homeHtml = homeHtml)), 100);
    }

    render({ subtitle }) {
        return `

${ this.title }

${ subtitle }

${ this.homeHtml }

        `;
    }

}

let engine = new Engine().register(
    Component,
    Home
);

engine.render(Component, { subtitle: 'sub title' })
    .then(html => console.log(html));
<commit_msg>Render all implementation<commit_after>const awaitMethodName = 'await';
const renderMethodName = 'render';

class Engine {
    constructor(container = {}) {
        this.container = container;
    }

    register(...types) {
        types.forEach(type => this.container[type.name] = type);
        return this;
    }

    instantiate(component) {
        return new component({
            render: (...args) => this.renderAll(...args),
            components: this.container
        });
    }

    renderAll(...components) {
        return new Promise((resolve, reject) => {
            let renderedComponents = {};
            let renderedComponentsCnt = 0;
            components.forEach(component => this.render(component)
                .then(result => {
                    renderedComponents[component.name] = result;
                    if (++renderedComponentsCnt === components.length) {
                        resolve(renderedComponents);
                    }
                })
                .catch(reject));
        });
    }

    render(component, params) {
        return new Promise((resolve, reject) => {
            let instance = this.instantiate(component),
                instanceRender = () => resolve(instance[renderMethodName](params));

            if (instance[awaitMethodName] !== undefined) {
                new Promise((awaitResolve, awaitReject) =>
                    instance[awaitMethodName](awaitResolve, awaitReject))
                .then(instanceRender)
                .catch(reject);
            } else {
                try {
                    resolve(instanceRender());
                } catch(error) {
                    reject(error);
                }
            }
        });
    }
}

class Home {
    render() {
        return `This is the home page!`;
    }
}

class Component {
    constructor({ render, components }) {
        this.rend = render;
        this.components = components;
        this.title = 'Hello world';
    }

    await(resolve) {
        setTimeout(() => this.rend(this.components.Home)
            .then(html => resolve(this.html = html)), 100);
    }

    render({ subtitle }) {
        return `

${ this.title }

${ subtitle }

${ this.html.Home }

        `;
    }

}

let engine = new Engine().register(
    Component,
    Home
);

engine.render(Component, { subtitle: 'subtitle' })
    .then(html => console.log(html));
<|endoftext|>


<commit_before>;(function(exports) {
  var consoleController, textGrabber;
  var Terminal = function() {
    consoleController = setUpConsoleController(this);
    this.events = new Eventer();

    textGrabber = new TextGrabber();
    this.events.on(this, "submit", function(line) {
      textGrabber.write({ event: "submit", text: line });
    });
    this.events.on(this, "keypress", function(line) {
      textGrabber.write({ event: "keypress", text: line });
    });
    this.events.on(this, "history", function(line) {
      textGrabber.write({ event: "keypress", text: line });
    });
  };

  Terminal.prototype = {
    setResult: function(result) {
      var className = "jquery-console-message-value";
      if (result.error === true) {
        className = "jquery-console-message-error";
      }

      lowlightOldPrompt();
      consoleController.commandResult([{
        msg: toHtml(result.msg), className: className
      }]);
    },

    setPromptText: function(data) {
      var markup = data.html;
      if (data.cursor === true) {
        markup += consoleController.cursor;
      }

      $("span.jquery-console-prompt").last().html(markup);
      consoleController.updateCursorOffset();
    },

    getText: function() {
      return textGrabber.getText();
    },

    getOffset: function() {
      var innerConsole = $('.jquery-console-inner');
      var padding = { t:0, l:17 };
      return {
        t: padding.t - innerConsole.scrollTop(),
        l: padding.l - innerConsole.scrollLeft()
      };
    },

    getLineOffset: function() {
      var innerConsole = $('.jquery-console-inner');
      var padding = { t:0, l:-17 }; // include chevron
      return {
        t: padding.t - innerConsole.scrollTop(),
        l: padding.l - innerConsole.scrollLeft()
      };
    },

    getWidth: function() {
      return $('.jquery-console-inner').width();
    },

    getCharDimes: function() {
      return { x:11, y:18 };
    }
  };

  var setUpConsoleController = function(terminal) {
    var consoleController = $("#console").console({
      promptLabel: '>',
      commandValidate: commandValid,
      commandHandle: function(line) {
        terminal.events.emit('submit', line);
      },
      autofocus:true,
      promptHistory:true
    });

    // cursor blinking

    consoleController.typer.bind("keyup", function() {
      $('.jquery-console-cursor').blink();
    });

    consoleController.typer.bind("focus", function() {
      $('.jquery-console-cursor').blink();
    });

    consoleController.typer.bind("blur", function() {
      $('.jquery-console-cursor').unblink();
    });

    // syntax highlighting as you type

    consoleController.typer.keypress(function(e) {
      terminal.events.emit("keypress", consoleController.promptText());
    });

    // extra for backspace because not caught by keydown.
    // Price is that highlight update is delayed until key goes up so
    // get tiny text flash during backspace
    consoleController.typer.keyup(function(e) {
      if (e.keyCode === 8) {
        terminal.events.emit("keypress", consoleController.promptText());
      }
    });

    // tell terminal when history item gets recalled
    consoleController.typer.bind("history", function(e) {
      terminal.events.emit("history", consoleController.promptText());
    });

    return consoleController;
  };

  var toHtml = function(str) {
    var out = str;
    var out = str.replace(/  /g, "  ");
    return out;
  };

  var commandValid = function(line) {
    return line !== "";
  };

  var lowlightOldPrompt = function() {
    $("span.jquery-console-prompt-label").last().css({ color: "#555" });
  };

  exports.Terminal = Terminal;
})(typeof exports === 'undefined' ? this : exports)
<commit_msg>Correct getLineOffset padding.<commit_after>;(function(exports) {
  var consoleController, textGrabber;
  var Terminal = function() {
    consoleController = setUpConsoleController(this);
    this.events = new Eventer();

    textGrabber = new TextGrabber();
    this.events.on(this, "submit", function(line) {
      textGrabber.write({ event: "submit", text: line });
    });
    this.events.on(this, "keypress", function(line) {
      textGrabber.write({ event: "keypress", text: line });
    });
    this.events.on(this, "history", function(line) {
      textGrabber.write({ event: "keypress", text: line });
    });
  };

  Terminal.prototype = {
    setResult: function(result) {
      var className = "jquery-console-message-value";
      if (result.error === true) {
        className = "jquery-console-message-error";
      }

      lowlightOldPrompt();
      consoleController.commandResult([{
        msg: toHtml(result.msg), className: className
      }]);
    },

    setPromptText: function(data) {
      var markup = data.html;
      if (data.cursor === true) {
        markup += consoleController.cursor;
      }

      $("span.jquery-console-prompt").last().html(markup);
      consoleController.updateCursorOffset();
    },

    getText: function() {
      return textGrabber.getText();
    getPadding: function() {
      return { t:0, l:17 };
    },

    getOffset: function() {
      var innerConsole = $('.jquery-console-inner');
      return {
        t: this.getPadding().t - innerConsole.scrollTop(),
        l: this.getPadding().l - innerConsole.scrollLeft()
      };
    },

    getLineOffset: function() {
      var innerConsole = $('.jquery-console-inner');
      return {
        t: -innerConsole.scrollTop(),
        l: -innerConsole.scrollLeft()
      };
    },

    getWidth: function() {
      return $('.jquery-console-inner').width();
    },

    getCharDimes: function() {
      return { x:11, y:18 };
    }
  };

  var setUpConsoleController = function(terminal) {
    var consoleController = $("#console").console({
      promptLabel: '>',
      commandValidate: commandValid,
      commandHandle: function(line) {
        terminal.events.emit('submit', line);
      },
      autofocus:true,
      promptHistory:true
    });

    // cursor blinking

    consoleController.typer.bind("keyup", function() {
      $('.jquery-console-cursor').blink();
    });

    consoleController.typer.bind("focus", function() {
      $('.jquery-console-cursor').blink();
    });

    consoleController.typer.bind("blur", function() {
      $('.jquery-console-cursor').unblink();
    });

    // syntax highlighting as you type

    consoleController.typer.keypress(function(e) {
      terminal.events.emit("keypress", consoleController.promptText());
    });

    // extra for backspace because not caught by keydown.
    // Price is that highlight update is delayed until key goes up so
    // get tiny text flash during backspace
    consoleController.typer.keyup(function(e) {
      if (e.keyCode === 8) {
        terminal.events.emit("keypress", consoleController.promptText());
      }
    });

    // tell terminal when history item gets recalled
    consoleController.typer.bind("history", function(e) {
      terminal.events.emit("history", consoleController.promptText());
    });

    return consoleController;
  };

  var toHtml = function(str) {
    var out = str;
    var out = str.replace(/  /g, "  ");
    return out;
  };

  var commandValid = function(line) {
    return line !== "";
  };

  var lowlightOldPrompt = function() {
    $("span.jquery-console-prompt-label").last().css({ color: "#555" });
  };

  exports.Terminal = Terminal;
})(typeof exports === 'undefined' ? this : exports)
<|endoftext|>


<commit_before>'use strict';

var noop             = require('es5-ext/function/noop')
  , assign           = require('es5-ext/object/assign')
  , map              = require('es5-ext/object/map')
  , normalizeOptions = require('es5-ext/object/normalize-options')
  , some             = require('es5-ext/object/some')
  , d                = require('d')
  , makeElement      = require('dom-ext/document/#/make-element')
  , resolveOptions   = require('./utils/resolve-options')
  , DOMInput         = require('./_controls/input')

  , Input;

module.exports = Input = function (document, type/*, options*/) {
	var options = arguments[2];
	this.items = {};
	this.type = type;
	options = resolveOptions(options, type);
	this.options = Object(options.item);
	if (options.required != null) this.options.required = options.required;
	this.options.control = assign(Object(options.control),
		Object(this.options.control));
	this.customOptions = Object(options.items);
	this.make = makeElement.bind(document);
	DOMInput.call(this, document, type, options);
};

Input.prototype = Object.create(DOMInput.prototype, {
	constructor: d(Input),
	_value: d(null),
	isComposite: d(true),
	controlAttributes: d({}),
	_render: d(function () { throw new Error("Not implemented"); }),
	onChange: d(function () {
		var value, changed, valid, emitChanged, emitValid;
		value = this.value;
		changed = some(this.items, function (item) { return item.changed; });
		valid = this.required ? (value != null) : true;

		if (this.changed !== changed) {
			this.changed = changed;
			emitChanged = true;
		}
		if (this.valid !== valid) {
			this.valid = valid;
			emitValid = true;
		}

		this.emit('change', value);
		if (emitChanged) this.emit('change:changed', this.changed);
		if (emitValid) this.emit('change:valid', this.valid);
	}),
	inputValue: d.gs(function () {
		return map(this.items, function (input) { return input.value; });
	}, noop),
	value: d.gs(function () { return this.inputValue; }, noop),
	castControlAttribute: d(noop),
	getOptions: d(function (desc) {
		var options = [this.options];
		if (this.customOptions[desc.key]) options.push(this.customOptions[desc.key]);
		if (this.customOptions[desc.__valueId__]) options.push(this.customOptions[desc.__valueId__]);
		return normalizeOptions.apply(null, options);
	}),
	addItem: d(function (input, name) {
		this.items[name] = input;
		input.parent = this;
		input.on('change', this.onChange);
		return input;
	})
});
<commit_msg>Rely on sKey instead of a key<commit_after>'use strict';

var noop             = require('es5-ext/function/noop')
  , assign           = require('es5-ext/object/assign')
  , map              = require('es5-ext/object/map')
  , normalizeOptions = require('es5-ext/object/normalize-options')
  , some             = require('es5-ext/object/some')
  , d                = require('d')
  , makeElement      = require('dom-ext/document/#/make-element')
  , resolveOptions   = require('./utils/resolve-options')
  , DOMInput         = require('./_controls/input')

  , Input;

module.exports = Input = function (document, type/*, options*/) {
	var options = arguments[2];
	this.items = {};
	this.type = type;
	options = resolveOptions(options, type);
	this.options = Object(options.item);
	if (options.required != null) this.options.required = options.required;
	this.options.control = assign(Object(options.control),
		Object(this.options.control));
	this.customOptions = Object(options.items);
	this.make = makeElement.bind(document);
	DOMInput.call(this, document, type, options);
};

Input.prototype = Object.create(DOMInput.prototype, {
	constructor: d(Input),
	_value: d(null),
	isComposite: d(true),
	controlAttributes: d({}),
	_render: d(function () { throw new Error("Not implemented"); }),
	onChange: d(function () {
		var value, changed, valid, emitChanged, emitValid;
		value = this.value;
		changed = some(this.items, function (item) { return item.changed; });
		valid = this.required ? (value != null) : true;

		if (this.changed !== changed) {
			this.changed = changed;
			emitChanged = true;
		}
		if (this.valid !== valid) {
			this.valid = valid;
			emitValid = true;
		}

		this.emit('change', value);
		if (emitChanged) this.emit('change:changed', this.changed);
		if (emitValid) this.emit('change:valid', this.valid);
	}),
	inputValue: d.gs(function () {
		return map(this.items, function (input) { return input.value; });
	}, noop),
	value: d.gs(function () { return this.inputValue; }, noop),
	castControlAttribute: d(noop),
	getOptions: d(function (desc) {
		var options = [this.options];
		if (this.customOptions[desc._sKey_]) options.push(this.customOptions[desc._sKey_]);
		if (this.customOptions[desc.__valueId__]) options.push(this.customOptions[desc.__valueId__]);
		return normalizeOptions.apply(null, options);
	}),
	addItem: d(function (input, name) {
		this.items[name] = input;
		input.parent = this;
		input.on('change', this.onChange);
		return input;
	})
});
<|endoftext|>


<commit_before>import { FETCH_MEDIA, SELECT_MEDIA } from '../../../../actions/topicActions';
import { createAsyncReducer } from '../../../../lib/reduxHelpers';

const info = createAsyncReducer({
  initialState: {
    id: null,
  },
  action: FETCH_MEDIA,
  SELECT_MEDIA: (payload) => ({ id: payload }),
});

export default info;
<commit_msg>refactor how collections are stored<commit_after>import { FETCH_MEDIA, SELECT_MEDIA } from '../../../../actions/topicActions';
import { createAsyncReducer } from '../../../../lib/reduxHelpers';

const TAG_SET_COLLECTIONS_ID = 5;

const info = createAsyncReducer({
  initialState: {
    id: null,
    collections: [],
  },
  action: FETCH_MEDIA,
  SELECT_MEDIA: (payload) => ({ id: payload }),
  handleSuccess: (payload) => ({
    ...payload,
    collections: payload.media_source_tags.filter(tag =>
      (tag.tag_sets_id === TAG_SET_COLLECTIONS_ID) && (tag.show_on_media === 1)
    ),
  }),
});

export default info;
<|endoftext|>


<commit_before>import { remote } from 'electron';
import fs from 'fs';
import path from 'path';

import React, { Component, PropTypes } from 'react';
import TextField from 'material-ui/TextField';
import RaisedButton from 'material-ui/RaisedButton';

import SettingsProvider from '../generic/SettingsProvider';

class FileInput extends Component {
  static propTypes = {
    bonusEvents: PropTypes.array.isRequired,
    label: PropTypes.string.isRequired,
    setSetting: PropTypes.func.isRequired,
    settingsKey: PropTypes.string.isRequired,
  };

  _triggerFile = () => {
    remote.dialog.showOpenDialog(remote.getCurrentWindow(), {
      title: 'Choose a CSS file',
      buttonLabel: 'Load CSS',
      properties: ['openFile'],
      filters: [
        { name: 'CSS Files', extensions: ['css'] },
        { name: 'All Files', extensions: ['*'] },
      ],
    }, (filenames) => {
      if (!filenames) return;
      const filePath = filenames[0];
      if (fs.existsSync(filePath)) {
        this.props.setSetting(this.props.settingsKey, filePath);
        this.props.bonusEvents.forEach((eventName) => Emitter.fire(eventName));
      }
    });
  }

  render() {
    return (

        <RaisedButton
          label={this.props.label}
          onTouchTap={this._triggerFile}
          style={{ backgroundColor: 'transparent', marginRight: 14, marginTop: 4, maxHeight: 0 }}
          primary
        />
        <TextField
          id={`${this.props.label.replace(/ /g, '-')}_value`}
          value={this.props[this.props.settingsKey] ? path.basename(this.props[this.props.settingsKey]) : ''}
          style={{ flex: 1 }}
          onClick={this._triggerFile}
        />

    );
  }
}

export default class WrappedFileInput extends Component {
  static propTypes = {
    label: PropTypes.string.isRequired,
    settingsKey: PropTypes.string.isRequired,
    bonusEvents: PropTypes.array,
  };

  render() {
    const { bonusEvents, label, settingsKey } = this.props;
    return (
      <SettingsProvider component={FileInput} componentProps={{ bonusEvents: bonusEvents || [], label, settingsKey }} keys={[settingsKey]} defaults={{}} />
    );
  }
}
<commit_msg>Reset theme file on escape key press<commit_after>import { remote } from 'electron';
import fs from 'fs';
import path from 'path';

import React, { Component, PropTypes } from 'react';
import TextField from 'material-ui/TextField';
import RaisedButton from 'material-ui/RaisedButton';

import SettingsProvider from '../generic/SettingsProvider';

class FileInput extends Component {
  static propTypes = {
    bonusEvents: PropTypes.array.isRequired,
    label: PropTypes.string.isRequired,
    setSetting: PropTypes.func.isRequired,
    settingsKey: PropTypes.string.isRequired,
  };

  _triggerFile = () => {
    remote.dialog.showOpenDialog(remote.getCurrentWindow(), {
      title: 'Choose a CSS file',
      buttonLabel: 'Load CSS',
      properties: ['openFile'],
      filters: [
        { name: 'CSS Files', extensions: ['css'] },
        { name: 'All Files', extensions: ['*'] },
      ],
    }, (filenames) => {
      if (!filenames) return;
      const filePath = filenames[0];
      if (fs.existsSync(filePath)) {
        this.props.setSetting(this.props.settingsKey, filePath);
        this.props.bonusEvents.forEach((eventName) => Emitter.fire(eventName));
      }
    });
  }

  _keyDown = (event) => {
    if (event.which === 27) {
      this.props.setSetting(this.props.settingsKey, null);
      this.props.bonusEvents.forEach((eventName) => Emitter.fire(eventName));
    }
  }

  render() {
    return (

        <RaisedButton
          label={this.props.label}
          onTouchTap={this._triggerFile}
          style={{ backgroundColor: 'transparent', marginRight: 14, marginTop: 4, maxHeight: 0 }}
          primary
        />
        <TextField
          id={`${this.props.label.replace(/ /g, '-')}_value`}
          value={this.props[this.props.settingsKey] ? path.basename(this.props[this.props.settingsKey]) : ''}
          style={{ flex: 1 }}
          onClick={this._triggerFile}
          onKeyDown={this._keyDown}
        />

    );
  }
}

export default class WrappedFileInput extends Component {
  static propTypes = {
    label: PropTypes.string.isRequired,
    settingsKey: PropTypes.string.isRequired,
    bonusEvents: PropTypes.array,
  };

  render() {
    const { bonusEvents, label, settingsKey } = this.props;
    return (
      <SettingsProvider component={FileInput} componentProps={{ bonusEvents: bonusEvents || [], label, settingsKey }} keys={[settingsKey]} defaults={{}} />
    );
  }
}
<|endoftext|>


<commit_before>import { css } from '@emotion/core'
export const globalStyles = css`
  /* http://meyerweb.com/eric/tools/css/reset/
 v2.0 | 20110126
 License: none (public domain)
*/
  html,
  body,
  div,
  span,
  applet,
  object,
  iframe,
  h1,
  h2,
  h3,
  h4,
  h5,
  h6,
  p,
  blockquote,
  pre,
  a,
  abbr,
  acronym,
  address,
  big,
  cite,
  code,
  del,
  dfn,
  em,
  img,
  ins,
  kbd,
  q,
  s,
  samp,
  small,
  strike,
  strong,
  sub,
  sup,
  tt,
  var,
  b,
  u,
  i,
  center,
  dl,
  dt,
  dd,
  ol,
  ul,
  li,
  fieldset,
  form,
  label,
  legend,
  table,
  caption,
  tbody,
  tfoot,
  thead,
  tr,
  th,
  td,
  article,
  aside,
  canvas,
  details,
  embed,
  figure,
  figcaption,
  footer,
  header,
  hgroup,
  menu,
  nav,
  output,
  ruby,
  section,
  summary,
  time,
  mark,
  audio,
  video {
    margin: 0;
    padding: 0;
    border: 0;
    font-size: 100%;
    /* stylelint-disable-next-line */
    font: inherit;
    vertical-align: baseline;
  }

  /* Added to Fix Footer to bottom of viewport */
  html,
  body {
    background: white;
    height: 100%;
  }
  .siteRoot {
    min-height: 100vh;
    height: 100%;
    display: flex;
    flex-direction: column;
  }
  .siteContent {
    display: flex;
    flex-direction: column;
    flex: 1 0 auto;
  }
  footer {
    width: 100%;
  }

  /* End Fix to Place Footer on Bottom of Viewport */

  article,
  aside,
  details,
  figcaption,
  figure,
  footer,
  header,
  hgroup,
  menu,
  nav,
  section {
    display: block;
  }

  @media screen and (min-width: 35em) {
    html {
      margin-right: calc(-100vw + 100%);
      overflow-x: hidden;
    }
  }

  ol,
  ul,
  li {
    list-style: none;
  }

  blockquote,
  q {
    quotes: none;
  }

  blockquote::before,
  blockquote::after,
  q::before,
  q::after {
    content: '';
    content: none;
  }

  table {
    border-collapse: collapse;
    border-spacing: 0;
  }

  * {
    box-sizing: border-box;
  }

  body {
    line-height: 1;
    font-size: 100%;
    font-variant-ligatures: none;
    text-rendering: optimizeLegibility;
    text-shadow: rgba(0, 0, 0, 0.01) 0 0 1px;
    font-weight: 400;
  }

  img {
    display: block;
    width: 100%;
    height: auto;
  }

  button,
  input,
  textarea,
  select {
    font-family: inherit;
    font-size: inherit;
    background: none;
    border: none;
    appearance: none;
    border-radius: 0;
    resize: none;
    &:invalid {
      box-shadow: none;
    }
    &:focus {
      outline: 5px auto #5e9ed6;
      outline: 5px auto -webkit-focus-ring-color;
    }
  }

  body:not(.user-is-tabbing) button:focus,
  body:not(.user-is-tabbing) input:focus,
  body:not(.user-is-tabbing) select:focus,
  body:not(.user-is-tabbing) textarea:focus,
  body:not(.user-is-tabbing) a:focus {
    outline: none;
  }
`
<commit_msg>Update globalStyles.js<commit_after>import { css } from '@emotion/core'
export const globalStyles = css`
  /* http://meyerweb.com/eric/tools/css/reset/
 v2.0 | 20110126
 License: none (public domain)
*/
  html,
  body,
  div,
  span,
  applet,
  object,
  iframe,
  h1,
  h2,
  h3,
  h4,
  h5,
  h6,
  p,
  blockquote,
  pre,
  a,
  abbr,
  acronym,
  address,
  big,
  cite,
  code,
  del,
  dfn,
  em,
  img,
  ins,
  kbd,
  q,
  s,
  samp,
  small,
  strike,
  strong,
  sub,
  sup,
  tt,
  var,
  b,
  u,
  i,
  center,
  dl,
  dt,
  dd,
  ol,
  ul,
  li,
  fieldset,
  form,
  label,
  legend,
  table,
  caption,
  tbody,
  tfoot,
  thead,
  tr,
  th,
  td,
  article,
  aside,
  canvas,
  details,
  embed,
  figure,
  figcaption,
  footer,
  header,
  hgroup,
  menu,
  nav,
  output,
  ruby,
  section,
  summary,
  time,
  mark,
  audio,
  video {
    margin: 0;
    padding: 0;
    border: 0;
    font-size: 100%;
    /* stylelint-disable-next-line */
    font: inherit;
    vertical-align: baseline;
  }

  /* Added to Fix Footer to bottom of viewport */
  html,
  body {
    background: ${props => props.theme.colors.background};
    height: 100%;
  }
  .siteRoot {
    min-height: 100vh;
    height: 100%;
    display: flex;
    flex-direction: column;
  }
  .siteContent {
    display: flex;
    flex-direction: column;
    flex: 1 0 auto;
  }
  footer {
    width: 100%;
  }

  /* End Fix to Place Footer on Bottom of Viewport */

  article,
  aside,
  details,
  figcaption,
  figure,
  footer,
  header,
  hgroup,
  menu,
  nav,
  section {
    display: block;
  }

  @media screen and (min-width: 35em) {
    html {
      margin-right: calc(-100vw + 100%);
      overflow-x: hidden;
    }
  }

  ol,
  ul,
  li {
    list-style: none;
  }

  blockquote,
  q {
    quotes: none;
  }

  blockquote::before,
  blockquote::after,
  q::before,
  q::after {
    content: '';
    content: none;
  }

  table {
    border-collapse: collapse;
    border-spacing: 0;
  }

  * {
    box-sizing: border-box;
  }

  body {
    line-height: 1;
    font-size: 100%;
    font-variant-ligatures: none;
    text-rendering: optimizeLegibility;
    text-shadow: rgba(0, 0, 0, 0.01) 0 0 1px;
    font-weight: 400;
  }

  img {
    display: block;
    width: 100%;
    height: auto;
  }

  button,
  input,
  textarea,
  select {
    font-family: inherit;
    font-size: inherit;
    background: none;
    border: none;
    appearance: none;
    border-radius: 0;
    resize: none;
    &:invalid {
      box-shadow: none;
    }
    &:focus {
      outline: 5px auto #5e9ed6;
      outline: 5px auto -webkit-focus-ring-color;
    }
  }

  body:not(.user-is-tabbing) button:focus,
  body:not(.user-is-tabbing) input:focus,
  body:not(.user-is-tabbing) select:focus,
  body:not(.user-is-tabbing) textarea:focus,
  body:not(.user-is-tabbing) a:focus {
    outline: none;
  }
`
<|endoftext|>


<commit_before>/* jshint node: true */

/**
 * Gulp Build Scripts Subtask
 *
 * This task bundles JavaScript together using Browserify.
 *
 * Regular front end dependencies need shimming, see package.json for the
 * "browserify-shim" attribute that contains dependencies and return values,
 * and see "browser" attribute for dependency aliases.
 *
 * Note that the default behavior for build:scripts is to run clean:scripts
 * first. Later on, if you start to use watchify, this may be undesirable.
 *
 * @example
 *     gulp build:scripts
 *
 * @package Esensi\Build
 * @author Daniel LaBarge <daniel@emersonmedia.com>
 * @author Matt Malinowski <matt@emersonmedia.com>
 * @copyright 2015 Emerson Media LP
 * @license https://github.com/esensi/build/blob/master/LICENSE.txt MIT License
 * @link http://www.emersonmedia.com
 *
 * @see https://medium.com/@sogko/gulp-browserify-the-gulp-y-way-bb359b3f9623
 */

"use strict";

var gulp       = require('gulp');
var browserify = require('browserify');
var babelify   = require('babelify');
var vueify     = require('vueify');
var gulpif     = require('gulp-if');
var rev        = require('gulp-rev');
var sourcemaps = require('gulp-sourcemaps');
var stream     = require('vinyl-source-stream');
var uglify     = require('gulp-uglify');
var buffer     = require('vinyl-buffer');
var glob       = require('glob');
var config     = global.buildOptions;

// Bundle source JS into minified destination JS files.
// Cleans scripts first to prepare for build.
gulp.task('build:scripts', ['clean:scripts'], function()
{
    var pipeline;
    var source = config.scripts.source;
    var dest   = config.scripts.dest;
    glob(source, {}, function(err, files)
    {
        files.forEach(function(filename)
        {
            var name = filename.split('/');
            name = name[name.length - 1];
            pipeline = browserify(filename, {
                debug: ! global.is_production,
                insertGlobals: true,
                detectGlobals: true,
                noParse: false
            })
            .transform(vueify)
            .transform(babelify, { presets: config.babelify.presets })
            .bundle()

            // Adding an error handler, for when the pipe breaks
            // According to: http://www.bennadel.com/blog/2692-you-have-to-explicitly-end-streams-after-pipes-break-in-node-js.htm
            // the stream has to be ended, but it works without ending it
            .on('error', function (err) {
                console.log(err.message);
            })

            .pipe(stream(name))
            .pipe(buffer())
            .pipe(gulpif(!global.is_production, sourcemaps.init({loadMaps: true}))) // load map from browserify file
            .pipe(gulpif(global.is_production, uglify())) // Minify in production

            // Build without revision
            .pipe(gulpif(!global.is_production && !config.revisions, sourcemaps.write('.'))) // Write maps externally to same directory
            .pipe(gulpif(!config.revisions, gulp.dest(dest)))

            // Build with revisions
            .pipe(gulpif(config.revisions, rev()))
            .pipe(gulpif(!global.is_production && config.revisions, sourcemaps.write('.'))) // Write maps externally to same directory
            .pipe(gulpif(config.revisions, gulp.dest(dest))) // write assets to build dir

            // Build revisions manifest
            .pipe(gulpif(config.revisions, rev.manifest( name.replace('.js', '.json') )))
            .pipe(gulpif(config.revisions, gulp.dest(dest))); // write manifest to build dir
        });
    });

    return pipeline;

});
<commit_msg>Fix in scripts with babelify config reference.<commit_after>/* jshint node: true */

/**
 * Gulp Build Scripts Subtask
 *
 * This task bundles JavaScript together using Browserify.
 *
 * Regular front end dependencies need shimming, see package.json for the
 * "browserify-shim" attribute that contains dependencies and return values,
 * and see "browser" attribute for dependency aliases.
 *
 * Note that the default behavior for build:scripts is to run clean:scripts
 * first. Later on, if you start to use watchify, this may be undesirable.
 *
 * @example
 *     gulp build:scripts
 *
 * @package Esensi\Build
 * @author Daniel LaBarge <daniel@emersonmedia.com>
 * @author Matt Malinowski <matt@emersonmedia.com>
 * @copyright 2015 Emerson Media LP
 * @license https://github.com/esensi/build/blob/master/LICENSE.txt MIT License
 * @link http://www.emersonmedia.com
 *
 * @see https://medium.com/@sogko/gulp-browserify-the-gulp-y-way-bb359b3f9623
 */

"use strict";

var gulp       = require('gulp');
var browserify = require('browserify');
var babelify   = require('babelify');
var vueify     = require('vueify');
var gulpif     = require('gulp-if');
var rev        = require('gulp-rev');
var sourcemaps = require('gulp-sourcemaps');
var stream     = require('vinyl-source-stream');
var uglify     = require('gulp-uglify');
var buffer     = require('vinyl-buffer');
var glob       = require('glob');
var config     = global.buildOptions;

// Bundle source JS into minified destination JS files.
// Cleans scripts first to prepare for build.
gulp.task('build:scripts', ['clean:scripts'], function()
{
    var pipeline;
    var source = config.scripts.source;
    var dest   = config.scripts.dest;
    glob(source, {}, function(err, files)
    {
        files.forEach(function(filename)
        {
            var name = filename.split('/');
            name = name[name.length - 1];
            pipeline = browserify(filename, {
                debug: ! global.is_production,
                insertGlobals: true,
                detectGlobals: true,
                noParse: false
            })
            .transform(vueify)
            .transform(babelify, { presets: config.scripts.babelify.presets })
            .bundle()

            // Adding an error handler, for when the pipe breaks
            // According to: http://www.bennadel.com/blog/2692-you-have-to-explicitly-end-streams-after-pipes-break-in-node-js.htm
            // the stream has to be ended, but it works without ending it
            .on('error', function (err) {
                console.log(err.message);
            })

            .pipe(stream(name))
            .pipe(buffer())
            .pipe(gulpif(!global.is_production, sourcemaps.init({loadMaps: true}))) // load map from browserify file
            .pipe(gulpif(global.is_production, uglify())) // Minify in production

            // Build without revision
            .pipe(gulpif(!global.is_production && !config.revisions, sourcemaps.write('.'))) // Write maps externally to same directory
            .pipe(gulpif(!config.revisions, gulp.dest(dest)))

            // Build with revisions
            .pipe(gulpif(config.revisions, rev()))
            .pipe(gulpif(!global.is_production && config.revisions, sourcemaps.write('.'))) // Write maps externally to same directory
            .pipe(gulpif(config.revisions, gulp.dest(dest))) // write assets to build dir

            // Build revisions manifest
            .pipe(gulpif(config.revisions, rev.manifest( name.replace('.js', '.json') )))
            .pipe(gulpif(config.revisions, gulp.dest(dest))); // write manifest to build dir
        });
    });

    return pipeline;

});
<|endoftext|>


<commit_before>/*!
 * CF Popover
 * A lightweight framework for positioning iPad-style popover elements against triggers.
 *
 * Copyright 2011, Crowd Favorite (http://crowdfavorite.com)
 * Licensed under the MIT license.
 * http://www.opensource.org/licenses/mit-license.php
 */
;(function ($) {
	/* Proxy this once to save computation */
	var uiPosition = $.ui.position;

	/**
	 * Constructor function for popovers
	 */
	var Popover = function ($trigger, opts) {
		this.opts = $.extend({}, this.opts, opts);
		this.$trigger = $($trigger.get(0));

		this.$popover = $(this.$trigger.attr('href'));

		this.$popover
			.prepend('')
			.append('')
			.hide();
	};
	Popover.prototype = {
		timeout: null,
		$win: $(window),

		opts: {
			my: 'center bottom',
			at: 'center top',
			offset: '0 0',
			collision: 'flop flop'
		},

		/**
		 * Custom collision handling for popovers (access via "flop" keyword)
		 * Identical to "flip", but adds class to element being flipped to let
		 * you know when it has been changed from default position.
		 * Functions get bound to this.$popover in the constructor.
		 * Used as a monkey patch below.
		 */
		flop: {
			left: function (position, data) {
				var cPosition = data.collisionPosition,
					$popover = $(this),
					c = 'flopped-x',
					out;

				/* Run the original first -- it modifies position
				and data by reference. Store return value
				anyway, since we want to make sure if they do
				decide to return something in future the API
				isn't broken */
				out = uiPosition.flip.left(position, data);

				(cPosition.left !== position.left) ? $popover.addClass(c) : $popover.removeClass(c);

				return out;
			},
			top: function (position, data) {
				var cPosition = data.collisionPosition,
					$popover = $(this),
					c = 'flopped-y',
					out;

				/* Run the original first -- it modifies position
				and data by reference. Store return value
				anyway, since we want to make sure if they do
				decide to return something in future the API
				isn't broken */
				out = uiPosition.flip.top(position, data);

				(cPosition.top !== position.top) ? $popover.addClass(c) : $popover.removeClass(c);

				return out;
			}
		},

		bindEvents: function () {
			this.$trigger.click($.proxy(function (e) {
				if (this.$popover.is(':visible')) {
					this.hidePopover(e);
				}
				else {
					this.showPopover(e);
				};
			}, this));

			$('body').click($.proxy(function () {
				this.$popover.fadeOut('fast');
			}, this));

			this.$popover.click(function (e) {
				e.stopPropagation();
			});

			this.$win.resize($.proxy(this.pinToTargetDebounced, this));
		},

		showPopover: function (e) {
			this.$popover.fadeIn();
			this.pinToTarget();
			e.preventDefault();
			e.stopPropagation();
		},

		hidePopover: function (e) {
			this.$popover.fadeOut('fast');
			e.preventDefault();
			e.stopPropagation();
		},

		/* Calculate and position against trigger */
		pinToTarget: function () {
			var $popover = this.$popover,
				opts = this.opts,
				defaultPosOpts = {
					of: this.$trigger
				},
				posOpts = $.extend(defaultPosOpts, opts),
				flop;

			/* Monkey-patch in our custom collision handling */
			flop = {
				/* Bind our custom collision handling to the popover element */
				left: $.proxy(this.flop.left, this.$popover),
				top: $.proxy(this.flop.top, this.$popover)
			};

			uiPosition.flop = flop;
			$popover.position(posOpts);
			uiPosition.flop = undefined;
		},

		/* Debounced to prevent hitting lots of times while resizing happens.
		Will fire a maximum of 20x per second. Useful for binding to the window
		resize event. */
		pinToTargetDebounced: function () {
			clearTimeout(this.timeout);
			this.timeout = setTimeout($.proxy(this.pinToTarget, this), 50);
		}
	};

	$.fn.popover = function (opts) {
		var Popover = $.fn.popover.Popover;

		this.each(function() {
			var $this = $(this);
			var popover = new Popover($this, opts);
			popover.bindEvents();

			/* Store Popover instance for easy method access.
			See: http://alexsexton.com/?p=51

			Example: $('.trigger').data('popover').hidePopover(); */
			$this.data('popover', popover);
		});
	};
	/* Expose constructor function for folks to duck-type when necessary */
	$.fn.popover.Popover = Popover;
})(jQuery);<commit_msg>Cleaning up formatting.<commit_after>/*!
 * CF Popover
 * A lightweight framework for positioning iPad-style popover elements against triggers.
 *
 * Copyright 2011, Crowd Favorite (http://crowdfavorite.com)
 * Licensed under the MIT license.
 * http://www.opensource.org/licenses/mit-license.php
 */
;(function ($) {
	/* Proxy this once to save computation */
	var uiPosition = $.ui.position;

	/**
	 * Constructor function for popovers
	 */
	var Popover = function ($trigger, opts) {
		this.opts = $.extend({}, this.opts, opts);
		this.$trigger = $($trigger.get(0));

		this.$popover = $(this.$trigger.attr('href'));

		this.$popover
			.prepend('')
			.append('')
			.hide();
	};
	Popover.prototype = {
		timeout: null,
		$win: $(window),

		opts: {
			my: 'center bottom',
			at: 'center top',
			offset: '0 0',
			collision: 'flop flop'
		},

		/**
		 * Custom collision handling for popovers (access via "flop" keyword)
		 * Identical to "flip", but adds class to element being flipped to let
		 * you know when it has been changed from default position.
		 * Functions get bound to this.$popover in the constructor.
		 * Used as a monkey patch below.
		 */
		flop: {
			left: function (position, data) {
				var cPosition = data.collisionPosition,
					$popover = $(this),
					c = 'flopped-x',
					out;

				/* Run the original first -- it modifies position
				and data by reference. Store return value
				anyway, since we want to make sure if they do
				decide to return something in future the API
				isn't broken */
				out = uiPosition.flip.left(position, data);

				(cPosition.left !== position.left) ? $popover.addClass(c) : $popover.removeClass(c);

				return out;
			},
			top: function (position, data) {
				var cPosition = data.collisionPosition,
					$popover = $(this),
					c = 'flopped-y',
					out;

				/* Run the original first -- it modifies position
				and data by reference. Store return value
				anyway, since we want to make sure if they do
				decide to return something in future the API
				isn't broken */
				out = uiPosition.flip.top(position, data);

				(cPosition.top !== position.top) ? $popover.addClass(c) : $popover.removeClass(c);

				return out;
			}
		},

		bindEvents: function () {
			this.$trigger.click($.proxy(function (e) {
				if (this.$popover.is(':visible')) {
					this.hidePopover(e);
				}
				else {
					this.showPopover(e);
				};
			}, this));

			$('body').click($.proxy(function () {
				this.$popover.fadeOut('fast');
			}, this));

			this.$popover.click(function (e) {
				e.stopPropagation();
			});

			this.$win.resize($.proxy(this.pinToTargetDebounced, this));
		},

		showPopover: function (e) {
			this.$popover.fadeIn();
			this.pinToTarget();
			e.preventDefault();
			e.stopPropagation();
		},

		hidePopover: function (e) {
			this.$popover.fadeOut('fast');
			e.preventDefault();
			e.stopPropagation();
		},

		/* Calculate and position against trigger */
		pinToTarget: function () {
			var $popover = this.$popover,
				posOpts = $.extend({
					of: this.$trigger
				}, this.opts),

				/* Monkey-patch in our custom collision handling */
				flop = {
					/* Bind our custom collision handling to the popover element */
					left: $.proxy(this.flop.left, this.$popover),
					top: $.proxy(this.flop.top, this.$popover)
				};

			uiPosition.flop = flop;
			$popover.position(posOpts);
			uiPosition.flop = undefined;
		},

		/* Debounced to prevent hitting lots of times while resizing happens.
		Will fire a maximum of 20x per second. Useful for binding to the window
		resize event. */
		pinToTargetDebounced: function () {
			clearTimeout(this.timeout);
			this.timeout = setTimeout($.proxy(this.pinToTarget, this), 50);
		}
	};

	$.fn.popover = function (opts) {
		var Popover = $.fn.popover.Popover;

		this.each(function() {
			var $this = $(this);
			var popover = new Popover($this, opts);
			popover.bindEvents();

			/* Store Popover instance for easy method access.
			See: http://alexsexton.com/?p=51

			Example: $('.trigger').data('popover').hidePopover(); */
			$this.data('popover', popover);
		});
	};
	/* Expose constructor function for folks to duck-type when necessary */
	$.fn.popover.Popover = Popover;
})(jQuery);<|endoftext|>


<commit_before>/*!
	Copyright 2010 Mal Curtis
*/

// Support for UMD: https://github.com/umdjs/umd/blob/master/jqueryPluginCommonjs.js
// This allows for tools such as Browserify to compose the components together into a single HTTP request.
(function (factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define(['jquery'], factory);
    } else if (typeof exports === 'object') {
        // Node/CommonJS
        module.exports = factory(require('jquery'));
    } else {
        // Browser globals
        factory(jQuery);
    }
}(function ($) {
    if (typeof $(document).on !== 'function') {
        if (typeof $(document).delegate === 'function') {
            // Patch jQuery 1.4.2 - 1.7 with an on function (that uses delegate).
            $.fn.on = function (events, selector, data, handler) {
                return $(this).delegate(selector, events, data, handler);
            };
        } else {
            throw ('jQuery 1.4.2 or higher is required by jquery.dirtyforms');
        }
    }

    // Public General Plugin methods $.DirtyForms
    $.extend({
        DirtyForms: {
            debug: false,
            message: 'You\'ve made changes on this page which aren\'t saved. If you leave you will lose these changes.',
            title: 'Are you sure you want to do that?',
            dirtyClass: 'dirty',
            listeningClass: 'dirtylisten',
            ignoreClass: 'ignoredirty',
            choiceContinue: false,
            helpers: [],
            dialog: {
                refire: function (content, ev) {
                    $.facebox(content);
                },
                fire: function (message, title) {
                    var content = '
' + title + '

' + message + '

ContinueStop';
                    $.facebox(content);
                },
                bind: function () {
                    var close = function (decision) {
                        return function (e) {
                            e.preventDefault();
                            $(document).trigger('close.facebox');
                            decision(e);
                        };
                    };
                    $('#facebox .cancel, #facebox .close, #facebox_overlay').click(close(decidingCancel));
                    $('#facebox .continue').click(close(decidingContinue));
                },
                stash: function () {
                    var fb = $('#facebox');
                    return ($.trim(fb.html()) === '' || fb.css('display') != 'block') ?
					   false :
					   $('#facebox .content').clone(true);
                },
                selector: '#facebox .content'
            },

            isDirty: function () {
                return $(':dirtylistening').dirtyForms('isDirty');
            },

            disable: function () {
                settings.disabled = true;
            },

            ignoreParentDocs: function () {
                settings.watchParentDocs = false;
            },

            choiceCommit: function (e) {
                choiceCommit(e);
            },

            isDeciding: function () {
                return settings.deciding;
            },

            decidingContinue: function (e) {
                decidingContinue(e);
            },

            decidingCancel: function (e) {
                decidingCancel(e);
            },

            dirtylog: function (msg) {
                dirtylog(msg);
            }
        }
    });

    // Create a custom selector $('form:dirty')
    $.extend($.expr[":"], {
        dirtylistening: function (a) {
            return $(a).hasClass(settings.listeningClass);
        },
        dirty: function (a) {
            return $(a).hasClass(settings.dirtyClass);
        }
    });

    // Public Element methods ( $('form').dirtyForms('methodName', args) )
    var methods = {
        init: function () {
            dirtylog('Adding forms to watch');
            bindExit();

            return this.each(function (e) {
                var $form = $(this);
                if (!$form.is('form')) return;
                dirtylog('Adding form ' + $form.attr('id') + ' to forms to watch');

                $form.addClass(settings.listeningClass)
                    // exclude all HTML 4 except text and password, but include HTML 5 except search
                    .on('focus change', "textarea,input:not([type='checkbox'],[type='radio'],[type='button']," +
					    "[type='image'],[type='submit'],[type='reset'],[type='file'],[type='search'])", onFocus)
                    .on('change', "input[type='checkbox'],input[type='radio'],select", onSelectionChange)
                    .on('click', "input[type='reset']", onReset);

                // Initialize settings with the currently focused element (autofocus)
                var focused = $form.find(inputSelector).filter(':focus');
                if (focused) {
                    settings.focused.element = focused;
                    settings.focused.value = focused.val();
                }
            });
        },
        // Returns true if any of the supplied elements are dirty
        isDirty: function () {
            var isDirty = false,
                node = this;
            if (settings.disabled) return false;
            if (focusedIsDirty()) {
                isDirty = true;
                return true;
            }
            this.each(function (e) {
                if ($(this).hasClass(settings.dirtyClass)) {
                    isDirty = true;
                    return true;
                }
            });
            $.each(settings.helpers, function (key, obj) {
                if ("isDirty" in obj) {
                    if (obj.isDirty(node)) {
                        isDirty = true;
                        return true;
                    }
                }
                // For backward compatibility, we call isNodeDirty (deprecated)
                if ("isNodeDirty" in obj) {
                    if (obj.isNodeDirty(node)) {
                        isDirty = true;
                        return true;
                    }
                }
            });

            dirtylog('isDirty returned ' + isDirty);
            return isDirty;
        },
        // Marks the element(s) that match the selector dirty
        setDirty: function () {
            dirtylog('setDirty called');
            return this.each(function (e) {
                $(this).addClass(settings.dirtyClass).parents('form').addClass(settings.dirtyClass);
            });
        },
        // "Cleans" this dirty form by essentially forgetting that it is dirty
        setClean: function () {
            dirtylog('setClean called');
            settings.focused = { element: false, value: false };

            return this.each(function (e) {
                var node = this, $node = $(this);

                // remove the current dirty class
                $node.removeClass(settings.dirtyClass);

                if ($node.is('form')) {
                    // remove all dirty classes from children
                    $node.find(':dirty').removeClass(settings.dirtyClass);
                } else {
                    // if this is last dirty child, set form clean
                    var $form = $node.parents('form');
                    if ($form.find(':dirty').length === 0) {
                        $form.removeClass(settings.dirtyClass);
                    }
                }

                // Clean helpers
                $.each(settings.helpers, function (key, obj) {
                    if ("setClean" in obj) {
                        obj.setClean(node);
                    }
                });
            });
        }

        // ADD NEW METHODS HERE
    };

    $.fn.dirtyForms = function (method) {
        // Method calling logic
        if (methods[method]) {
            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
        } else if (typeof method === 'object' || !method) {
            return methods.init.apply(this, arguments);
        } else {
            $.error('Method ' + method + ' does not exist on jQuery.dirtyForms');
        }
    };

    // Deprecated Methods for Backward Compatibility
    // DO NOT ADD MORE METHODS LIKE THESE, ADD METHODS WHERE INDICATED ABOVE
    $.fn.setDirty = function () {
        return this.dirtyForms('setDirty');
    };
    $.fn.isDirty = function () {
        return this.dirtyForms('isDirty');
    };
    $.fn.cleanDirty = function () {
        return this.dirtyForms('setClean');
    };

    // Private Properties and Methods
    var settings = $.DirtyForms = $.extend({
        watchParentDocs: true,
        disabled: false,
        exitBound: false,
        formStash: false,
        dialogStash: false,
        deciding: false,
        decidingEvent: false,
        currentForm: false,
        hasFirebug: "console" in window && "firebug" in window.console,
        hasConsoleLog: "console" in window && "log" in window.console,
        focused: { "element": false, "value": false }
    }, $.DirtyForms);

    var onReset = function () {
        $(this).parents('form').dirtyForms('setClean');
        if (settings.onFormCheck) {
            settings.onFormCheck();
        }
    };

    var onSelectionChange = function () {
        if ($(this).hasClass(settings.ignoreClass)) return;
        $(this).dirtyForms('setDirty');
        if (settings.onFormCheck) {
            settings.onFormCheck();
        }
    };

    var onFocus = function () {
        var $this = $(this);
        if (focusedIsDirty() && !$this.hasClass(settings.ignoreClass)) {
            settings.focused.element.dirtyForms('setDirty');
            if (settings.onFormCheck) {
                settings.onFormCheck();
            }
        }
        settings.focused.element = $this;
        settings.focused.value = $this.val();
    };

    var focusedIsDirty = function () {
        // Check, whether the value of focused element has changed
        return settings.focused.element &&
			(settings.focused.element.val() !== settings.focused.value);
    };

    var dirtylog = function (msg) {
        if (!settings.debug) return;
        msg = "[DirtyForms] " + msg;
        if (settings.hasFirebug) {
            console.log(msg);
        } else if (settings.hasConsoleLog) {
            window.console.log(msg);
        } else {
            alert(msg);
        }
    };

    var bindExit = function () {
        if (settings.exitBound) return;

        var inIframe = (top !== self);

        $(document).on('click', 'a[href]', aBindFn)
                   .on('submit', 'form', formBindFn);
        if (settings.watchParentDocs && inIframe) {
            $(top.document).on('click', 'a[href]', aBindFn)
                           .on('submit', 'form', formBindFn);
        }

        $(window).bind('beforeunload', beforeunloadBindFn);
        if (settings.watchParentDocs && inIframe) {
            $(top.window).bind('beforeunload', beforeunloadBindFn);
        }

        settings.exitBound = true;
    };

    var getIgnoreAnchorSelector = function () {
        var result = '';
        $.each(settings.helpers, function (key, obj) {
            if ("ignoreAnchorSelector" in obj) {
                if (result.length > 0) { result += ','; }
                result += obj.ignoreAnchorSelector;
            }
        });
        return result;
    };

    var aBindFn = function (ev) {
        // Filter out any anchors the helpers wish to exclude
        if (!$(this).is(getIgnoreAnchorSelector())) {
            bindFn(ev);
        }
    };

    var formBindFn = function (ev) {
        settings.currentForm = this;
        bindFn(ev);
    };

    var beforeunloadBindFn = function (ev) {
        var result = bindFn(ev);

        if (result && settings.doubleunloadfix !== true) {
            dirtylog('Before unload will be called, resetting');
            settings.deciding = false;
        }

        settings.doubleunloadfix = true;
        setTimeout(function () { settings.doubleunloadfix = false; }, 200);

        // Bug Fix: Only return the result if it is a string,
        // otherwise don't return anything.
        if (typeof (result) == 'string') {
            ev = ev || window.event;

            // For IE and Firefox prior to version 4
            if (ev) {
                ev.returnValue = result;
            }

            // For Safari
            return result;
        }
    };

    var bindFn = function (ev) {
        var $element = $(ev.target), eventType = ev.type;
        dirtylog('Entering: Leaving Event fired, type: ' + eventType + ', element: ' + ev.target + ', class: ' + $element.attr('class') + ' and id: ' + ev.target.id);

        if (eventType == 'beforeunload' && settings.doubleunloadfix) {
            dirtylog('Skip this unload, Firefox bug triggers the unload event multiple times');
            settings.doubleunloadfix = false;
            return false;
        }

        if ($element.hasClass(settings.ignoreClass) || isDifferentTarget($element)) {
            dirtylog('Leaving: Element has ignore class or has target=\'_blank\'');
            if (!ev.isDefaultPrevented()) {
                clearUnload();
            }
            return false;
        }

        if (settings.deciding) {
            dirtylog('Leaving: Already in the deciding process');
            return false;
        }

        if (ev.isDefaultPrevented()) {
            dirtylog('Leaving: Event has been stopped elsewhere');
            return false;
        }

        if (!settings.isDirty()) {
            dirtylog('Leaving: Not dirty');
            if (!ev.isDefaultPrevented()) {
                clearUnload();
            }
            return false;
        }

        if (eventType == 'submit' && $element.dirtyForms('isDirty')) {
            dirtylog('Leaving: Form submitted is a dirty form');
            if (!ev.isDefaultPrevented()) {
                clearUnload();
            }
            return true;
        }

        if (settings.dialog) {
            settings.deciding = true;
            settings.decidingEvent = ev;
            dirtylog('Setting deciding active');

            dirtylog('Saving dialog content');
            settings.dialogStash = settings.dialog.stash();
            dirtylog(settings.dialogStash);
        }

        // Callback for page access in current state
        $(document).trigger('defer.dirtyforms');

        if (eventType == 'beforeunload') {
            dirtylog('Returning to beforeunload browser handler with: ' + settings.message);
            return settings.message;
        }
        if (!settings.dialog) return;

        ev.preventDefault();
        ev.stopImmediatePropagation();

        if ($element.is('form') && $element.parents(settings.dialog.selector).length > 0) {
            dirtylog('Stashing form');
            settings.formStash = $element.clone(true).hide();
        } else {
            settings.formStash = false;
        }

        dirtylog('Deferring to the dialog');
        settings.dialog.fire(settings.message, settings.title);
        settings.dialog.bind();
    };

    var isDifferentTarget = function ($element) {
        var aTarget = $element.attr('target');
        return typeof aTarget === 'string' ? aTarget.toLowerCase() === '_blank' : false;
    };

    var choiceCommit = function (ev) {
        if (settings.deciding) {
            $(document).trigger('choicecommit.dirtyforms');
            if (settings.choiceContinue) {
                decidingContinue(ev);
            } else {
                decidingCancel(ev);
            }
            $(document).trigger('choicecommitAfter.dirtyforms');
        }
    };

    var decidingCancel = function (ev) {
        ev.preventDefault();
        $(document).trigger('decidingcancelled.dirtyforms');
        if (settings.dialog !== false && settings.dialogStash !== false) {
            dirtylog('Refiring the dialog with stashed content');
            settings.dialog.refire(settings.dialogStash.html(), ev);
        }
        $(document).trigger('decidingcancelledAfter.dirtyforms');
        settings.deciding = settings.currentForm = settings.decidingEvent = settings.dialogStash = false;
    };

    var decidingContinue = function (ev) {
        clearUnload(); // fix for chrome/safari
        ev.preventDefault();
        settings.dialogStash = false;
        $(document).trigger('decidingcontinued.dirtyforms');
        refire(settings.decidingEvent);
        settings.deciding = settings.currentForm = settings.decidingEvent = false;
    };

    var clearUnload = function () {
        // I'd like to just be able to unbind this but there seems
        // to be a bug in jQuery which doesn't unbind onbeforeunload
        dirtylog('Clearing the beforeunload event');
        $(window).unbind('beforeunload', beforeunloadBindFn);
        window.onbeforeunload = null;
        $(document).trigger('beforeunload.dirtyforms');
    };

    var refire = function (e) {
        $(document).trigger('beforeRefire.dirtyforms');
        $(document).trigger('beforeunload.dirtyforms');
        if (e.type === 'click') {
            dirtylog("Refiring click event");
            var event = new $.Event('click');
            $(e.target).trigger(event);
            if (!event.isDefaultPrevented()) {
                var href = $(e.target).attr('href');
                dirtylog('Sending location to ' + href);
                location.href = href;
                return;
            }
        } else {
            dirtylog("Refiring " + e.type + " event on " + e.target);
            var target;
            if (settings.formStash) {
                dirtylog('Appending stashed form to body');
                target = settings.formStash;
                $('body').append(target);
            }
            else {
                target = $(e.target);
                if (!target.is('form'))
                    target = target.closest('form');
            }
            target.trigger(e.type);
        }
    };

}));
<commit_msg>Removed redundant call to $(document) in refire function.<commit_after>/*!
	Copyright 2010 Mal Curtis
*/

// Support for UMD: https://github.com/umdjs/umd/blob/master/jqueryPluginCommonjs.js
// This allows for tools such as Browserify to compose the components together into a single HTTP request.
(function (factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define(['jquery'], factory);
    } else if (typeof exports === 'object') {
        // Node/CommonJS
        module.exports = factory(require('jquery'));
    } else {
        // Browser globals
        factory(jQuery);
    }
}(function ($) {
    if (typeof $(document).on !== 'function') {
        if (typeof $(document).delegate === 'function') {
            // Patch jQuery 1.4.2 - 1.7 with an on function (that uses delegate).
            $.fn.on = function (events, selector, data, handler) {
                return $(this).delegate(selector, events, data, handler);
            };
        } else {
            throw ('jQuery 1.4.2 or higher is required by jquery.dirtyforms');
        }
    }

    // Public General Plugin methods $.DirtyForms
    $.extend({
        DirtyForms: {
            debug: false,
            message: 'You\'ve made changes on this page which aren\'t saved. If you leave you will lose these changes.',
            title: 'Are you sure you want to do that?',
            dirtyClass: 'dirty',
            listeningClass: 'dirtylisten',
            ignoreClass: 'ignoredirty',
            choiceContinue: false,
            helpers: [],
            dialog: {
                refire: function (content, ev) {
                    $.facebox(content);
                },
                fire: function (message, title) {
                    var content = '
' + title + '

' + message + '

ContinueStop';
                    $.facebox(content);
                },
                bind: function () {
                    var close = function (decision) {
                        return function (e) {
                            e.preventDefault();
                            $(document).trigger('close.facebox');
                            decision(e);
                        };
                    };
                    $('#facebox .cancel, #facebox .close, #facebox_overlay').click(close(decidingCancel));
                    $('#facebox .continue').click(close(decidingContinue));
                },
                stash: function () {
                    var fb = $('#facebox');
                    return ($.trim(fb.html()) === '' || fb.css('display') != 'block') ?
					   false :
					   $('#facebox .content').clone(true);
                },
                selector: '#facebox .content'
            },

            isDirty: function () {
                return $(':dirtylistening').dirtyForms('isDirty');
            },

            disable: function () {
                settings.disabled = true;
            },

            ignoreParentDocs: function () {
                settings.watchParentDocs = false;
            },

            choiceCommit: function (e) {
                choiceCommit(e);
            },

            isDeciding: function () {
                return settings.deciding;
            },

            decidingContinue: function (e) {
                decidingContinue(e);
            },

            decidingCancel: function (e) {
                decidingCancel(e);
            },

            dirtylog: function (msg) {
                dirtylog(msg);
            }
        }
    });

    // Create a custom selector $('form:dirty')
    $.extend($.expr[":"], {
        dirtylistening: function (a) {
            return $(a).hasClass(settings.listeningClass);
        },
        dirty: function (a) {
            return $(a).hasClass(settings.dirtyClass);
        }
    });

    // Public Element methods ( $('form').dirtyForms('methodName', args) )
    var methods = {
        init: function () {
            dirtylog('Adding forms to watch');
            bindExit();

            return this.each(function (e) {
                var $form = $(this);
                if (!$form.is('form')) return;
                dirtylog('Adding form ' + $form.attr('id') + ' to forms to watch');

                $form.addClass(settings.listeningClass)
                    // exclude all HTML 4 except text and password, but include HTML 5 except search
                    .on('focus change', "textarea,input:not([type='checkbox'],[type='radio'],[type='button']," +
					    "[type='image'],[type='submit'],[type='reset'],[type='file'],[type='search'])", onFocus)
                    .on('change', "input[type='checkbox'],input[type='radio'],select", onSelectionChange)
                    .on('click', "input[type='reset']", onReset);

                // Initialize settings with the currently focused element (autofocus)
                var focused = $form.find(inputSelector).filter(':focus');
                if (focused) {
                    settings.focused.element = focused;
                    settings.focused.value = focused.val();
                }
            });
        },
        // Returns true if any of the supplied elements are dirty
        isDirty: function () {
            var isDirty = false,
                node = this;
            if (settings.disabled) return false;
            if (focusedIsDirty()) {
                isDirty = true;
                return true;
            }
            this.each(function (e) {
                if ($(this).hasClass(settings.dirtyClass)) {
                    isDirty = true;
                    return true;
                }
            });
            $.each(settings.helpers, function (key, obj) {
                if ("isDirty" in obj) {
                    if (obj.isDirty(node)) {
                        isDirty = true;
                        return true;
                    }
                }
                // For backward compatibility, we call isNodeDirty (deprecated)
                if ("isNodeDirty" in obj) {
                    if (obj.isNodeDirty(node)) {
                        isDirty = true;
                        return true;
                    }
                }
            });

            dirtylog('isDirty returned ' + isDirty);
            return isDirty;
        },
        // Marks the element(s) that match the selector dirty
        setDirty: function () {
            dirtylog('setDirty called');
            return this.each(function (e) {
                $(this).addClass(settings.dirtyClass).parents('form').addClass(settings.dirtyClass);
            });
        },
        // "Cleans" this dirty form by essentially forgetting that it is dirty
        setClean: function () {
            dirtylog('setClean called');
            settings.focused = { element: false, value: false };

            return this.each(function (e) {
                var node = this, $node = $(this);

                // remove the current dirty class
                $node.removeClass(settings.dirtyClass);

                if ($node.is('form')) {
                    // remove all dirty classes from children
                    $node.find(':dirty').removeClass(settings.dirtyClass);
                } else {
                    // if this is last dirty child, set form clean
                    var $form = $node.parents('form');
                    if ($form.find(':dirty').length === 0) {
                        $form.removeClass(settings.dirtyClass);
                    }
                }

                // Clean helpers
                $.each(settings.helpers, function (key, obj) {
                    if ("setClean" in obj) {
                        obj.setClean(node);
                    }
                });
            });
        }

        // ADD NEW METHODS HERE
    };

    $.fn.dirtyForms = function (method) {
        // Method calling logic
        if (methods[method]) {
            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
        } else if (typeof method === 'object' || !method) {
            return methods.init.apply(this, arguments);
        } else {
            $.error('Method ' + method + ' does not exist on jQuery.dirtyForms');
        }
    };

    // Deprecated Methods for Backward Compatibility
    // DO NOT ADD MORE METHODS LIKE THESE, ADD METHODS WHERE INDICATED ABOVE
    $.fn.setDirty = function () {
        return this.dirtyForms('setDirty');
    };
    $.fn.isDirty = function () {
        return this.dirtyForms('isDirty');
    };
    $.fn.cleanDirty = function () {
        return this.dirtyForms('setClean');
    };

    // Private Properties and Methods
    var settings = $.DirtyForms = $.extend({
        watchParentDocs: true,
        disabled: false,
        exitBound: false,
        formStash: false,
        dialogStash: false,
        deciding: false,
        decidingEvent: false,
        currentForm: false,
        hasFirebug: "console" in window && "firebug" in window.console,
        hasConsoleLog: "console" in window && "log" in window.console,
        focused: { "element": false, "value": false }
    }, $.DirtyForms);

    var onReset = function () {
        $(this).parents('form').dirtyForms('setClean');
        if (settings.onFormCheck) {
            settings.onFormCheck();
        }
    };

    var onSelectionChange = function () {
        if ($(this).hasClass(settings.ignoreClass)) return;
        $(this).dirtyForms('setDirty');
        if (settings.onFormCheck) {
            settings.onFormCheck();
        }
    };

    var onFocus = function () {
        var $this = $(this);
        if (focusedIsDirty() && !$this.hasClass(settings.ignoreClass)) {
            settings.focused.element.dirtyForms('setDirty');
            if (settings.onFormCheck) {
                settings.onFormCheck();
            }
        }
        settings.focused.element = $this;
        settings.focused.value = $this.val();
    };

    var focusedIsDirty = function () {
        // Check, whether the value of focused element has changed
        return settings.focused.element &&
			(settings.focused.element.val() !== settings.focused.value);
    };

    var dirtylog = function (msg) {
        if (!settings.debug) return;
        msg = "[DirtyForms] " + msg;
        if (settings.hasFirebug) {
            console.log(msg);
        } else if (settings.hasConsoleLog) {
            window.console.log(msg);
        } else {
            alert(msg);
        }
    };

    var bindExit = function () {
        if (settings.exitBound) return;

        var inIframe = (top !== self);

        $(document).on('click', 'a[href]', aBindFn)
                   .on('submit', 'form', formBindFn);
        if (settings.watchParentDocs && inIframe) {
            $(top.document).on('click', 'a[href]', aBindFn)
                           .on('submit', 'form', formBindFn);
        }

        $(window).bind('beforeunload', beforeunloadBindFn);
        if (settings.watchParentDocs && inIframe) {
            $(top.window).bind('beforeunload', beforeunloadBindFn);
        }

        settings.exitBound = true;
    };

    var getIgnoreAnchorSelector = function () {
        var result = '';
        $.each(settings.helpers, function (key, obj) {
            if ("ignoreAnchorSelector" in obj) {
                if (result.length > 0) { result += ','; }
                result += obj.ignoreAnchorSelector;
            }
        });
        return result;
    };

    var aBindFn = function (ev) {
        // Filter out any anchors the helpers wish to exclude
        if (!$(this).is(getIgnoreAnchorSelector())) {
            bindFn(ev);
        }
    };

    var formBindFn = function (ev) {
        settings.currentForm = this;
        bindFn(ev);
    };

    var beforeunloadBindFn = function (ev) {
        var result = bindFn(ev);

        if (result && settings.doubleunloadfix !== true) {
            dirtylog('Before unload will be called, resetting');
            settings.deciding = false;
        }

        settings.doubleunloadfix = true;
        setTimeout(function () { settings.doubleunloadfix = false; }, 200);

        // Bug Fix: Only return the result if it is a string,
        // otherwise don't return anything.
        if (typeof (result) == 'string') {
            ev = ev || window.event;

            // For IE and Firefox prior to version 4
            if (ev) {
                ev.returnValue = result;
            }

            // For Safari
            return result;
        }
    };

    var bindFn = function (ev) {
        var $element = $(ev.target), eventType = ev.type;
        dirtylog('Entering: Leaving Event fired, type: ' + eventType + ', element: ' + ev.target + ', class: ' + $element.attr('class') + ' and id: ' + ev.target.id);

        if (eventType == 'beforeunload' && settings.doubleunloadfix) {
            dirtylog('Skip this unload, Firefox bug triggers the unload event multiple times');
            settings.doubleunloadfix = false;
            return false;
        }

        if ($element.hasClass(settings.ignoreClass) || isDifferentTarget($element)) {
            dirtylog('Leaving: Element has ignore class or has target=\'_blank\'');
            if (!ev.isDefaultPrevented()) {
                clearUnload();
            }
            return false;
        }

        if (settings.deciding) {
            dirtylog('Leaving: Already in the deciding process');
            return false;
        }

        if (ev.isDefaultPrevented()) {
            dirtylog('Leaving: Event has been stopped elsewhere');
            return false;
        }

        if (!settings.isDirty()) {
            dirtylog('Leaving: Not dirty');
            if (!ev.isDefaultPrevented()) {
                clearUnload();
            }
            return false;
        }

        if (eventType == 'submit' && $element.dirtyForms('isDirty')) {
            dirtylog('Leaving: Form submitted is a dirty form');
            if (!ev.isDefaultPrevented()) {
                clearUnload();
            }
            return true;
        }

        if (settings.dialog) {
            settings.deciding = true;
            settings.decidingEvent = ev;
            dirtylog('Setting deciding active');

            dirtylog('Saving dialog content');
            settings.dialogStash = settings.dialog.stash();
            dirtylog(settings.dialogStash);
        }

        // Callback for page access in current state
        $(document).trigger('defer.dirtyforms');

        if (eventType == 'beforeunload') {
            dirtylog('Returning to beforeunload browser handler with: ' + settings.message);
            return settings.message;
        }
        if (!settings.dialog) return;

        ev.preventDefault();
        ev.stopImmediatePropagation();

        if ($element.is('form') && $element.parents(settings.dialog.selector).length > 0) {
            dirtylog('Stashing form');
            settings.formStash = $element.clone(true).hide();
        } else {
            settings.formStash = false;
        }

        dirtylog('Deferring to the dialog');
        settings.dialog.fire(settings.message, settings.title);
        settings.dialog.bind();
    };

    var isDifferentTarget = function ($element) {
        var aTarget = $element.attr('target');
        return typeof aTarget === 'string' ? aTarget.toLowerCase() === '_blank' : false;
    };

    var choiceCommit = function (ev) {
        if (settings.deciding) {
            $(document).trigger('choicecommit.dirtyforms');
            if (settings.choiceContinue) {
                decidingContinue(ev);
            } else {
                decidingCancel(ev);
            }
            $(document).trigger('choicecommitAfter.dirtyforms');
        }
    };

    var decidingCancel = function (ev) {
        ev.preventDefault();
        $(document).trigger('decidingcancelled.dirtyforms');
        if (settings.dialog !== false && settings.dialogStash !== false) {
            dirtylog('Refiring the dialog with stashed content');
            settings.dialog.refire(settings.dialogStash.html(), ev);
        }
        $(document).trigger('decidingcancelledAfter.dirtyforms');
        settings.deciding = settings.currentForm = settings.decidingEvent = settings.dialogStash = false;
    };

    var decidingContinue = function (ev) {
        clearUnload(); // fix for chrome/safari
        ev.preventDefault();
        settings.dialogStash = false;
        $(document).trigger('decidingcontinued.dirtyforms');
        refire(settings.decidingEvent);
        settings.deciding = settings.currentForm = settings.decidingEvent = false;
    };

    var clearUnload = function () {
        // I'd like to just be able to unbind this but there seems
        // to be a bug in jQuery which doesn't unbind onbeforeunload
        dirtylog('Clearing the beforeunload event');
        $(window).unbind('beforeunload', beforeunloadBindFn);
        window.onbeforeunload = null;
        $(document).trigger('beforeunload.dirtyforms');
    };

    var refire = function (e) {
        $(document).trigger('beforeRefire.dirtyforms')
                   .trigger('beforeunload.dirtyforms');
        if (e.type === 'click') {
            dirtylog("Refiring click event");
            var event = new $.Event('click');
            $(e.target).trigger(event);
            if (!event.isDefaultPrevented()) {
                var href = $(e.target).attr('href');
                dirtylog('Sending location to ' + href);
                location.href = href;
                return;
            }
        } else {
            dirtylog("Refiring " + e.type + " event on " + e.target);
            var target;
            if (settings.formStash) {
                dirtylog('Appending stashed form to body');
                target = settings.formStash;
                $('body').append(target);
            }
            else {
                target = $(e.target);
                if (!target.is('form'))
                    target = target.closest('form');
            }
            target.trigger(e.type);
        }
    };

}));
<|endoftext|>