<commit_before>/**
 * Logger
 * ======
 *
 * purpose: to create a single shared logger
 *
 * usage:
 *
 *   a. `require('logger')                  - defaults to a bunyan Logger
 *   b. `require('logger')(bunyanOpts)      - uses bunyan logger with bunyanOpts
 *   c. `require('logger').use(someLogger)` - use someLogger instead
 *
 * logger api:
 *
 *   https://github.com/trentm/node-bunyan
 *   functions; info, warn, error, trace, and maybe debug
 */

var extend = require('util')._extend;

var bunyan;
try {
  bunyan = require('bunyan');
} catch (e) {
  console.warn('Warning: Bunyan logging is not installed.');
}

var defaults = {
  name: 'zuora'
}

var myLogger = {};
if (bunyan) {
  myLogger.reference = bunyan.createLogger(defaults)
} else {
  myLogger.reference = console;
}

function Emptiness (options) {
  if (options) {
    myLogger.reference = bunyan.createLogger(extend(defaults, options))
  }
  this.switchTo = function(someLogger) {
    myLogger.reference = someLogger;
  }
}
Emptiness.prototype = myLogger;

module.exports = new Emptiness;
<commit_msg>oops, not so easy<commit_after>/**
 * Logger
 * ======
 *
 * purpose: to create a single shared logger
 *
 * usage:
 *
 *   a. `require('logger')                  - defaults to a bunyan Logger
 *   b. `require('logger')(bunyanOpts)      - uses bunyan logger with bunyanOpts
 *   c. `require('logger').use(someLogger)` - use someLogger instead
 *
 * logger api:
 *
 *   https://github.com/trentm/node-bunyan
 *   functions; info, warn, error, trace, and maybe debug
 */

//var extend = require('util')._extend;

var bunyan;
try {
  bunyan = require('bunyan');
} catch (e) {
  console.warn('Warning: Bunyan logging is not installed.');
}

var defaults = {
  name: 'zuora'
}

var myLogger = {};
if (bunyan) {
  myLogger.reference = bunyan.createLogger(defaults)
} else {
  myLogger.reference = console;
}

function Emptiness (options) {
  //myLogger.reference = bunyan.createLogger(extend(defaults, options))
  this.use = function(someLogger) {
    if (bunyan && someLogger instanceof bunyan) {
      myLogger.reference = someLogger.child({module: 'zuora'});
    } else {
      myLogger.reference = someLogger;
    }
  }
}
Emptiness.prototype = myLogger.reference;

module.exports = new Emptiness;
<|endoftext|>


<commit_before>'use strict'

const path = require('path')
const bunyan = require('bunyan')

const isRunningTests = process.env.npm_lifecycle_event === 'test'
const stdoutLevel = isRunningTests ? 'FATAL' : 'INFO'

const daysToKeepLogs = process.env.KEEP_LOGS || 10

module.exports = bunyan.createLogger({
  name: 'bot',
  streams: [
    {
      stream: process.stdout,
      level: stdoutLevel
    },
    {
      type: 'rotating-file',
      path: path.join(__dirname, '../logs/bot.log'),
      period: '1d', // daily rotation
      count: daysToKeepLogs
    }
  ]
})
<commit_msg>Set file log level from INFO -> DEBUG<commit_after>'use strict'

const path = require('path')
const bunyan = require('bunyan')

const isRunningTests = process.env.npm_lifecycle_event === 'test'
const stdoutLevel = isRunningTests ? 'FATAL' : 'INFO'

const daysToKeepLogs = process.env.KEEP_LOGS || 10

module.exports = bunyan.createLogger({
  name: 'bot',
  streams: [
    {
      stream: process.stdout,
      level: stdoutLevel
    },
    {
      type: 'rotating-file',
      path: path.join(__dirname, '../logs/bot.log'),
      period: '1d', // daily rotation
      count: daysToKeepLogs,
      level: 'debug'
    }
  ]
})
<|endoftext|>


<commit_before>'use strict';

var Console = require('unilog-console');

if (!global._unilog_console) {
	global._unilog_console = new Console();
}

var Logger = module.exports = exports = function Logger(groupId, mod) {
	this._groupId = sanitizeGroupId(groupId) || null;
	this._module = mod || null;
};

Logger.prototype.eventEnabled = function eventEnabled(event) {
	event.callee = event.callee || eventEnabled;
	return this.getFinalTarget().eventEnabled(this.prepareEvent(event));
};

Logger.prototype.getConsole = function getConsole() {
	return global._unilog_console;
};

Logger.prototype.getFinalTarget = function getFinalTarget() {
	var globalTarget;
	if (globalTarget && globalTarget !== this) {
		return globalTarget;
	}

	return global._unilog_console;
};

Logger.prototype.getGlobalTarget = function getGlobalTarget() {
	return global.unilogTarget;
};

Logger.prototype.prepareEvent = function prepareEvent(event) {
	event.groupId = event.groupId || this._groupId;
	event.module = event.module || this._module;

	return event;
};

Logger.prototype.putEvent = function putEvent(event) {
	event.callee = event.callee || putEvent;
	return this.getFinalTarget().putEvent(this.prepareEvent(event));
};

Logger.prototype.setGlobalTarget = function setGlobalTarget(target) {
	global.unilogTarget = target;
};

Logger.prototype.withGroupId = function withGroupId(groupId) {
	return new Logger(groupId, null);
};

Logger.prototype.withModule = function withModule(mod) {
	return new Logger(null, mod);
};

// redirect <logLevel>(...)     -> putEvent()
// redirect <logLevel>Enabled() -> eventEnabled()

['trace', 'debug', 'info', 'warn', 'error', 'fatal'].forEach(function(level) {
	Logger.prototype[level] = function x() {
		this.putEvent({
			callee:  x,
			level:   level,
			message: Array.prototype.slice.call(arguments),
		});
	};

	Logger.prototype[level + 'Enabled'] = function xEnabled() {
		this.eventEnabled({
			callee: xEnabled,
			level:  level,
		});
	};
});

function sanitizeGroupId(groupId) {
	if (!groupId) {
		return null;
	}

	return String(groupId).replace(/[^a-z0-9_.-]/gi, '_').replace(/^\.+|\.+$|(\.)\.+/g, '$1') || 'unknown';
}
<commit_msg>Fixed that global target was ignored.<commit_after>'use strict';

var Console = require('unilog-console');

if (!global._unilog_console) {
	global._unilog_console = new Console();
}

var Logger = module.exports = exports = function Logger(groupId, mod) {
	this._groupId = sanitizeGroupId(groupId) || null;
	this._module = mod || null;
};

Logger.prototype.eventEnabled = function eventEnabled(event) {
	event.callee = event.callee || eventEnabled;
	return this.getFinalTarget().eventEnabled(this.prepareEvent(event));
};

Logger.prototype.getConsole = function getConsole() {
	return global._unilog_console;
};

Logger.prototype.getFinalTarget = function getFinalTarget() {
	var globalTarget = global.unilogTarget;
	if (globalTarget && globalTarget !== this) {
		return globalTarget;
	}

	return global._unilog_console;
};

Logger.prototype.getGlobalTarget = function getGlobalTarget() {
	return global.unilogTarget;
};

Logger.prototype.prepareEvent = function prepareEvent(event) {
	event.groupId = event.groupId || this._groupId;
	event.module = event.module || this._module;

	return event;
};

Logger.prototype.putEvent = function putEvent(event) {
	event.callee = event.callee || putEvent;
	return this.getFinalTarget().putEvent(this.prepareEvent(event));
};

Logger.prototype.setGlobalTarget = function setGlobalTarget(target) {
	global.unilogTarget = target;
};

Logger.prototype.withGroupId = function withGroupId(groupId) {
	return new Logger(groupId, null);
};

Logger.prototype.withModule = function withModule(mod) {
	return new Logger(null, mod);
};

// redirect <logLevel>(...)     -> putEvent()
// redirect <logLevel>Enabled() -> eventEnabled()

['trace', 'debug', 'info', 'warn', 'error', 'fatal'].forEach(function(level) {
	Logger.prototype[level] = function x() {
		this.putEvent({
			callee:  x,
			level:   level,
			message: Array.prototype.slice.call(arguments),
		});
	};

	Logger.prototype[level + 'Enabled'] = function xEnabled() {
		this.eventEnabled({
			callee: xEnabled,
			level:  level,
		});
	};
});

function sanitizeGroupId(groupId) {
	if (!groupId) {
		return null;
	}

	return String(groupId).replace(/[^a-z0-9_.-]/gi, '_').replace(/^\.+|\.+$|(\.)\.+/g, '$1') || 'unknown';
}
<|endoftext|>


<commit_before>"use strict";

var messages = require("./connect-utils");
var utils    = require("./utils");
var _        = require("lodash");
var ucfirst  = require("ucfirst");

var template = "[{blue:%s}] ";

var logger   = require("eazy-logger").Logger({
    prefix: template.replace("%s", "BS"),
    useLevelPrefixes: false
});

module.exports.logger = logger;

/**
 * @param name
 * @returns {*}
 */
module.exports.getLogger = function (name) {
    return logger.clone(function (config) {
        config.prefix = config.prefix + template.replace("%s", name);
        return config;
    });
};

/**
 * Logging Callbacks
 */
module.exports.callbacks = {
    /**
     * Log when file-watching has started
     * @param {BrowserSync} bs
     * @param data
     */
    "file:watching": function (bs, data) {
        if (Object.keys(data).length) {
            logger.info("Watching files...");
        }
    },
    /**
     * Log when a file changes
     * @param {BrowserSync} bs
     * @param data
     */
    "file:reload": function (bs, data) {
        if (canLogFileChange(bs, data)) {

            if (data.path[0] === "*") {
                return logger.info("{cyan:Reloading files that match: {magenta:%s", data.path);
            }

            logger.info("{cyan:File changed: {magenta:%s", data.path);
        }
    },
    /**
     *
     */
    "service:exit": function () {
        logger.debug("Exiting...");
    },
    /**
     *
     */
    "browser:reload": function (bs) {
        if (canLogFileChange(bs)) {
            logger.info("{cyan:Reloading Browsers...");
        }
    },
    /**
     * @param {BrowserSync} bs
     * @param data
     */
    "stream:changed": function (bs, data) {
        if (canLogFileChange(bs)) {
            var changed = data.changed;

            logger.info("{cyan:%s %s changed} ({magenta:%s})",
                changed.length,
                changed.length > 1 ? "files" : "file",
                changed.join(", ")
            );
        }
    },
    /**
     * Client connected logging
     * @param {BrowserSync} bs
     * @param data
     */
    "client:connected": function (bs, data) {

        var uaString = utils.getUaString(data.ua);
        var msg = "{cyan:Browser Connected: {magenta:%s, version: %s}";
        var method = "info";

        if (!bs.options.get("logConnections")) {
            method = "debug";
        }

        logger.log(method, msg,
            uaString.name,
            uaString.version
        );
    },
    /**
     * Main logging when the service is running
     * @param {BrowserSync} bs
     * @param data
     */
    "service:running": function (bs, data) {

        var type    = data.type;

        if (type === "server") {

            var baseDir = bs.options.getIn(["server", "baseDir"]);

            logUrls(bs.options.get("urls").toJS());

            if (baseDir) {
                if (utils.isList(baseDir)) {
                    baseDir.forEach(serveFiles);
                } else {
                    serveFiles(baseDir);
                }
            }
        }

        if (type === "proxy") {

            logger.info("Proxying: {cyan:%s}", bs.options.getIn(["proxy", "target"]));
            logUrls(bs.options.get("urls").toJS());
        }

        if (type === "snippet" && bs.options.get("logSnippet")) {

            logger.info(
                "{bold:Copy the following snippet into your website, " +
                "just before the closing {cyan:} tag"
            );

            logger.unprefixed("info",
                messages.scriptTags(bs.options)
            );

            logUrls(bs.options.get("urls").filter(function (value, key) {
                return key.slice(0, 2) === "ui";
            }).toJS());
        }

        function serveFiles (base) {
            logger.info("Serving files from: {magenta:%s}", base);
        }
    }
};

/**
 * Plugin interface for BrowserSync
 * @param {EventEmitter} emitter
 * @param {BrowserSync} bs
 * @returns {Object}
 */
module.exports.plugin = function (emitter, bs) {

    var logPrefix = bs.options.get("logPrefix");
    var logLevel  = bs.options.get("logLevel");

    // Should set logger level here!
    logger.setLevel(logLevel);

    if (logPrefix) {
        if (_.isFunction(logPrefix)) {
            logger.setPrefix(logPrefix);
        } else {
            logger.setPrefix(template.replace("%s", logPrefix));
        }
    }

    _.each(exports.callbacks, function (func, event) {
        emitter.on(event, func.bind(this, bs));
    });

    return logger;
};

/**
 *
 * @param urls
 */
function logUrls (urls) {

    var keys = Object.keys(urls);
    var longestName = 0;
    var longesturl  = 0;
    var offset      = 2;

    if (!keys.length) {
        return;
    }

    var names = keys.map(function (key) {
        if (key.length > longestName) {
            longestName = key.length;
        }
        if (urls[key].length > longesturl) {
            longesturl = urls[key].length;
        }
        return key;
    });

    var underline  = getChars(longestName + offset + longesturl + 1, "-");
    var underlined = false;

    logger.info("{bold:Access URLs:");
    logger.unprefixed("info", "{grey: %s", underline);

    keys.forEach(function (key, i) {
        var keyname = getKeyName(key);
        logger.unprefixed("info", " %s: {magenta:%s}",
            getPadding(key.length, longestName + offset) + keyname,
            urls[key]
        );
        if (!underlined && names[i + 1] && names[i + 1].indexOf("ui") > -1) {
            underlined = true;
            logger.unprefixed("info", "{grey: %s}", underline);
        }
    });

    logger.unprefixed("info", "{grey: %s}", underline);
}

/**
 * @param {Number} len
 * @param {Number} max
 * @returns {string}
 */
function getPadding (len, max) {
    return new Array(max - (len + 1)).join(" ");
}

/**
 * @param {Number} len
 * @param {String} char
 * @returns {string}
 */
function getChars (len, char) {
    return new Array(len).join(char);
}

/**
 * Transform url-key names into something more presentable
 * @param key
 * @returns {string}
 */
function getKeyName(key) {
    if (key.indexOf("ui") > -1) {
        if (key === "ui") {
            return "UI";
        }
        if (key === "ui-external") {
            return "UI External";
        }
    }
    return ucfirst(key);
}

/**
 * Determine if file changes should be logged
 * @param bs
 * @param data
 * @returns {boolean}
 */
function canLogFileChange(bs, data) {
    if (data && data.log === false) {
        return false;
    }

    return bs.options.get("logFileChanges");
}
<commit_msg>Fix #1094<commit_after>"use strict";

var messages = require("./connect-utils");
var utils    = require("./utils");
var _        = require("lodash");
var ucfirst  = require("ucfirst");

var template = "[{blue:%s}] ";

var logger   = require("eazy-logger").Logger({
    prefix: template.replace("%s", "BS"),
    useLevelPrefixes: false
});

module.exports.logger = logger;

/**
 * @param name
 * @returns {*}
 */
module.exports.getLogger = function (name) {
    return logger.clone(function (config) {
        config.prefix = config.prefix + template.replace("%s", name);
        return config;
    });
};

/**
 * Logging Callbacks
 */
module.exports.callbacks = {
    /**
     * Log when file-watching has started
     * @param {BrowserSync} bs
     * @param data
     */
    "file:watching": function (bs, data) {
        if (Object.keys(data).length) {
            logger.info("Watching files...");
        }
    },
    /**
     * Log when a file changes
     * @param {BrowserSync} bs
     * @param data
     */
    "file:reload": function (bs, data) {
        if (canLogFileChange(bs, data)) {

            if (data.path[0] === "*") {
                return logger.info("{cyan:Reloading files that match: {magenta:%s", data.path);
            }

            logger.info("{cyan:File changed: {magenta:%s", data.path);
        }
    },
    /**
     *
     */
    "service:exit": function () {
        logger.debug("Exiting...");
    },
    /**
     *
     */
    "browser:reload": function (bs) {
        if (canLogFileChange(bs)) {
            logger.info("{cyan:Reloading Browsers...");
        }
    },
    /**
     * @param {BrowserSync} bs
     * @param data
     */
    "stream:changed": function (bs, data) {
        if (canLogFileChange(bs)) {
            var changed = data.changed;

            logger.info("{cyan:%s %s changed} ({magenta:%s})",
                changed.length,
                changed.length > 1 ? "files" : "file",
                changed.join(", ")
            );
        }
    },
    /**
     * Client connected logging
     * @param {BrowserSync} bs
     * @param data
     */
    "client:connected": function (bs, data) {

        var uaString = utils.getUaString(data.ua);
        var msg = "{cyan:Browser Connected: {magenta:%s, version: %s}";
        var method = "info";

        if (!bs.options.get("logConnections")) {
            method = "debug";
        }

        logger.log(method, msg,
            uaString.name,
            uaString.version
        );
    },
    /**
     * Main logging when the service is running
     * @param {BrowserSync} bs
     * @param data
     */
    "service:running": function (bs, data) {

        var type    = data.type;

        if (type === "server") {

            var baseDir = bs.options.getIn(["server", "baseDir"]);

            logUrls(bs.options.get("urls").toJS());

            if (baseDir) {
                if (utils.isList(baseDir)) {
                    baseDir.forEach(serveFiles);
                } else {
                    serveFiles(baseDir);
                }
            }
        }

        if (type === "proxy") {

            logger.info("Proxying: {cyan:%s}", bs.options.getIn(["proxy", "target"]));
            logUrls(bs.options.get("urls").toJS());
        }

        if (type === "snippet" && bs.options.get("logSnippet")) {

            logger.info(
                "{bold:Copy the following snippet into your website, " +
                "just before the closing {cyan:} tag"
            );

            logger.unprefixed("info",
                messages.scriptTags(bs.options)
            );
        }

        if (type === "snippet") {

            logUrls(bs.options.get("urls").filter(function (value, key) {
                return key.slice(0, 2) === "ui";
            }).toJS());
        }

        function serveFiles (base) {
            logger.info("Serving files from: {magenta:%s}", base);
        }
    }
};

/**
 * Plugin interface for BrowserSync
 * @param {EventEmitter} emitter
 * @param {BrowserSync} bs
 * @returns {Object}
 */
module.exports.plugin = function (emitter, bs) {

    var logPrefix = bs.options.get("logPrefix");
    var logLevel  = bs.options.get("logLevel");

    // Should set logger level here!
    logger.setLevel(logLevel);

    if (logPrefix) {
        if (_.isFunction(logPrefix)) {
            logger.setPrefix(logPrefix);
        } else {
            logger.setPrefix(template.replace("%s", logPrefix));
        }
    }

    _.each(exports.callbacks, function (func, event) {
        emitter.on(event, func.bind(this, bs));
    });

    return logger;
};

/**
 *
 * @param urls
 */
function logUrls (urls) {

    var keys = Object.keys(urls);
    var longestName = 0;
    var longesturl  = 0;
    var offset      = 2;

    if (!keys.length) {
        return;
    }

    var names = keys.map(function (key) {
        if (key.length > longestName) {
            longestName = key.length;
        }
        if (urls[key].length > longesturl) {
            longesturl = urls[key].length;
        }
        return key;
    });

    var underline  = getChars(longestName + offset + longesturl + 1, "-");
    var underlined = false;

    logger.info("{bold:Access URLs:");
    logger.unprefixed("info", "{grey: %s", underline);

    keys.forEach(function (key, i) {
        var keyname = getKeyName(key);
        logger.unprefixed("info", " %s: {magenta:%s}",
            getPadding(key.length, longestName + offset) + keyname,
            urls[key]
        );
        if (!underlined && names[i + 1] && names[i + 1].indexOf("ui") > -1) {
            underlined = true;
            logger.unprefixed("info", "{grey: %s}", underline);
        }
    });

    logger.unprefixed("info", "{grey: %s}", underline);
}

/**
 * @param {Number} len
 * @param {Number} max
 * @returns {string}
 */
function getPadding (len, max) {
    return new Array(max - (len + 1)).join(" ");
}

/**
 * @param {Number} len
 * @param {String} char
 * @returns {string}
 */
function getChars (len, char) {
    return new Array(len).join(char);
}

/**
 * Transform url-key names into something more presentable
 * @param key
 * @returns {string}
 */
function getKeyName(key) {
    if (key.indexOf("ui") > -1) {
        if (key === "ui") {
            return "UI";
        }
        if (key === "ui-external") {
            return "UI External";
        }
    }
    return ucfirst(key);
}

/**
 * Determine if file changes should be logged
 * @param bs
 * @param data
 * @returns {boolean}
 */
function canLogFileChange(bs, data) {
    if (data && data.log === false) {
        return false;
    }

    return bs.options.get("logFileChanges");
}
<|endoftext|>


<commit_before>(function($) {

  $.fn.tweet = function(o){
    var s = $.extend({
      username: null,                           // [string or array] required unless using the 'query' option; one or more twitter screen names
      list: null,                               // [string]   optional name of list belonging to username
      favorites: false,                         // [boolean]  display the user's favorites instead of his tweets
      query: null,                              // [string]   optional search query
      avatar_size: null,                        // [integer]  height and width of avatar if displayed (48px max)
      count: 3,                                 // [integer]  how many tweets to display?
      fetch: null,                              // [integer]  how many tweets to fetch via the API (set this higher than 'count' if using the 'filter' option)
      retweets: true,                           // [boolean]  whether to fetch (official) retweets (not supported in all display modes)
      intro_text: null,                         // [string]   do you want text BEFORE your your tweets?
      outro_text: null,                         // [string]   do you want text AFTER your tweets?
      join_text:  null,                         // [string]   optional text in between date and tweet, try setting to "auto"
      auto_join_text_default: "i said,",        // [string]   auto text for non verb: "i said" bullocks
      auto_join_text_ed: "i",                   // [string]   auto text for past tense: "i" surfed
      auto_join_text_ing: "i am",               // [string]   auto tense for present tense: "i was" surfing
      auto_join_text_reply: "i replied to",     // [string]   auto tense for replies: "i replied to" @someone "with"
      auto_join_text_url: "i was looking at",   // [string]   auto tense for urls: "i was looking at" http:...
      loading_text: null,                       // [string]   optional loading text, displayed while tweets load
      refresh_interval: null ,                  // [integer]  optional number of seconds after which to reload tweets
      twitter_url: "twitter.com",               // [string]   custom twitter url, if any (apigee, etc.)
      twitter_api_url: "api.twitter.com",       // [string]   custom twitter api url, if any (apigee, etc.)
      twitter_search_url: "search.twitter.com", // [string]   custom twitter search url, if any (apigee, etc.)
      template: "{avatar}{time}{join}{text}",   // [string or function] template used to construct each tweet
 - see code for available vars
      comparator: function(tweet1, tweet2) {    // [function] comparator used to sort tweets (see Array.sort)
        return tweet2["tweet_time"] - tweet1["tweet_time"];
      },
      filter: function(tweet) {                 // [function] whether or not to include a particular tweet (be sure to also set 'fetch')
        return true;
      }
    }, o);

    $.fn.extend({
      linkUrl: function() {
        var returning = [];
        // See http://daringfireball.net/2010/07/improved_regex_for_matching_urls
        var regexp = /\b((?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))/gi;
        this.each(function() {
          returning.push(this.replace(regexp,
                                      function(match) {
                                        var url = (/^[a-z]+:/i).test(match) ? match : "http://"+match;
                                        return ""+match+"";
                                      }));
        });
        return $(returning);
      },
      linkUser: function() {
        var returning = [];
        var regexp = /[\@]+(\w+)/gi;
        this.each(function() {
          returning.push(this.replace(regexp,"@$1"));
        });
        return $(returning);
      },
      linkHash: function() {
        var returning = [];
        // Support various latin1 (\u00**) and arabic (\u06**) alphanumeric chars
        var regexp = /(?:^| )[\#]+([\w\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u00ff\u0600-\u06ff]+)/gi;
        var usercond = (s.username && s.username.length == 1) ? '&from='+s.username.join("%2BOR%2B") : '';
        this.each(function() {
          returning.push(this.replace(regexp, ' #$1'));
        });
        return $(returning);
      },
      capAwesome: function() {
        var returning = [];
        this.each(function() {
          returning.push(this.replace(/\b(awesome)\b/gi, '$1'));
        });
        return $(returning);
      },
      capEpic: function() {
        var returning = [];
        this.each(function() {
          returning.push(this.replace(/\b(epic)\b/gi, '$1'));
        });
        return $(returning);
      },
      makeHeart: function() {
        var returning = [];
        this.each(function() {
          returning.push(this.replace(/(<)+[3]/gi, "<tt class='heart'>♥</tt>"));
        });
        return $(returning);
      }
    });

    function parse_date(date_str) {
      // The non-search twitter APIs return inconsistently-formatted dates, which Date.parse
      // cannot handle in IE. We therefore perform the following transformation:
      // "Wed Apr 29 08:53:31 +0000 2009" => "Wed, Apr 29 2009 08:53:31 +0000"
      return Date.parse(date_str.replace(/^([a-z]{3})( [a-z]{3} \d\d?)(.*)( \d{4})$/i, '$1,$2$4$3'));
    }

    function relative_time(date) {
      var relative_to = (arguments.length > 1) ? arguments[1] : new Date();
      var delta = parseInt((relative_to.getTime() - date) / 1000, 10);
      var r = '';
      if (delta < 60) {
        r = delta + ' seconds ago';
      } else if(delta < 120) {
        r = 'a minute ago';
      } else if(delta < (45*60)) {
        r = (parseInt(delta / 60, 10)).toString() + ' minutes ago';
      } else if(delta < (2*60*60)) {
        r = 'an hour ago';
      } else if(delta < (24*60*60)) {
        r = '' + (parseInt(delta / 3600, 10)).toString() + ' hours ago';
      } else if(delta < (48*60*60)) {
        r = 'a day ago';
      } else {
        r = (parseInt(delta / 86400, 10)).toString() + ' days ago';
      }
      return 'about ' + r;
    }

    function build_url() {
      var proto = ('https:' == document.location.protocol ? 'https:' : 'http:');
      var count = (s.fetch === null) ? s.count : s.fetch;
      if (s.list) {
        return proto+"//"+s.twitter_api_url+"/1/"+s.username[0]+"/lists/"+s.list+"/statuses.json?per_page="+count+"&callback=?";
      } else if (s.favorites) {
        return proto+"//"+s.twitter_api_url+"/favorites/"+s.username[0]+".json?count="+s.count+"&callback=?";
      } else if (s.query === null && s.username.length == 1) {
        return proto+'//'+s.twitter_api_url+'/1/statuses/user_timeline.json?screen_name='+s.username[0]+'&count='+count+(s.retweets ? '&include_rts=1' : '')+'&callback=?';
      } else {
        var query = (s.query || 'from:'+s.username.join(' OR from:'));
        return proto+'//'+s.twitter_search_url+'/search.json?&q='+encodeURIComponent(query)+'&rpp='+count+'&callback=?';
      }
    }

    return this.each(function(i, widget){
      var list = $('
').appendTo(widget);
      var intro = '
'+s.intro_text+'
';
      var outro = '
'+s.outro_text+'
';
      var loading = $('
'+s.loading_text+'
');

      if(s.username && typeof(s.username) == "string"){
        s.username = [s.username];
      }

      var expand_template = function(info) {
        if (typeof s.template === "string") {
          var result = s.template;
          for(var key in info) {
            var val = info[key];
            result = result.replace(new RegExp('{'+key+'}','g'), val === null ? '' : val);
          }
          return result;
        } else return s.template(info);
      };

      if (s.loading_text) $(widget).append(loading);
      $(widget).bind("load", function(){
        $.getJSON(build_url(), function(data){
          if (s.loading_text) loading.remove();
          if (s.intro_text) list.before(intro);
          list.empty();

          var tweets = $.map(data.results || data, function(item){
            var join_text = s.join_text;

            // auto join text based on verb tense and content
            if (s.join_text == "auto") {
              if (item.text.match(/^(@([A-Za-z0-9-_]+)) .*/i)) {
                join_text = s.auto_join_text_reply;
              } else if (item.text.match(/(^\w+:\/\/[A-Za-z0-9-_]+\.[A-Za-z0-9-_:%&\?\/.=]+) .*/i)) {
                join_text = s.auto_join_text_url;
              } else if (item.text.match(/^((\w+ed)|just) .*/im)) {
                join_text = s.auto_join_text_ed;
              } else if (item.text.match(/^(\w*ing) .*/i)) {
                join_text = s.auto_join_text_ing;
              } else {
                join_text = s.auto_join_text_default;
              }
            }

            // Basic building blocks for constructing tweet
 using a template
            var screen_name = item.from_user || item.user.screen_name;
            var source = item.source;
            var user_url = "http://"+s.twitter_url+"/"+screen_name;
            var avatar_size = s.avatar_size;
            var avatar_url = item.profile_image_url || item.user.profile_image_url;
            var tweet_url = "http://"+s.twitter_url+"/"+screen_name+"/status/"+item.id_str;
            var retweet = (typeof(item.retweeted_status) != 'undefined');
            var retweeted_screen_name = retweet ? item.retweeted_status.user.screen_name : null;
            var tweet_time = parse_date(item.created_at);
            var tweet_relative_time = relative_time(tweet_time);
            var tweet_raw_text = retweet ? ('RT @'+retweeted_screen_name+' '+item.retweeted_status.text) : item.text; // avoid '...' in long retweets
            var tweet_text = $([tweet_raw_text]).linkUrl().linkUser().linkHash()[0];

            // Default spans, and pre-formatted blocks for common layouts
            var user = ''+screen_name+'';
            var join = ((s.join_text) ? (' '+join_text+' ') : ' ');
            var avatar = (avatar_size ?
                          ('') : '');
            var time = ''+tweet_relative_time+'';
            var text = ''+$([tweet_text]).makeHeart().capAwesome().capEpic()[0]+ '';

            return { item: item, // For advanced users who want to dig out other info
                     screen_name: screen_name,
                     user_url: user_url,
                     avatar_size: avatar_size,
                     avatar_url: avatar_url,
                     source: source,
                     tweet_url: tweet_url,
                     tweet_time: tweet_time,
                     tweet_relative_time: tweet_relative_time,
                     tweet_raw_text: tweet_raw_text,
                     tweet_text: tweet_text,
                     retweet: retweet,
                     retweeted_screen_name: retweeted_screen_name,
                     user: user,
                     join: join,
                     avatar: avatar,
                     time: time,
                     text: text
                   };
          });

          tweets = $.grep(tweets, s.filter).sort(s.comparator).slice(0, s.count);
          list.append($.map(tweets,
                            function(t) { return "
" + expand_template(t) + "
"; }).join('')).
              children('li:first').addClass('tweet_first').end().
              children('li:odd').addClass('tweet_even').end().
              children('li:even').addClass('tweet_odd');

          if (s.outro_text) list.after(outro);
          $(widget).trigger("loaded").trigger((tweets.length === 0 ? "empty" : "full"));
          if (s.refresh_interval) {
            window.setTimeout(function() { $(widget).trigger("load"); }, 1000 * s.refresh_interval);
          }
        });
      }).trigger("load");
    });
  };
})(jQuery);
<commit_msg>Support a 'page' option, so developers can easily add "load more tweets" buttons (fixes #118)<commit_after>(function($) {

  $.fn.tweet = function(o){
    var s = $.extend({
      username: null,                           // [string or array] required unless using the 'query' option; one or more twitter screen names
      list: null,                               // [string]   optional name of list belonging to username
      favorites: false,                         // [boolean]  display the user's favorites instead of his tweets
      query: null,                              // [string]   optional search query
      avatar_size: null,                        // [integer]  height and width of avatar if displayed (48px max)
      count: 3,                                 // [integer]  how many tweets to display?
      fetch: null,                              // [integer]  how many tweets to fetch via the API (set this higher than 'count' if using the 'filter' option)
      page: 1,                                  // [integer]  which page of results to fetch (if count != fetch, you'll get unexpected results)
      retweets: true,                           // [boolean]  whether to fetch (official) retweets (not supported in all display modes)
      intro_text: null,                         // [string]   do you want text BEFORE your your tweets?
      outro_text: null,                         // [string]   do you want text AFTER your tweets?
      join_text:  null,                         // [string]   optional text in between date and tweet, try setting to "auto"
      auto_join_text_default: "i said,",        // [string]   auto text for non verb: "i said" bullocks
      auto_join_text_ed: "i",                   // [string]   auto text for past tense: "i" surfed
      auto_join_text_ing: "i am",               // [string]   auto tense for present tense: "i was" surfing
      auto_join_text_reply: "i replied to",     // [string]   auto tense for replies: "i replied to" @someone "with"
      auto_join_text_url: "i was looking at",   // [string]   auto tense for urls: "i was looking at" http:...
      loading_text: null,                       // [string]   optional loading text, displayed while tweets load
      refresh_interval: null ,                  // [integer]  optional number of seconds after which to reload tweets
      twitter_url: "twitter.com",               // [string]   custom twitter url, if any (apigee, etc.)
      twitter_api_url: "api.twitter.com",       // [string]   custom twitter api url, if any (apigee, etc.)
      twitter_search_url: "search.twitter.com", // [string]   custom twitter search url, if any (apigee, etc.)
      template: "{avatar}{time}{join}{text}",   // [string or function] template used to construct each tweet
 - see code for available vars
      comparator: function(tweet1, tweet2) {    // [function] comparator used to sort tweets (see Array.sort)
        return tweet2["tweet_time"] - tweet1["tweet_time"];
      },
      filter: function(tweet) {                 // [function] whether or not to include a particular tweet (be sure to also set 'fetch')
        return true;
      }
    }, o);

    $.fn.extend({
      linkUrl: function() {
        var returning = [];
        // See http://daringfireball.net/2010/07/improved_regex_for_matching_urls
        var regexp = /\b((?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))/gi;
        this.each(function() {
          returning.push(this.replace(regexp,
                                      function(match) {
                                        var url = (/^[a-z]+:/i).test(match) ? match : "http://"+match;
                                        return ""+match+"";
                                      }));
        });
        return $(returning);
      },
      linkUser: function() {
        var returning = [];
        var regexp = /[\@]+(\w+)/gi;
        this.each(function() {
          returning.push(this.replace(regexp,"@$1"));
        });
        return $(returning);
      },
      linkHash: function() {
        var returning = [];
        // Support various latin1 (\u00**) and arabic (\u06**) alphanumeric chars
        var regexp = /(?:^| )[\#]+([\w\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u00ff\u0600-\u06ff]+)/gi;
        var usercond = (s.username && s.username.length == 1) ? '&from='+s.username.join("%2BOR%2B") : '';
        this.each(function() {
          returning.push(this.replace(regexp, ' #$1'));
        });
        return $(returning);
      },
      capAwesome: function() {
        var returning = [];
        this.each(function() {
          returning.push(this.replace(/\b(awesome)\b/gi, '$1'));
        });
        return $(returning);
      },
      capEpic: function() {
        var returning = [];
        this.each(function() {
          returning.push(this.replace(/\b(epic)\b/gi, '$1'));
        });
        return $(returning);
      },
      makeHeart: function() {
        var returning = [];
        this.each(function() {
          returning.push(this.replace(/(<)+[3]/gi, "<tt class='heart'>♥</tt>"));
        });
        return $(returning);
      }
    });

    function parse_date(date_str) {
      // The non-search twitter APIs return inconsistently-formatted dates, which Date.parse
      // cannot handle in IE. We therefore perform the following transformation:
      // "Wed Apr 29 08:53:31 +0000 2009" => "Wed, Apr 29 2009 08:53:31 +0000"
      return Date.parse(date_str.replace(/^([a-z]{3})( [a-z]{3} \d\d?)(.*)( \d{4})$/i, '$1,$2$4$3'));
    }

    function relative_time(date) {
      var relative_to = (arguments.length > 1) ? arguments[1] : new Date();
      var delta = parseInt((relative_to.getTime() - date) / 1000, 10);
      var r = '';
      if (delta < 60) {
        r = delta + ' seconds ago';
      } else if(delta < 120) {
        r = 'a minute ago';
      } else if(delta < (45*60)) {
        r = (parseInt(delta / 60, 10)).toString() + ' minutes ago';
      } else if(delta < (2*60*60)) {
        r = 'an hour ago';
      } else if(delta < (24*60*60)) {
        r = '' + (parseInt(delta / 3600, 10)).toString() + ' hours ago';
      } else if(delta < (48*60*60)) {
        r = 'a day ago';
      } else {
        r = (parseInt(delta / 86400, 10)).toString() + ' days ago';
      }
      return 'about ' + r;
    }

    function build_url() {
      var proto = ('https:' == document.location.protocol ? 'https:' : 'http:');
      var count = (s.fetch === null) ? s.count : s.fetch;
      if (s.list) {
        return proto+"//"+s.twitter_api_url+"/1/"+s.username[0]+"/lists/"+s.list+"/statuses.json?page="+s.page+"&per_page="+count+"&callback=?";
      } else if (s.favorites) {
        return proto+"//"+s.twitter_api_url+"/favorites/"+s.username[0]+".json?page="+s.page+"&count="+s.count+"&callback=?";
      } else if (s.query === null && s.username.length == 1) {
        return proto+'//'+s.twitter_api_url+'/1/statuses/user_timeline.json?screen_name='+s.username[0]+'&count='+count+(s.retweets ? '&include_rts=1' : '')+'&page='+s.page+'&callback=?';
      } else {
        var query = (s.query || 'from:'+s.username.join(' OR from:'));
        return proto+'//'+s.twitter_search_url+'/search.json?&q='+encodeURIComponent(query)+'&rpp='+count+'&page='+s.page+'&callback=?';
      }
    }

    return this.each(function(i, widget){
      var list = $('
').appendTo(widget);
      var intro = '
'+s.intro_text+'
';
      var outro = '
'+s.outro_text+'
';
      var loading = $('
'+s.loading_text+'
');

      if(s.username && typeof(s.username) == "string"){
        s.username = [s.username];
      }

      var expand_template = function(info) {
        if (typeof s.template === "string") {
          var result = s.template;
          for(var key in info) {
            var val = info[key];
            result = result.replace(new RegExp('{'+key+'}','g'), val === null ? '' : val);
          }
          return result;
        } else return s.template(info);
      };

      if (s.loading_text) $(widget).append(loading);
      $(widget).bind("load", function(){
        $.getJSON(build_url(), function(data){
          if (s.loading_text) loading.remove();
          if (s.intro_text) list.before(intro);
          list.empty();

          var tweets = $.map(data.results || data, function(item){
            var join_text = s.join_text;

            // auto join text based on verb tense and content
            if (s.join_text == "auto") {
              if (item.text.match(/^(@([A-Za-z0-9-_]+)) .*/i)) {
                join_text = s.auto_join_text_reply;
              } else if (item.text.match(/(^\w+:\/\/[A-Za-z0-9-_]+\.[A-Za-z0-9-_:%&\?\/.=]+) .*/i)) {
                join_text = s.auto_join_text_url;
              } else if (item.text.match(/^((\w+ed)|just) .*/im)) {
                join_text = s.auto_join_text_ed;
              } else if (item.text.match(/^(\w*ing) .*/i)) {
                join_text = s.auto_join_text_ing;
              } else {
                join_text = s.auto_join_text_default;
              }
            }

            // Basic building blocks for constructing tweet
 using a template
            var screen_name = item.from_user || item.user.screen_name;
            var source = item.source;
            var user_url = "http://"+s.twitter_url+"/"+screen_name;
            var avatar_size = s.avatar_size;
            var avatar_url = item.profile_image_url || item.user.profile_image_url;
            var tweet_url = "http://"+s.twitter_url+"/"+screen_name+"/status/"+item.id_str;
            var retweet = (typeof(item.retweeted_status) != 'undefined');
            var retweeted_screen_name = retweet ? item.retweeted_status.user.screen_name : null;
            var tweet_time = parse_date(item.created_at);
            var tweet_relative_time = relative_time(tweet_time);
            var tweet_raw_text = retweet ? ('RT @'+retweeted_screen_name+' '+item.retweeted_status.text) : item.text; // avoid '...' in long retweets
            var tweet_text = $([tweet_raw_text]).linkUrl().linkUser().linkHash()[0];

            // Default spans, and pre-formatted blocks for common layouts
            var user = ''+screen_name+'';
            var join = ((s.join_text) ? (' '+join_text+' ') : ' ');
            var avatar = (avatar_size ?
                          ('') : '');
            var time = ''+tweet_relative_time+'';
            var text = ''+$([tweet_text]).makeHeart().capAwesome().capEpic()[0]+ '';

            return { item: item, // For advanced users who want to dig out other info
                     screen_name: screen_name,
                     user_url: user_url,
                     avatar_size: avatar_size,
                     avatar_url: avatar_url,
                     source: source,
                     tweet_url: tweet_url,
                     tweet_time: tweet_time,
                     tweet_relative_time: tweet_relative_time,
                     tweet_raw_text: tweet_raw_text,
                     tweet_text: tweet_text,
                     retweet: retweet,
                     retweeted_screen_name: retweeted_screen_name,
                     user: user,
                     join: join,
                     avatar: avatar,
                     time: time,
                     text: text
                   };
          });

          tweets = $.grep(tweets, s.filter).sort(s.comparator).slice(0, s.count);
          list.append($.map(tweets,
                            function(t) { return "
" + expand_template(t) + "
"; }).join('')).
              children('li:first').addClass('tweet_first').end().
              children('li:odd').addClass('tweet_even').end().
              children('li:even').addClass('tweet_odd');

          if (s.outro_text) list.after(outro);
          $(widget).trigger("loaded").trigger((tweets.length === 0 ? "empty" : "full"));
          if (s.refresh_interval) {
            window.setTimeout(function() { $(widget).trigger("load"); }, 1000 * s.refresh_interval);
          }
        });
      }).trigger("load");
    });
  };
})(jQuery);
<|endoftext|>


<commit_before>
var FiwareDemo = ICameraApplication.$extend(
{
    __init__ : function()
    {
        console.log("FIWARE Demo");
        this.$super("FIWARE Demo");

      	this.subscribeEvent(TundraSDK.framework.client.onConnected(this, this.onConnected));
        this.subscribeEvent(TundraSDK.framework.client.onDisconnected(this, this.onDisconnected));
        this.subscribeEvent(TundraSDK.framework.frame.onUpdate(this, this.onUpdate));

        /* red test pilar with three.js code directly
        var dmat = new THREE.MeshBasicMaterial({color: 0xFF0000});
        var dcubegeom = new THREE.CubeGeometry(3, 8, 3);
        var dcube = new THREE.Mesh(dcubegeom, dmat);
        dcube.scale.set(4, 18, 4);
        TundraSDK.framework.renderer.scene.add(dcube)
        this.dcube = dcube;
        this.move = 1;
        */

        /* using tundra apis to create an entity (for networking, but this is local)
        var scene = TundraSDK.framework.scene;
        var ECEnt = scene.createLocalEntity(); // 100, ["Name"]);
        this.log.debug("Created entity", ECEnt);

        var plc = ECEnt.createLocalComponent("Placeable");
        plc.setScale(50, 50, 50)
        var mesh = ECEnt.createLocalComponent("Mesh", "cube");
        mesh.meshRef = "suzanne.js";
        scene.addEntity(ECEnt);
        this.ECEnt = ECEnt
        */

        //and the same with using three json loading directly
        var loader = new THREE.JSONLoader();
		var buildings = ["data/3d/rautatieasema.js", "data/3d/tuomiokirkko.js"];
		var building = null;
		for(var index in buildings)
		{
			building = buildings[index];
			console.log("Loading " + building + " model.");
			loader.load( building, function(geometry, materials) {
				console.log(building + " loaded.");
				var mesh = new THREE.Mesh( geometry, new THREE.MeshFaceMaterial( materials ) );
				mesh.scale.set( 0.008, 0.008, 0.008 );
				TundraSDK.framework.renderer.scene.add( mesh );
			});
		}
    },

    onConnected : function()
    {
        this.log.debug("Connected to server");
    },

    onDisconnected : function()
    {
	this.log.debug("Disconnected from server");
    },

    onUpdate : function(frametime)
    {
        /*
        var x = this.dcube.position.x;
        if (Math.abs(this.dcube.position.x) > 150) { //stupid simple bounce
            this.move = -this.move;
        }
        this.dcube.position.x = x + this.move;

        //and let the monkey dance too
        if (this.mesh) {
            this.mesh.position.z = this.dcube.position.x;
        }

        //.. and the tundra ent monkey
        if (this.ECEnt) {
            this.ECEnt.placeable.setPosition(0, 0, -this.dcube.position.x);
        }
        */
    },

    onKeyEvent : function(event)
    {
    },

    onMouseMove : function(event)
    {
    }
});
<commit_msg>Fixed high model scale again.<commit_after>
var FiwareDemo = ICameraApplication.$extend(
{
    __init__ : function()
    {
        console.log("FIWARE Demo");
        this.$super("FIWARE Demo");

      	this.subscribeEvent(TundraSDK.framework.client.onConnected(this, this.onConnected));
        this.subscribeEvent(TundraSDK.framework.client.onDisconnected(this, this.onDisconnected));
        this.subscribeEvent(TundraSDK.framework.frame.onUpdate(this, this.onUpdate));

        /* red test pilar with three.js code directly
        var dmat = new THREE.MeshBasicMaterial({color: 0xFF0000});
        var dcubegeom = new THREE.CubeGeometry(3, 8, 3);
        var dcube = new THREE.Mesh(dcubegeom, dmat);
        dcube.scale.set(4, 18, 4);
        TundraSDK.framework.renderer.scene.add(dcube)
        this.dcube = dcube;
        this.move = 1;
        */

        /* using tundra apis to create an entity (for networking, but this is local)
        var scene = TundraSDK.framework.scene;
        var ECEnt = scene.createLocalEntity(); // 100, ["Name"]);
        this.log.debug("Created entity", ECEnt);

        var plc = ECEnt.createLocalComponent("Placeable");
        plc.setScale(50, 50, 50)
        var mesh = ECEnt.createLocalComponent("Mesh", "cube");
        mesh.meshRef = "suzanne.js";
        scene.addEntity(ECEnt);
        this.ECEnt = ECEnt
        */

        //and the same with using three json loading directly
        var loader = new THREE.JSONLoader();
		var buildings = ["data/3d/rautatieasema.js", "data/3d/tuomiokirkko.js"];
		var building = null;
		for(var index in buildings)
		{
			building = buildings[index];
			console.log("Loading " + building + " model.");
			loader.load( building, function(geometry, materials) {
				console.log(building + " loaded.");
				var mesh = new THREE.Mesh( geometry, new THREE.MeshFaceMaterial( materials ) );
				mesh.scale.set( 0.8582932963847628, 0.8582932963847628, 0.8582932963847628 );
				TundraSDK.framework.renderer.scene.add( mesh );
			});
		}
    },

    onConnected : function()
    {
        this.log.debug("Connected to server");
    },

    onDisconnected : function()
    {
	this.log.debug("Disconnected from server");
    },

    onUpdate : function(frametime)
    {
        /*
        var x = this.dcube.position.x;
        if (Math.abs(this.dcube.position.x) > 150) { //stupid simple bounce
            this.move = -this.move;
        }
        this.dcube.position.x = x + this.move;

        //and let the monkey dance too
        if (this.mesh) {
            this.mesh.position.z = this.dcube.position.x;
        }

        //.. and the tundra ent monkey
        if (this.ECEnt) {
            this.ECEnt.placeable.setPosition(0, 0, -this.dcube.position.x);
        }
        */
    },

    onKeyEvent : function(event)
    {
    },

    onMouseMove : function(event)
    {
    }
});
<|endoftext|>


<commit_before>(function($) {

  $.fn.tweet = function(o){
    var s = {
      username: ["seaofclouds"],              // [string]   required, unless you want to display our tweets. :) it can be an array, just do ["username1","username2","etc"]
      avatar_size: null,                      // [integer]  height and width of avatar if displayed (48px max)
      count: 3,                               // [integer]  how many tweets to display?
      intro_text: null,                       // [string]   do you want text BEFORE your your tweets?
      outro_text: null,                       // [string]   do you want text AFTER your tweets?
      join_text:  null,                       // [string]   optional text in between date and tweet, try setting to "auto"
      auto_join_text_default: "i said,",      // [string]   auto text for non verb: "i said" bullocks
      auto_join_text_ed: "i",                 // [string]   auto text for past tense: "i" surfed
      auto_join_text_ing: "i am",             // [string]   auto tense for present tense: "i was" surfing
      auto_join_text_reply: "i replied to",   // [string]   auto tense for replies: "i replied to" @someone "with"
      auto_join_text_url: "i was looking at", // [string]   auto tense for urls: "i was looking at" http:...
      loading_text: null,                     // [string]   optional loading text, displayed while tweets load
      query: null                             // [string]   optional search query
    };

    if(o) $.extend(s, o);

    $.fn.extend({
      linkUrl: function() {
        var returning = [];
        var regexp = /((ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?)/gi;
        this.each(function() {
          returning.push(this.replace(regexp,"$1"))
        });
        return $(returning);
      },
      linkUser: function() {
        var returning = [];
        var regexp = /[\@]+([A-Za-z0-9-_]+)/gi;
        this.each(function() {
          returning.push(this.replace(regexp,"@$1"))
        });
        return $(returning);
      },
      linkHash: function() {
        var returning = [];
        var regexp = / [\#]+([A-Za-z0-9-_]+)/gi;
        this.each(function() {
          returning.push(this.replace(regexp, ' #$1'))
        });
        return $(returning);
      },
      capAwesome: function() {
        var returning = [];
        this.each(function() {
          returning.push(this.replace(/(a|A)wesome/gi, 'AWESOME'))
        });
        return $(returning);
      },
      capEpic: function() {
        var returning = [];
        this.each(function() {
          returning.push(this.replace(/(e|E)pic/gi, 'EPIC'))
        });
        return $(returning);
      },
      makeHeart: function() {
        var returning = [];
        this.each(function() {
          returning.push(this.replace(/(<)+[3]/gi, "<tt class='heart'>♥</tt>"))
        });
        return $(returning);
      }
    });

    function relative_time(time_value) {
      var parsed_date = Date.parse(time_value);
      var relative_to = (arguments.length > 1) ? arguments[1] : new Date();
      var delta = parseInt((relative_to.getTime() - parsed_date) / 1000);
      if(delta < 60) {
      return 'less than a minute ago';
      } else if(delta < 120) {
      return 'about a minute ago';
      } else if(delta < (45*60)) {
      return (parseInt(delta / 60)).toString() + ' minutes ago';
      } else if(delta < (90*60)) {
      return 'about an hour ago';
      } else if(delta < (24*60*60)) {
      return 'about ' + (parseInt(delta / 3600)).toString() + ' hours ago';
      } else if(delta < (48*60*60)) {
      return '1 day ago';
      } else {
      return (parseInt(delta / 86400)).toString() + ' days ago';
      }
    }

    return this.each(function(){
      var list = $('
').appendTo(this);
      var intro = '
'+s.intro_text+'
'
      var outro = '
'+s.outro_text+'
'
      var loading = $('
'+s.loading_text+'
');
      if(typeof(s.username) == "string"){
        s.username = [s.username];
      }
      var query = '';
      if(s.query) {
        query += 'q='+s.query;
      }
      query += '&q=from:'+s.username.join('%20OR%20from:');
      var url = 'http://search.twitter.com/search.json?&'+query+'&rpp='+s.count+'&callback=?';
      if (s.loading_text) $(this).append(loading);
      $.getJSON(url, function(data){
        if (s.loading_text) loading.remove();
        if (s.intro_text) list.before(intro);
        $.each(data.results, function(i,item){
          // auto join text based on verb tense and content
          if (s.join_text == "auto") {
            if (item.text.match(/^(@([A-Za-z0-9-_]+)) .*/i)) {
              var join_text = s.auto_join_text_reply;
            } else if (item.text.match(/(^\w+:\/\/[A-Za-z0-9-_]+\.[A-Za-z0-9-_:%&\?\/.=]+) .*/i)) {
              var join_text = s.auto_join_text_url;
            } else if (item.text.match(/^((\w+ed)|just) .*/im)) {
              var join_text = s.auto_join_text_ed;
            } else if (item.text.match(/^(\w*ing) .*/i)) {
              var join_text = s.auto_join_text_ing;
            } else {
              var join_text = s.auto_join_text_default;
            }
          } else {
            var join_text = s.join_text;
          };

          var join_template = ' '+join_text+' ';
          var join = ((s.join_text) ? join_template : ' ')
          var avatar_template = '';
          var avatar = (s.avatar_size ? avatar_template : '')
          var date = ''+relative_time(item.created_at)+'';
          var text = '' +$([item.text]).linkUrl().linkUser().linkHash().makeHeart().capAwesome().capEpic()[0]+ '';

          // until we create a template option, arrange the items below to alter a tweet's display.
          list.append('
' + avatar + date + join + text + '
');

          list.children('li:first').addClass('tweet_first');
          list.children('li:odd').addClass('tweet_even');
          list.children('li:even').addClass('tweet_odd');
        });
        if (s.outro_text) list.after(outro);
      });

    });
  };
})(jQuery);<commit_msg>Support showing tweets from a specific list on Twitter<commit_after>(function($) {

  $.fn.tweet = function(o){
    var s = {
      username: ["seaofclouds"],              // [string]   required, unless you want to display our tweets. :) it can be an array, just do ["username1","username2","etc"]
      list: null,                              //[string]   optional name of list belonging to username
      avatar_size: null,                      // [integer]  height and width of avatar if displayed (48px max)
      count: 3,                               // [integer]  how many tweets to display?
      intro_text: null,                       // [string]   do you want text BEFORE your your tweets?
      outro_text: null,                       // [string]   do you want text AFTER your tweets?
      join_text:  null,                       // [string]   optional text in between date and tweet, try setting to "auto"
      auto_join_text_default: "i said,",      // [string]   auto text for non verb: "i said" bullocks
      auto_join_text_ed: "i",                 // [string]   auto text for past tense: "i" surfed
      auto_join_text_ing: "i am",             // [string]   auto tense for present tense: "i was" surfing
      auto_join_text_reply: "i replied to",   // [string]   auto tense for replies: "i replied to" @someone "with"
      auto_join_text_url: "i was looking at", // [string]   auto tense for urls: "i was looking at" http:...
      loading_text: null,                     // [string]   optional loading text, displayed while tweets load
      query: null                             // [string]   optional search query
    };

    if(o) $.extend(s, o);

    $.fn.extend({
      linkUrl: function() {
        var returning = [];
        var regexp = /((ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?)/gi;
        this.each(function() {
          returning.push(this.replace(regexp,"$1"))
        });
        return $(returning);
      },
      linkUser: function() {
        var returning = [];
        var regexp = /[\@]+([A-Za-z0-9-_]+)/gi;
        this.each(function() {
          returning.push(this.replace(regexp,"@$1"))
        });
        return $(returning);
      },
      linkHash: function() {
        var returning = [];
        var regexp = / [\#]+([A-Za-z0-9-_]+)/gi;
        this.each(function() {
          returning.push(this.replace(regexp, ' #$1'))
        });
        return $(returning);
      },
      capAwesome: function() {
        var returning = [];
        this.each(function() {
          returning.push(this.replace(/(a|A)wesome/gi, 'AWESOME'))
        });
        return $(returning);
      },
      capEpic: function() {
        var returning = [];
        this.each(function() {
          returning.push(this.replace(/(e|E)pic/gi, 'EPIC'))
        });
        return $(returning);
      },
      makeHeart: function() {
        var returning = [];
        this.each(function() {
          returning.push(this.replace(/(<)+[3]/gi, "<tt class='heart'>♥</tt>"))
        });
        return $(returning);
      }
    });

    function relative_time(time_value) {
      var parsed_date = Date.parse(time_value);
      var relative_to = (arguments.length > 1) ? arguments[1] : new Date();
      var delta = parseInt((relative_to.getTime() - parsed_date) / 1000);
      if(delta < 60) {
      return 'less than a minute ago';
      } else if(delta < 120) {
      return 'about a minute ago';
      } else if(delta < (45*60)) {
      return (parseInt(delta / 60)).toString() + ' minutes ago';
      } else if(delta < (90*60)) {
      return 'about an hour ago';
      } else if(delta < (24*60*60)) {
      return 'about ' + (parseInt(delta / 3600)).toString() + ' hours ago';
      } else if(delta < (48*60*60)) {
      return '1 day ago';
      } else {
      return (parseInt(delta / 86400)).toString() + ' days ago';
      }
    }

    return this.each(function(){
      var list = $('
').appendTo(this);
      var intro = '
'+s.intro_text+'
'
      var outro = '
'+s.outro_text+'
'
      var loading = $('
'+s.loading_text+'
');

      if(typeof(s.username) == "string"){
        s.username = [s.username];
      }
      if (s.list) {
        var url = "http://api.twitter.com/1/"+s.username[0]+"/lists/"+s.list+"/statuses.json?per_page="+s.count+"&callback=?";
      } else {
        var query = (s.query || 'from:'+s.username.join('%20OR%20from:'));
        var url = 'http://search.twitter.com/search.json?&q='+query+'&rpp='+s.count+'&callback=?';
      }

      if (s.loading_text) $(this).append(loading);
      $.getJSON(url, function(data){
        if (s.loading_text) loading.remove();
        if (s.intro_text) list.before(intro);
        $.each((data.results || data), function(i,item){
          // auto join text based on verb tense and content
          if (s.join_text == "auto") {
            if (item.text.match(/^(@([A-Za-z0-9-_]+)) .*/i)) {
              var join_text = s.auto_join_text_reply;
            } else if (item.text.match(/(^\w+:\/\/[A-Za-z0-9-_]+\.[A-Za-z0-9-_:%&\?\/.=]+) .*/i)) {
              var join_text = s.auto_join_text_url;
            } else if (item.text.match(/^((\w+ed)|just) .*/im)) {
              var join_text = s.auto_join_text_ed;
            } else if (item.text.match(/^(\w*ing) .*/i)) {
              var join_text = s.auto_join_text_ing;
            } else {
              var join_text = s.auto_join_text_default;
            }
          } else {
            var join_text = s.join_text;
          };

          var from_user = item.from_user || item.user.screen_name;
          var profile_image_url = item.profile_image_url || item.user.profile_image_url;
          var join_template = ' '+join_text+' ';
          var join = ((s.join_text) ? join_template : ' ')
          var avatar_template = '';
          var avatar = (s.avatar_size ? avatar_template : '')
          var date = ''+relative_time(item.created_at)+'';
          var text = '' +$([item.text]).linkUrl().linkUser().linkHash().makeHeart().capAwesome().capEpic()[0]+ '';

          // until we create a template option, arrange the items below to alter a tweet's display.
          list.append('
' + avatar + date + join + text + '
');

          list.children('li:first').addClass('tweet_first');
          list.children('li:odd').addClass('tweet_even');
          list.children('li:even').addClass('tweet_odd');
        });
        if (s.outro_text) list.after(outro);
      });

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


<commit_before>import app from '../app';
import { integerToDecimal } from '../utils/currency';
import { Collection } from 'backbone';
import ListingShort from '../models/listing/ListingShort';

export default class extends Collection {
  constructor(models = [], options = {}) {
    if (!options.guid) {
      throw new Error('Please provide a guid.');
    }

    super(models, options);
    this.guid = options.guid;
  }

  model(attrs, options) {
    return new ListingShort(attrs, options);
  }

  url() {
    let url;

    if (this.guid === app.profile.id) {
      url = app.getServerUrl('ob/listings');
    } else {
      url = app.getServerUrl(`ipns/${this.guid}/listings/index.json`);
    }

    return url;
  }

  /**
   * Returns a list of the aggregate categories from all
   * the listing in the collection.
   */
  get categories() {
    const cats = [];

    this.models.forEach(listing => {
      listing.get('categories')
        .forEach(cat => {
          if (cats.indexOf(cat) === -1) cats.push(cat);
        });
    });

    // todo: For now sort will only be accurate for standard ascii
    // characters. In order to properly sort categories with
    // foreign characters, we will need to know what language
    // the listing is in and pass that into localeCompare().
    // https://github.com/OpenBazaar/openbazaar-go/issues/143
    return cats.sort();
  }

  parse(response) {
    const parsedResponse = [];

    response.forEach(listing => {
      const updatedListing = listing;
      const priceObj = updatedListing.price;

      updatedListing.price.amount =
        integerToDecimal(priceObj.amount, priceObj.currencyCode === 'BTC');

      parsedResponse.push(updatedListing);
    });

    return parsedResponse;
  }
}
<commit_msg>update listings collection url<commit_after>import app from '../app';
import { integerToDecimal } from '../utils/currency';
import { Collection } from 'backbone';
import ListingShort from '../models/listing/ListingShort';

export default class extends Collection {
  constructor(models = [], options = {}) {
    if (!options.guid) {
      throw new Error('Please provide a guid.');
    }

    super(models, options);
    this.guid = options.guid;
  }

  model(attrs, options) {
    return new ListingShort(attrs, options);
  }

  url() {
    return app.getServerUrl(`ob/listings/${this.guid}`);
  }

  /**
   * Returns a list of the aggregate categories from all
   * the listing in the collection.
   */
  get categories() {
    const cats = [];

    this.models.forEach(listing => {
      listing.get('categories')
        .forEach(cat => {
          if (cats.indexOf(cat) === -1) cats.push(cat);
        });
    });

    // todo: For now sort will only be accurate for standard ascii
    // characters. In order to properly sort categories with
    // foreign characters, we will need to know what language
    // the listing is in and pass that into localeCompare().
    // https://github.com/OpenBazaar/openbazaar-go/issues/143
    return cats.sort();
  }

  parse(response) {
    const parsedResponse = [];

    response.forEach(listing => {
      const updatedListing = listing;
      const priceObj = updatedListing.price;

      updatedListing.price.amount =
        integerToDecimal(priceObj.amount, priceObj.currencyCode === 'BTC');

      parsedResponse.push(updatedListing);
    });

    return parsedResponse;
  }
}
<|endoftext|>


<commit_before>// Copyright 2018, University of Colorado Boulder

/**
 * Common model (base type) for Graphing Quadratics.
 *
 * @author Chris Malley (PixelZoom, Inc.)
 * @author Andrea Lin
 */
define( function( require ) {
  'use strict';

  // modules
  var graphingQuadratics = require( 'GRAPHING_QUADRATICS/graphingQuadratics' );
  var inherit = require( 'PHET_CORE/inherit' );
  var Property = require( 'AXON/Property' );

  /**
   * @param {GQScene[]} scenes
   * @constructor
   */
  function GQModel( scenes ) {

    // @public {GQScene[]} scenes, in the order that they appear from left-to-right as radio buttons
    this.scenes = scenes;

    // @public {Property.<Scene>} the selected scene
    this.sceneProperty = new Property( scenes[ 0 ], {
      validValues: scenes
    } );
  }

  graphingQuadratics.register( 'GQModel', GQModel );

  return inherit( Object, GQModel, {

    /**
     * Resets this model by resetting each of its scenes
     *
     * @public
     */
    reset: function() {
      this.scenes.forEach( function( scene ) { scene.reset(); } );
    }
  } );
} );
<commit_msg>reset which scene is selected<commit_after>// Copyright 2018, University of Colorado Boulder

/**
 * Common model (base type) for Graphing Quadratics.
 *
 * @author Chris Malley (PixelZoom, Inc.)
 * @author Andrea Lin
 */
define( function( require ) {
  'use strict';

  // modules
  var graphingQuadratics = require( 'GRAPHING_QUADRATICS/graphingQuadratics' );
  var inherit = require( 'PHET_CORE/inherit' );
  var Property = require( 'AXON/Property' );

  /**
   * @param {GQScene[]} scenes
   * @constructor
   */
  function GQModel( scenes ) {

    // @public {GQScene[]} scenes, in the order that they appear from left-to-right as radio buttons
    this.scenes = scenes;

    // @public {Property.<Scene>} the selected scene
    this.sceneProperty = new Property( scenes[ 0 ], {
      validValues: scenes
    } );
  }

  graphingQuadratics.register( 'GQModel', GQModel );

  return inherit( Object, GQModel, {

    /**
     * Resets this model by resetting each of its scenes
     *
     * @public
     */
    reset: function() {
      this.scenes.forEach( function( scene ) { scene.reset(); } );
      this.sceneProperty.reset();
    }
  } );
} );
<|endoftext|>


<commit_before>'use strict';
(function (ns, _) {
  var filterLabel = Handlebars.compile('{{#if label}}{{label}}{{else}}{{value}}{{/if}}');

  /**
   * @class
   */
  ns.SmartTable = ns.BaseList.extend({
    $context: null,
    $ranger: null,
    autoFetch: true,
    events: {
      'click .archive-button': 'archiveButton_clickHandler',
      'click .delete-button': 'deleteButton_clickHandler',
      'click .refresh-button': 'refreshButton_clickHandler',
      'click .edit': 'edit_clickHandler',
      'click tbody .filter': 'tbodyFilter_clickHandler',
      'click thead .filter': 'theadFilter_clickHandler',
      'click .order': 'order_clickHandler',
      'change select.edit': 'select_changeHandler',
      'change .stars input': 'star_changeHandler',
      'change .status-button': 'statusButton_changeHandler'
    },
    initialize: function (options) {
      var data = this.$el.data()
        , autoFetch = 'autoFetch' in data ? data.autoFetch : this.autoFetch
        , typeahead = 'typeahead' in data ? data.typeahead : true;
      ns.BaseList.prototype.initialize.call(this, _.extend(options, {
        autoFetch: false,
        container: 'tbody',
        reset: true
      }));

      // 通过页面中介来实现翻页等功能
      this.model = this.model && this.model instanceof tp.model.TableMemento ? this.model : new tp.model.TableMemento(this.params, {tableId: this.el.id});
      this.model.on('change', this.model_changeHandler, this);
      this.model.on('invalid', this.model_invalidHandler, this);
      if (options.tags) {
        this.model.tags = options.tags.split(',');
      }
      if (this.model.has('start')) {
        if (this.collection.model && !_.isString(this.collection.model)) {
          _.extend(this.collection.model.prototype.defaults, this.model.pick('start', 'end'));
        }
      }
      this.renderHeader();

      // 启用搜索
      if ('search' in options) {
        this.search = new ns.table.Search({
          el: options.search,
          model: this.model,
          collection: this.collection
        });
      }

      // 翻页
      if ('pagesize' in options && options.pagesize > 0) {
        this.pagination = new ns.table.Pager(_.extend({}, options, {
          el: 'pagination' in options ? options.pagination : '.pager',
          model: this.model,
          collection: this.collection
        }));
      }

      // 调整每页数量
      if ('pagesizeController' in options) {
        this.pagesizeController = $(options.pagesizeController);
        this.pagesizeController.val(this.collection.pagesize);
        this.pagesizeController.on('change', _.bind(this.pagesize_changeHandler, this));
      }

      // 起止日期
      if ('ranger' in options) {
        if (!this.model.has('start')) {
          this.model.set(_.pick(options, 'start', 'end'), {silent: true});
        }
        if ('dateFormat' in options) {
          this.model.set('dateFormat', options.dateFormat, {silent: true});
        }
        this.$ranger.use(this.model);
      }

      // 删选器
      if ('filter' in options) {
        this.filter = new ns.table.Filter({
          el: options.filter,
          model: this.model,
          collection: this.collection
        });
      }

      // 导出按钮
      if ('exportButton' in options) {
        this.exportButton = new tp.component.ExportButton({
          model: this.model,
          el: options.exportButton
        });
      }

      // 桌面默认都固定表头
      if (document.body.clientWidth >= 768 && this.$el.closest('modal').length === 0 && typeahead) {
        this.header = new ns.table.FixedHeader({
          target: this
        });
      }

      if (autoFetch) {
        this.refresh(options);
      }
      this.options = options;
    },
    remove: function () {
      if (this.pagination) {
        this.pagination.remove();
      }
      if (this.pagesizeController) {
        this.pagesizeController.off('change');
      }
      if (this.ranger) {
        this.ranger.remove();
      }
      if (this.filter) {
        this.filter.remove();
      }
      if (this.header) {
        this.header.remove();
      }
      if (this.exportButton) {
        this.exportButton.remove();
      }
      this.model.off(null, null, this);
      this.collection.off(null, null, this);
      tp.model.ListCollection.destroyInstance(this.$el.data('collection-id'));
      ns.BaseList.prototype.remove.call(this);
    },
    render: function () {
      ns.BaseList.prototype.render.call(this);
      this.$context.trigger('table-rendered', this);
      this.trigger('table-rendered', this);
      // 排序
      if ('order' in this.model.changed || 'seq' in  this.model.changed) {
        var container = this.container;
        this.collection.each(function (model) {
          container.append(container.find('#' + model.id));
        });
      }
    },
    refresh: function (options) {
      options = options || {};
      options.data = _.extend(this.model.toJSON(), options.data);
      this.collection.fetch(options);
    },
    renderHeader: function () {
      // 排序
      var order = this.model.get('order')
        , seq = this.model.get('seq')
        , status = this.model.getTags()
        , labels = _.chain(status)
          .omit(function (value, key) {
            return key.match(/_label$/);
          })
          .map(function (value, key) {
            var attr = {key: key, value: value};
            if (status[key + '_label']) {
              attr['label'] = status[key + '_label'];
            }
            return filterLabel(attr);
          })
          .value();
      if (order) {
        this.$('.order').removeClass('active inverse');
        this.$('.order[href="#' + order + '"]').addClass('active').toggleClass('inverse', seq == 'desc');
      }
      this.$('.filters').append(labels.join(''));
    },
    saveModel: function (button, id, prop, value, options) {
      button.spinner();
      this.collection.get(id).save(prop, value, {
        patch: true,
        wait: true,
        context: this,
        success: function () {
          button.spinner(false);
          if (options && options.remove) {
            this.collection.remove(id, {fadeOut: true});
          }
        }
      });
    },
    archiveButton_clickHandler: function (event) {
      var button = $(event.currentTarget)
        , msg = button.data('msg') || '确定归档么？';
      if (!confirm(msg)) {
        return;
      }
      var id = button.closest('tr').attr('id');
      this.saveModel(button, id, button.attr('name'), button.val(), {remove: true});
    },
    collection_errorHandler: function (collection, response) {
      this.$('.waiting td').html(ns.Manager.createErrorMsg(response));
    },
    collection_syncHandler: function () {
      ns.BaseList.prototype.collection_syncHandler.call(this);
      this.model.waiting = false;
      if (this.options.amount) {
        var data = this.collection.getAmount(this.options.omits);
        this.$('.amount').remove();
        this.collection_addHandler(data, null, {immediately: true});
      }
    },
    deleteButton_clickHandler: function (event) {
      var button = $(event.currentTarget)
        , id = button.closest('tr').attr('id')
        , data = button.data()
        , msg = data.msg || '确定删除么？'
        , hasPopup = data.hasPopup
        , destroy = _.bind(function (popup) {
          var param = {};
          if (popup) {
            _.each(popup.$el.find('form').serializeArray(), function(element) {
              param[element.name] = element.value
            });
          }
          button.spinner();
          this.collection.get(id).destroy({
            fadeOut: true,
            data: JSON.stringify(param),
            contentType: 'application/json',
            wait: true,
            error: function (model, xhr) {
              var response = 'responseJSON' in xhr ? xhr.responseJSON : xhr;
              button.spinner(false);
              alert(response.msg || '删除失败');
            }
          });
        }, this);
      if (hasPopup) {
        var popup = tp.popup.Manager.popup(_.defaults({
          isRemote: true,
          content: button.attr('href'),
          model: this.collection.get(data.id)
        }, data));
        popup.on('confirm', destroy, this);
      } else if (confirm(msg)) {
        destroy();
      }
      event.preventDefault();
    },
    edit_clickHandler: function (event) {
      if (event.currentTarget.tagName.toLowerCase() === 'select') {
        return;
      }
      var target = $(event.currentTarget)
        , data = target.data()
        , index = target.closest('td').index()
        , prop = event.currentTarget.hash.substr(1)
        , tr = target.closest('tr')
        , id = tr.attr('id')
        , options = _.extend({
          label: this.$('thead th').eq(index).text()
        }, data);
      if (!id) {
        var relate = tr.attr('class').match(/\brelate-to-(\w+)\b/);
        id = relate ? relate[1] : false;
      }
      if (!id) {
        alert('未查询到对象id，无法启动编辑。');
        return;
      }
      var model = this.collection.get(id);
      options.type = data.type || 'short-text';
      this.$context.trigger('edit-model', model, prop, options);
      event.stopPropagation();
      event.preventDefault();
    },
    model_changeHandler: function (model, options) {
      options = _.omit(options, 'unset') || {};
      this.refresh(options);

      if (this.collection.model && ('start' in model.changed || 'end' in model.changed)) {
        _.extend(this.collection.model.prototype.defaults, _.pick(model.changed, 'start', 'end'));
      }
      this.$el.addClass('loading');
      model.warting = true;
    },
    model_invalidHandler: function (model, error) {
      alert(error);
    },
    order_clickHandler: function (event) {
      var target = $(event.currentTarget)
        , order = target.attr('href').substr(1);
      this.$('.order.active').not(target).removeClass('active inverse');
      target.toggleClass('inverse', target.hasClass('active') && !target.hasClass('inverse')).addClass('active');
      this.model.set({
        order: order,
        seq: target.hasClass('inverse') ? 'desc' : 'asc'
      }, {reset: true});
      event.preventDefault();
    },
    pagesize_changeHandler: function (event) {
      this.collection.setPagesize(event.target.value);
      if (this.model.get('page') === 0) {
        this.model.trigger('change', this.model);
      } else {
       this.model.set('page', 0);
      }
    },
    refreshButton_clickHandler: function (event) {
      this.refresh();
      $(event.currentTarget).spinner();
    },
    select_changeHandler: function (event) {
      var target = $(event.currentTarget)
        , id = target.closest('tr').attr('id');
      this.saveModel(target, id, target.attr('name'), target.val());
    },
    star_changeHandler: function (event) {
      var target = $(event.currentTarget)
        , id = target.closest('tr').attr('id');
      this.saveModel(target.add(target.siblings('.star')), id, target.attr('name'), target.val());
    },
    statusButton_changeHandler: function (event) {
      var target = $(event.currentTarget)
        , data = _.extend({active: 1, deactive: 0}, target.data())
        , value = target.prop('checked') ? data.active : data.deactive
        , id = target.closest('tr').attr('id')
        , button = $(target[0].labels).filter('.btn');
      this.saveModel(button, id, target.attr('name'), value);
    },
    tbodyFilter_clickHandler: function (event) {
      var target = $(event.currentTarget)
        , label = target.text()
        , path = target.attr('href').split('/').slice(-2)
        , hasFilter = this.model.has(path[0])
        , attr = { page: 0 }; // 要自动切回第一页
      attr[path[0]] = path[1];
      if (path[0] != label) {
        attr[path[0] + '_label'] = label;
      }
      this.model.set(attr, {reset: true});
      if (hasFilter) {
        this.$('.filters').find('[href="#/' + path[0] + '"]').replaceWith(target.clone());
      } else {
        this.$('.filters').append(target.clone());
      }
      event.preventDefault();
    },
    theadFilter_clickHandler: function (event) {
      var target = $(event.currentTarget)
        , path = target.attr('href').split('/').slice(-2);
      this.model.set('page', 0, {silent: true}) // 自动切回第一页
        .unset(path[0], {reset: true});
      target.remove();
      event.preventDefault();
    }
  });
}(Nervenet.createNameSpace('tp.component'), _));<commit_msg>  已经有id<commit_after>'use strict';
(function (ns, _) {
  var filterLabel = Handlebars.compile('{{#if label}}{{label}}{{else}}{{value}}{{/if}}');

  /**
   * @class
   */
  ns.SmartTable = ns.BaseList.extend({
    $context: null,
    $ranger: null,
    autoFetch: true,
    events: {
      'click .archive-button': 'archiveButton_clickHandler',
      'click .delete-button': 'deleteButton_clickHandler',
      'click .refresh-button': 'refreshButton_clickHandler',
      'click .edit': 'edit_clickHandler',
      'click tbody .filter': 'tbodyFilter_clickHandler',
      'click thead .filter': 'theadFilter_clickHandler',
      'click .order': 'order_clickHandler',
      'change select.edit': 'select_changeHandler',
      'change .stars input': 'star_changeHandler',
      'change .status-button': 'statusButton_changeHandler'
    },
    initialize: function (options) {
      var data = this.$el.data()
        , autoFetch = 'autoFetch' in data ? data.autoFetch : this.autoFetch
        , typeahead = 'typeahead' in data ? data.typeahead : true;
      ns.BaseList.prototype.initialize.call(this, _.extend(options, {
        autoFetch: false,
        container: 'tbody',
        reset: true
      }));

      // 通过页面中介来实现翻页等功能
      this.model = this.model && this.model instanceof tp.model.TableMemento ? this.model : new tp.model.TableMemento(this.params, {tableId: this.el.id});
      this.model.on('change', this.model_changeHandler, this);
      this.model.on('invalid', this.model_invalidHandler, this);
      if (options.tags) {
        this.model.tags = options.tags.split(',');
      }
      if (this.model.has('start')) {
        if (this.collection.model && !_.isString(this.collection.model)) {
          _.extend(this.collection.model.prototype.defaults, this.model.pick('start', 'end'));
        }
      }
      this.renderHeader();

      // 启用搜索
      if ('search' in options) {
        this.search = new ns.table.Search({
          el: options.search,
          model: this.model,
          collection: this.collection
        });
      }

      // 翻页
      if ('pagesize' in options && options.pagesize > 0) {
        this.pagination = new ns.table.Pager(_.extend({}, options, {
          el: 'pagination' in options ? options.pagination : '.pager',
          model: this.model,
          collection: this.collection
        }));
      }

      // 调整每页数量
      if ('pagesizeController' in options) {
        this.pagesizeController = $(options.pagesizeController);
        this.pagesizeController.val(this.collection.pagesize);
        this.pagesizeController.on('change', _.bind(this.pagesize_changeHandler, this));
      }

      // 起止日期
      if ('ranger' in options) {
        if (!this.model.has('start')) {
          this.model.set(_.pick(options, 'start', 'end'), {silent: true});
        }
        if ('dateFormat' in options) {
          this.model.set('dateFormat', options.dateFormat, {silent: true});
        }
        this.$ranger.use(this.model);
      }

      // 删选器
      if ('filter' in options) {
        this.filter = new ns.table.Filter({
          el: options.filter,
          model: this.model,
          collection: this.collection
        });
      }

      // 导出按钮
      if ('exportButton' in options) {
        this.exportButton = new tp.component.ExportButton({
          model: this.model,
          el: options.exportButton
        });
      }

      // 桌面默认都固定表头
      if (document.body.clientWidth >= 768 && this.$el.closest('modal').length === 0 && typeahead) {
        this.header = new ns.table.FixedHeader({
          target: this
        });
      }

      if (autoFetch) {
        this.refresh(options);
      }
      this.options = options;
    },
    remove: function () {
      if (this.pagination) {
        this.pagination.remove();
      }
      if (this.pagesizeController) {
        this.pagesizeController.off('change');
      }
      if (this.ranger) {
        this.ranger.remove();
      }
      if (this.filter) {
        this.filter.remove();
      }
      if (this.header) {
        this.header.remove();
      }
      if (this.exportButton) {
        this.exportButton.remove();
      }
      this.model.off(null, null, this);
      this.collection.off(null, null, this);
      tp.model.ListCollection.destroyInstance(this.$el.data('collection-id'));
      ns.BaseList.prototype.remove.call(this);
    },
    render: function () {
      ns.BaseList.prototype.render.call(this);
      this.$context.trigger('table-rendered', this);
      this.trigger('table-rendered', this);
      // 排序
      if ('order' in this.model.changed || 'seq' in  this.model.changed) {
        var container = this.container;
        this.collection.each(function (model) {
          container.append(container.find('#' + model.id));
        });
      }
    },
    refresh: function (options) {
      options = options || {};
      options.data = _.extend(this.model.toJSON(), options.data);
      this.collection.fetch(options);
    },
    renderHeader: function () {
      // 排序
      var order = this.model.get('order')
        , seq = this.model.get('seq')
        , status = this.model.getTags()
        , labels = _.chain(status)
          .omit(function (value, key) {
            return key.match(/_label$/);
          })
          .map(function (value, key) {
            var attr = {key: key, value: value};
            if (status[key + '_label']) {
              attr['label'] = status[key + '_label'];
            }
            return filterLabel(attr);
          })
          .value();
      if (order) {
        this.$('.order').removeClass('active inverse');
        this.$('.order[href="#' + order + '"]').addClass('active').toggleClass('inverse', seq == 'desc');
      }
      this.$('.filters').append(labels.join(''));
    },
    saveModel: function (button, id, prop, value, options) {
      button.spinner();
      this.collection.get(id).save(prop, value, {
        patch: true,
        wait: true,
        context: this,
        success: function () {
          button.spinner(false);
          if (options && options.remove) {
            this.collection.remove(id, {fadeOut: true});
          }
        }
      });
    },
    archiveButton_clickHandler: function (event) {
      var button = $(event.currentTarget)
        , msg = button.data('msg') || '确定归档么？';
      if (!confirm(msg)) {
        return;
      }
      var id = button.closest('tr').attr('id');
      this.saveModel(button, id, button.attr('name'), button.val(), {remove: true});
    },
    collection_errorHandler: function (collection, response) {
      this.$('.waiting td').html(ns.Manager.createErrorMsg(response));
    },
    collection_syncHandler: function () {
      ns.BaseList.prototype.collection_syncHandler.call(this);
      this.model.waiting = false;
      if (this.options.amount) {
        var data = this.collection.getAmount(this.options.omits);
        this.$('.amount').remove();
        this.collection_addHandler(data, null, {immediately: true});
      }
    },
    deleteButton_clickHandler: function (event) {
      var button = $(event.currentTarget)
        , id = button.closest('tr').attr('id')
        , data = button.data()
        , msg = data.msg || '确定删除么？'
        , hasPopup = data.hasPopup
        , destroy = _.bind(function (popup) {
          var param = {};
          if (popup) {
            _.each(popup.$el.find('form').serializeArray(), function(element) {
              param[element.name] = element.value
            });
          }
          button.spinner();
          this.collection.get(id).destroy({
            fadeOut: true,
            data: JSON.stringify(param),
            contentType: 'application/json',
            wait: true,
            error: function (model, xhr) {
              var response = 'responseJSON' in xhr ? xhr.responseJSON : xhr;
              button.spinner(false);
              alert(response.msg || '删除失败');
            }
          });
        }, this);
      if (hasPopup) {
        var popup = tp.popup.Manager.popup(_.defaults({
          isRemote: true,
          content: button.attr('href'),
          model: this.collection.get(id)
        }, data));
        popup.on('confirm', destroy, this);
      } else if (confirm(msg)) {
        destroy();
      }
      event.preventDefault();
    },
    edit_clickHandler: function (event) {
      if (event.currentTarget.tagName.toLowerCase() === 'select') {
        return;
      }
      var target = $(event.currentTarget)
        , data = target.data()
        , index = target.closest('td').index()
        , prop = event.currentTarget.hash.substr(1)
        , tr = target.closest('tr')
        , id = tr.attr('id')
        , options = _.extend({
          label: this.$('thead th').eq(index).text()
        }, data);
      if (!id) {
        var relate = tr.attr('class').match(/\brelate-to-(\w+)\b/);
        id = relate ? relate[1] : false;
      }
      if (!id) {
        alert('未查询到对象id，无法启动编辑。');
        return;
      }
      var model = this.collection.get(id);
      options.type = data.type || 'short-text';
      this.$context.trigger('edit-model', model, prop, options);
      event.stopPropagation();
      event.preventDefault();
    },
    model_changeHandler: function (model, options) {
      options = _.omit(options, 'unset') || {};
      this.refresh(options);

      if (this.collection.model && ('start' in model.changed || 'end' in model.changed)) {
        _.extend(this.collection.model.prototype.defaults, _.pick(model.changed, 'start', 'end'));
      }
      this.$el.addClass('loading');
      model.warting = true;
    },
    model_invalidHandler: function (model, error) {
      alert(error);
    },
    order_clickHandler: function (event) {
      var target = $(event.currentTarget)
        , order = target.attr('href').substr(1);
      this.$('.order.active').not(target).removeClass('active inverse');
      target.toggleClass('inverse', target.hasClass('active') && !target.hasClass('inverse')).addClass('active');
      this.model.set({
        order: order,
        seq: target.hasClass('inverse') ? 'desc' : 'asc'
      }, {reset: true});
      event.preventDefault();
    },
    pagesize_changeHandler: function (event) {
      this.collection.setPagesize(event.target.value);
      if (this.model.get('page') === 0) {
        this.model.trigger('change', this.model);
      } else {
       this.model.set('page', 0);
      }
    },
    refreshButton_clickHandler: function (event) {
      this.refresh();
      $(event.currentTarget).spinner();
    },
    select_changeHandler: function (event) {
      var target = $(event.currentTarget)
        , id = target.closest('tr').attr('id');
      this.saveModel(target, id, target.attr('name'), target.val());
    },
    star_changeHandler: function (event) {
      var target = $(event.currentTarget)
        , id = target.closest('tr').attr('id');
      this.saveModel(target.add(target.siblings('.star')), id, target.attr('name'), target.val());
    },
    statusButton_changeHandler: function (event) {
      var target = $(event.currentTarget)
        , data = _.extend({active: 1, deactive: 0}, target.data())
        , value = target.prop('checked') ? data.active : data.deactive
        , id = target.closest('tr').attr('id')
        , button = $(target[0].labels).filter('.btn');
      this.saveModel(button, id, target.attr('name'), value);
    },
    tbodyFilter_clickHandler: function (event) {
      var target = $(event.currentTarget)
        , label = target.text()
        , path = target.attr('href').split('/').slice(-2)
        , hasFilter = this.model.has(path[0])
        , attr = { page: 0 }; // 要自动切回第一页
      attr[path[0]] = path[1];
      if (path[0] != label) {
        attr[path[0] + '_label'] = label;
      }
      this.model.set(attr, {reset: true});
      if (hasFilter) {
        this.$('.filters').find('[href="#/' + path[0] + '"]').replaceWith(target.clone());
      } else {
        this.$('.filters').append(target.clone());
      }
      event.preventDefault();
    },
    theadFilter_clickHandler: function (event) {
      var target = $(event.currentTarget)
        , path = target.attr('href').split('/').slice(-2);
      this.model.set('page', 0, {silent: true}) // 自动切回第一页
        .unset(path[0], {reset: true});
      target.remove();
      event.preventDefault();
    }
  });
}(Nervenet.createNameSpace('tp.component'), _));<|endoftext|>