<commit_before>(function() {

    var postman = {};
    var clients = {};

    /**
     * Creates a client.
     * @param {Window} contentWindow
     * @param {string} domain
     * @param {number=} opt_timeout
     * @return {Client}
     */
    postman.createClient = function(contentWindow, domain, opt_timeout) {
        return new Client(contentWindow, domain, opt_timeout);
    };

    /**
     * Gets a client with content window.
     * @param {Window} contentWindow
     * @return {?Client}
     */
    postman.getClientByWindow = function(contentWindow) {
        var client;

        for (var clientId in clients) {
            if (clients[clientId].contentWindow == contentWindow)
                client = clients[clientId];
        }

        return client;
    };

    /**
     * @constructor
     * @param {Object=} data
     */
    function Message(data) {
        data = data || {};
        this.id = data.id || generateId_();
        this.type = data.type; // req or res
        this.name = data.name;
        this.error = data.error;
        this.payload = data.payload;
    }

    /**
     * Creates a message.
     * @param {Object=} opt_data
     * @return {Message}
     */
    Message.create = function(opt_data) {
        return new Message(opt_data || {});
    };

    /**
     * Creates message from event object.
     * @param {Event} e
     * @return {Message}
     */
    Message.parse = function(e) {
        var data = JSON.parse(e.data);
        return new Message(data);
    };

    /**
     * @return {Object}
     */
    Message.prototype.toJSON = function() {
        var json = {
            id: this.id,
            type: this.type,
            name: this.name,
            error: this.error,
            payload: this.payload
        };

        // TODO: _.pick

        return JSON.stringify(json);
    };

    /**
     * @constructor
     * @param {Window} contentWindow
     * @param {string} domain
     * @param {number=} opt_timeout
     */
    function Client(contentWindow, domain, opt_timeout) {
        this.id = generateId_();

        this.contentWindow = contentWindow;
        this.domain = domain;
        this.handlers = {};
        this.timeoutDuration = opt_timeout;

        if (!this.timeoutDuration && this.timeoutDuration !== 0)
            this.timeoutDuration = 10000;

        this.callbacks = {};
        this.timeoutHandlers = {};

        clients[this.id] = this;
    }

    /**
     * Main send message method.
     * @param {Message} message
     */
    Client.prototype.sendMessage = function(message) {
        this.contentWindow.postMessage(message.toJSON(), this.domain);
    };

    /**
     * Emits.
     * @param {string} name
     * @param {?Object=} opt_data
     * @param {Function} opt_callback
     */
    Client.prototype.emit = function(name, opt_data, opt_callback) {
        var that = this;

        var message = Message.create({
            type: 'req',
            name: name,
            payload: opt_data
        });

        if (opt_callback) {
            this.callbacks[message.id] = opt_callback;

            if (this.timeoutDuration > 0) {
                this.timeoutHandlers[message.id] = setTimeout(function() {
                    var callback = that.callbacks[message.id];
                    callback && callback(new Error('Timeout exceed.'));
                    delete that.callbacks[message.id];
                    delete that.timeoutHandlers[message.id];
                }, this.timeoutDuration);
            }
        }

        this.sendMessage(message);
    };

    /**
     * Binds a handler to event.
     * @param {string} name
     * @param {Function} handler
     */
    Client.prototype.on = function(name, handler) {
        this.handlers[name] = handler;
    };

    /**
     * Handles request. Passes request message to handler if exists.
     * @param {Message} message
     */
    Client.prototype.handleRequest = function(message) {
        var that = this;
        var handler = this.handlers[message.name];

        if (!handler)
            return;

        var callback = function(err, data) {
            var responseMessage = Message.create({
                id: message.id,
                name: message.name,
                type: 'res',
                error: err,
                payload: data
            });

            that.sendMessage(responseMessage);
        };

        handler && handler(message.payload, callback);
    };

    /**
     * Handles response. Clears timeout and executes callback.
     * @param {Message} message
     */
    Client.prototype.handleResponse = function(message) {
        var callback = this.callbacks[message.id];
        callback && callback(message.error, message.payload);

        if (this.timeoutHandlers[message.id])
            clearTimeout(this.timeoutHandlers[message.id]);

        delete this.callbacks[message.id];
    };

    /**
     * Gracefully destorys itself.
     */
    Client.prototype.destroy = function() {
        // Delete timeout handlers.
        for (var messageId in this.timeoutHandlers) {
            clearTimeout(this.timeoutHandlers[messageId]);
        }

        // Fail callback
        for (var messageId in this.callbacks) {
            this.callbacks[messageId](new Error('Postman client has destoyed.'));
        }

        delete clients[this.id];
    };

    /**
     * Listen for message events.
     */
    window.addEventListener('message', function(e) {
        try {
            var message = Message.parse(e);
            var client = postman.getClientByWindow(e.source);

            if (!client)
                return;

            switch (message.type) {
                case 'req':
                    client.handleRequest(message);
                    break;
                case 'res':
                    client.handleResponse(message);
                    break;
            }
        } catch(err) {
            // Don't do anything
        }
    }, false)

    /**
     * Generate randon string, default length is 6.
     * @param {number=} opt_length
     * @return {string}
     */
    function generateId_(opt_length) {
        var chars = '23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghkmnpqrstuvwxyz',
            string = '';

        opt_length = opt_length || 6;

        for (var i = 0; i < opt_length; i++) {
            var randomNumber = Math.floor(Math.random() * chars.length);
            string += chars.substring(randomNumber, randomNumber + 1);
        }

        return string;
    }

    if (typeof module !== 'undefined') module.exports = postman;
    if (typeof window !== 'undefined') window.postman = postman;
})();
<commit_msg>:sparkles: client: Support message based timeouts<commit_after>(function() {

    var postman = {};
    var clients = {};

    /**
     * Creates a client.
     * @param {Window} contentWindow
     * @param {string} domain
     * @param {number=} opt_timeout
     * @return {Client}
     */
    postman.createClient = function(contentWindow, domain, opt_timeout) {
        return new Client(contentWindow, domain, opt_timeout);
    };

    /**
     * Gets a client with content window.
     * @param {Window} contentWindow
     * @return {?Client}
     */
    postman.getClientByWindow = function(contentWindow) {
        var client;

        for (var clientId in clients) {
            if (clients[clientId].contentWindow == contentWindow)
                client = clients[clientId];
        }

        return client;
    };

    /**
     * @constructor
     * @param {Object=} data
     */
    function Message(data) {
        data = data || {};
        this.id = data.id || generateId_();
        this.type = data.type; // req or res
        this.name = data.name;
        this.error = data.error;
        this.payload = data.payload;
    }

    /**
     * Creates a message.
     * @param {Object=} opt_data
     * @return {Message}
     */
    Message.create = function(opt_data) {
        return new Message(opt_data || {});
    };

    /**
     * Creates message from event object.
     * @param {Event} e
     * @return {Message}
     */
    Message.parse = function(e) {
        var data = JSON.parse(e.data);
        return new Message(data);
    };

    /**
     * @return {Object}
     */
    Message.prototype.toJSON = function() {
        var json = {
            id: this.id,
            type: this.type,
            name: this.name,
            error: this.error,
            payload: this.payload
        };

        // TODO: _.pick

        return JSON.stringify(json);
    };

    /**
     * @constructor
     * @param {Window} contentWindow
     * @param {string} domain
     * @param {number=} opt_timeout
     */
    function Client(contentWindow, domain, opt_timeout) {
        this.id = generateId_();

        this.contentWindow = contentWindow;
        this.domain = domain;
        this.handlers = {};
        this.timeoutDuration = opt_timeout;

        if (!this.timeoutDuration && this.timeoutDuration !== 0)
            this.timeoutDuration = 10000;

        this.callbacks = {};
        this.timeoutHandlers = {};

        clients[this.id] = this;
    }

    /**
     * Main send message method.
     * @param {Message} message
     */
    Client.prototype.sendMessage = function(message) {
        this.contentWindow.postMessage(message.toJSON(), this.domain);
    };

    /**
     * Emits.
     * @param {string} name
     * @param {?Object=} opt_data
     * @param {Function} opt_callback
     */
    Client.prototype.emit = function(name, opt_data, opt_callback, opt_timeout) {
        var that = this;

        var message = Message.create({
            type: 'req',
            name: name,
            payload: opt_data
        });

        if (opt_callback) {
            this.callbacks[message.id] = opt_callback;

            var timeout = isNaN(Number(opt_timeout)) ? this.timeoutDuration : Number(opt_timeout);

            if (timeout > 0) {
                this.timeoutHandlers[message.id] = setTimeout(function() {
                    var callback = that.callbacks[message.id];
                    callback && callback(new Error('Timeout exceed.'));
                    delete that.callbacks[message.id];
                    delete that.timeoutHandlers[message.id];
                }, timeout);
            }
        }

        this.sendMessage(message);
    };

    /**
     * Binds a handler to event.
     * @param {string} name
     * @param {Function} handler
     */
    Client.prototype.on = function(name, handler) {
        this.handlers[name] = handler;
    };

    /**
     * Handles request. Passes request message to handler if exists.
     * @param {Message} message
     */
    Client.prototype.handleRequest = function(message) {
        var that = this;
        var handler = this.handlers[message.name];

        if (!handler)
            return;

        var callback = function(err, data) {
            var responseMessage = Message.create({
                id: message.id,
                name: message.name,
                type: 'res',
                error: err,
                payload: data
            });

            that.sendMessage(responseMessage);
        };

        handler && handler(message.payload, callback);
    };

    /**
     * Handles response. Clears timeout and executes callback.
     * @param {Message} message
     */
    Client.prototype.handleResponse = function(message) {
        var callback = this.callbacks[message.id];
        callback && callback(message.error, message.payload);

        if (this.timeoutHandlers[message.id])
            clearTimeout(this.timeoutHandlers[message.id]);

        delete this.callbacks[message.id];
    };

    /**
     * Gracefully destorys itself.
     */
    Client.prototype.destroy = function() {
        // Delete timeout handlers.
        for (var messageId in this.timeoutHandlers) {
            clearTimeout(this.timeoutHandlers[messageId]);
        }

        // Fail callback
        for (var messageId in this.callbacks) {
            this.callbacks[messageId](new Error('Postman client has destoyed.'));
        }

        delete clients[this.id];
    };

    /**
     * Listen for message events.
     */
    window.addEventListener('message', function(e) {
        try {
            var message = Message.parse(e);
            var client = postman.getClientByWindow(e.source);

            if (!client)
                return;

            switch (message.type) {
                case 'req':
                    client.handleRequest(message);
                    break;
                case 'res':
                    client.handleResponse(message);
                    break;
            }
        } catch(err) {
            // Don't do anything
        }
    }, false)

    /**
     * Generate randon string, default length is 6.
     * @param {number=} opt_length
     * @return {string}
     */
    function generateId_(opt_length) {
        var chars = '23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghkmnpqrstuvwxyz',
            string = '';

        opt_length = opt_length || 6;

        for (var i = 0; i < opt_length; i++) {
            var randomNumber = Math.floor(Math.random() * chars.length);
            string += chars.substring(randomNumber, randomNumber + 1);
        }

        return string;
    }

    if (typeof module !== 'undefined') module.exports = postman;
    if (typeof window !== 'undefined') window.postman = postman;
})();
<|endoftext|>


<commit_before>var slideIndex;

$(document).ready(function(){
	$("#btn-right").click(function(){
		pic(1)
	});
	$("#btn-left").click(function(){
		pic(-1)});

	showPic(0);

	slideIndex = 1;
	showPic(slideIndex);

});

function pic(n){
	$('#current').parent().trigger('zoom.destroy');
	$('#current').unwrap();
	showPic(slideIndex += n);
}

function showPic(n){
	var i;
	var x = document.getElementsByClassName("images");
	if (n > x.length) {slideIndex = 1}
	if (n < 1) {slideIndex = x.length}
	for (i = 0; i < x.length; i++) {
		$(x[i]).css("display", "none");
		$(x[i]).removeAttr('id');
	}
	$(x[slideIndex-1]).css("display", "block");
	$(x[slideIndex-1]).attr("id", "current");
	$("#current")
		.wrap('')
	    .css('display', 'block')
	    .parent()
	    .zoom();
}

function getPrice()
{

    var startDate = $("#from").val();
    var endDate = $("#to").val();

    var msDay = 1000*60*60*24;

    var d1 = new Date(startDate);
    var d2 = new Date(endDate);

    var totalTime = Math.abs(d1-d2);
    //difference in milliseconds between two dates.

    totalTime = Number(totalTime);
    //converts date to stirng.

    totalTime = totalTime % msDay;

    var totalPrice = 20 * totalTime;

    $("#priceBox").val(totalPrice);

    //return 20 * totalTime;
    //calculates the price and returns.

}<commit_msg>moved price to calendar.js<commit_after>var slideIndex;

$(document).ready(function(){
	$("#btn-right").click(function(){
		pic(1)
	});
	$("#btn-left").click(function(){
		pic(-1)});

	showPic(0);

	slideIndex = 1;
	showPic(slideIndex);

});

function pic(n){
	$('#current').parent().trigger('zoom.destroy');
	$('#current').unwrap();
	showPic(slideIndex += n);
}

function showPic(n){
	var i;
	var x = document.getElementsByClassName("images");
	if (n > x.length) {slideIndex = 1}
	if (n < 1) {slideIndex = x.length}
	for (i = 0; i < x.length; i++) {
		$(x[i]).css("display", "none");
		$(x[i]).removeAttr('id');
	}
	$(x[slideIndex-1]).css("display", "block");
	$(x[slideIndex-1]).attr("id", "current");
	$("#current")
		.wrap('')
	    .css('display', 'block')
	    .parent()
	    .zoom();
}
<|endoftext|>


<commit_before>/**
 * @file Promise
 * @author treelite(c.xinle@gmail.com)
 */

define(function () {

    /**
     * resolver的状态
     *
     * @type {Object}
     */
    var STATUS = {
        PENDING: 0,
        FULFILLED: 1,
        REJECTED: 2
    };

    /**
     * 是否捕获异常
     * 规范要求捕获所有异常 see #2.2.7.2
     *
     * but 捕获了所有异常 开发可能比较难找错误...
     * 可以在debug下调用`Resolver.disableExceptionCapture()`
     * 关闭异常捕获简单粗暴管事儿
     *
     * 更优雅点的方式是`Resolver.on('reject', fn)`注册全局事件来统一处理异常
     *
     *
     * @type {boolean}
     */
    var captureException = true;

    /**
     * 是否启用全局事件
     * 默认不启用
     *
     * @type {boolean}
     */
    var globalEvent = false;

    /**
     * 函数判断
     *
     * @inner
     * @param {*} value
     * @return {boolean}
     */
    function isFunction(value) {
        return '[object Function]'
            == Object.prototype.toString.call(value);
    }

    /**
     * object判断
     *
     * @inner
     * @param {*} value
     * @return {boolean}
     */
    function isObject(value) {
        return '[object Object]'
            == Object.prototype.toString.call(value);
    }

    /**
     * 使用value确定resolver的状态
     *
     * @param {Resolver}
     * @param {Object} value
     */
    function resolve(resolver, value) {
        // 不再额外判断value是否是Promise对象
        if (isObject(value) || isFunction(value)) {
            // 保证resolvePromise与rejectPromise
            // 只能被调用一次
            // （不确定value是否是Promise对象）
            // see #2.3.3.3.3
            var called;
            try {
                // 可能抛异常
                var then = value.then;
                if (isFunction(then)) {
                    // 可能抛异常
                    then.call(
                        value,
                        function (data) {
                            if (!called) {
                                resolve(resolver, data);
                                called = true;
                            }
                        },
                        function (reason) {
                            if (!called) {
                                resolver.reject(reason);
                                called = true;
                            }
                        }
                    );
                }
                else {
                    resolver.fulfill(value);
                }
            }
            catch (e) {
                if (!captureException) {
                    throw e;
                }
                else if (!called) {
                    resolver.reject(e);
                }
            }
        }
        else {
            resolver.fulfill(value);
        }
    }

    /**
     * 包装then的回调参数
     * 使其能根据回调的返回结果设置then返回的Resolver对象状态
     *
     * @inner
     * @param {Resolver} resolver
     * @param {Promise} promise
     * @param {Function} callback
     */
    function wrapCallback(resolver, promise, callback) {
        return function (data) {
            try {
                // 可能抛异常
                var res = callback(data);
                // 返回结果与当前的promise对象相同
                // 抛异常
                // see # 2.3.1
                if (res === promise) {
                    throw new TypeError();
                }

                resolve(resolver, res);
            }
            catch (e) {
                if (captureException) {
                    resolver.reject(e);
                }
                else {
                    throw e;
                }
            }
        };
    }

    /**
     * 注册resolver的回调函数
     * 如果resolver已处于非PENDING状态
     * 则“立即”调用回调函数
     *
     * @inner
     * @param {Object} resolver
     * @param {number} status 回调函数类型 FULFILLED 或者 REJECTED
     * @param {Function} callback
     */
    function addListener(resolver, status, callback) {
        if (resolver.status == status) {
            // 设置延迟
            // 为了让then函数先返回再执行回调
            // see #2.2.4
            setTimeout(
                function () {
                    callback(resolver.data);
                },
                0
            );
        }
        else if (status == STATUS.FULFILLED) {
            resolver.fulfillList.push(callback);
        }
        else if (status == STATUS.REJECTED) {
            resolver.rejectList.push(callback);
        }
    }

    /**
     * 触发resolver回调函数
     * 根据状态，执行resolver的回调函数
     *
     * @inner
     * @param {Object} resolver
     */
    function emit(resolver) {
        var items = resolver.status == STATUS.FULFILLED
            ? resolver.fulfillList
            : resolver.rejectList;

        fireGlobalEvent(resolver);

        if (items.length <= 0 ) {
            return;
        }

        // 触发注册的回调函数必须
        // 在状态改变完成后
        // see #2.2.2 #2.2.3 #2.2.4
        setTimeout(
            function () {
                var item;
                while (item = items.shift()) {
                    item(resolver.data);
                }
            },
            0
        );
    }

    /**
     * then
     * 将fulfill回调与reject回调注册到resolver上
     * 并返回新的Promise对象
     *
     * @inner
     * @param {Resolver} resolver
     * @param {Function} onFulfilled
     * @param {Function} onRejected
     * @return {Promise}
     */
    function then(resolver, onFulfilled, onRejected) {
        var res = new Resolver();
        var promise = createPromise(res);

        if (isFunction(onFulfilled)) {
            onFulfilled = wrapCallback(res, promise, onFulfilled);
        }
        else {
            // not function
            // 'return promise' must fulfill with the same value
            // when 'main promise' is resolved
            // see #2.2.7.3
            onFulfilled = function (data) {
                res.fulfill(data);
            };
        }
        addListener(resolver, STATUS.FULFILLED, onFulfilled);

        if (isFunction(onRejected)) {
            onRejected = wrapCallback(res, promise, onRejected);
        }
        else {
            // not function
            // 'return promise' must reject with the same reason
            // when 'main promise' is rejected
            // see #2.2.7.4
            onRejected = function (reason) {
                res.reject(reason);
            };
        }
        addListener(resolver, STATUS.REJECTED, onRejected);

        return promise;
    }

    /**
     * 创建Promise对象
     *
     * @inner
     * @param {Resolver} resolver
     */
    function createPromise(resolver) {
        return {
            then: function (onFulfilled, onRejected) {
                return then(resolver, onFulfilled, onRejected);
            }
        };
    }

    /**
     * 触发全局事件
     *
     * @inner
     * @param {Resolver} resolver
     * @param {string} type 事件类型
     */
    function fireGlobalEvent(resolver) {
        var type = resolver.status == STATUS.FULFILLED
                    ? 'resolve'
                    : 'reject';

        if (globalEvent) {
            Resolver.emit(type, {
                data: resolver.data
            });
        }
    }

    /**
     * Resolver
     *
     * @constructor
     */
    function Resolver() {
        this.status = STATUS.PENDING;
        this.fulfillList = [];
        this.rejectList = [];
    }

    /**
     * 启动
     */
    Resolver.enableGlobalEvent = function (Emitter) {
        Emitter.mixin(this);
        globalEvent = true;
    };

    Resolver.disableExceptionCapture = function () {
        captureException = false;
    };

    Resolver.enableExceptionCapture = function () {
        captureException = true;
    };

    /**
     * fulfill
     *
     * @public
     * @param {*} data
     */
    Resolver.prototype.fulfill = function (data) {
        if (this.status != STATUS.PENDING) {
            return;
        }

        this.data = data;
        this.status = STATUS.FULFILLED;
        emit(this);
    };

    /**
     * resolve
     *
     * @public
     * @param {*} data
     */
    Resolver.prototype.resolve = Resolver.prototype.fulfill;

    /**
     * reject
     *
     * @public
     * @param {*} reason
     */
    Resolver.prototype.reject = function (reason) {
        if (this.status != STATUS.PENDING) {
            return;
        }

        this.data = reason;
        this.status = STATUS.REJECTED;
        emit(this);
    };

    /**
     * 生成Promise
     *
     * @public
     * @return {Promise}
     */
    Resolver.prototype.promise = function () {
        return createPromise(this);
    };

    return Resolver;
});
<commit_msg>`nextTick` replace `setTimeout`, improve performance<commit_after>/**
 * @file Promise
 * @author treelite(c.xinle@gmail.com)
 */

define(function () {

    /**
     * resolver的状态
     *
     * @type {Object}
     */
    var STATUS = {
        PENDING: 0,
        FULFILLED: 1,
        REJECTED: 2
    };

    /**
     * 是否捕获异常
     * 规范要求捕获所有异常 see #2.2.7.2
     *
     * but 捕获了所有异常 开发可能比较难找错误...
     * 可以在debug下调用`Resolver.disableExceptionCapture()`
     * 关闭异常捕获简单粗暴管事儿
     *
     * 更优雅点的方式是`Resolver.on('reject', fn)`注册全局事件来统一处理异常
     *
     *
     * @type {boolean}
     */
    var captureException = true;

    /**
     * 是否启用全局事件
     * 默认不启用
     *
     * @type {boolean}
     */
    var globalEvent = false;

    /**
     * 延迟执行
     *
     * @inner
     */
    var nextTick = (function () {
        var res;

        var Observer;
        var callbacks = [];
        var attributeName = 'promise';
        function handler(mutations) {
            var item = mutations[0];
            if (item.attributeName == attributeName) {
                var len = callbacks.length;
                for (var i = 0; i < len; i++) {
                    callbacks[i]();
                }
                callbacks.splice(0, i);
            }
        }

        // only IE, currently
        // https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/setImmediate/Overview.html#processingmodel
        if (typeof setImmediate == 'function') {
            res = setImmediate;
        }
        // for modern browser
        else if (Observer = window.MutationObserver
            || window.webKitMutationObserver
        ) {
            var observer = new Observer(handler);
            var ele = document.createElement('div');
            observer.observe(ele, {attributes: true});

            res = function (fn) {
                callbacks.push(fn);
                ele.setAttribute(
                    attributeName,
                    Date.now ? Date.now() : (new Date()).getTime()
                );
            };
        }
        // for older browser
        else {
            res = function (fn) {
                setTimeout(fn, 0);
            };
        }

        return res;
    })();

    /**
     * 函数判断
     *
     * @inner
     * @param {*} value
     * @return {boolean}
     */
    function isFunction(value) {
        return '[object Function]'
            == Object.prototype.toString.call(value);
    }

    /**
     * object判断
     *
     * @inner
     * @param {*} value
     * @return {boolean}
     */
    function isObject(value) {
        return '[object Object]'
            == Object.prototype.toString.call(value);
    }

    /**
     * 使用value确定resolver的状态
     *
     * @param {Resolver}
     * @param {Object} value
     */
    function resolve(resolver, value) {
        // 不再额外判断value是否是Promise对象
        if (isObject(value) || isFunction(value)) {
            // 保证resolvePromise与rejectPromise
            // 只能被调用一次
            // （不确定value是否是Promise对象）
            // see #2.3.3.3.3
            var called;
            try {
                // 可能抛异常
                var then = value.then;
                if (isFunction(then)) {
                    // 可能抛异常
                    then.call(
                        value,
                        function (data) {
                            if (!called) {
                                resolve(resolver, data);
                                called = true;
                            }
                        },
                        function (reason) {
                            if (!called) {
                                resolver.reject(reason);
                                called = true;
                            }
                        }
                    );
                }
                else {
                    resolver.fulfill(value);
                }
            }
            catch (e) {
                if (!captureException) {
                    throw e;
                }
                else if (!called) {
                    resolver.reject(e);
                }
            }
        }
        else {
            resolver.fulfill(value);
        }
    }

    /**
     * 包装then的回调参数
     * 使其能根据回调的返回结果设置then返回的Resolver对象状态
     *
     * @inner
     * @param {Resolver} resolver
     * @param {Promise} promise
     * @param {Function} callback
     */
    function wrapCallback(resolver, promise, callback) {
        return function (data) {
            try {
                // 可能抛异常
                var res = callback(data);
                // 返回结果与当前的promise对象相同
                // 抛异常
                // see # 2.3.1
                if (res === promise) {
                    throw new TypeError();
                }

                resolve(resolver, res);
            }
            catch (e) {
                if (captureException) {
                    resolver.reject(e);
                }
                else {
                    throw e;
                }
            }
        };
    }

    /**
     * 注册resolver的回调函数
     * 如果resolver已处于非PENDING状态
     * 则“立即”调用回调函数
     *
     * @inner
     * @param {Object} resolver
     * @param {number} status 回调函数类型 FULFILLED 或者 REJECTED
     * @param {Function} callback
     */
    function addListener(resolver, status, callback) {
        if (resolver.status == status) {
            // 设置延迟
            // 为了让then函数先返回再执行回调
            // see #2.2.4
            nextTick(
                function () {
                    callback(resolver.data);
                }
            );
        }
        else if (status == STATUS.FULFILLED) {
            resolver.fulfillList.push(callback);
        }
        else if (status == STATUS.REJECTED) {
            resolver.rejectList.push(callback);
        }
    }

    /**
     * 触发resolver回调函数
     * 根据状态，执行resolver的回调函数
     *
     * @inner
     * @param {Object} resolver
     */
    function emit(resolver) {
        var items = resolver.status == STATUS.FULFILLED
            ? resolver.fulfillList
            : resolver.rejectList;

        fireGlobalEvent(resolver);

        if (items.length <= 0 ) {
            return;
        }

        // 触发注册的回调函数必须
        // 在状态改变完成后
        // see #2.2.2 #2.2.3 #2.2.4
        nextTick(
            function () {
                var item;
                while (item = items.shift()) {
                    item(resolver.data);
                }
            }
        );
    }

    /**
     * then
     * 将fulfill回调与reject回调注册到resolver上
     * 并返回新的Promise对象
     *
     * @inner
     * @param {Resolver} resolver
     * @param {Function} onFulfilled
     * @param {Function} onRejected
     * @return {Promise}
     */
    function then(resolver, onFulfilled, onRejected) {
        var res = new Resolver();
        var promise = createPromise(res);

        if (isFunction(onFulfilled)) {
            onFulfilled = wrapCallback(res, promise, onFulfilled);
        }
        else {
            // not function
            // 'return promise' must fulfill with the same value
            // when 'main promise' is resolved
            // see #2.2.7.3
            onFulfilled = function (data) {
                res.fulfill(data);
            };
        }
        addListener(resolver, STATUS.FULFILLED, onFulfilled);

        if (isFunction(onRejected)) {
            onRejected = wrapCallback(res, promise, onRejected);
        }
        else {
            // not function
            // 'return promise' must reject with the same reason
            // when 'main promise' is rejected
            // see #2.2.7.4
            onRejected = function (reason) {
                res.reject(reason);
            };
        }
        addListener(resolver, STATUS.REJECTED, onRejected);

        return promise;
    }

    /**
     * 创建Promise对象
     *
     * @inner
     * @param {Resolver} resolver
     */
    function createPromise(resolver) {
        return {
            then: function (onFulfilled, onRejected) {
                return then(resolver, onFulfilled, onRejected);
            }
        };
    }

    /**
     * 触发全局事件
     *
     * @inner
     * @param {Resolver} resolver
     * @param {string} type 事件类型
     */
    function fireGlobalEvent(resolver) {
        var type = resolver.status == STATUS.FULFILLED
                    ? 'resolve'
                    : 'reject';

        if (globalEvent) {
            Resolver.emit(type, {
                data: resolver.data
            });
        }
    }

    /**
     * Resolver
     *
     * @constructor
     */
    function Resolver() {
        this.status = STATUS.PENDING;
        this.fulfillList = [];
        this.rejectList = [];
    }

    /**
     * 启动
     */
    Resolver.enableGlobalEvent = function (Emitter) {
        Emitter.mixin(this);
        globalEvent = true;
    };

    Resolver.disableExceptionCapture = function () {
        captureException = false;
    };

    Resolver.enableExceptionCapture = function () {
        captureException = true;
    };

    /**
     * fulfill
     *
     * @public
     * @param {*} data
     */
    Resolver.prototype.fulfill = function (data) {
        if (this.status != STATUS.PENDING) {
            return;
        }

        this.data = data;
        this.status = STATUS.FULFILLED;
        emit(this);
    };

    /**
     * resolve
     *
     * @public
     * @param {*} data
     */
    Resolver.prototype.resolve = Resolver.prototype.fulfill;

    /**
     * reject
     *
     * @public
     * @param {*} reason
     */
    Resolver.prototype.reject = function (reason) {
        if (this.status != STATUS.PENDING) {
            return;
        }

        this.data = reason;
        this.status = STATUS.REJECTED;
        emit(this);
    };

    /**
     * 生成Promise
     *
     * @public
     * @return {Promise}
     */
    Resolver.prototype.promise = function () {
        return createPromise(this);
    };

    return Resolver;
});
<|endoftext|>


<commit_before>/*
 * Chrome-Last.fm-Scrobbler BandCamp.com Connector by George Pollard
 *                (loosely based on Yasin Okumus's MySpace connector)
 * v0.1
 */
'use strict';

var lastTrack = null;

$(function(){
	// bind page unload function to discard current 'now listening'
	cancel();
});

var durationPart = '.track_info .time';
var durationRegex = /[ \n]*(\d+):(\d+)[ \n]*\/[ \n]*(\d+):(\d+)[ \n]*/;
function parseDuration(match){
	try{
		var m = durationRegex.exec(match);
		return {current: parseInt(m[1],10)*60 + parseInt(m[2],10), total: parseInt(m[3],10)*60 + parseInt(m[4],10)};
	}catch(err){
		return 0;
	}
}

function parseArtist()
{
	var byLine = '';
	if (isAlbum())
	{
		byLine = $('dt.hiddenAccess:contains("band name") ~ dd').text();
	}
	else // isTrack
	{
		byLine = $('.albumTitle nobr').text();
	}

	var artist = $.trim($.trim(byLine).substring(2));
	if(!artist) {
		artist = $('span[itemprop=byArtist]').text();
	}

	return $.trim(artist);
}

function parseAlbum() {
	if (isAlbum()) {
		return $('h2.trackTitle').text().trim();
	}
	else { // isTrack
		return $('[itemprop="inAlbum"] [itemprop="name"]').text();
	}
}

function parseTitle()
{
	if (isAlbum())
	{
		return $('.track_info .title').first().text();
	}
	else //isTrack
	{
		return $('.trackTitle').first().text();
	}
}

function isAlbum()
{
	return $('.trackView[itemtype="http://schema.org/MusicAlbum"]').length > 0;
}

/**
 * Check to see if all tracks are dashed.
 *
 * @return bool the result
 */
function allTracksDashed()
{
	var allDashed = true;

	$('.track_list span[itemprop="name"]').each(function() {
		if ($(this).text().indexOf('-') === -1) {
			allDashed = false;
			return false; // Break out loop
		}
	});

	return allDashed;
}

function cancel(){
	$(window).unload(function() {
		// reset the background scrobbler song data
		chrome.runtime.sendMessage({type: 'reset'});
		return true;
	});
}

console.log('BandCampScrobbler: loaded');

$(durationPart).bind('DOMSubtreeModified',function() {
	var duration = parseDuration($(durationPart).text());

	//console.log('duration - ' + duration.current + ' / ' + duration.total);

	if(duration.current > 0) { // it's playing

		var artist = parseArtist();
		var track = parseTitle();
		var album = parseAlbum();

		/**
		 * Work out artist from the track if either:
		 *
		 *  - The artist is set to 'Various' or 'Various Artists' and track has a dash
		 *  - This is an album and all the tracks have a dash
		 */
		var dashIndex = track.indexOf('-');
		if ((/^Various(\sArtists)?$/.test(artist) && dashIndex > 0) || (isAlbum() && allTracksDashed()))
		{
			artist = track.substring(0, dashIndex);
			track = track.substring(dashIndex + 1);
		}

		artist = $.trim(artist);
		track = $.trim(track);

		if (lastTrack != track)
		{
			lastTrack = track;

			//console.log('BandCampScrobbler: scrobbling - Artist: ' + artist + '; Album:  ' + album + '; Track: ' + track + '; duration: ' + duration.total);
			chrome.runtime.sendMessage({type: 'validate', artist: artist, track: track}, function(response) {
				if (response !== false){
					chrome.runtime.sendMessage({type: 'nowPlaying', artist: response.artist, track: response.track, duration: duration.total, album: album});
				}
				else
				{
					chrome.runtime.sendMessage({type: 'nowPlaying', duration: duration.total});
				}
			});
		}
	}
});
<commit_msg>bind to audio 'playing' event instead of duration DOM modification<commit_after>/**
 * Improved Bandcamp Scrobbler by Malachi Soord.
 *
 * Inspired by the Spotify scrobbler.
 */

$(function(){
	'use strict';

	$(document).ready(function() {

		console.log('BandCampScrobbler: loaded');

		/**
		 * The audio reference.
		 */
		var audio = document.getElementsByTagName('audio')[0];

		/**
		 * Duration selector.
		 */
		var durationPart = '.track_info .time';

		/**
		 * Duration regex.
		 */
		var durationRegex = /[ \n]*(\d+):(\d+)[ \n]*\/[ \n]*(\d+):(\d+)[ \n]*/;

		/**
		 * Last playing track.
		 */
		var lastTrack = null;

		/**
		 * Bind events to audio
		 */
		audio.addEventListener('playing', function() {

			console.log('BandCampScrobbler: onPlayerChange()');

			var duration = parseDuration($(durationPart).text());
			var artist = parseArtist();
			var track = parseTitle();
			var album = parseAlbum();

			/**
			 * Work out artist from the track if either:
			 *
			 *  - The artist is set to 'Various' or 'Various Artists' and track has a dash
			 *  - This is an album and all the tracks have a dash
			 */
			var dashIndex = track.indexOf('-');
			if ((/^Various(\sArtists)?$/.test(artist) && dashIndex > 0) || (isAlbum() && allTracksDashed()))
			{
				artist = track.substring(0, dashIndex);
				track = track.substring(dashIndex + 1);
			}

			artist = $.trim(artist);
			track = $.trim(track);

			if (track !== lastTrack) {

				console.log('BandCampScrobbler: scrobbling - Artist: ' + artist + '; Album:  ' + album + '; Track: ' + track + '; duration: ' + duration.total);

				chrome.runtime.sendMessage({type: 'validate', artist: artist, track: track}, function(response) {
					if (response !== false){
						chrome.runtime.sendMessage({type: 'nowPlaying', artist: response.artist, track: response.track, duration: duration.total, album: album});
					}
					else
					{
						chrome.runtime.sendMessage({type: 'nowPlaying', duration: duration.total});
					}
				});
			}
		});

		/**
		 * Parse artist information.
		 */
		function parseArtist()
		{
			var byLine = '';
			if (isAlbum())
			{
				byLine = $('dt.hiddenAccess:contains("band name") ~ dd').text();
			}
			else // isTrack
			{
				byLine = $('.albumTitle nobr').text();
			}

			var artist = $.trim($.trim(byLine).substring(2));
			if(!artist) {
				artist = $('span[itemprop=byArtist]').text();
			}

			return $.trim(artist);
		}

		/**
		 * Parse album information.
		 */
		function parseAlbum() {
			if (isAlbum()) {
				return $('h2.trackTitle').text().trim();
			}
			else { // isTrack
				return $('[itemprop="inAlbum"] [itemprop="name"]').text();
			}
		}

		/**
		 * Parse title information.
		 */
		function parseTitle()
		{
			if (isAlbum())
			{
				return $('.track_info .title').first().text();
			}
			else //isTrack
			{
				return $('.trackTitle').first().text();
			}
		}

		/**
		 * Determine whether the current playing page is an album.
		 */
		function isAlbum()
		{
			return $('.trackView[itemtype="http://schema.org/MusicAlbum"]').length > 0;
		}

		/**
		 * Parse duration information.
		 */
		function parseDuration(match){
			try{
				var m = durationRegex.exec(match);
				return {current: parseInt(m[1],10)*60 + parseInt(m[2],10), total: parseInt(m[3],10)*60 + parseInt(m[4],10)};
			}catch(err){
				return 0;
			}
		}

		/**
		 * Check to see if all tracks are dashed.
		 *
		 * @return bool the result
		 */
		function allTracksDashed()
		{
			var allDashed = true;

			$('.track_list span[itemprop="name"]').each(function() {
				if ($(this).text().indexOf('-') === -1) {
					allDashed = false;
					return false; // Break out loop
				}
			});

			return allDashed;
		}
	});

	// bind page unload function to discard current 'now listening'
	cancel();

	function cancel(){
		$(window).unload(function() {
			// reset the background scrobbler song data
			chrome.runtime.sendMessage({type: 'reset'});
			return true;
		});
	}
});
<|endoftext|>


<commit_before>goog.provide('lang.Promise');

goog.require('lang.async');

goog.scope(function () {
  var async = lang.async;

  /**
   * Create a new Promise.
   *
   * @param {function(function(*),function(*))} executor
   * @constructor
   */
  lang.PromiseImpl = function Promise(executor) {
    /**
     * @private
     * @type {lang.PromiseImpl.State}
     */
    this.state = lang.PromiseImpl.State.PENDING;
    this.value = undefined;
    this.deferred = [];

    var promise = this;

    try {
      executor(function(x) {
        promise.resolve(x);
      }, function (r) {
        promise.reject(r);
      });
    } catch (e) {
      promise.reject(e);
    }
  };

  /**
   * @private
   * @enum {number}
   */
  lang.PromiseImpl.State = {
    RESOLVED: 0,
    REJECTED: 1,
    PENDING: 2
  };

  var PromiseImpl = lang.PromiseImpl;

  /**
   * Create a rejected Promise.
   * @param {*} r The reason for rejection.
   * @return {!lang.PromiseImpl}
   */
  PromiseImpl.reject = function (r) {
    return new PromiseImpl(function (resolve, reject) {
      reject(r);
    });
  };

  /**
   * Create a resolved Promise.
   * @param {*} x The value to resolve the Promise with.
   * @return {!lang.PromiseImpl}
   */
  PromiseImpl.resolve = function (x) {
    return new PromiseImpl(function (resolve, reject) {
      resolve(x);
    });
  };

  /**
   * Resolve this Promise.
   * @param {*} x The value to resolve the Promise with.
   * @private
   */
  PromiseImpl.prototype.resolve = function resolve(x) {
    var promise = this;

    if (promise.state === PromiseImpl.State.PENDING) {
      if (x === promise) {
        throw new TypeError('Promise settled with itself.');
      }

      var called = false;

      try {
        var then = x && x['then'];

        if (x !== null && typeof x === 'object' && typeof then === 'function') {
          then.call(x, function (x) {
            if (!called) {
              promise.resolve(x);
            }
            called = true;

          }, function (r) {
            if (!called) {
              promise.reject(r);
            }
            called = true;
          });
          return;
        }
      } catch (e) {
        if (!called) {
          promise.reject(e);
        }
        return;
      }
      promise.state = PromiseImpl.State.RESOLVED;
      promise.value = x;
      promise.notify();
    }
  };

  /**
   * Reject this Promise.
   * @private
   * @param {*} reason The reason for rejection.
   */
  PromiseImpl.prototype.reject = function reject(reason) {
    var promise = this;

    if (promise.state === PromiseImpl.State.PENDING) {
      if (reason === promise) {
        throw new TypeError('Promise settled with itself.');
      }

      promise.state = PromiseImpl.State.REJECTED;
      promise.value = reason;
      promise.notify();
    }
  };

  /**
   * Notify all handlers of a change in state.
   * @private
   */
  PromiseImpl.prototype.notify = function notify() {
    var promise = this;

    async(function () {
      if (promise.state !== PromiseImpl.State.PENDING) {
        while (promise.deferred.length) {
          var deferred = promise.deferred.shift(),
              onResolved = deferred[0],
              onRejected = deferred[1],
              resolve = deferred[2],
              reject = deferred[3];

          try {
            if (promise.state === PromiseImpl.State.RESOLVED) {
              if (typeof onResolved === 'function') {
                resolve(onResolved.call(undefined, promise.value));
              } else {
                resolve(promise.value);
              }
            } else if (promise.state === PromiseImpl.State.REJECTED) {
              if (typeof onRejected === 'function') {
                resolve(onRejected.call(undefined, promise.value));
              } else {
                reject(promise.value);
              }
            }
          } catch (e) {
            reject(e);
          }
        }
      }
    });
  };

  /**
   * @param {function(*):*} onRejected Called when this Promise is rejected.
   * @return {!lang.PromiseImpl}
   */
  PromiseImpl.prototype.catch = function (onRejected) {
    return this.then(undefined, onRejected);
  };

  /**
   * @param {function(*):*=} onResolved Called when this Promise is resolved.
   * @param {function(*):*=} onRejected Called when this Promise is rejected.
   * @return {!lang.PromiseImpl}
   */
  PromiseImpl.prototype.then = function then(onResolved, onRejected) {
    var promise = this;

    return new PromiseImpl(function (resolve, reject) {
      promise.deferred.push([onResolved, onRejected, resolve, reject]);
      promise.notify();
    });
  };

  /**
   * @param {Array.<!lang.PromiseImpl>} iterable
   * @return {!lang.PromiseImpl}
   */
  PromiseImpl.all = function all(iterable) {
    return new PromiseImpl(function (resolve, reject) {
      var count = 0,
          result = [];

      if (iterable.length === 0) {
        resolve(result);
      }

      function resolver(i) {
        return function (x) {
          result[i] = x;
          count += 1;

          if (count === iterable.length) {
            resolve(result);
          }
        };
      }

      for (var i = 0; i < iterable.length; i += 1) {
        iterable[i].then(resolver(i), reject);
      }
    });
  };

  /**
   * @param {Array.<!lang.PromiseImpl>} iterable
   * @return {!lang.PromiseImpl}
   */
  PromiseImpl.race = function race(iterable) {
    return new PromiseImpl(function (resolve, reject) {
      for (var i = 0; i < iterable.length; i += 1) {
        iterable[i].then(resolve, reject);
      }
    });
  };
});

/**
 * Set this to false if you're not using
 * Promis as a library with Closure Compiler.
 *
 * @define {boolean}
 */
var USE_AS_LIB = true;

if (USE_AS_LIB) {
  if (window['Promise']) {
    lang.Promise = window['Promise'];
    lang.Promise.prototype.then = window['Promise']['prototype']['then'];
    lang.Promise.prototype.catch = window['Promise']['prototype']['catch'];

    lang.Promise.all = window['Promise']['all'];
    lang.Promise.race = window['Promise']['race'];
    lang.Promise.resolve = window['Promise']['resolve'];
    lang.Promise.reject = window['Promise']['reject'];
  } else {
    lang.Promise = lang.PromiseImpl;
    lang.Promise.prototype.then = lang.PromiseImpl.prototype.then;
    lang.Promise.prototype.catch = lang.PromiseImpl.prototype.catch;

    lang.Promise.all = lang.PromiseImpl.all;
    lang.Promise.race = lang.PromiseImpl.race;
    lang.Promise.resolve = lang.PromiseImpl.resolve;
    lang.Promise.reject = lang.PromiseImpl.reject;
  }
}
<commit_msg>Make all calls to .catch with [catch] so that errors do not occur with YUI in later builds :zap:<commit_after>goog.provide('lang.Promise');

goog.require('lang.async');

goog.scope(function () {
  var async = lang.async;

  /**
   * Create a new Promise.
   *
   * @param {function(function(*),function(*))} executor
   * @constructor
   */
  lang.PromiseImpl = function Promise(executor) {
    /**
     * @private
     * @type {lang.PromiseImpl.State}
     */
    this.state = lang.PromiseImpl.State.PENDING;
    this.value = undefined;
    this.deferred = [];

    var promise = this;

    try {
      executor(function(x) {
        promise.resolve(x);
      }, function (r) {
        promise.reject(r);
      });
    } catch (e) {
      promise.reject(e);
    }
  };

  /**
   * @private
   * @enum {number}
   */
  lang.PromiseImpl.State = {
    RESOLVED: 0,
    REJECTED: 1,
    PENDING: 2
  };

  var PromiseImpl = lang.PromiseImpl;

  /**
   * Create a rejected Promise.
   * @param {*} r The reason for rejection.
   * @return {!lang.PromiseImpl}
   */
  PromiseImpl.reject = function (r) {
    return new PromiseImpl(function (resolve, reject) {
      reject(r);
    });
  };

  /**
   * Create a resolved Promise.
   * @param {*} x The value to resolve the Promise with.
   * @return {!lang.PromiseImpl}
   */
  PromiseImpl.resolve = function (x) {
    return new PromiseImpl(function (resolve, reject) {
      resolve(x);
    });
  };

  /**
   * Resolve this Promise.
   * @param {*} x The value to resolve the Promise with.
   * @private
   */
  PromiseImpl.prototype.resolve = function resolve(x) {
    var promise = this;

    if (promise.state === PromiseImpl.State.PENDING) {
      if (x === promise) {
        throw new TypeError('Promise settled with itself.');
      }

      var called = false;

      try {
        var then = x && x['then'];

        if (x !== null && typeof x === 'object' && typeof then === 'function') {
          then.call(x, function (x) {
            if (!called) {
              promise.resolve(x);
            }
            called = true;

          }, function (r) {
            if (!called) {
              promise.reject(r);
            }
            called = true;
          });
          return;
        }
      } catch (e) {
        if (!called) {
          promise.reject(e);
        }
        return;
      }
      promise.state = PromiseImpl.State.RESOLVED;
      promise.value = x;
      promise.notify();
    }
  };

  /**
   * Reject this Promise.
   * @private
   * @param {*} reason The reason for rejection.
   */
  PromiseImpl.prototype.reject = function reject(reason) {
    var promise = this;

    if (promise.state === PromiseImpl.State.PENDING) {
      if (reason === promise) {
        throw new TypeError('Promise settled with itself.');
      }

      promise.state = PromiseImpl.State.REJECTED;
      promise.value = reason;
      promise.notify();
    }
  };

  /**
   * Notify all handlers of a change in state.
   * @private
   */
  PromiseImpl.prototype.notify = function notify() {
    var promise = this;

    async(function () {
      if (promise.state !== PromiseImpl.State.PENDING) {
        while (promise.deferred.length) {
          var deferred = promise.deferred.shift(),
              onResolved = deferred[0],
              onRejected = deferred[1],
              resolve = deferred[2],
              reject = deferred[3];

          try {
            if (promise.state === PromiseImpl.State.RESOLVED) {
              if (typeof onResolved === 'function') {
                resolve(onResolved.call(undefined, promise.value));
              } else {
                resolve(promise.value);
              }
            } else if (promise.state === PromiseImpl.State.REJECTED) {
              if (typeof onRejected === 'function') {
                resolve(onRejected.call(undefined, promise.value));
              } else {
                reject(promise.value);
              }
            }
          } catch (e) {
            reject(e);
          }
        }
      }
    });
  };

  /**
   * @param {function(*):*} onRejected Called when this Promise is rejected.
   * @return {!lang.PromiseImpl}
   */
  PromiseImpl.prototype['catch'] = function (onRejected) {
    return this.then(undefined, onRejected);
  };

  /**
   * @param {function(*):*=} onResolved Called when this Promise is resolved.
   * @param {function(*):*=} onRejected Called when this Promise is rejected.
   * @return {!lang.PromiseImpl}
   */
  PromiseImpl.prototype.then = function then(onResolved, onRejected) {
    var promise = this;

    return new PromiseImpl(function (resolve, reject) {
      promise.deferred.push([onResolved, onRejected, resolve, reject]);
      promise.notify();
    });
  };

  /**
   * @param {Array.<!lang.PromiseImpl>} iterable
   * @return {!lang.PromiseImpl}
   */
  PromiseImpl.all = function all(iterable) {
    return new PromiseImpl(function (resolve, reject) {
      var count = 0,
          result = [];

      if (iterable.length === 0) {
        resolve(result);
      }

      function resolver(i) {
        return function (x) {
          result[i] = x;
          count += 1;

          if (count === iterable.length) {
            resolve(result);
          }
        };
      }

      for (var i = 0; i < iterable.length; i += 1) {
        iterable[i].then(resolver(i), reject);
      }
    });
  };

  /**
   * @param {Array.<!lang.PromiseImpl>} iterable
   * @return {!lang.PromiseImpl}
   */
  PromiseImpl.race = function race(iterable) {
    return new PromiseImpl(function (resolve, reject) {
      for (var i = 0; i < iterable.length; i += 1) {
        iterable[i].then(resolve, reject);
      }
    });
  };
});

/**
 * Set this to false if you're not using
 * Promis as a library with Closure Compiler.
 *
 * @define {boolean}
 */
var USE_AS_LIB = true;

if (USE_AS_LIB) {
  if (window['Promise']) {
    lang.Promise = window['Promise'];
    lang.Promise.prototype.then = window['Promise']['prototype']['then'];
    lang.Promise.prototype['catch'] = window['Promise']['prototype']['catch'];

    lang.Promise.all = window['Promise']['all'];
    lang.Promise.race = window['Promise']['race'];
    lang.Promise.resolve = window['Promise']['resolve'];
    lang.Promise.reject = window['Promise']['reject'];
  } else {
    lang.Promise = lang.PromiseImpl;
    lang.Promise.prototype.then = lang.PromiseImpl.prototype.then;
    lang.Promise.prototype['catch'] = lang.PromiseImpl.prototype['catch'];

    lang.Promise.all = lang.PromiseImpl.all;
    lang.Promise.race = lang.PromiseImpl.race;
    lang.Promise.resolve = lang.PromiseImpl.resolve;
    lang.Promise.reject = lang.PromiseImpl.reject;
  }
}
<|endoftext|>


<commit_before>'use strict';

/* global Connector */

var trackInfo = null;

function updateTrackInfo() {
	trackInfo = JSON.parse(localStorage.getItem('audio_v10_track'));
}

Connector.artistTrackSelector = ".top_audio_player_title";
Connector.playerSelector = "#top_audio_player";

Connector.getArtist = function () {
			updateTrackInfo();
			return trackInfo[4] || null;
		};
Connector.getTrack = function () {
			updateTrackInfo();
			return trackInfo[3] || null;
		};
Connector.getCurrentTime = function () {
			updateTrackInfo();
			var progress = parseFloat(localStorage.getItem('audio_v10_progress'));
			return Math.round(parseInt(trackInfo[5])*progress);
		};
Connector.getDuration = function () {
			updateTrackInfo();
			return parseInt(trackInfo[5]);
		};
Connector.isPlaying = function() {
	return $(this.playerSelector).hasClass('top_audio_player_playing');
		};
<commit_msg>strings must use singlequote<commit_after>'use strict';

/* global Connector */

var trackInfo = null;

function updateTrackInfo() {
	trackInfo = JSON.parse(localStorage.getItem('audio_v10_track'));
}

Connector.artistTrackSelector = '.top_audio_player_title';
Connector.playerSelector = '#top_audio_player';

Connector.getArtist = function () {
			updateTrackInfo();
			return trackInfo[4] || null;
		};
Connector.getTrack = function () {
			updateTrackInfo();
			return trackInfo[3] || null;
		};
Connector.getCurrentTime = function () {
			updateTrackInfo();
			var progress = parseFloat(localStorage.getItem('audio_v10_progress'));
			return Math.round(parseInt(trackInfo[5])*progress);
		};
Connector.getDuration = function () {
			updateTrackInfo();
			return parseInt(trackInfo[5]);
		};
Connector.isPlaying = function() {
	return $(this.playerSelector).hasClass('top_audio_player_playing');
		};
<|endoftext|>


<commit_before>import run from '@cycle/xstream-run';
import xs from 'xstream';
import restartable from './restartable';
import {timeDriver, mockTimeSource} from '@cycle/time';

function restart (main, drivers, cb, {sources, sinks, dispose}, isolate = {}, timeToTravelTo = null) {
  if (typeof isolate === 'function' && 'reset' in isolate) {
    isolate.reset();
  }

  const realTime = timeDriver();
  realTime._pause();

  drivers.Time = () => realTime;

  for (let driverName in drivers) {
    const driver = drivers[driverName];

    const newDriver = (sink$, adapter) => driver(sink$, adapter, realTime);

    newDriver.replayLog = driver.replayLog;
    newDriver.onPostReplay = driver.onPostReplay;
    newDriver.log$ = driver.log$;

    drivers[driverName] = newDriver;

    if (driver.onPreReplay) {
      driver.onPreReplay();
    }
  }

  const newSourcesSinksAndRun = run(main, drivers);

  const newDispose = newSourcesSinksAndRun.run();

  const sourcesAndSinksAndDispose = {
    sources: newSourcesSinksAndRun.sources,
    sinks: newSourcesSinksAndRun.sinks,
    dispose: newDispose
  };

  if (typeof cb === 'object') {
    cb.start(sourcesAndSinksAndDispose);
  }

  for (let driverName in drivers) {
    const driver = drivers[driverName];

    if (driver.replayLog) {
      const log$ = sources[driverName].log$;

      driver.replayLog(realTime._scheduler, log$, timeToTravelTo);
    }
  }

  const timeToRunTo = (sources.Time && sources.Time._time()) || null;

  realTime._runVirtually((err) => {
    if (err) {
      throw err;
    }

    for (let driverName in drivers) {
      const driver = drivers[driverName];

      if (driver.onPostReplay) {
        driver.onPostReplay();
      }
    }

    setTimeout(() => {
      // dispose();

      if (typeof cb === 'object') {
        cb.stop(err);
      } else {
        cb(err);
      }

      realTime._resume(timeToRunTo);
    });
  }, timeToRunTo);

  return sourcesAndSinksAndDispose;
}

function rerunner (Cycle, driversFn, isolate) {
  let sourcesAndSinksAndDispose = {};
  let first = true;
  let drivers;
  function noop () {}

  return function(main, cb = noop, timeToTravelTo = null) {
    if (first) {
      drivers = driversFn();

      let realTime = timeDriver();
      drivers.Time = () => realTime;

      for (let driverName in drivers) {
        const driver = drivers[driverName];

        const newDriver = (sink$, adapter) => driver(sink$, adapter, realTime);

        drivers[driverName] = newDriver;
      }

      const {sources, sinks, run} = Cycle(main, drivers);

      realTime = sources.Time;

      const dispose = run();

      sourcesAndSinksAndDispose = {sources, sinks, dispose};

      first = false;

      if (typeof cb === 'object') {
        cb.start(sourcesAndSinksAndDispose);
      }

      setTimeout(() => {
        if (typeof cb === 'object') {
          cb.stop();
        } else {
          cb();
        }
      });
    } else {
      drivers = driversFn();

      sourcesAndSinksAndDispose = restart(main, drivers, cb, sourcesAndSinksAndDispose, isolate, timeToTravelTo);
    }
    return sourcesAndSinksAndDispose;
  }
}

module.exports = {
  restart,
  restartable,
  rerunner
}
<commit_msg>Remove dispose call<commit_after>import run from '@cycle/xstream-run';
import xs from 'xstream';
import restartable from './restartable';
import {timeDriver, mockTimeSource} from '@cycle/time';

function restart (main, drivers, cb, {sources, sinks, dispose}, isolate = {}, timeToTravelTo = null) {
  if (typeof isolate === 'function' && 'reset' in isolate) {
    isolate.reset();
  }

  const realTime = timeDriver();
  realTime._pause();

  drivers.Time = () => realTime;

  for (let driverName in drivers) {
    const driver = drivers[driverName];

    const newDriver = (sink$, adapter) => driver(sink$, adapter, realTime);

    newDriver.replayLog = driver.replayLog;
    newDriver.onPostReplay = driver.onPostReplay;
    newDriver.log$ = driver.log$;

    drivers[driverName] = newDriver;

    if (driver.onPreReplay) {
      driver.onPreReplay();
    }
  }

  const newSourcesSinksAndRun = run(main, drivers);

  const newDispose = newSourcesSinksAndRun.run();

  const sourcesAndSinksAndDispose = {
    sources: newSourcesSinksAndRun.sources,
    sinks: newSourcesSinksAndRun.sinks,
    dispose: newDispose
  };

  if (typeof cb === 'object') {
    cb.start(sourcesAndSinksAndDispose);
  }

  for (let driverName in drivers) {
    const driver = drivers[driverName];

    if (driver.replayLog) {
      const log$ = sources[driverName].log$;

      driver.replayLog(realTime._scheduler, log$, timeToTravelTo);
    }
  }

  const timeToRunTo = (sources.Time && sources.Time._time()) || null;

  realTime._runVirtually((err) => {
    if (err) {
      throw err;
    }

    for (let driverName in drivers) {
      const driver = drivers[driverName];

      if (driver.onPostReplay) {
        driver.onPostReplay();
      }
    }

    setTimeout(() => {
      if (typeof cb === 'object') {
        cb.stop(err);
      } else {
        cb(err);
      }

      realTime._resume(timeToRunTo);
    });
  }, timeToRunTo);

  return sourcesAndSinksAndDispose;
}

function rerunner (Cycle, driversFn, isolate) {
  let sourcesAndSinksAndDispose = {};
  let first = true;
  let drivers;
  function noop () {}

  return function(main, cb = noop, timeToTravelTo = null) {
    if (first) {
      drivers = driversFn();

      let realTime = timeDriver();
      drivers.Time = () => realTime;

      for (let driverName in drivers) {
        const driver = drivers[driverName];

        const newDriver = (sink$, adapter) => driver(sink$, adapter, realTime);

        drivers[driverName] = newDriver;
      }

      const {sources, sinks, run} = Cycle(main, drivers);

      realTime = sources.Time;

      const dispose = run();

      sourcesAndSinksAndDispose = {sources, sinks, dispose};

      first = false;

      if (typeof cb === 'object') {
        cb.start(sourcesAndSinksAndDispose);
      }

      setTimeout(() => {
        if (typeof cb === 'object') {
          cb.stop();
        } else {
          cb();
        }
      });
    } else {
      drivers = driversFn();

      sourcesAndSinksAndDispose = restart(main, drivers, cb, sourcesAndSinksAndDispose, isolate, timeToTravelTo);
    }
    return sourcesAndSinksAndDispose;
  }
}

module.exports = {
  restart,
  restartable,
  rerunner
}
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { connect } from 'react-redux';
import { pushState } from 'redux-router';
import getUniqueValues from '../lib/get_unique_values';

import rejectError from '../lib/reject_error';

import Content from './Content';

import Header from '../components/Header';
import Notification from '../components/Notification';
import DonationForm from '../components/DonationForm';

import validateTransaction from '../actions/form/validate_transaction';
import createTransaction from '../actions/transactions/create';
import appendDonationForm from '../actions/form/append_donation';
import setDonationCustom from '../actions/form/set_donation_custom';
import resetNotifications from '../actions/notification/reset';
import fetchGroup from '../actions/groups/fetch_by_id';
import fetchUser from '../actions/users/fetch_by_id';
import fetchCards from '../actions/users/fetch_cards';
import notify from '../actions/notification/notify';

export class Donation extends Component {
  render() {
    const backLink = `/groups/${this.props.groupid}/transactions/`;

    return (

        <Content>
          <Notification {...this.props} />

            <DonationForm {...this.props} donate={donate.bind(this)}/>

        </Content>

    );
  }

  componentWillMount() {
    this.props.fetchGroup(this.props.groupid);
    this.props.fetchUser(this.props.userid);
    this.props.fetchCards(this.props.userid);
  }

}

export function donate() {
  const {
    validateTransaction,
    createTransaction,
    groupid,
    amount,
    group,
    user,
    notify,
    pushState,
    description
  } = this.props;

  const transaction = {
    amount,
    description: description || `Donation from ${user.email} to ${group.name}`,
    tags: ['Donation'],
    approvedAt: Date.now(),
    approved: true,
    createdAt: Date.now()
  };

  return validateTransaction(transaction)
  .then(rejectError.bind(this, 'validationError'))
  .then(() => createTransaction(groupid, transaction))
  .then(rejectError.bind(this, 'serverError'))
  .then(() => pushState(null, `/groups/${groupid}/transactions`))
  .catch(error => notify('error', error.message));
}

export default connect(mapStateToProps, {
  resetNotifications,
  fetchUser,
  fetchGroup,
  fetchCards,
  setDonationCustom,
  createTransaction,
  validateTransaction,
  notify,
  pushState,
  appendDonationForm
})(Donation);

function mapStateToProps({router, groups, form, session, users, transactions, notification}) {
  const groupid = router.params.groupid;
  const userid = session.user.id;
  const currentUser = users[userid];

  let userCardsLabels = [];
  if (currentUser) {
    userCardsLabels = getUniqueValues(currentUser.cards, 'number');
  }

  return {
    groupid,
    userid,
    notification,
    form,
    transactions,
    isCustomMode: form.donation.isCustomMode,
    description: form.donation.attributes.description,
    amount: form.donation.attributes.amount,
    group: groups[groupid] || {},
    userCardsLabels: userCardsLabels,
    validationError: form.transaction.error,
    serverError: transactions.error
  };
}
<commit_msg>clean up syntax<commit_after>import React, { Component } from 'react';
import { connect } from 'react-redux';
import { pushState } from 'redux-router';
import getUniqueValues from '../lib/get_unique_values';

import rejectError from '../lib/reject_error';

import Content from './Content';

import Header from '../components/Header';
import Notification from '../components/Notification';
import DonationForm from '../components/DonationForm';

import validateTransaction from '../actions/form/validate_transaction';
import createTransaction from '../actions/transactions/create';
import appendDonationForm from '../actions/form/append_donation';
import setDonationCustom from '../actions/form/set_donation_custom';
import resetNotifications from '../actions/notification/reset';
import fetchGroup from '../actions/groups/fetch_by_id';
import fetchUser from '../actions/users/fetch_by_id';
import fetchCards from '../actions/users/fetch_cards';
import notify from '../actions/notification/notify';

export class Donation extends Component {
  render() {
    const backLink = `/groups/${this.props.groupid}/transactions/`;

    return (

        <Content>
          <Notification {...this.props} />

            <DonationForm {...this.props} donate={donate.bind(this)}/>

        </Content>

    );
  }

  componentWillMount() {
    this.props.fetchGroup(this.props.groupid);
    this.props.fetchUser(this.props.userid);
    this.props.fetchCards(this.props.userid);
  }

}

export function donate() {
  const {
    validateTransaction,
    createTransaction,
    groupid,
    amount,
    group,
    user,
    notify,
    pushState,
    description
  } = this.props;

  const transaction = {
    amount,
    description: description || `Donation from ${user.email} to ${group.name}`,
    tags: ['Donation'],
    approvedAt: Date.now(),
    approved: true,
    createdAt: Date.now()
  };

  return validateTransaction(transaction)
  .then(rejectError.bind(this, 'validationError'))
  .then(() => createTransaction(groupid, transaction))
  .then(rejectError.bind(this, 'serverError'))
  .then(() => pushState(null, `/groups/${groupid}/transactions`))
  .catch(error => notify('error', error.message));
}

export default connect(mapStateToProps, {
  resetNotifications,
  fetchUser,
  fetchGroup,
  fetchCards,
  setDonationCustom,
  createTransaction,
  validateTransaction,
  notify,
  pushState,
  appendDonationForm
})(Donation);

function mapStateToProps({router, groups, form, session, users, transactions, notification}) {
  const groupid = router.params.groupid;
  const userid = session.user.id;
  const currentUser = users[userid];
  const userCardsLabels = currentUser ?
    getUniqueValues(currentUser.cards, 'number') : [];

  return {
    groupid,
    userid,
    notification,
    form,
    transactions,
    isCustomMode: form.donation.isCustomMode,
    description: form.donation.attributes.description,
    amount: form.donation.attributes.amount,
    group: groups[groupid] || {},
    userCardsLabels,
    validationError: form.transaction.error,
    serverError: transactions.error
  };
}
<|endoftext|>


<commit_before>'use strict';

angular.module('rte-angular', [
]).
directive('rte', function ($sce) {
  function link (scope, element, attrs, ngModel) {
    var rteContent = element.find('.rte-content');

    var textSelection;
    var textRange;

    /// format block items

    scope.formatBlockItems = [
      { idx: 1, opt: 'div', labelPlain: 'Normal', label: $sce.trustAsHtml("Normal") },
      { idx: 2, opt: 'h1', labelPlain: 'Heading 1', label: $sce.trustAsHtml("
Heading 1
") },
      { idx: 3, opt: 'h2', labelPlain: 'Heading 2', label: $sce.trustAsHtml("
Heading 2
") },
      { idx: 4, opt: 'h3', labelPlain: 'Heading 3', label: $sce.trustAsHtml("
Heading 3
") },
      { idx: 5, opt: 'h4', labelPlain: 'Heading 4', label: $sce.trustAsHtml("
Heading 4
") },
      { idx: 6, opt: 'h5', labelPlain: 'Heading 5', label: $sce.trustAsHtml("
Heading 5
") },
      { idx: 7, opt: 'h6', labelPlain: 'Heading 6', label: $sce.trustAsHtml("
Heading 6
") },
      { idx: 8, opt: 'blockquote', labelPlain: 'Quote', label: $sce.trustAsHtml("
Quote
") },
      { idx: 9, opt: 'pre', labelPlain: 'Code', label: $sce.trustAsHtml("
Code
") }
    ];

    scope.defaultFormatBlockItem = scope.formatBlockItems[0];
    scope.activeFormatBlockItem = scope.defaultFormatBlockItem;
    scope.setActiveFormatBlockItem = setActiveFormatBlockItem;

    /// format buttons

    scope.formatFontStyleBtns = [
      { idx: 1, cmd: 'bold', icon: $sce.trustAsHtml("") },
      { idx: 2, cmd: 'italic', icon: $sce.trustAsHtml("") },
      { idx: 3, cmd: 'underline', icon: $sce.trustAsHtml("") },
      { idx: 4, cmd: 'strikethrough', icon: $sce.trustAsHtml("") }
    ];

    scope.formatListBtns = [
      { idx: 1, cmd: 'insertUnorderedList', icon: $sce.trustAsHtml("") },
      { idx: 2, cmd: 'insertOrderedList', icon: $sce.trustAsHtml("") },
      { idx: 3, cmd: 'outdent', icon: $sce.trustAsHtml("") },
      { idx: 4, cmd: 'indent', icon: $sce.trustAsHtml("") }
    ];

    scope.formatAlignBtns = [
      { idx: 1, cmd: 'justifyLeft', icon: $sce.trustAsHtml("") },
      { idx: 2, cmd: 'justifyCenter', icon: $sce.trustAsHtml("") },
      { idx: 3, cmd: 'justifyRight', icon: $sce.trustAsHtml("") }
    ];

    scope.format = format;
    scope.getFormatState = getFormatState;

    /// link buttons

    scope.linkBtns = [
      {
        idx: 1,
        opt: 'link',
        icon: $sce.trustAsHtml(""),
        disable: function () {
          return !checkTextSelected();
        },
        dialog: {
          url: undefined,
          isVisible: false,
          position: { top: '0px', left: '0px' },
          actionStr: 'Insert link',
          action: function () {
            textSelection.addRange(textRange);
            insertHtml("" + textSelection + "");
            this.isVisible = false;
          }
        }
      },
      {
        idx: 2,
        opt: 'image',
        icon: $sce.trustAsHtml(""),
        dialog: {
          url: undefined,
          isVisible: false,
          position: { top: '0px', left: '0px' },
          actionStr: 'Insert image URL',
          action: function () {
            textSelection.addRange(textRange);
            insertHtml("");
            this.isVisible = false;
          }
        }
      },
      {
        idx: 3,
        opt: 'video',
        icon: $sce.trustAsHtml(""),
        dialog: {
          url: undefined,
          isVisible: false,
          position: { top: '0px', left: '0px' },
          actionStr: 'Insert video URL',
          action: function () {
            textSelection.addRange(textRange);
            insertHtml("");
            this.isVisible = false;
        }
        }
      }
    ];

    scope.showDialog = showDialog;

    /// functions for formatBlock items

    function formatBlock(opt) {
      document.execCommand('formatBlock', false, '<' + opt + '>');
      setNgModel();
    }

    function getFormatBlockState(opt) {
      return document.queryCommandValue('formatBlock') == opt ? true: false;
    }

    function setActiveFormatBlockItem(item) {
      scope.activeFormatBlockItem = item;
      formatBlock(item.opt);
    }

    function checkFormatBlockState() {
      angular.forEach(scope.formatBlockItems, function (item) {
        if(getFormatBlockState(item.opt)) {
          scope.activeFormatBlockItem = item;
        }
      });
    }

    /// functions for format buttons

    function format(cmd) {
      document.execCommand(cmd, false, null);
      setNgModel();
    }

    function getFormatState(cmd) {
      return document.queryCommandState(cmd);
    }

    function checkFontStyleStates() {
      angular.forEach(scope.formatFontStyleBtns, function (btn) {
        getFormatState(btn.cmd);
      });
    }

    /// functions for link buttons

    function insertHtml(markup) {
      document.execCommand('insertHTML', false, markup);
      setNgModel();
    }

    function checkTextSelected() {
      return document.getSelection().toString() ? true: false;
    }

    function showDialog(btn) {
      btn.dialog.url = '';
      saveTextSelectionRange();
      setActiveLinkBtn(btn);
      positionDialog(btn);
    }

    function saveTextSelectionRange() {
      textSelection = document.getSelection();
      if(textSelection.rangeCount > 0) {
        textRange = textSelection.getRangeAt(0);
      }
    }

    function setActiveLinkBtn(btn) {
      var isVisible = btn.dialog.isVisible;

      angular.forEach(scope.linkBtns, function (b) {
        b.dialog.isVisible = false;
      });

      btn.dialog.isVisible = !isVisible;
    }

    function positionDialog(btn) {
      var btnPosition = $('#btn-' + btn.opt).offset();
      var btnHeight = $('#btn-' + btn.opt).outerHeight();
      var btnWidth = $('#btn-' + btn.opt).outerWidth();
      var dialogContentWidth = $('.rte-dialog').outerWidth();

      btn.dialog.position = {
        top: (btnPosition.top - $(window).scrollTop() + btnHeight).toString() + 'px',
        left: (btnPosition.left - dialogContentWidth / 2 + btnWidth / 2).toString() + 'px'
      };
    }

    /// 2-way data binding

    // view --> model
    function setNgModel() {
      var html = rteContent.html();

      // strip out extra
 tag that is left behind when a contenteditable is cleared
      if(html == '
') {
        html = '';
      }

      ngModel.$setViewValue(html);
    }

    // model --> view
    ngModel.$render = function () {
      rteContent.html($sce.getTrustedHtml(ngModel.$viewValue || ''));
    };

    // update states
    rteContent.on('mouseup keyup', function () {
      scope.$apply(function () {
        // update model first...
        setNgModel();

        if(ngModel.$viewValue == '') {
          setActiveFormatBlockItem(scope.defaultFormatBlockItem);
        }

        checkFormatBlockState();
        checkFontStyleStates();

      });
    });
  }

  return {
    restrict: 'E',
    require: 'ngModel',
    templateUrl: '/src/rte/rte.html',
    link: link
  };
}).
directive('rteDialog', function () {
  return {
    restrict: 'E',
    scope: {
      position: '=',
      url: '=',
      actionStr: '=',
      action: '&',
      close: '&'
    },
    templateUrl: '/src/rte/rte-dialog.html'
  };
});<commit_msg>Add condition to clear out '

' when contenteditable is cleared<commit_after>'use strict';

angular.module('rte-angular', [
]).
directive('rte', function ($sce) {
  function link (scope, element, attrs, ngModel) {
    var rteContent = element.find('.rte-content');

    var textSelection;
    var textRange;

    /// format block items

    scope.formatBlockItems = [
      { idx: 1, opt: 'div', labelPlain: 'Normal', label: $sce.trustAsHtml("Normal") },
      { idx: 2, opt: 'h1', labelPlain: 'Heading 1', label: $sce.trustAsHtml("
Heading 1
") },
      { idx: 3, opt: 'h2', labelPlain: 'Heading 2', label: $sce.trustAsHtml("
Heading 2
") },
      { idx: 4, opt: 'h3', labelPlain: 'Heading 3', label: $sce.trustAsHtml("
Heading 3
") },
      { idx: 5, opt: 'h4', labelPlain: 'Heading 4', label: $sce.trustAsHtml("
Heading 4
") },
      { idx: 6, opt: 'h5', labelPlain: 'Heading 5', label: $sce.trustAsHtml("
Heading 5
") },
      { idx: 7, opt: 'h6', labelPlain: 'Heading 6', label: $sce.trustAsHtml("
Heading 6
") },
      { idx: 8, opt: 'blockquote', labelPlain: 'Quote', label: $sce.trustAsHtml("
Quote
") },
      { idx: 9, opt: 'pre', labelPlain: 'Code', label: $sce.trustAsHtml("
Code
") }
    ];

    scope.defaultFormatBlockItem = scope.formatBlockItems[0];
    scope.activeFormatBlockItem = scope.defaultFormatBlockItem;
    scope.setActiveFormatBlockItem = setActiveFormatBlockItem;

    /// format buttons

    scope.formatFontStyleBtns = [
      { idx: 1, cmd: 'bold', icon: $sce.trustAsHtml("") },
      { idx: 2, cmd: 'italic', icon: $sce.trustAsHtml("") },
      { idx: 3, cmd: 'underline', icon: $sce.trustAsHtml("") },
      { idx: 4, cmd: 'strikethrough', icon: $sce.trustAsHtml("") }
    ];

    scope.formatListBtns = [
      { idx: 1, cmd: 'insertUnorderedList', icon: $sce.trustAsHtml("") },
      { idx: 2, cmd: 'insertOrderedList', icon: $sce.trustAsHtml("") },
      { idx: 3, cmd: 'outdent', icon: $sce.trustAsHtml("") },
      { idx: 4, cmd: 'indent', icon: $sce.trustAsHtml("") }
    ];

    scope.formatAlignBtns = [
      { idx: 1, cmd: 'justifyLeft', icon: $sce.trustAsHtml("") },
      { idx: 2, cmd: 'justifyCenter', icon: $sce.trustAsHtml("") },
      { idx: 3, cmd: 'justifyRight', icon: $sce.trustAsHtml("") }
    ];

    scope.format = format;
    scope.getFormatState = getFormatState;

    /// link buttons

    scope.linkBtns = [
      {
        idx: 1,
        opt: 'link',
        icon: $sce.trustAsHtml(""),
        disable: function () {
          return !checkTextSelected();
        },
        dialog: {
          url: undefined,
          isVisible: false,
          position: { top: '0px', left: '0px' },
          actionStr: 'Insert link',
          action: function () {
            textSelection.addRange(textRange);
            insertHtml("" + textSelection + "");
            this.isVisible = false;
          }
        }
      },
      {
        idx: 2,
        opt: 'image',
        icon: $sce.trustAsHtml(""),
        dialog: {
          url: undefined,
          isVisible: false,
          position: { top: '0px', left: '0px' },
          actionStr: 'Insert image URL',
          action: function () {
            textSelection.addRange(textRange);
            insertHtml("");
            this.isVisible = false;
          }
        }
      },
      {
        idx: 3,
        opt: 'video',
        icon: $sce.trustAsHtml(""),
        dialog: {
          url: undefined,
          isVisible: false,
          position: { top: '0px', left: '0px' },
          actionStr: 'Insert video URL',
          action: function () {
            textSelection.addRange(textRange);
            insertHtml("");
            this.isVisible = false;
        }
        }
      }
    ];

    scope.showDialog = showDialog;

    /// functions for formatBlock items

    function formatBlock(opt) {
      document.execCommand('formatBlock', false, '<' + opt + '>');
      setNgModel();
    }

    function getFormatBlockState(opt) {
      return document.queryCommandValue('formatBlock') == opt ? true: false;
    }

    function setActiveFormatBlockItem(item) {
      scope.activeFormatBlockItem = item;
      formatBlock(item.opt);
    }

    function checkFormatBlockState() {
      angular.forEach(scope.formatBlockItems, function (item) {
        if(getFormatBlockState(item.opt)) {
          scope.activeFormatBlockItem = item;
        }
      });
    }

    /// functions for format buttons

    function format(cmd) {
      document.execCommand(cmd, false, null);
      setNgModel();
    }

    function getFormatState(cmd) {
      return document.queryCommandState(cmd);
    }

    function checkFontStyleStates() {
      angular.forEach(scope.formatFontStyleBtns, function (btn) {
        getFormatState(btn.cmd);
      });
    }

    /// functions for link buttons

    function insertHtml(markup) {
      document.execCommand('insertHTML', false, markup);
      setNgModel();
    }

    function checkTextSelected() {
      return document.getSelection().toString() ? true: false;
    }

    function showDialog(btn) {
      btn.dialog.url = '';
      saveTextSelectionRange();
      setActiveLinkBtn(btn);
      positionDialog(btn);
    }

    function saveTextSelectionRange() {
      textSelection = document.getSelection();
      if(textSelection.rangeCount > 0) {
        textRange = textSelection.getRangeAt(0);
      }
    }

    function setActiveLinkBtn(btn) {
      var isVisible = btn.dialog.isVisible;

      angular.forEach(scope.linkBtns, function (b) {
        b.dialog.isVisible = false;
      });

      btn.dialog.isVisible = !isVisible;
    }

    function positionDialog(btn) {
      var btnPosition = $('#btn-' + btn.opt).offset();
      var btnHeight = $('#btn-' + btn.opt).outerHeight();
      var btnWidth = $('#btn-' + btn.opt).outerWidth();
      var dialogContentWidth = $('.rte-dialog').outerWidth();

      btn.dialog.position = {
        top: (btnPosition.top - $(window).scrollTop() + btnHeight).toString() + 'px',
        left: (btnPosition.left - dialogContentWidth / 2 + btnWidth / 2).toString() + 'px'
      };
    }

    /// 2-way data binding

    // view --> model
    function setNgModel() {
      var html = rteContent.html();

      // strip out extra
 tag that is left behind when a contenteditable is cleared
      if(html == '
' || html == '

') {
        html = '';
      }

      ngModel.$setViewValue(html);
    }

    // model --> view
    ngModel.$render = function () {
      rteContent.html($sce.getTrustedHtml(ngModel.$viewValue || ''));
    };

    // update states
    rteContent.on('mouseup keyup', function () {
      scope.$apply(function () {
        // update model first...
        setNgModel();

        if(ngModel.$viewValue == '') {
          setActiveFormatBlockItem(scope.defaultFormatBlockItem);
        }

        checkFormatBlockState();
        checkFontStyleStates();

      });
    });
  }

  return {
    restrict: 'E',
    require: 'ngModel',
    templateUrl: '/src/rte/rte.html',
    link: link
  };
}).
directive('rteDialog', function () {
  return {
    restrict: 'E',
    scope: {
      position: '=',
      url: '=',
      actionStr: '=',
      action: '&',
      close: '&'
    },
    templateUrl: '/src/rte/rte-dialog.html'
  };
});<|endoftext|>


<commit_before>// Simple JavaScript Templating
// John Resig - http://ejohn.org/ - MIT Licensed
// http://ejohn.org/blog/javascript-micro-templating/
//
// new feature:
//   - escape "<" and ">" by default.
//   - set __NOESCAPING__ in data to pass escaping.
(function(){
  var cache = {};

  this.tmpl = function tmpl(str, data){
    // Figure out if we're getting a template, or if we need to
    // load the template - and be sure to cache the result.
    var fn = !/\W/.test(str) ?
      cache[str] = cache[str] ||
        tmpl(document.getElementById(str).innerHTML) :

      // Generate a reusable function that will serve as a template
      // generator (and which will be cached).
      new Function("obj",
        "var p=[],print=function(){p.push.apply(p,arguments);};" +

        // Introduce the data as local variables using with(){}
        "with(obj){" +

        // escape < >
        "function _q(s){if(typeof __NOESCAPING__!='undefined'&&__NOESCAPING__)" +
        " return s; if(!s || !isNaN(s))return s; " +
        " return s.replace(/</g, '<').replace(/>/g, '>'); };" +

        "p.push('" +

        // Convert the template into pure JavaScript
        str
          .replace(/[\r\t\n]/g, " ")
          .split("<%").join("\t")
          .replace(/((^|%>)[^\t]*)'/g, "$1\r")
          .replace(/\t=(.*?)%>/g, "',_q($1),'")
          .split("\t").join("');")
          .split("%>").join("p.push('")
          .split("\r").join("\\'")
      + "');}return p.join('');");
    // Provide some basic currying to the user
    return data ? fn( data ) : fn;
  };
})();

<commit_msg>Update tmpl.js, escaping data.toString()<commit_after>// Simple JavaScript Templating
// John Resig - http://ejohn.org/ - MIT Licensed
// http://ejohn.org/blog/javascript-micro-templating/
//
// new feature:
//   - escape "<" and ">" by default.
//   - set __NOESCAPING__ in data to pass escaping.
(function(){
  var cache = {};

  this.tmpl = function tmpl(str, data){
    // Figure out if we're getting a template, or if we need to
    // load the template - and be sure to cache the result.
    var fn = !/\W/.test(str) ?
      cache[str] = cache[str] ||
        tmpl(document.getElementById(str).innerHTML) :

      // Generate a reusable function that will serve as a template
      // generator (and which will be cached).
      new Function("obj",
        "var p=[],print=function(){p.push.apply(p,arguments);};" +

        // Introduce the data as local variables using with(){}
        "with(obj){" +

        // escape < >
        "function _q(s){if(typeof __NOESCAPING__!='undefined'&&__NOESCAPING__)" +
        " return s; if(!s) return s; " +
        " return s.toString().replace(/</g, '<').replace(/>/g, '>'); };" +

        "p.push('" +

        // Convert the template into pure JavaScript
        str
          .replace(/[\r\t\n]/g, " ")
          .split("<%").join("\t")
          .replace(/((^|%>)[^\t]*)'/g, "$1\r")
          .replace(/\t=(.*?)%>/g, "',_q($1),'")
          .split("\t").join("');")
          .split("%>").join("p.push('")
          .split("\r").join("\\'")
      + "');}return p.join('');");
    // Provide some basic currying to the user
    return data ? fn( data ) : fn;
  };
})();

<|endoftext|>


<commit_before>require('./vendor/date')

var path        = require('path')
  , fs          = require('fs')
  , yaml        = require('js-yaml')
  , showdown    = require('./vendor/showdown')
  , markdown    = new showdown.converter()
  , slugify     = require('./lib').slugify
  , titleize    = require('./lib').titleize
  ;

//
// :: Parse Header -> Turn YAML into a meaningful structure

var parseHeader = function(raw, path) {
    // Init empty stub
    var header = {
        tags: []
    };

    // Check for YAML configuration data
    if (typeof raw === 'string' && raw.length > 0) {
        var config = yaml.load(raw);

        // Convert config to lowercase
        for (var prop in config) {
            if (config.hasOwnProperty(prop)) {
                config[prop.toLowerCase()] = config[prop];
            }
        }

        header.title = config.title;
        header.tags = config.tags ? config.tags.map(function(x) { return x.toLowerCase(); }) : [];
        header.date = Date.parse(config.date);
    }

    // Fill in date if it's lacking
    if (typeof header.date === 'undefined') {
        var stats = fs.statSync(path);
        header.date = stats.ctime;
    }

    // Fill in title if it's lacking
    if (typeof header.title === 'undefined') {
        var name = fileNameFromPath(path);
        if (name.indexOf('.') > -1) {
            name = name.substr(0, name.lastIndexOf('.'));
        }
        var seperator = (name.lastIndexOf('\\') > -1) ? '\\' : '/';
        name = name.substr(name.lastIndexOf(seperator) + 1, name.length);
		header.title = titleize(name);
    }

    // Generate slug
    header.slug = slugify(header.title);

    return header;
};

//
// :: Render Body -> Format blog post in proper HTML

var renderBody = function(raw, format) {
    var addPrettifyHints = function(html) {
        html = html.replace(/
/gi, '
');
        html = html.replace(//gi, '');
        html = html.replace(/\s<\/code>/gi, '');
        return html;
    };

    if (format === 'md' || format === 'markdown') {             // Markdown
        // Convert github style code into regular markdown
        if (raw.indexOf('```') > -1) {
            var githubCodeBlockPattern = new RegExp('```([\\s\\S]+)```', 'g');
            var m = githubCodeBlockPattern.exec(raw);
            while (m) {
                var lines = m[1].split('\n');
                raw = raw.replace(m[0], lines.reduce(function(acc, x){
                    return acc + '\n    ' + x;
                }, ''));
                m = githubCodeBlockPattern.exec(raw);
            }
        }
        // Html -> Markdown
        var html = markdown.makeHtml(raw);
        return addPrettifyHints(html);
    } else if (format === 'html' || format === 'htm') {         // HTML
        return addPrettifyHints(raw);
    } else {                                                    // Plain / other
        return raw;
    }
};

//
// :: Parse Blog Post File -> Given a file path, turn it into a meaningful structure

var parseBlogPostFile = function(path) {
    // Read the file off of disk and slice it by it's config
    var raw = fs.readFileSync(path, 'ascii')
      , headerTerminator = raw.indexOf('*/')
      , rawHeader = ''
      , rawBody = ''
      ;

    if (headerTerminator > 0) {
        rawHeader = raw.substr(2, headerTerminator - 2).trim();
        rawBody = raw.substr(headerTerminator + 2).trim();
    } else {
        rawBody = raw;
    }

    // Parse the header and render the body
    var post = parseHeader(rawHeader, path)
      , format = path.substr(path.lastIndexOf('.') + 1)
      ;

    post.body = renderBody(rawBody, format);
    return post;
};

//
// :: File Name From Path -> Get the file name from the full path minus the extension
var fileNameFromPath = function(path){
	var name = path;
	if(name.lastIndexOf('/') > 0){
		name = name.split('/').pop();
	}
	name = name.substr(0, name.lastIndexOf('.'));
	return name;
};

//
// :: Scan -> Search the given directory for files, assumed to be blog posts

var scan = function(app, settings, routes, callback) {

    var postTable = {}
      , postList = []
      , postDir = path.join(__dirname, '../', settings.posts)
      ;

    fs.readdir(postDir, function(err, files){
        files.forEach(function(f){
            var filePath = path.join(__dirname, '../', settings.posts, f)
              , post = parseBlogPostFile(filePath, f);
            if (postTable[post.slug]){
                console.warn('An entry for slug "' + post.slug + '" already exists!');
            } else {
                // Data is stored in two formats
                // First, a "full details" table, in which posts are indexed by their slug
                postTable[post.slug] = post;
                // Seconed, an ordered list with only the minimal amount of information
                postList.push({
                    slug: post.slug,
                    date: post.date
                });
            }
        });

        // Sort list
        postList.sort(function(a, b){
            return b.date - a.date;
        });

        routes(app, postTable, postList);
        callback(app, postTable, postList);
    });
};

// Exports
exports.scan = scan;<commit_msg>corrected comments boolean on posts config to not always be 'undefined'<commit_after>require('./vendor/date')

var path        = require('path')
  , fs          = require('fs')
  , yaml        = require('js-yaml')
  , showdown    = require('./vendor/showdown')
  , markdown    = new showdown.converter()
  , slugify     = require('./lib').slugify
  , titleize    = require('./lib').titleize
  ;

//
// :: Parse Header -> Turn YAML into a meaningful structure

var parseHeader = function(raw, path) {
    // Init empty stub
    var header = {
        tags: []
    };

    // Check for YAML configuration data
    if (typeof raw === 'string' && raw.length > 0) {
        var config = yaml.load(raw);

        // Convert config to lowercase
        for (var prop in config) {
            if (config.hasOwnProperty(prop)) {
                config[prop.toLowerCase()] = config[prop];
            }
        }

        header.comments = config.comments;
        header.title = config.title;
        header.tags = config.tags ? config.tags.map(function(x) { return x.toLowerCase(); }) : [];
        header.date = Date.parse(config.date);
    }

    // Fill in date if it's lacking
    if (typeof header.date === 'undefined') {
        var stats = fs.statSync(path);
        header.date = stats.ctime;
    }

    // Fill in title if it's lacking
    if (typeof header.title === 'undefined') {
        var name = fileNameFromPath(path);
        if (name.indexOf('.') > -1) {
            name = name.substr(0, name.lastIndexOf('.'));
        }
        var seperator = (name.lastIndexOf('\\') > -1) ? '\\' : '/';
        name = name.substr(name.lastIndexOf(seperator) + 1, name.length);
		header.title = titleize(name);
    }

    // Generate slug
    header.slug = slugify(header.title);

    return header;
};

//
// :: Render Body -> Format blog post in proper HTML

var renderBody = function(raw, format) {
    var addPrettifyHints = function(html) {
        html = html.replace(/<pre><code>/gi, '<pre class="prettyprint linenums" tabIndex="0"><code data-inner="1">');
        html = html.replace(/<code>/gi, '<code class="prettyprint" tabIndex="0">');
        html = html.replace(/\s<\/code>/gi, '</code>');
        return html;
    };

    if (format === 'md' || format === 'markdown') {             // Markdown
        // Convert github style code into regular markdown
        if (raw.indexOf('```') > -1) {
            var githubCodeBlockPattern = new RegExp('```([\\s\\S]+)```', 'g');
            var m = githubCodeBlockPattern.exec(raw);
            while (m) {
                var lines = m[1].split('\n');
                raw = raw.replace(m[0], lines.reduce(function(acc, x){
                    return acc + '\n    ' + x;
                }, ''));
                m = githubCodeBlockPattern.exec(raw);
            }
        }
        // Html -> Markdown
        var html = markdown.makeHtml(raw);
        return addPrettifyHints(html);
    } else if (format === 'html' || format === 'htm') {         // HTML
        return addPrettifyHints(raw);
    } else {                                                    // Plain / other
        return raw;
    }
};

//
// :: Parse Blog Post File -> Given a file path, turn it into a meaningful structure

var parseBlogPostFile = function(path) {
    // Read the file off of disk and slice it by it's config
    var raw = fs.readFileSync(path, 'ascii')
      , headerTerminator = raw.indexOf('*/')
      , rawHeader = ''
      , rawBody = ''
      ;

    if (headerTerminator > 0) {
        rawHeader = raw.substr(2, headerTerminator - 2).trim();
        rawBody = raw.substr(headerTerminator + 2).trim();
    } else {
        rawBody = raw;
    }

    // Parse the header and render the body
    var post = parseHeader(rawHeader, path)
      , format = path.substr(path.lastIndexOf('.') + 1)
      ;

    post.body = renderBody(rawBody, format);
    return post;
};

//
// :: File Name From Path -> Get the file name from the full path minus the extension
var fileNameFromPath = function(path){
	var name = path;
	if(name.lastIndexOf('/') > 0){
		name = name.split('/').pop();
	}
	name = name.substr(0, name.lastIndexOf('.'));
	return name;
};

//
// :: Scan -> Search the given directory for files, assumed to be blog posts

var scan = function(app, settings, routes, callback) {

    var postTable = {}
      , postList = []
      , postDir = path.join(__dirname, '../', settings.posts)
      ;

    fs.readdir(postDir, function(err, files){
        files.forEach(function(f){
            var filePath = path.join(__dirname, '../', settings.posts, f)
              , post = parseBlogPostFile(filePath, f);
            if (postTable[post.slug]){
                console.warn('An entry for slug "' + post.slug + '" already exists!');
            } else {
                // Data is stored in two formats
                // First, a "full details" table, in which posts are indexed by their slug
                postTable[post.slug] = post;
                // Seconed, an ordered list with only the minimal amount of information
                postList.push({
                    slug: post.slug,
                    date: post.date
                });
            }
        });

        // Sort list
        postList.sort(function(a, b){
            return b.date - a.date;
        });

        routes(app, postTable, postList);
        callback(app, postTable, postList);
    });
};

// Exports
exports.scan = scan;<|endoftext|>