<commit_before>/*
    {
        name: 'myinlines',
        type: 'inlines',
        form: {
            name: 'myform',
            fields: [
                {
                    name: 'Position',
                    type: 'integer'
                },
                {
                    name: 'Description',
                    type: 'textarea'
                },
                {
                    name: 'Price',
                    type: 'float'
                }
            ]
        }
    }
*/

schnipp.dynforms.fields.inlines = function(field_descriptor, field_data, parent_dynform) {
    var self = schnipp.dynforms.abstract_field(field_descriptor, field_data)
    self.form = schnipp.dynforms.form(field_descriptor.form, {}, parent_dynform.fieldtypes)
    self.change_form = schnipp.dynforms.form(field_descriptor.form, {}, parent_dynform.fieldtypes)
    self.objects = schnipp.models.observable_list()
    self.templates.holder = '\

\
             Hinzufügen\

\

\
    '
    self.templates.action_td = '\
        \
            \
            \
        	\
    '

    var super_initialize = self.initialize
    self.initialize = function() {
        super_initialize()
        var tbody = self.dom.changelist_table.find('tbody')
        // handle insert
        self.objects.events.bind('insert', function(args) {
            tbody.append(self.render_row(args.element))
            self.dom.changelist_table.sortable().find('tbody').sortable('refresh')
        })
        // handle remove
        self.objects.events.bind('remove', function(args) {
            $(tbody.children()[args.index]).remove()
        })
        // make rows sortable
        self.make_sortable()
        // set initial data.
        $.each(self.get_initial_data(), function(i, obj) {
            self.objects.append(obj)
        })
    }

    /**
    *   Render object row with change buttons.
    */
    self.render_row = function(obj) {
        var tr = $('

')
        var tds = {}

        $.each(field_descriptor.form.fields, function(i, field) {
            var td = $('	').text(obj.get(field.name))
            tds[field.name] = td
            tr.append(td)
        })

        var td = $(self.templates.action_td)
        var edit = td.find('.schnippforms-inlines-edit')
        var del = td.find('.schnippforms-inlines-delete')
        tr.append(td)

        // this is hacky but necessary to enable data change on row sort.
        tr.data('obj', obj)

        edit.click(function() {
            var d = schnipp.ui.Dialog().init()
            d.set_content(self.change_form.render())
            self.change_form.set_data(obj.raw_data)
            self.change_form.initialize()
            var f = d.dom.main.find('form')
            f.append($('<input type="submit" value="Übernehmen"/>'))
            f.submit(function() {
                if (self.change_form.is_valid()) {
                    var data = self.change_form.get_data()
                    for (key in data) {
                        tds[key].text(data[key])
                        obj.set(key, data[key])
                    }
                    d.close()
                }
                return false
            })
            d.show()
            return false
        })

        del.click(function() {
            self.objects.remove($(this).closest('tr').prevAll().length)
            return false
        })
        return tr
    }

    /**
    *   Main visualization of the field. Handle add button;
    */
    self.render_input = function() {
        var holder = $(self.templates.holder)
        var a = holder.find('a.schnippforms-inline-add')
        var changelist = holder.find('.schnippforms-inline-objects')
        self.dom.changelist_table = self.render_changelist()
        changelist.append(self.dom.changelist_table)

        a.click(function() {
            var d = schnipp.ui.Dialog().init()
            var dialog_content = self.render_add_form(d)
            d.set_content(dialog_content)
            d.show()
            return false
        })

        return holder
    }

    /**
    *   Render add form.
    */
    self.render_add_form = function(d) {
        var content = $('

')
        var submit = $('<input type="submit" value="anlegen"/>')
        content.append(self.form.render())
        self.form.initialize()

        var f =  content.find('form')
        f.append(submit)

        f.submit(function() {
            if (self.form.is_valid()) {
                self.objects.append(self.form.get_data())
                for (var i=0; i<self.form.fields.length; i++) {
                    var field = self.form.fields[i]
                    field.clear()
                }
                d.close()
            }
            return false
        })

        return content
    }

    /**
    *   Render empty the changelist.
    */
    self.render_changelist = function() {
        var table = $('

')
        var thead = table.find('thead')
        var tr = $('

')
        $.each(self.form.schema.fields, function(i, field) {
            th = $('	').text(field.label)
            if (i == self.form.schema.fields.length - 1)
                th.attr('colspan', '2')
            if (i == 0)
                th.attr('colspan', '2')
            tr.append(th)
        })
        thead.append(tr)
        return table
    }

    /**
    *   Apply sortable functionality on table rows.
    */
    self.make_sortable = function() {
        var tbody = self.dom.changelist_table.find('tbody')
        tbody.sortable({
            distance: 10,
            helper: function(e, ui) {
	            ui.children().each(function() {
		            $(this).width($(this).width())
	            })
	            return ui
            },
            stop: function() {
                self.objects.clear()
                tbody.children().each(function(i, elem) {
                    self.objects.data.push($(elem).data('obj'))
                })
            }
        }).disableSelection()
    }

    self.get_data = function() {
        return self.objects.get_data()
    }

    self._set = function(objects) {
        for (var i=0; i<objects.length; i++) {
            var obj = objects[i]
            self.objects.append(obj)
        }
    }

    return self
}

<commit_msg>removed empty line<commit_after>/*
    {
        name: 'myinlines',
        type: 'inlines',
        form: {
            name: 'myform',
            fields: [
                {
                    name: 'Position',
                    type: 'integer'
                },
                {
                    name: 'Description',
                    type: 'textarea'
                },
                {
                    name: 'Price',
                    type: 'float'
                }
            ]
        }
    }
*/

schnipp.dynforms.fields.inlines = function(field_descriptor, field_data, parent_dynform) {
    var self = schnipp.dynforms.abstract_field(field_descriptor, field_data)
    self.form = schnipp.dynforms.form(field_descriptor.form, {}, parent_dynform.fieldtypes)
    self.change_form = schnipp.dynforms.form(field_descriptor.form, {}, parent_dynform.fieldtypes)
    self.objects = schnipp.models.observable_list()
    self.templates.holder = '\

\
             Hinzufügen\

\

\
    '
    self.templates.action_td = '\
        \
            \
            \
        	\
    '

    var super_initialize = self.initialize
    self.initialize = function() {
        super_initialize()
        var tbody = self.dom.changelist_table.find('tbody')
        // handle insert
        self.objects.events.bind('insert', function(args) {
            tbody.append(self.render_row(args.element))
            self.dom.changelist_table.sortable().find('tbody').sortable('refresh')
        })
        // handle remove
        self.objects.events.bind('remove', function(args) {
            $(tbody.children()[args.index]).remove()
        })
        // make rows sortable
        self.make_sortable()
        // set initial data.
        $.each(self.get_initial_data(), function(i, obj) {
            self.objects.append(obj)
        })
    }

    /**
    *   Render object row with change buttons.
    */
    self.render_row = function(obj) {
        var tr = $('

')
        var tds = {}

        $.each(field_descriptor.form.fields, function(i, field) {
            var td = $('	').text(obj.get(field.name))
            tds[field.name] = td
            tr.append(td)
        })

        var td = $(self.templates.action_td)
        var edit = td.find('.schnippforms-inlines-edit')
        var del = td.find('.schnippforms-inlines-delete')
        tr.append(td)

        // this is hacky but necessary to enable data change on row sort.
        tr.data('obj', obj)

        edit.click(function() {
            var d = schnipp.ui.Dialog().init()
            d.set_content(self.change_form.render())
            self.change_form.set_data(obj.raw_data)
            self.change_form.initialize()
            var f = d.dom.main.find('form')
            f.append($('<input type="submit" value="Übernehmen"/>'))
            f.submit(function() {
                if (self.change_form.is_valid()) {
                    var data = self.change_form.get_data()
                    for (key in data) {
                        tds[key].text(data[key])
                        obj.set(key, data[key])
                    }
                    d.close()
                }
                return false
            })
            d.show()
            return false
        })

        del.click(function() {
            self.objects.remove($(this).closest('tr').prevAll().length)
            return false
        })
        return tr
    }

    /**
    *   Main visualization of the field. Handle add button;
    */
    self.render_input = function() {
        var holder = $(self.templates.holder)
        var a = holder.find('a.schnippforms-inline-add')
        var changelist = holder.find('.schnippforms-inline-objects')
        self.dom.changelist_table = self.render_changelist()
        changelist.append(self.dom.changelist_table)

        a.click(function() {
            var d = schnipp.ui.Dialog().init()
            var dialog_content = self.render_add_form(d)
            d.set_content(dialog_content)
            d.show()
            return false
        })

        return holder
    }

    /**
    *   Render add form.
    */
    self.render_add_form = function(d) {
        var content = $('

')
        var submit = $('<input type="submit" value="anlegen"/>')
        content.append(self.form.render())
        self.form.initialize()

        var f =  content.find('form')
        f.append(submit)

        f.submit(function() {
            if (self.form.is_valid()) {
                self.objects.append(self.form.get_data())
                for (var i=0; i<self.form.fields.length; i++) {
                    var field = self.form.fields[i]
                    field.clear()
                }
                d.close()
            }
            return false
        })

        return content
    }

    /**
    *   Render empty the changelist.
    */
    self.render_changelist = function() {
        var table = $('

')
        var thead = table.find('thead')
        var tr = $('

')
        $.each(self.form.schema.fields, function(i, field) {
            th = $('	').text(field.label)
            if (i == self.form.schema.fields.length - 1)
                th.attr('colspan', '2')
            if (i == 0)
                th.attr('colspan', '2')
            tr.append(th)
        })
        thead.append(tr)
        return table
    }

    /**
    *   Apply sortable functionality on table rows.
    */
    self.make_sortable = function() {
        var tbody = self.dom.changelist_table.find('tbody')
        tbody.sortable({
            distance: 10,
            helper: function(e, ui) {
	            ui.children().each(function() {
		            $(this).width($(this).width())
	            })
	            return ui
            },
            stop: function() {
                self.objects.clear()
                tbody.children().each(function(i, elem) {
                    self.objects.data.push($(elem).data('obj'))
                })
            }
        }).disableSelection()
    }

    self.get_data = function() {
        return self.objects.get_data()
    }

    self._set = function(objects) {
        for (var i=0; i<objects.length; i++) {
            var obj = objects[i]
            self.objects.append(obj)
        }
    }

    return self
}

<|endoftext|>


<commit_before>/**
 * Summary: inherit from lib.PubSub if a class wants publish/subscribe ability
 * Methods:
 *  - publish(signal, args...) - all subscribers to signal will be called
 *     with the list of arguments provided.
 *  - subscribe(signal, ctx, method, args...) - register a bound method
 *     to a signal.  Any args that are passed in will be the first args
 *     when the method is invoked during a publish.
 *  Usage notes: There is one special signal '__any'.  Any subscribers to
 *     '__any' will be called on every publish with the first publish
 *     argument being the signal itself (after any args passed in during
 *     the corresponding subscribe).
 *     Calling the super constructor is not required for descendants of
 *     lib.PubSub.
 */
var ctx = jsio.__env.global;

exports = Class(function() {
	this.init = function() {}

	this.publish = function(signal) {
		if(this._subscribers) {
			var args = Array.prototype.slice.call(arguments, 1);
			if(this._subscribers.__any) {
				var anyArgs = [signal].concat(args),
					subs = this._subscribers.__any.slice(0);
				for(var i = 0, sub; sub = subs[i]; ++i) {
					sub.apply(ctx, anyArgs);
				}
			}

			if(!this._subscribers[signal]) { return; }

			var subs = this._subscribers[signal].slice(0);
			for(var i = 0, sub; sub = subs[i]; ++i) {
				sub.apply(ctx, args);
			}
		}
		return this;
	}

	this.subscribe = function(signal, ctx, method) {
		if(!this._subscribers) { this._subscribers = {}; }
		if(!this._subscribers[signal]) { this._subscribers[signal] = []; }
		var cb = bind.apply(ctx, Array.prototype.slice.call(arguments, 1));
		cb._ctx = ctx; // references for unsubscription
		cb._method = method;
		this._subscribers[signal].push(cb);
		return this;
	}

	// if no method is specified, all subscriptions with a callback context of ctx will be removed
	this.unsubscribe = function(signal, ctx, method) {
		if (!this._subscribers || !this._subscribers[signal]) { return; }
		var subs = this._subscribers[signal];
		for (var i = 0, c; c = subs[i]; ++i) {
			if (c._ctx == ctx && (!method || c._method == method)) {
				subs.splice(i--, 1);
			}
		}
		return this;
	}
});

<commit_msg>allow subscriptions with 2 arguments: signal and callback; add subscribeOnce ability<commit_after>/**
 * Summary: inherit from lib.PubSub if a class wants publish/subscribe ability
 * Methods:
 *  - publish(signal, args...) - all subscribers to signal will be called
 *     with the list of arguments provided.
 *  - subscribe(signal, ctx, method, args...) - register a bound method
 *     to a signal.  Any args that are passed in will be the first args
 *     when the method is invoked during a publish.
 *  Usage notes: There is one special signal '__any'.  Any subscribers to
 *     '__any' will be called on every publish with the first publish
 *     argument being the signal itself (after any args passed in during
 *     the corresponding subscribe).
 *     Calling the super constructor is not required for descendants of
 *     lib.PubSub.
 */
var ctx = jsio.__env.global,
	SLICE = Array.prototype.slice;

exports = Class(function() {
	this.init = function() {}

	this.publish = function(signal) {
		if(this._subscribers) {
			var args = SLICE.call(arguments, 1);
			if(this._subscribers.__any) {
				var anyArgs = [signal].concat(args),
					subs = this._subscribers.__any.slice(0);
				for(var i = 0, sub; sub = subs[i]; ++i) {
					sub.apply(ctx, anyArgs);
				}
			}

			if(!this._subscribers[signal]) { return; }

			var subs = this._subscribers[signal].slice(0);
			for(var i = 0, sub; sub = subs[i]; ++i) {
				sub.apply(ctx, args);
			}
		}
		return this;
	}

	this.subscribe = function(signal, ctx, method) {
		var cb;
		if (arguments.length == 2) {
			cb = ctx;
		} else {
			cb = bind.apply(GLOBAL, SLICE.call(arguments, 1));
			cb._ctx = ctx; // references for unsubscription
			cb._method = method;
		}

		var s = this._subscribers || (this._subscribers = {});
		(s[signal] || (s[signal] = [])).push(cb);
		return this;
	}

	this.subscribeOnce = function(signal, ctx, method) {
		var args = arguments,
			cb = bind(this, function() {
				this.unsubscribe(this, cb);
				if (args.length == 2) {
					ctx.apply(GLOBAL, arguments);
				} else {
					bind.apply(GLOBAL, SLICE.call(args, 1))
						.apply(GLOBAL, arguments);
				}
			});

		this.subscribe(signal, cb);
	}

	// if no method is specified, all subscriptions with a callback context of ctx will be removed
	this.unsubscribe = function(signal, ctx, method) {
		if (!this._subscribers || !this._subscribers[signal]) { return; }
		var subs = this._subscribers[signal];
		for (var i = 0, c; c = subs[i]; ++i) {
			if (c == ctx || c._ctx == ctx && (!method || c._method == method)) {
				subs.splice(i--, 1);
			}
		}
		return this;
	}
});

<|endoftext|>


<commit_before>/*
---
name: Event.Mock

description: Supplies a Mock Event object for use on fireEvent

license: MIT-style

authors:
- Arieh Glazer

requires:
- Core/Event

provides: [Event.Mock]

...
*/

(function($,window,undef){

/**
 * creates a Mock event to be used with fire event
 * @param Element target an element to set as the target of the event - not required
 *  @param string type the type of the event to be fired. Will not be used by IE - not required.
 *
 */
Event.Mock = function(target,type){
	var e = window.event;

	type = type || 'click';

	if (document.createEvent){
		e = document.createEvent('HTMLEvents');
		e.initEvent(
			type //event type
			, false //bubbles - set to false because the event should like normal fireEvent
			, true //cancelable
		);
	}

	e = new Event(e);

	e.target = target;

	return e;
};

})(document.id,window);<commit_msg>YAML header fixes<commit_after>/*
---
name: Event.Mock

description: Supplies a Mock Event object for use on fireEvent

license: MIT-style

authors:
- Arieh Glazer

requires: Core/Event

provides: [Event.Mock]

...
*/

(function($,window,undef){

/**
 * creates a Mock event to be used with fire event
 * @param Element target an element to set as the target of the event - not required
 *  @param string type the type of the event to be fired. Will not be used by IE - not required.
 *
 */
Event.Mock = function(target,type){
	var e = window.event;

	type = type || 'click';

	if (document.createEvent){
		e = document.createEvent('HTMLEvents');
		e.initEvent(
			type //event type
			, false //bubbles - set to false because the event should like normal fireEvent
			, true //cancelable
		);
	}

	e = new Event(e);

	e.target = target;

	return e;
};

})(document.id,window);<|endoftext|>


<commit_before>/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */
define([
    'rjsResolver'
], function (resolver) {
    'use strict';

    /**
     * Removes provided loader element from DOM.
     *
     * @param {HTMLElement} $loader - Loader DOM element.
     */
    function hideLoader($loader) {
        $loader.parentNode.removeChild($loader);
    }

    /**
     * Initializes assets loading process listener.
     *
     * @param {Object} config - Optional configuration
     * @param {HTMLElement} $loader - Loader DOM element.
     */
    function init(config, $loader) {
        resolver(hideLoader.bind(null, $loader));
    }

    return init;
});
<commit_msg>#72271 - Remove checkout loader<commit_after><|endoftext|>


<commit_before>'use strict';

var Args = require('./../../helpers/args');
var NodeStore = require('./../../node-store');
var Targets = require('./../../helpers/targets');
var VirtualDOM = require('./../../virtual-dom');

var TIME_KEY = '$time';
var NOW_KEY = '$now';
var FRAME_KEY = '$frame';

var FRAMES = {};

function create(behavior, node) {
    var states = node.stateManager.getStatesObject();
    FRAMES[node.uid] = 0;
    return function(time) {
        var now = Date.now();
        var frame = FRAMES[node.uid]++;

        var i;
        var args = [];
        var params = behavior.params || [];
        for (i = 0; i < params.length; i++) {
            var name = params[i];
            if (name === TIME_KEY) {
                args[i] = time;
            }
            else if (name === FRAME_KEY) {
                args[i] = frame;
            }
            else if (name === NOW_KEY) {
                args[i] = now;
            }
            else {
                args[i] = Args.fetchOne(name, states);
            }
        }
        var payload = behavior.action.apply(null, args);
        var targets = Targets.fetch(node.domStore.domNode, behavior.selector);
        for (i = 0; i < targets.length; i++) {
            var target = targets[i];
            var targetNode = NodeStore.findNode(VirtualDOM.getUID(target));
            targetNode.eventChannel.sendMessage(behavior.name, payload);
        }
    };
}

module.exports = {
    create: create
};
<commit_msg>Use correct state manager method<commit_after>'use strict';

var Args = require('./../../helpers/args');
var NodeStore = require('./../../node-store');
var Targets = require('./../../helpers/targets');
var VirtualDOM = require('./../../virtual-dom');

var TIME_KEY = '$time';
var NOW_KEY = '$now';
var FRAME_KEY = '$frame';

var FRAMES = {};

function create(behavior, node) {
    var states = node.stateManager.getStateObject();
    FRAMES[node.uid] = 0;
    return function(time) {
        var now = Date.now();
        var frame = FRAMES[node.uid]++;

        var i;
        var args = [];
        var params = behavior.params || [];
        for (i = 0; i < params.length; i++) {
            var name = params[i];
            if (name === TIME_KEY) {
                args[i] = time;
            }
            else if (name === FRAME_KEY) {
                args[i] = frame;
            }
            else if (name === NOW_KEY) {
                args[i] = now;
            }
            else {
                args[i] = Args.fetchOne(name, states);
            }
        }
        var payload = behavior.action.apply(null, args);
        var targets = Targets.fetch(node.domStore.domNode, behavior.selector);
        for (i = 0; i < targets.length; i++) {
            var target = targets[i];
            var targetNode = NodeStore.findNode(VirtualDOM.getUID(target));
            targetNode.eventChannel.sendMessage(behavior.name, payload);
        }
    };
}

module.exports = {
    create: create
};
<|endoftext|>


<commit_before>// ==UserScript==
// @name         Spam Reporter
// @namespace    http://github.com/Tiny-Giant
// @version      1.0.0.0
// @description  Adds a link to the post menu for most posts.
// @author       @TinyGiant
// @include      /^https?:\/\/\w*.?(stackexchange.com|stackoverflow.com|serverfault.com|superuser.com|askubuntu.com|stackapps.com|mathoverflow.net)\/q(uestions)?\/\d+/
// @grant        GM_xmlhttpRequest
// ==/UserScript==
/* jshint -W097 */

(function(){
    'use strict';

    var notify = (function(){
        var count = 0, timeout;
        return function(m,t) {
            console.log(m,t);
            if($('#notify-' + count).length) {
                clearTimeout(timeout);
                StackExchange.notify.close(count);
            }
            StackExchange.notify.show(m,++count);
            if(t) timeout = setTimeout(StackExchange.notify.close.bind(null,count), t);
        };
    })();

    var engage = function(scope) {

        if (!scope) {
            return false;
        }

        var room = 41570; // use 68414 for testing

        var post = /\d+/.exec(scope.querySelector('.short-link').id)[0];

        var reportSent = function(response) {
            console.log(response);

            if (response.status !== 200) {
                notify('Error sending request: ' + resp.responseText);
                return false;
            }

            notify('Close vote request sent.',1000);
        };

        var sendReport = function(response) {
            console.log(response);

            if (response.status !== 200) {
                notify('Failed sending report, check the console for more information.');
                return false;
            }

            var fkey = response.responseText.match(/hidden" value="([\dabcdef]{32})/)[1];

            if (!fkey) {
                notify('Failed retrieving key, is the room URL valid?');
                return false;
            }

            var reportStr = '!!/report http://stackoverflow.com/posts/' + post;

            var options = {
                method: 'POST',
                url: 'http://chat.stackoverflow.com/chats/' + room + '/messages/new',
                headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
                data: 'text=' + encodeURIComponent(reportStr) + '&fkey=' + fkey,
                onload: reportSent
            };

            GM_xmlhttpRequest(options);
        };

        var report = function() {
            if(!confirm('Do you really want to report this post?')) {
                return false;
            }

            var options = {
                method: 'GET',
                url: 'http://chat.stackoverflow.com/rooms/' + room,
                onload: sendReport
            };

            GM_xmlhttpRequest(options);
        };

        var sep = document.createElement('span');
        sep.className = 'lsep';
        sep.textContent = '|';
        scope.appendChild(sep);

        var link = document.createElement('a');
        link.href = '#';
        link.textContent = 'report';
        link.addEventListener('click', report, false);
        scope.appendChild(link);
    };

    var menus = document.querySelectorAll('.post-menu');

    for(var i in Object.keys(menus)) engage(menus[i]);

    $(document).ajaxComplete(function(){
        var url = arguments[2].url;
        if (/^\/posts\/ajax-load-realtime\//.test(url)) engage(/\d+/.exec(url)[0]);
    });
})();
<commit_msg>Smokey only understands the Share link for reporting posts<commit_after>// ==UserScript==
// @name         Spam Reporter
// @namespace    http://github.com/Tiny-Giant
// @version      1.0.0.0
// @description  Adds a link to the post menu for most posts.
// @author       @TinyGiant
// @include      /^https?:\/\/\w*.?(stackexchange.com|stackoverflow.com|serverfault.com|superuser.com|askubuntu.com|stackapps.com|mathoverflow.net)\/q(uestions)?\/\d+/
// @grant        GM_xmlhttpRequest
// ==/UserScript==
/* jshint -W097 */

(function(){
    'use strict';

    var notify = (function(){
        var count = 0, timeout;
        return function(m,t) {
            console.log(m,t);
            if($('#notify-' + count).length) {
                clearTimeout(timeout);
                StackExchange.notify.close(count);
            }
            StackExchange.notify.show(m,++count);
            if(t) timeout = setTimeout(StackExchange.notify.close.bind(null,count), t);
        };
    })();

    var engage = function(scope) {

        if (!scope) {
            return false;
        }

        var room = 41570; // use 68414 for testing

        var postLink = scope.querySelector('.short-link').href;

        var reportSent = function(response) {
            console.log(response);

            if (response.status !== 200) {
                notify('Error sending request: ' + resp.responseText);
                return false;
            }

            notify('Close vote request sent.',1000);
        };

        var sendReport = function(response) {
            console.log(response);

            if (response.status !== 200) {
                notify('Failed sending report, check the console for more information.');
                return false;
            }

            var fkey = response.responseText.match(/hidden" value="([\dabcdef]{32})/)[1];

            if (!fkey) {
                notify('Failed retrieving key, is the room URL valid?');
                return false;
            }

            var reportStr = '!!/report ' + postLink;

            var options = {
                method: 'POST',
                url: 'http://chat.stackoverflow.com/chats/' + room + '/messages/new',
                headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
                data: 'text=' + encodeURIComponent(reportStr) + '&fkey=' + fkey,
                onload: reportSent
            };

            GM_xmlhttpRequest(options);
        };

        var report = function() {
            if(!confirm('Do you really want to report this post?')) {
                return false;
            }

            var options = {
                method: 'GET',
                url: 'http://chat.stackoverflow.com/rooms/' + room,
                onload: sendReport
            };

            GM_xmlhttpRequest(options);
        };

        var sep = document.createElement('span');
        sep.className = 'lsep';
        sep.textContent = '|';
        scope.appendChild(sep);

        var link = document.createElement('a');
        link.href = '#';
        link.textContent = 'report';
        link.addEventListener('click', report, false);
        scope.appendChild(link);
    };

    var menus = document.querySelectorAll('.post-menu');

    for(var i in Object.keys(menus)) engage(menus[i]);

    $(document).ajaxComplete(function(){
        var url = arguments[2].url;
        if (/^\/posts\/ajax-load-realtime\//.test(url)) engage(/\d+/.exec(url)[0]);
    });
})();
<|endoftext|>


<commit_before>'use strict'

let whitelist
let whitelistArray = new Array()

chrome.storage.sync.get(function(items) {
	if (items.whitelist) {
		whitelist = items.whitelist
		whitelistArray = whitelist.split('\n')
	}
})

function inWhitelist(url) {
	let listed = false
	whitelistArray.forEach(function(item) {
		if (url.startsWith(item)) {
			listed = true
		}
	})
	return listed
}

function sleepTab(html, tab) {
	const pageInfo = {
		url: tab.url,
		title: tab.title,
		hibernationInfo: chrome.i18n.getMessage('hibernationPageInfo'),
		buttonText: chrome.i18n.getMessage('hibernationPageButton'),
		favIconUrl: tab.favIconUrl
	}
	const pageHtml = html.replace(/\{\/\*pageInfoObject\*\/\}/, JSON.stringify(pageInfo))
	const dataURL = 'data:text/html;base64,' + btoa(pageHtml)
	chrome.tabs.update(tab.id, {url: dataURL})
}

chrome.browserAction.onClicked.addListener(function() {
	const xmlHttp = new XMLHttpRequest()
	xmlHttp.open('GET', chrome.runtime.getURL('hibernationPage/index.html'), true)
	xmlHttp.onload = function() {
		const html = xmlHttp.responseText

		chrome.windows.getAll({populate: true}, function(windows) {
			windows.forEach(function(win) {
				win.tabs.forEach(function(tab) {
					if (tab.active || tab.highlighted || tab.pinned) return
					if (tab.status !== 'complete') return
					if (!tab.url.match(/^https?:\/\//)) return
					if (inWhitelist(tab.url)) return

					sleepTab(html, tab)
				})
			})
		})
	}
	xmlHttp.send(null)
})

chrome.runtime.onInstalled.addListener(function() {
	chrome.contextMenus.create({
		id : 'SleepTab',
		title : chrome.i18n.getMessage('contextMenuTitle'),
		contexts : ['page']
	})
})

chrome.contextMenus.onClicked.addListener(function(info, tab) {
	const xmlHttp = new XMLHttpRequest()
	xmlHttp.open('GET', chrome.runtime.getURL('hibernationPage/index.html'), true)
	xmlHttp.onload = function() {
		const html = xmlHttp.responseText
		sleepTab(html, tab)
	}
	xmlHttp.send(null)
})

chrome.commands.onCommand.addListener(function() {
	chrome.tabs.query({active: true, lastFocusedWindow: true}, function(tabs) {
		const xmlHttp = new XMLHttpRequest()
		xmlHttp.open('GET', chrome.runtime.getURL('hibernationPage/index.html'), true)
		xmlHttp.onload = function() {
			const html = xmlHttp.responseText
			sleepTab(html, tabs[0])
		}
		xmlHttp.send(null)
	})
})
<commit_msg>explicitly allow to discard content of sleeping tabs from memory<commit_after>'use strict'

let whitelist
let whitelistArray = new Array()

chrome.storage.sync.get(function(items) {
	if (items.whitelist) {
		whitelist = items.whitelist
		whitelistArray = whitelist.split('\n')
	}
})

function inWhitelist(url) {
	let listed = false
	whitelistArray.forEach(function(item) {
		if (url.startsWith(item)) {
			listed = true
		}
	})
	return listed
}

function sleepTab(html, tab) {
	const pageInfo = {
		url: tab.url,
		title: tab.title,
		hibernationInfo: chrome.i18n.getMessage('hibernationPageInfo'),
		buttonText: chrome.i18n.getMessage('hibernationPageButton'),
		favIconUrl: tab.favIconUrl
	}
	const pageHtml = html.replace(/\{\/\*pageInfoObject\*\/\}/, JSON.stringify(pageInfo))
	const dataURL = 'data:text/html;base64,' + btoa(pageHtml)
	chrome.tabs.update(tab.id, {url: dataURL, autoDiscardable: true})
}

chrome.browserAction.onClicked.addListener(function() {
	const xmlHttp = new XMLHttpRequest()
	xmlHttp.open('GET', chrome.runtime.getURL('hibernationPage/index.html'), true)
	xmlHttp.onload = function() {
		const html = xmlHttp.responseText

		chrome.windows.getAll({populate: true}, function(windows) {
			windows.forEach(function(win) {
				win.tabs.forEach(function(tab) {
					if (tab.active || tab.highlighted || tab.pinned) return
					if (tab.status !== 'complete') return
					if (!tab.url.match(/^https?:\/\//)) return
					if (inWhitelist(tab.url)) return

					sleepTab(html, tab)
				})
			})
		})
	}
	xmlHttp.send(null)
})

chrome.runtime.onInstalled.addListener(function() {
	chrome.contextMenus.create({
		id : 'SleepTab',
		title : chrome.i18n.getMessage('contextMenuTitle'),
		contexts : ['page']
	})
})

chrome.contextMenus.onClicked.addListener(function(info, tab) {
	const xmlHttp = new XMLHttpRequest()
	xmlHttp.open('GET', chrome.runtime.getURL('hibernationPage/index.html'), true)
	xmlHttp.onload = function() {
		const html = xmlHttp.responseText
		sleepTab(html, tab)
	}
	xmlHttp.send(null)
})

chrome.commands.onCommand.addListener(function() {
	chrome.tabs.query({active: true, lastFocusedWindow: true}, function(tabs) {
		const xmlHttp = new XMLHttpRequest()
		xmlHttp.open('GET', chrome.runtime.getURL('hibernationPage/index.html'), true)
		xmlHttp.onload = function() {
			const html = xmlHttp.responseText
			sleepTab(html, tabs[0])
		}
		xmlHttp.send(null)
	})
})
<|endoftext|>


<commit_before>define([], function() {
   return TP_Server;
});

function TP_Server() {
   var self = this;

   // private vars
   var protocol = {
      request : {},
      response : {},
      struct : {},
      message : {},
      consts : {},
      reverseMap : {}
   };
   var requestCounter = 0;
   var requestContexts = {};
   var messageHandlers = [];
   var openHandlers = [];
   var closeHandlers = [];
   var socket;
   var simulator = null;
   var lastHeardFrom = 0;
   var lastSpokeTo = 0;

   // public interface
   self.forceLongPolling = false;
   self.commsLog = false;
   self.commsLogKeepAlives = false;
   self.register = register;
   self.registerConst = registerConst;
   self.addMessageHandler = addMessageHandler;
   self.send = send; // to any
   self.sendTo = sendTo;
   self.sendDirect = sendDirect;
   self.sendRequest = sendRequest;
   self.connect = connect;
   self.disconnect = disconnect;
   self.nameOf = nameOf;
   self.consts = protocol.consts;
   self.connected = false;
   self.polling = false;
   self.setSimulator = function(s) {
      simulator = s;
   };

   for (var i = 0; i < arguments.length; i++) {
      new arguments[i](self);
   }

   function register(type, contractName, structName, contractId, structId) {
      var map = protocol[type];
      var val = {
         contractId : contractId,
         structId : structId
      };
      map[contractName + "." + structName] = val;
      if (map[structName]) {
         map[structName] = 0;
      } else {
         map[structName] = val;
      }
      protocol.reverseMap["" + contractId + "." + structId] = contractName + "." + structName;
   }

   function registerConst(contractName, structName, constName, constValue) {
      var map = protocol["consts"];
      var o;
      if (structName != null && structName != "null") {
         o = map[contractName + "." + structName] || {};
         map[contractName + "." + structName] = o;
      } else {
         o = map[contractName] || {};
         map[contractName] = o;
      }
      o[constName] = constValue;
   }

   function consts(name) {
      return protocol["consts"][name];
   }

   function nameOf(arg1, arg2) {
      // call with either a single arg = object with _contractId and _structId
      // or with explicit contractId, structId
      var key;
      if (typeof arg2 !== 'undefined') {
         key = "" + arg1 + "." + arg2;
      } else {
         key = "" + arg1._contractId + "." + arg1._structId;
      }
      return protocol.reverseMap[key];
   }

   function addMessageHandler(message, handler) {
      var val = protocol.message[message];
      if (!val) {
         console.log("unknown message: " + message);
         return;
      }
      if (val === 0) {
         console.log("ambiguous message: " + message);
         return;
      }
      messageHandlers[val.contractId + "." + val.structId] = handler;
   }

   // sends to any available service for this request's contract
   function send(request, args, requestHandler) {
      sendTo(request, args, 0, requestHandler);
   }

   // sends direct to the other end of the connection
   function sendDirect(request, args, requestHandler) {
      sendTo(request, args, 1, requestHandler);
   }

   // sends to the passed in toId
   function sendTo(request, args, toId, requestHandler) {
      var val = protocol.request[request];
      if (!val) {
         console.log("unknown request: " + request);
         return;
      }
      if (val === 0) {
         console.log("ambiguous request: " + request);
         return;
      }
      return sendRequest(val.contractId, val.structId, args, toId, requestHandler);
   }

   // dispatch a request
   function sendRequest(contractId, structId, args, toId, requestHandler) {
      toId = typeof toId !== 'undefined' ? toId : 0;
      var requestId = requestCounter++;
      args._requestId = requestId;
      args._contractId = contractId;
      args._structId = structId;
      args._toId = toId;

      logRequest(args, toId);

      requestContexts[requestId] = {
         request : args,
         handler : requestHandler
      }

      if (simulator != null) {
         var resp = simulator.request(request, args, toId);
         var i;
         for (i = 0; i < resp.messages.length; i++) {
            var mess = resp.messages[i];
            handleMessage(mess);
         }
         handleResponse(resp.response);
      }

      if (self.polling) {
         lastSpokeTo = Date.now();
         sendRPC(args);
      } else {
         if (isConnected()) {
            var data = JSON.stringify(args, null, 3);
            if (data.length < 1024 * 128) {
               lastSpokeTo = Date.now();
               socket.send(data);
            } else {
               console.log("RPC too big : " + data.length + "\n" + data);
               handleResponse(makeError(requestId, 1)); // UNKNOWN
            }
         } else {
            handleResponse(makeError(requestId, 7)); // CONNECTION_CLOSED
         }
      }
   }

   function makeError(requestId, code) {
      return {
         _requestId : requestId,
         _contractId : 1,
         _structId : 1,
         errorCode : code
      }
   }

   function isConnected() {
      return (socket && socket.readyState == WebSocket.OPEN);
   }

   function connect(server, secure, port) {
      port = typeof port !== 'undefined' ? port : window.location.port;
      if (!window.WebSocket) {
         window.WebSocket = window.MozWebSocket;
      }

      // I suspect Safari 5.1 fails because it claims to have websockets but the implementation is only partial, so we detect the user agent and force it here
      // Mozilla/5.0 (iPad; CPU OS 5_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9B176 Safari/7534.48.3
      if (navigator.userAgent.indexOf("AppleWebKit") > 0 && navigator.userAgent.indexOf("Version/5.1") > 0) {
         self.forceLongPolling = true;
      }

      // fall back to long polling if we have no WebSocket support
      if (!window.WebSocket || self.forceLongPolling) {
         // have to long poll to same-origin
         return startPollingSession(window.location.hostname, secure);
      }

      if (simulator != null) {
         return {
            listen : function(onOpen, onClose) {
               onOpen();
            }
         }
      }

      // support for websocket spec 76 and make sure we're closed before unloading the page
      // or else we crash on iOS
      window.onbeforeunload = function() {
         closeHandlers = [];
         disconnect();
      };

      var url = (secure ? "wss:" : "ws:") + "//" + server + (port ? ":" + port : "") + "/sockets";
      console.log("Connecting to: " + url);
      socket = new WebSocket(url);
      socket.onopen = onSocketOpen;
      socket.onmessage = onSocketMessage;
      socket.onclose = onSocketClose;
      socket.onerror = onSocketError;
      return {
         listen : function(onOpen, onClose) {
            openHandlers = [];
            closeHandlers = [];
            openHandlers.push(onOpen);
            closeHandlers.push(onClose);
         }
      }
   }

   function disconnect() {
      if (socket) {
         commslog("Disconnecting... " + socket.readyState);
         var closeHack = (socket.readyState == WebSocket.CLOSING);
         if (closeHack) {
            // some sort of bug here when waking from sleep, it can take a very long long time
            // to transition from CLOSING to CLOSED and call our close handler, so we
            // take away the onclose handler and call it manually
            socket.onclose = null;
         }
         socket.close();
         commslog("socket.close() called: " + socket.readyState);
         if (closeHack) { // call onSocketClose manually
            onSocketClose();
         }
      }
   }

   function logResponse(result, req) {
      if (self.commsLog) {
         if (!isKeepAlive(req._contractId, req._structId) || self.commsLogKeepAlives) {
            var str = logstamp() + ' [' + result._requestId + '] <- ' + nameOf(result) + ' '
                  + JSON.stringify(result, dropUnderscored);
            if (result.isError()) {
               console.warn(str);
            } else {
               console.debug(str);
            }
         }
      }
   }

   function logRequest(req, toId) {
      if (self.commsLog) {
         if (!isKeepAlive(req._contractId, req._structId) || self.commsLogKeepAlives) {
            var toStr = toId == 0 ? " to any" : (toId == 1 ? " to direct" : " to " + toId);
            console.debug(logstamp() + ' [' + req._requestId + '] => ' + nameOf(req) + ' '
                  + JSON.stringify(req, dropUnderscored) + toStr);
         }
      }
   }

   function logMessage(result) {
      if (self.commsLog) {
         console.debug(logstamp() + ' [M:' + result._topicId + '] <- ' + nameOf(result) + ' '
               + JSON.stringify(result, dropUnderscored));
      }
   }

   function dropUnderscored(key, value) {
      if (typeof key == 'string' || key instanceof String) {
         if (key.indexOf("_") == 0)
            return undefined;
      }
      return value;
   }

   function handleResponse(result) {
      result.isError = function() {
         return result._contractId == 1 && result._structId == 1;
      };
      var ctx = requestContexts[result._requestId];

      logResponse(result, ctx.request);

      if (ctx.handler) {
         ctx.handler(result);
      }
      delete requestContexts[result._requestId];
   }

   function handleMessage(result) {
      logMessage(result);
      var func = messageHandlers[result._contractId + "." + result._structId];
      if (func) {
         func(result);
      }
   }

   // --- socket methods

   function onSocketOpen(event) {
      lastHeardFrom = Date.now();
      self.connected = true;
      commslog("[socket] open: " + socket.URL);
      var i, array = openHandlers;
      for (i = 0; i < array.length; i++)
         array[i]();

      self.keepAlive = setInterval(function() {
         var elapsedHeard = Date.now() - lastHeardFrom;
         var elapsedSpoke = Date.now() - lastSpokeTo;
         if (elapsedSpoke > 6000) {
            // this keep alive is a backup
            sendDirect("KeepAlive", {});
         }
         if (elapsedHeard > 6000) {
            commslog("We haven't heard from the server in " + elapsedHeard + " ms")
         }
         if (elapsedHeard > 20000) {
            disconnect();
         }
      }, 5000);

   }

   function onSocketClose(event) {
      self.connected = false;
      if (self.keepAlive != null) {
         clearInterval(self.keepAlive);
         self.keepAlive = null;
      }
      commslog("[socket] closed")
      var i, array = closeHandlers;
      for (i = 0; i < array.length; i++)
         array[i]();

      // terminate all pending requests (only if using websockets I think...)
      //      for ( var requestId in requestContexts) {
      //         handleResponse(7);
      //      }
   }

   function onSocketMessage(event) {
      lastHeardFrom = Date.now();
      var result = null;
      if (event.data.indexOf("{") == 0) {
         result = JSON.parse(event.data);
      } else {
         // TODO figure out how to communicate errors
         result = parseInt(event.data);
      }
      if (result._requestId != null) {
         handleResponse(result);
      } else if (result._topicId != null) {
         handleMessage(result);
      }
   }

   function pad(pad, str) {
      str = str.toString();
      while (str.length < pad) {
         str = '0' + str;
      }
      return str;
   }

   function logstamp() {
      var now = new Date();
      var p2 = '00';
      return pad(2, now.getHours()) + ':' + pad(2, now.getMinutes()) + ':' + pad(2, now.getSeconds()) + '.'
            + pad(3, now.getMilliseconds());
   }

   function commslog(msg) {
      if (self.commsLog)
         console.log(logstamp() + ' ' + msg);
   }

   function onSocketError(event) {
      commslog("[socket] error: " + JSON.stringify(event));
   }

   function isKeepAlive(contractId, structId) {
      return (contractId == 1 && structId == 5512920) || (contractId == 10 && structId == 15966706);
   }

   // ------------------------ long polling fall-back ----------------------------- //

   function startPollingSession(host, secure) {
      self.polling = true;
      self.pollPending = false;
      self.connected = true;
      self.entityInfo = null;
      lastHeardFrom = Date.now();
      commslog("[poller] open: " + host);
      return {
         listen : function(onOpen, onClose) {
            onOpen();
         }
      }
   }

   function sendRPC(data) {
      if (self.entityInfo != null) {
         data._token = self.entityInfo.token;
      }
      //console.debug("SEND RPC: " + JSON.stringify(data));
      $.ajax({
         type : "POST",
         url : "/poll",
         timeout : 24000,
         data : JSON.stringify(data),
         dataType : 'json',
         success : function(data) {
            self.connected = true;
            handleResponse(data);
            schedulePoll(100);
         },
         error : function(XMLHttpRequest, textStatus, errorThrown) {
            console.error(textStatus + " (" + errorThrown + ")");
            if (textStatus == 'timeout') {
               handleResponse(makeError(data._requestId, 3));
            } else {
               handleResponse(makeError(data._requestId, 1));
            }
            onSocketClose(); // do a fake socket close event
         }
      });
   }

   function schedulePoll(millis) {
      setTimeout(function() {
         poll()
      }, millis);
   }

   function poll() {
      if (!self.polling)
         return;
      if (self.entityInfo != null && self.entityInfo.entityId != 0) {
         if (self.pollPending == false) {
            var data = {
               _token : self.entityInfo.token
            };
            console.debug("POLL -> " + JSON.stringify(data));
            self.pollPending = true;
            $.ajax({
               type : "POST",
               url : "/poll",
               timeout : 12000,
               data : JSON.stringify(data),
               dataType : 'json',
               success : function(data) {
                  self.connected = true;
                  self.pollPending = false;
                  if (data.error) {
                     console.debug("POLL <- ERROR: " + data.error);
                     schedulePoll(1000);
                  } else {
                     console.debug("POLL <- " + data.messages.length + " items");
                     $.each(data.messages, function(i, m) {
                        handleMessage(m)
                     });
                     schedulePoll(100);
                  }
               },
               error : function(XMLHttpRequest, textStatus, errorThrown) {
                  console.error(textStatus + " (" + errorThrown + ")");
                  self.pollPending = false;
                  onSocketClose(); // fake socket close event
               }
            });
         }
      }
   }

}
<commit_msg>chrome is saying .URL is deprecated, use .url...<commit_after>define([], function() {
   return TP_Server;
});

function TP_Server() {
   var self = this;

   // private vars
   var protocol = {
      request : {},
      response : {},
      struct : {},
      message : {},
      consts : {},
      reverseMap : {}
   };
   var requestCounter = 0;
   var requestContexts = {};
   var messageHandlers = [];
   var openHandlers = [];
   var closeHandlers = [];
   var socket;
   var simulator = null;
   var lastHeardFrom = 0;
   var lastSpokeTo = 0;

   // public interface
   self.forceLongPolling = false;
   self.commsLog = false;
   self.commsLogKeepAlives = false;
   self.register = register;
   self.registerConst = registerConst;
   self.addMessageHandler = addMessageHandler;
   self.send = send; // to any
   self.sendTo = sendTo;
   self.sendDirect = sendDirect;
   self.sendRequest = sendRequest;
   self.connect = connect;
   self.disconnect = disconnect;
   self.nameOf = nameOf;
   self.consts = protocol.consts;
   self.connected = false;
   self.polling = false;
   self.setSimulator = function(s) {
      simulator = s;
   };

   for (var i = 0; i < arguments.length; i++) {
      new arguments[i](self);
   }

   function register(type, contractName, structName, contractId, structId) {
      var map = protocol[type];
      var val = {
         contractId : contractId,
         structId : structId
      };
      map[contractName + "." + structName] = val;
      if (map[structName]) {
         map[structName] = 0;
      } else {
         map[structName] = val;
      }
      protocol.reverseMap["" + contractId + "." + structId] = contractName + "." + structName;
   }

   function registerConst(contractName, structName, constName, constValue) {
      var map = protocol["consts"];
      var o;
      if (structName != null && structName != "null") {
         o = map[contractName + "." + structName] || {};
         map[contractName + "." + structName] = o;
      } else {
         o = map[contractName] || {};
         map[contractName] = o;
      }
      o[constName] = constValue;
   }

   function consts(name) {
      return protocol["consts"][name];
   }

   function nameOf(arg1, arg2) {
      // call with either a single arg = object with _contractId and _structId
      // or with explicit contractId, structId
      var key;
      if (typeof arg2 !== 'undefined') {
         key = "" + arg1 + "." + arg2;
      } else {
         key = "" + arg1._contractId + "." + arg1._structId;
      }
      return protocol.reverseMap[key];
   }

   function addMessageHandler(message, handler) {
      var val = protocol.message[message];
      if (!val) {
         console.log("unknown message: " + message);
         return;
      }
      if (val === 0) {
         console.log("ambiguous message: " + message);
         return;
      }
      messageHandlers[val.contractId + "." + val.structId] = handler;
   }

   // sends to any available service for this request's contract
   function send(request, args, requestHandler) {
      sendTo(request, args, 0, requestHandler);
   }

   // sends direct to the other end of the connection
   function sendDirect(request, args, requestHandler) {
      sendTo(request, args, 1, requestHandler);
   }

   // sends to the passed in toId
   function sendTo(request, args, toId, requestHandler) {
      var val = protocol.request[request];
      if (!val) {
         console.log("unknown request: " + request);
         return;
      }
      if (val === 0) {
         console.log("ambiguous request: " + request);
         return;
      }
      return sendRequest(val.contractId, val.structId, args, toId, requestHandler);
   }

   // dispatch a request
   function sendRequest(contractId, structId, args, toId, requestHandler) {
      toId = typeof toId !== 'undefined' ? toId : 0;
      var requestId = requestCounter++;
      args._requestId = requestId;
      args._contractId = contractId;
      args._structId = structId;
      args._toId = toId;

      logRequest(args, toId);

      requestContexts[requestId] = {
         request : args,
         handler : requestHandler
      }

      if (simulator != null) {
         var resp = simulator.request(request, args, toId);
         var i;
         for (i = 0; i < resp.messages.length; i++) {
            var mess = resp.messages[i];
            handleMessage(mess);
         }
         handleResponse(resp.response);
      }

      if (self.polling) {
         lastSpokeTo = Date.now();
         sendRPC(args);
      } else {
         if (isConnected()) {
            var data = JSON.stringify(args, null, 3);
            if (data.length < 1024 * 128) {
               lastSpokeTo = Date.now();
               socket.send(data);
            } else {
               console.log("RPC too big : " + data.length + "\n" + data);
               handleResponse(makeError(requestId, 1)); // UNKNOWN
            }
         } else {
            handleResponse(makeError(requestId, 7)); // CONNECTION_CLOSED
         }
      }
   }

   function makeError(requestId, code) {
      return {
         _requestId : requestId,
         _contractId : 1,
         _structId : 1,
         errorCode : code
      }
   }

   function isConnected() {
      return (socket && socket.readyState == WebSocket.OPEN);
   }

   function connect(server, secure, port) {
      port = typeof port !== 'undefined' ? port : window.location.port;
      if (!window.WebSocket) {
         window.WebSocket = window.MozWebSocket;
      }

      // I suspect Safari 5.1 fails because it claims to have websockets but the implementation is only partial, so we detect the user agent and force it here
      // Mozilla/5.0 (iPad; CPU OS 5_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9B176 Safari/7534.48.3
      if (navigator.userAgent.indexOf("AppleWebKit") > 0 && navigator.userAgent.indexOf("Version/5.1") > 0) {
         self.forceLongPolling = true;
      }

      // fall back to long polling if we have no WebSocket support
      if (!window.WebSocket || self.forceLongPolling) {
         // have to long poll to same-origin
         return startPollingSession(window.location.hostname, secure);
      }

      if (simulator != null) {
         return {
            listen : function(onOpen, onClose) {
               onOpen();
            }
         }
      }

      // support for websocket spec 76 and make sure we're closed before unloading the page
      // or else we crash on iOS
      window.onbeforeunload = function() {
         closeHandlers = [];
         disconnect();
      };

      var url = (secure ? "wss:" : "ws:") + "//" + server + (port ? ":" + port : "") + "/sockets";
      console.log("Connecting to: " + url);
      socket = new WebSocket(url);
      socket.onopen = onSocketOpen;
      socket.onmessage = onSocketMessage;
      socket.onclose = onSocketClose;
      socket.onerror = onSocketError;
      return {
         listen : function(onOpen, onClose) {
            openHandlers = [];
            closeHandlers = [];
            openHandlers.push(onOpen);
            closeHandlers.push(onClose);
         }
      }
   }

   function disconnect() {
      if (socket) {
         commslog("Disconnecting... " + socket.readyState);
         var closeHack = (socket.readyState == WebSocket.CLOSING);
         if (closeHack) {
            // some sort of bug here when waking from sleep, it can take a very long long time
            // to transition from CLOSING to CLOSED and call our close handler, so we
            // take away the onclose handler and call it manually
            socket.onclose = null;
         }
         socket.close();
         commslog("socket.close() called: " + socket.readyState);
         if (closeHack) { // call onSocketClose manually
            onSocketClose();
         }
      }
   }

   function logResponse(result, req) {
      if (self.commsLog) {
         if (!isKeepAlive(req._contractId, req._structId) || self.commsLogKeepAlives) {
            var str = logstamp() + ' [' + result._requestId + '] <- ' + nameOf(result) + ' '
                  + JSON.stringify(result, dropUnderscored);
            if (result.isError()) {
               console.warn(str);
            } else {
               console.debug(str);
            }
         }
      }
   }

   function logRequest(req, toId) {
      if (self.commsLog) {
         if (!isKeepAlive(req._contractId, req._structId) || self.commsLogKeepAlives) {
            var toStr = toId == 0 ? " to any" : (toId == 1 ? " to direct" : " to " + toId);
            console.debug(logstamp() + ' [' + req._requestId + '] => ' + nameOf(req) + ' '
                  + JSON.stringify(req, dropUnderscored) + toStr);
         }
      }
   }

   function logMessage(result) {
      if (self.commsLog) {
         console.debug(logstamp() + ' [M:' + result._topicId + '] <- ' + nameOf(result) + ' '
               + JSON.stringify(result, dropUnderscored));
      }
   }

   function dropUnderscored(key, value) {
      if (typeof key == 'string' || key instanceof String) {
         if (key.indexOf("_") == 0)
            return undefined;
      }
      return value;
   }

   function handleResponse(result) {
      result.isError = function() {
         return result._contractId == 1 && result._structId == 1;
      };
      var ctx = requestContexts[result._requestId];

      logResponse(result, ctx.request);

      if (ctx.handler) {
         ctx.handler(result);
      }
      delete requestContexts[result._requestId];
   }

   function handleMessage(result) {
      logMessage(result);
      var func = messageHandlers[result._contractId + "." + result._structId];
      if (func) {
         func(result);
      }
   }

   // --- socket methods

   function onSocketOpen(event) {
      lastHeardFrom = Date.now();
      self.connected = true;
      commslog("[socket] open: " + socket.url);
      var i, array = openHandlers;
      for (i = 0; i < array.length; i++)
         array[i]();

      self.keepAlive = setInterval(function() {
         var elapsedHeard = Date.now() - lastHeardFrom;
         var elapsedSpoke = Date.now() - lastSpokeTo;
         if (elapsedSpoke > 6000) {
            // this keep alive is a backup
            sendDirect("KeepAlive", {});
         }
         if (elapsedHeard > 6000) {
            commslog("We haven't heard from the server in " + elapsedHeard + " ms")
         }
         if (elapsedHeard > 20000) {
            disconnect();
         }
      }, 5000);

   }

   function onSocketClose(event) {
      self.connected = false;
      if (self.keepAlive != null) {
         clearInterval(self.keepAlive);
         self.keepAlive = null;
      }
      commslog("[socket] closed")
      var i, array = closeHandlers;
      for (i = 0; i < array.length; i++)
         array[i]();

      // terminate all pending requests (only if using websockets I think...)
      //      for ( var requestId in requestContexts) {
      //         handleResponse(7);
      //      }
   }

   function onSocketMessage(event) {
      lastHeardFrom = Date.now();
      var result = null;
      if (event.data.indexOf("{") == 0) {
         result = JSON.parse(event.data);
      } else {
         // TODO figure out how to communicate errors
         result = parseInt(event.data);
      }
      if (result._requestId != null) {
         handleResponse(result);
      } else if (result._topicId != null) {
         handleMessage(result);
      }
   }

   function pad(pad, str) {
      str = str.toString();
      while (str.length < pad) {
         str = '0' + str;
      }
      return str;
   }

   function logstamp() {
      var now = new Date();
      var p2 = '00';
      return pad(2, now.getHours()) + ':' + pad(2, now.getMinutes()) + ':' + pad(2, now.getSeconds()) + '.'
            + pad(3, now.getMilliseconds());
   }

   function commslog(msg) {
      if (self.commsLog)
         console.log(logstamp() + ' ' + msg);
   }

   function onSocketError(event) {
      commslog("[socket] error: " + JSON.stringify(event));
   }

   function isKeepAlive(contractId, structId) {
      return (contractId == 1 && structId == 5512920) || (contractId == 10 && structId == 15966706);
   }

   // ------------------------ long polling fall-back ----------------------------- //

   function startPollingSession(host, secure) {
      self.polling = true;
      self.pollPending = false;
      self.connected = true;
      self.entityInfo = null;
      lastHeardFrom = Date.now();
      commslog("[poller] open: " + host);
      return {
         listen : function(onOpen, onClose) {
            onOpen();
         }
      }
   }

   function sendRPC(data) {
      if (self.entityInfo != null) {
         data._token = self.entityInfo.token;
      }
      //console.debug("SEND RPC: " + JSON.stringify(data));
      $.ajax({
         type : "POST",
         url : "/poll",
         timeout : 24000,
         data : JSON.stringify(data),
         dataType : 'json',
         success : function(data) {
            self.connected = true;
            handleResponse(data);
            schedulePoll(100);
         },
         error : function(XMLHttpRequest, textStatus, errorThrown) {
            console.error(textStatus + " (" + errorThrown + ")");
            if (textStatus == 'timeout') {
               handleResponse(makeError(data._requestId, 3));
            } else {
               handleResponse(makeError(data._requestId, 1));
            }
            onSocketClose(); // do a fake socket close event
         }
      });
   }

   function schedulePoll(millis) {
      setTimeout(function() {
         poll()
      }, millis);
   }

   function poll() {
      if (!self.polling)
         return;
      if (self.entityInfo != null && self.entityInfo.entityId != 0) {
         if (self.pollPending == false) {
            var data = {
               _token : self.entityInfo.token
            };
            console.debug("POLL -> " + JSON.stringify(data));
            self.pollPending = true;
            $.ajax({
               type : "POST",
               url : "/poll",
               timeout : 12000,
               data : JSON.stringify(data),
               dataType : 'json',
               success : function(data) {
                  self.connected = true;
                  self.pollPending = false;
                  if (data.error) {
                     console.debug("POLL <- ERROR: " + data.error);
                     schedulePoll(1000);
                  } else {
                     console.debug("POLL <- " + data.messages.length + " items");
                     $.each(data.messages, function(i, m) {
                        handleMessage(m)
                     });
                     schedulePoll(100);
                  }
               },
               error : function(XMLHttpRequest, textStatus, errorThrown) {
                  console.error(textStatus + " (" + errorThrown + ")");
                  self.pollPending = false;
                  onSocketClose(); // fake socket close event
               }
            });
         }
      }
   }

}
<|endoftext|>


<commit_before>/* Experimental: a new Option for the display of era.
	Character set is UTF-8
This is an experimental method for DateTimeFormat.
It uses an extra Boolean option, "exceptCurrentEra"
If the option is set or missing, era is displayed as required following resolved .era option, but only if era of date is not era of today.
That is, if date is in same era as today, the era part is not displayed.
Versions
	M2020-03-12 Initial version
		Version note: at this time, for most calendar era is displayed even if .era is not set.
Contents
	Intl.DateTimeFormat.prototype.conditionalEraFormat : : return a string with date and time, according to DateTimeFormat, but hidding era if necessary.
Required:
	Intl object
*/
/* Copyright Miletus 2020 - Louis A. de Fouquières
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sub-license, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
	1. The above copyright notice and this permission notice shall be included
	in all copies or substantial portions of the Software.
	2. Changes with respect to any former version shall be documented.

The software is provided "as is", without warranty of any kind,
express of implied, including but not limited to the warranties of
merchantability, fitness for a particular purpose and non infringement.
In no event shall the authors of copyright holders be liable for any
claim, damages or other liability, whether in an action of contract,
tort or otherwise, arising from, out of or in connection with the software
or the use or other dealings in the software.
Inquiries: www.calendriermilesien.org
*/
"use strict";
/** @description a .format method that issues a string representing a Japanese calendar date.
 * @param {Date object} myDate - the date to display, like for standard Intl.DateTimeFormat.format method.
 * @param (Boolean) exceptCurrentEra - if set, then era shall not be displayed if it is the same as today's date.
 * @returns {string} the date following the Unicode options, except for the display of era.
*/
Intl.DateTimeFormat.prototype.conditionalEraFormat = function (myDate, exceptCurrentEra = true) {
	var
		myOptions = this.resolvedOptions();
	if (exceptCurrentEra && myOptions.era != null) {
		let
			myComponents = this.formatToParts(myDate),
			todaysComponents = this.formatToParts(new Date());
		for (let i = 0; i <  myComponents.length; i++) {
			if (myComponents[i].type == "era" && myComponents[i].value == todaysComponents[i].value) delete myOptions.era;
		}
		return new Intl.DateTimeFormat(myOptions.locale, myOptions).format(myDate)
	} else return this.format(myDate);
}
<commit_msg>eraDisplay option<commit_after>/* Experimental: a new Option for the display of era.
	Character set is UTF-8
This is an experimental method for DateTimeFormat.
It uses an extra Boolean option, "exceptCurrentEra"
If the option is set or missing, era is displayed as required following resolved .era option, but only if era of date is not era of today.
That is, if date is in same era as today, the era part is not displayed.
Versions
	M2020-03-12 Initial version
		Version note: at this time, for most calendar era is displayed even if .era is not set.
	M2020-10-06
		In this version, we delete the era part, since deleting the era option is not sufficient
Contents
	Intl.DateTimeFormat.prototype.conditionalEraFormat : : return a string with date and time, according to DateTimeFormat, but hidding era if necessary.
Required:
	Intl object
*/
/* Copyright Miletus 2020 - Louis A. de Fouquières
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sub-license, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
	1. The above copyright notice and this permission notice shall be included
	in all copies or substantial portions of the Software.
	2. Changes with respect to any former version shall be documented.

The software is provided "as is", without warranty of any kind,
express of implied, including but not limited to the warranties of
merchantability, fitness for a particular purpose and non infringement.
In no event shall the authors of copyright holders be liable for any
claim, damages or other liability, whether in an action of contract,
tort or otherwise, arising from, out of or in connection with the software
or the use or other dealings in the software.
Inquiries: www.calendriermilesien.org
*/
"use strict";
/** @description a .format method with an experimental eraDisplay option
 * @param {Date object} myDate - the date to display, like for standard Intl.DateTimeFormat.format method.
 * @param (string) eraDisplay - "never": era not displayed; "always": era displayed (short by default), "past": era displayed only if different from today's date.
 * @returns {string} the date following the Unicode options, except for the display of era.
*/
Intl.DateTimeFormat.prototype.conditionalEraFormat = function (myDate, eraDisplay = "past") {
	var
		myOptions = this.resolvedOptions();
	if (eraDisplay == "past") {
		let testingOptions = Object.create(myOptions);
		testingOptions.era = "short"; // force era option
		let eraFormat = new Intl.DateTimeFormat( testingOptions.locale, testingOptions),
			myComponents = eraFormat.formatToParts (myDate),
			todaysComponents = eraFormat.formatToParts (new Date());
		for (let i = 0; i <  myComponents.length; i++) {
			if (myComponents[i].type == "era") eraDisplay = (myComponents[i].value == todaysComponents[i].value ? "never" : "always");
		}
	}
	switch (eraDisplay) {
		case "never" : delete myOptions.era ; break;
		case "always" : if (myOptions.era == undefined) myOptions.era = "short"; break;
	} // nothing done if other value

	// return new Intl.DateTimeFormat(myOptions.locale, myOptions).format(myDate) // this would works if undefined 'era' would protect from displaying era
	let myDateParts = new Intl.DateTimeFormat(myOptions.locale, myOptions).formatToParts(myDate).map ( ({type, value}) => {
		switch (type) {
			case "era" : return (eraDisplay == "always" ? {type:type, value: value} : {type:type, value: ""}); // we have to insist...
			default : return {type: type, value: value};
		}
	}) // end of mapping function
	return myDateParts.map(({type, value}) => {return value;}).reduce((buf, part)=> buf + part, "");
	// End of section replacing return new Intl.DateTimeFormat(myOptions.locale, myOptions).format(myDate)
}
<|endoftext|>


<commit_before>/*!
Cloud4all Preferences Management Tools

Copyright 2013 Astea

Licensed under the New BSD license. You may not use this file except in
compliance with this License.

You may obtain a copy of the License at
https://github.com/GPII/prefsEditors/LICENSE.txt
*/

(function ($, fluid) {
    fluid.defaults("gpii.prefsEditor", {
        gradeNames: ["fluid.prefs.GPIIEditor", "autoInit"],
        prefsEditor: {
            gradeNames: ["fluid.prefs.stringBundle"],
            members: {
                messageResolver: "{prefsEditorLoader}.msgBundle"
            },
            events: {
                onLogin: null,
                onLogout: null,
                onSaveClicked: null,
                onRequestPageTransition: null,
                onSettingChanged: null
            },
            model: {
                userLoggedIn: false
            },
            listeners: {
                "onReady.setATTRsaveButton": {
                    "this": "{that}.dom.saveButton",
                    "method": "attr",
                    "args": ["value", "{that}.stringBundle.saveAndApplyText"]
                },
                "onReady.bindSaveAndApplyClick": {
                    "this": "{that}.dom.saveAndApply",
                    "method": "click",
                    "args": ["{that}.events.onSaveClicked.fire"]
                },
                "onSaveClicked.saveSettings": {
                    // currently this triggers a save,
                    // which logs in and out to apply the settings.
                    "listener": "{that}.saveSettings"
                },
                "onSaveClicked.hideSaveButton": {
                    "this": "{that}.dom.saveAndApply",
                    "method": "hide",
                    "args": []
                },
                "onReady.fullEditorLink": {
                    "this": "{that}.dom.fullEditorLink",
                    "method": "click",
                    "args": ["{that}.events.onRequestPageTransition.fire"]
                },
                "onRequestPageTransition.save": "{that}.saveSettings",
                "onRequestPageTransition.goToPMT": {
                    "funcName": "fluid.set",
                    "args": [window, "location.href", "{prefsEditorLoader}.options.pmtUrl"]
                },
                "onLogin.setUserLoggedIn": {
                    listener: "{that}.applier.requestChange",
                    args: ["userLoggedIn", true]
                },
                "onLogin.showSaveMessage": {
                    "this": "{that}.dom.messageLineLabel",
                    "method": "text",
                    "args": ["{that}.stringBundle.preferencesModified"]
                },
                "onLogin.showUserStatusBar": {
                    "listener": "{that}.showUserStatusBar"
                },
                "onReset.triggerLogoutEvent": {
                    "listener": "{that}.events.onLogout.fire"
                },
                "onLogout.setUserLoggedIn": {
                    listener: "{that}.applier.requestChange",
                    args: ["userLoggedIn", false]
                },
                "onLogout.clearMessage": {
                    "this": "{that}.dom.messageLineLabel",
                    "method": "text",
                    "args": [""]
                },
                "onLogout.gpiiLogout": {
                    listener: "{gpiiSession}.logout"
                },
                "onReady.setSaveAndApplyButtonText": {
                    "this": "{that}.dom.saveAndApplyButtonLabel",
                    "method": "attr",
                    "args": ["value", "{that}.stringBundle.saveAndApplyText"]
                },
                "onReady.setFullEditorLinkText": {
                    "this": "{that}.dom.fullEditorLink",
                    "method": "text",
                    "args": ["{that}.stringBundle.fullEditorText"]
                },
                "onReady.setLogoutLinkText": {
                    "this": "{that}.dom.logoutLink",
                    "method": "text",
                    "args": ["{that}.stringBundle.logoutText"]
                },
                "onReady.bindLogout": {
                    "this": "{that}.dom.logoutLink",
                    "method": "click",
                    "args": ["{that}.events.onLogout.fire"]
                },
                "onReady.addModelChangedListener": {
                    "listener": "{that}.applier.modelChanged.addListener",
                    "args": ["", "{that}.events.onSettingChanged.fire"]
                },
                "onSettingChanged.showSaveButton": {
                    "this": "{that}.dom.saveAndApply",
                    "method": "show",
                    "args": []
                }
            },
            invokers: {
                applySettings: {
                    "funcName": "gpii.applySettings",
                    "args": "{that}"
                },
                showUserStatusBar: {
                    "this": "{that}.dom.userStatusBar",
                    "method": "slideDown"
                },
                saveSettings: {
                    "func": "{gpiiStore}.set",
                    "args": "{that}.model",
                    "dynamic": true
                }
            },
            selectors: {
                saveAndApply: ".flc-prefsEditor-save",
                saveAndApplyButtonLabel: ".flc-prefsEditor-save",
                messageLineLabel: ".gpiic-prefsEditor-messageLine",
                fullEditorLink: ".gpiic-prefsEditor-fullEditorLink",
                logoutLink: ".gpiic-prefsEditor-userLogoutLink"
            },
            selectorsToIgnore: ["saveAndApply"]
        }
    });

    gpii.applySettings = function (that) {
        var savedSettings = that.modelTransform(that.model);
        if (that.socket) {
            that.socket.emit("message", savedSettings, fluid.log);
        } else {
            that.socket = that.socket || io.connect("http://localhost:8081/update");
            that.socket.on("connect", function () {
                that.socket.emit("message", savedSettings, fluid.log);
            });
            fluid.each(["error", "disconnect"], function (event) {
                that.socket.on(event, function (data) {
                    fluid.log(data);
                    that.socket.disconnect();
                    delete that.socket;
                });
            });
        }
    };

    gpii.prefsEditor.triggerEvent = function (that, targetSelector, event) {
        that.locate(targetSelector).trigger(event);
    };
})(jQuery, fluid);
<commit_msg>GPII-669: Listener for any setting changed moved to 'modelListeners: {...}'.<commit_after>/*!
Cloud4all Preferences Management Tools

Copyright 2013 Astea

Licensed under the New BSD license. You may not use this file except in
compliance with this License.

You may obtain a copy of the License at
https://github.com/GPII/prefsEditors/LICENSE.txt
*/

(function ($, fluid) {
    fluid.defaults("gpii.prefsEditor", {
        gradeNames: ["fluid.prefs.GPIIEditor", "autoInit"],
        prefsEditor: {
            gradeNames: ["fluid.prefs.stringBundle"],
            members: {
                messageResolver: "{prefsEditorLoader}.msgBundle"
            },
            events: {
                onLogin: null,
                onLogout: null,
                onSaveClicked: null,
                onRequestPageTransition: null,
                onSettingChanged: null
            },
            model: {
                userLoggedIn: false
            },
            modelListeners: {
                "*": "{that}.events.onSettingChanged.fire"
            },
            listeners: {
                "onReady.setATTRsaveButton": {
                    "this": "{that}.dom.saveButton",
                    "method": "attr",
                    "args": ["value", "{that}.stringBundle.saveAndApplyText"]
                },
                "onReady.bindSaveAndApplyClick": {
                    "this": "{that}.dom.saveAndApply",
                    "method": "click",
                    "args": ["{that}.events.onSaveClicked.fire"]
                },
                "onSaveClicked.saveSettings": {
                    // currently this triggers a save,
                    // which logs in and out to apply the settings.
                    "listener": "{that}.saveSettings"
                },
                "onSaveClicked.hideSaveButton": {
                    "this": "{that}.dom.saveAndApply",
                    "method": "hide",
                    "args": []
                },
                "onReady.fullEditorLink": {
                    "this": "{that}.dom.fullEditorLink",
                    "method": "click",
                    "args": ["{that}.events.onRequestPageTransition.fire"]
                },
                "onRequestPageTransition.save": "{that}.saveSettings",
                "onRequestPageTransition.goToPMT": {
                    "funcName": "fluid.set",
                    "args": [window, "location.href", "{prefsEditorLoader}.options.pmtUrl"]
                },
                "onLogin.setUserLoggedIn": {
                    listener: "{that}.applier.requestChange",
                    args: ["userLoggedIn", true]
                },
                "onLogin.showSaveMessage": {
                    "this": "{that}.dom.messageLineLabel",
                    "method": "text",
                    "args": ["{that}.stringBundle.preferencesModified"]
                },
                "onLogin.showUserStatusBar": {
                    "listener": "{that}.showUserStatusBar"
                },
                "onReset.triggerLogoutEvent": {
                    "listener": "{that}.events.onLogout.fire"
                },
                "onLogout.setUserLoggedIn": {
                    listener: "{that}.applier.requestChange",
                    args: ["userLoggedIn", false]
                },
                "onLogout.clearMessage": {
                    "this": "{that}.dom.messageLineLabel",
                    "method": "text",
                    "args": [""]
                },
                "onLogout.gpiiLogout": {
                    listener: "{gpiiSession}.logout"
                },
                "onReady.setSaveAndApplyButtonText": {
                    "this": "{that}.dom.saveAndApplyButtonLabel",
                    "method": "attr",
                    "args": ["value", "{that}.stringBundle.saveAndApplyText"]
                },
                "onReady.setFullEditorLinkText": {
                    "this": "{that}.dom.fullEditorLink",
                    "method": "text",
                    "args": ["{that}.stringBundle.fullEditorText"]
                },
                "onReady.setLogoutLinkText": {
                    "this": "{that}.dom.logoutLink",
                    "method": "text",
                    "args": ["{that}.stringBundle.logoutText"]
                },
                "onReady.bindLogout": {
                    "this": "{that}.dom.logoutLink",
                    "method": "click",
                    "args": ["{that}.events.onLogout.fire"]
                },
                "onSettingChanged.showSaveButton": {
                    "this": "{that}.dom.saveAndApply",
                    "method": "show",
                    "args": []
                }
            },
            invokers: {
                applySettings: {
                    "funcName": "gpii.applySettings",
                    "args": "{that}"
                },
                showUserStatusBar: {
                    "this": "{that}.dom.userStatusBar",
                    "method": "slideDown"
                },
                saveSettings: {
                    "func": "{gpiiStore}.set",
                    "args": "{that}.model",
                    "dynamic": true
                }
            },
            selectors: {
                saveAndApply: ".flc-prefsEditor-save",
                saveAndApplyButtonLabel: ".flc-prefsEditor-save",
                messageLineLabel: ".gpiic-prefsEditor-messageLine",
                fullEditorLink: ".gpiic-prefsEditor-fullEditorLink",
                logoutLink: ".gpiic-prefsEditor-userLogoutLink"
            },
            selectorsToIgnore: ["saveAndApply"]
        }
    });

    gpii.applySettings = function (that) {
        var savedSettings = that.modelTransform(that.model);
        if (that.socket) {
            that.socket.emit("message", savedSettings, fluid.log);
        } else {
            that.socket = that.socket || io.connect("http://localhost:8081/update");
            that.socket.on("connect", function () {
                that.socket.emit("message", savedSettings, fluid.log);
            });
            fluid.each(["error", "disconnect"], function (event) {
                that.socket.on(event, function (data) {
                    fluid.log(data);
                    that.socket.disconnect();
                    delete that.socket;
                });
            });
        }
    };

    gpii.prefsEditor.triggerEvent = function (that, targetSelector, event) {
        that.locate(targetSelector).trigger(event);
    };
})(jQuery, fluid);
<|endoftext|>


<commit_before>Mongo.Collection.prototype.helpers = function(helpers) {
  var self = this;

  if (self._transform && ! self._helpers)
    throw new Meteor.Error("Can't apply helpers to '" +
      self._name + "' a transform function already exists!");

  if (! self._helpers) {
      self._helpers = function Document(doc) {
          console.log(this);
      };
      self._helpers._nest = function (tree, currentLevel) {
          for (var node in tree) {
              if (typeof tree[node] === "function") {
                  // we expect tree leaves to be helper functions
                  currentLevel[node] = tree[node];
              } else {
                  if (!currentLevel[node]) {
                      console.error("Cannot navigate past node " + node + " it does not exist.");
                      return;
                  }
                  if (!tree[node].$ && !currentLevel[node]) {
                      console.error(["Property " + node + " does not exist.", tree, currentLevel]);
                      return;
                  }
                  if (node.indexOf("$") !== -1) {
                      console.error("$ must be preceded by an array");
                      return;
                  }
                  if (tree[node].$) {
                      for (var i = 0; i < currentLevel[node].length; i++) {
                          self._helpers._nest(tree[node].$, currentLevel[node][i]);
                      }
                  } else {
                      self._helpers._nest(tree[node], currentLevel[node]);
                  }
              }
           }
        };
    self._transform = function(doc) {
      return new self._helpers(doc);
    };
  }

  _.each(helpers, function (helper, key) {
      var path = key.split(".");
      if (path.length === 1) {
          // key is root
          if (self._helpers.prototype[key]) {
              console.error("Cannot add helper at" + key + ". Helpers cannot override existing properties");
              return;
          }
          self._helpers.prototype[key] = helper;
          return;
      } else {
          // key is nested
          self._helpers._nestedHelperTree = self._helpers._nestedHelperTree || {};
          var tree = self._helpers._nestedHelperTree;
          for (var i = 0; i < path.length; i++) {
              if (i === path.length - 1) {
                  if (tree[path[i]]) {
                      console.error("Cannot add helper at" + key + ". Helper already defined");
                      return;
                  } else {
                      tree[path[i]] = helper;
                  }
              } else {
                  if (!tree[path[i]]) {
                      tree[path[i]] = {};
                  }
                  tree = tree[path[i]];
              }
          }
      }
  });
};
<commit_msg>Attach the helpers on transform<commit_after>Mongo.Collection.prototype.helpers = function(helpers) {
  var self = this;

  if (self._transform && ! self._helpers)
    throw new Meteor.Error("Can't apply helpers to '" +
      self._name + "' a transform function already exists!");

  if (! self._helpers) {
      self._helpers = function Document(doc) {
          _.extend(this, doc);
          self._helpers._nest(self._helpers._nestedHelperTree, this);
          return this;
      };
      self._helpers._nest = function (tree, currentLevel) {
          for (var node in tree) {
              if (typeof tree[node] === "function") {
                  // we expect tree leaves to be helper functions
                  currentLevel[node] = tree[node];
              } else {
                  if (!currentLevel[node]) {
                      console.error("Cannot navigate past node " + node + " it does not exist.");
                      return;
                  }
                  if (!tree[node].$ && !currentLevel[node]) {
                      console.error(["Property " + node + " does not exist.", tree, currentLevel]);
                      return;
                  }
                  if (node.indexOf("$") !== -1) {
                      console.error("$ must be preceded by an array");
                      return;
                  }
                  if (tree[node].$) {
                      for (var i = 0; i < currentLevel[node].length; i++) {
                          self._helpers._nest(tree[node].$, currentLevel[node][i]);
                      }
                  } else {
                      self._helpers._nest(tree[node], currentLevel[node]);
                  }
              }
           }
        };
    self._transform = function(doc) {
      return new self._helpers(doc);
    };
  }

  _.each(helpers, function (helper, key) {
      var path = key.split(".");
      if (path.length === 1) {
          // key is root
          if (self._helpers.prototype[key]) {
              console.error("Cannot add helper at" + key + ". Helpers cannot override existing properties");
              return;
          }
          self._helpers.prototype[key] = helper;
          return;
      } else {
          // key is nested
          self._helpers._nestedHelperTree = self._helpers._nestedHelperTree || {};
          var tree = self._helpers._nestedHelperTree;
          for (var i = 0; i < path.length; i++) {
              if (i === path.length - 1) {
                  if (tree[path[i]]) {
                      console.error("Cannot add helper at" + key + ". Helper already defined");
                      return;
                  } else {
                      tree[path[i]] = helper;
                  }
              } else {
                  if (!tree[path[i]]) {
                      tree[path[i]] = {};
                  }
                  tree = tree[path[i]];
              }
          }
      }
  });
};
<|endoftext|>


<commit_before>import React, { Component } from 'react'
import Draggable from 'react-draggable'

import Icon from '../narrative/icon'

const noop = () => {}

export default class DraggableWindow extends Component {
  render () {
    const {children, draggableProps, header, style} = this.props
    const GREY_BORDER = '#777 1.3px solid'
    return (
      <Draggable
        handle='.handle'
        {...draggableProps}
        // axis='x'
        // grid={[25, 25]}
        // scale={1}
        // FIXME: Update position in store on drag?
        // onStart={this.handleStart}
        // onDrag={this.handleDrag}
        // onStop={this.handleStop}
      >

            <button
              onClick={this.props.onClickClose}
              className='clear-button-formatting pull-right'>
              <Icon type='times' />
            </button>
            {header}

            {children}

      </Draggable>
    )
  }
}

DraggableWindow.defaultProps = {
  onClickClose: noop
}
<commit_msg>refactor(draggable-window): fix draggable handle margins<commit_after>import React, { Component } from 'react'
import Draggable from 'react-draggable'

import Icon from '../narrative/icon'

const noop = () => {}

export default class DraggableWindow extends Component {
  render () {
    const {children, draggableProps, header, style} = this.props
    const GREY_BORDER = '#777 1.3px solid'
    return (
      <Draggable
        handle='.handle'
        {...draggableProps}
        // axis='x'
        // grid={[25, 25]}
        // scale={1}
        // FIXME: Update position in store on drag?
        // onStart={this.handleStart}
        // onDrag={this.handleDrag}
        // onStop={this.handleStop}
      >

            <button
              onClick={this.props.onClickClose}
              className='clear-button-formatting pull-right'>
              <Icon type='times' />
            </button>
            {header}

            {children}

      </Draggable>
    )
  }
}

DraggableWindow.defaultProps = {
  onClickClose: noop
}
<|endoftext|>


<commit_before>if (window.characters == null) {
    window.characters = {};
}

(function (characters) {
    characters.CHARACTER_NAME_HERE = {
        summary: {
            name: "",
            fullName: "",
            title: "",
            hitPoints: 0,
            maxCombo: 0,
            attackDefaults: {
                speedOffset: 0.2
            },
            throwDefaults: {
                speedOffset: 0.2,
                damage: 6,
                comboPts: 0,
                comboType: "Starter",
                kd: true
            },
            attacks: [2, 3, 4, 5, 6, "J", "Q", "K", "A"],
            throws: [6, 7, 8, 9, "T"],
            blocks: [7, 8, 9, "T"],
            dodges: [2, 3, 4, 5],
            innateAbilities: [
                {
                    name: "",
                    text: ""
                }
            ],
            cardAbilities: [
                {
                    rank: 7,
                    name: "",
                    timing: "",
                    text: ""
                }
            ]
        },
        attacks: [
            {
                speed: "",
                rank: "",
                name: "",
                pumpWith: "",
                damage: "",
                pump: "",
                chip: "",
                comboPts: 1,
                comboType: "Starter",
                kd: false,
                maxCombo: "",
                maxDamage: "",
                goodCombo: "",
                goodDamage: "",
                notes: ""
            }
        ],
        throws: [
            {
                speed: "",
                rank: "",
                pumpWith: "",
                damage: "",
                pump: "",
                maxCombo: "",
                maxDamage: "",
                goodCombo: "",
                goodDamage: "",
                notes: ""
            }
        ]
    }
})(window.characters);
<commit_msg>Clean up the template<commit_after>if (window.characters == null) {
    window.characters = {};
}

(function (characters) {
    characters.CHARACTER_NAME_HERE = {
        summary: {
            name: "",
            fullName: "",
            title: "",
            hitPoints: 0,
            maxCombo: 0,
            attackDefaults: {
                speedOffset: 0.2
            },
            throwDefaults: {
                speedOffset: 0.2,
                damage: 6,
                comboPts: 0,
                comboType: "Starter",
                kd: true
            },
            attacks: [2, 3, 4, 5, 6, "J", "Q", "K", "A"],
            throws: [6, 7, 8, 9, "T"],
            blocks: [7, 8, 9, "T"],
            dodges: [2, 3, 4, 5],
            innateAbilities: [
                {
                    name: "",
                    text: ""
                }
            ],
            cardAbilities: [
                {
                    rank: 7,
                    name: "",
                    timing: "",
                    text: ""
                },
                {
                    rank: "T",
                    name: "",
                    timing: "",
                    text: ""
                }
            ]
        },
        attacks: [
            {
                speed: 0, rank: "", name: "", pumpWith: "",
                damage: "", pump: "", chip: "", comboPts: 1, comboType: "Starter", kd: false,
                maxCombo: "", maxDamage: "", goodCombo: "", goodDamage: "", notes: ""
            }
        ],
        throws: [
            {
                speed: "",
                rank: "",
                pumpWith: "",
                damage: "",
                pump: "",
                maxCombo: "",
                maxDamage: "",
                goodCombo: "",
                goodDamage: "",
                notes: ""
            }
        ]
    }
})(window.characters);
<|endoftext|>