<commit_before>/*
 * vim: ts=4:sw=4:expandtab
 */

(function () {
    'use strict';
    window.Whisper             = window.Whisper             || {};
    window.Whisper.Database    = window.Whisper.Database    || {};
    window.Whisper.Database.id = window.Whisper.Database.id || 'signal';
    window.Whisper.Database.nolog = true;

    Whisper.Database.migrations = [
        {
            version: "1.0",
            migrate: function(transaction, next) {
                console.log('migration 1.0');
                console.log('creating object stores');
                var messages = transaction.db.createObjectStore("messages");
                messages.createIndex("conversation", ["conversationId", "received_at"], { unique: false });
                messages.createIndex("receipt", "sent_at", { unique: false });

                var conversations = transaction.db.createObjectStore("conversations");
                conversations.createIndex("inbox", "active_at", { unique: false });
                conversations.createIndex("group", "members", { unique: false, multiEntry: true });
                conversations.createIndex("type", "type", { unique: false });

                var groups = transaction.db.createObjectStore('groups');

                var sessions = transaction.db.createObjectStore('sessions');
                var identityKeys = transaction.db.createObjectStore('identityKeys');

                var preKeys = transaction.db.createObjectStore("preKeys");
                var signedPreKeys = transaction.db.createObjectStore("signedPreKeys");

                var items = transaction.db.createObjectStore("items");
                next();
            }
        },
        {
            version: "2.0",
            migrate: function(transaction, next) {
                console.log('migration 2.0');
                var conversations = transaction.objectStore("conversations");
                conversations.createIndex("search", "tokens", { unique: false, multiEntry: true });

                window.addEventListener('storage_ready', function() {
                    console.log('migrating search tokens');
                    var all = new Whisper.ConversationCollection();
                    all.fetch().then(function() {
                        all.each(function(model) {
                            model.updateTokens();
                            model.save();
                        });
                    });
                });
                next();
            }
        },
        {
            version: "3.0",
            migrate: function(transaction, next) {
                console.log('migration 3.0');
                var conversations = transaction.objectStore("items");

                window.addEventListener('storage_ready', function() {
                    console.log('migrating unread count');
                    var all = new Whisper.ConversationCollection();
                    all.fetch().then(function() {
                        var unreadCount = all.reduce(function(total, model) {
                            var count = model.get('unreadCount');
                            if (count === undefined) {
                                count = 0;
                            }
                            return total + count;
                        }, 0);
                        storage.remove('unreadCount');
                        storage.put('unreadCount', unreadCount);
                    });
                });
                next();
            }
        },
        {
            version: "4.0",
            migrate: function(transaction, next) {
                console.log('migration 4.0');
                window.addEventListener('storage_ready', function() {
                    console.log('migrating search tokens');
                    var all = new Whisper.ConversationCollection();
                    all.fetch().then(function() {
                        all.each(function(c) {
                            c.updateTokens();
                            c.save();
                        });
                    });
                });
                next();
            }
        },
        {
            version: "5.0",
            migrate: function(transaction, next) {
                console.log('migration 5.0');
                window.addEventListener('storage_ready', function() {
                    console.log('migrating registration flags');
                    if (storage.get("chromiumRegistrationDone") === "") {
                        storage.put("chromiumRegistrationDoneEver", "");
                    }
                });
                next();
            }
        },
        {
            version: "6.0",
            migrate: function(transaction, next) {
                console.log('migration 6.0');
                window.addEventListener('storage_ready', function() {
                    console.log('migrating registration flags');
                    storage.onready(function() {
                        if (storage.get("chromiumRegistrationDone") === "") {
                            storage.put("chromiumRegistrationDoneEver", "");
                            next();
                        }
                    });
                });
                next();
            }
        },
        {
            version: "7.0",
            migrate: function(transaction, next) {
                console.log('migration 7.0');
                console.log('creating debug log');
                transaction.db.createObjectStore("debug");
                next();
            }
        },
        {
            version: "8.0",
            migrate: function(transaction, next) {
                console.log('migration 8.0');
                console.log('creating unread message index');
                var conversations = transaction.objectStore('messages');
                conversations.createIndex('unread', ['conversationId', 'unread'], { unique: false });
                next();
            }
        },
        {
            version: "9.0",
            migrate: function(transaction, next) {
                console.log('migration 9.0');
                window.addEventListener('storage_ready', function() {
                    console.log('marking contacts and groups active');
                    var all = new Whisper.ConversationCollection();
                    var myNumber = textsecure.storage.user.getNumber();
                    all.fetch().then(function() {
                        var inactive = all.filter(function(model) {
                            return !model.get('active_at') && model.id !== myNumber;
                        });
                        inactive.sort(function(m1, m2) {
                            var title1 = m1.getTitle().toLowerCase();
                            var title2 = m2.getTitle().toLowerCase();
                            if (title1 ===  title2) {
                                return 0;
                            }
                            if (title1 < title2) {
                                return -1;
                            }
                            if (title1 > title2) {
                                return 1;
                            }
                        });
                        inactive.forEach(function(model) {
                            if (model.isPrivate() || !model.get('left')) {
                                model.save({ active_at: 1 });
                            }
                        });
                    });
                });
                next();
            }
        },
        {
            version: "10.0",
            migrate: function(transaction, next) {
                console.log('migration 10.0');
                console.log('creating expiring message index');
                var messages = transaction.objectStore('messages');
                messages.createIndex('expire', 'expireTimer', { unique: false });
                next();
            }
        },
        {
            version: "11.0",
            migrate: function(transaction, next) {
                console.log('migration 11.0');
                console.log('creating expires_at message index');
                var messages = transaction.objectStore('messages');
                messages.createIndex('expires_at', 'expires_at', { unique: false });
                next();
            }
        }
    ];
}());
<commit_msg>Add migration to clean up old expiring messages<commit_after>/*
 * vim: ts=4:sw=4:expandtab
 */

(function () {
    'use strict';
    window.Whisper             = window.Whisper             || {};
    window.Whisper.Database    = window.Whisper.Database    || {};
    window.Whisper.Database.id = window.Whisper.Database.id || 'signal';
    window.Whisper.Database.nolog = true;

    Whisper.Database.migrations = [
        {
            version: "1.0",
            migrate: function(transaction, next) {
                console.log('migration 1.0');
                console.log('creating object stores');
                var messages = transaction.db.createObjectStore("messages");
                messages.createIndex("conversation", ["conversationId", "received_at"], { unique: false });
                messages.createIndex("receipt", "sent_at", { unique: false });

                var conversations = transaction.db.createObjectStore("conversations");
                conversations.createIndex("inbox", "active_at", { unique: false });
                conversations.createIndex("group", "members", { unique: false, multiEntry: true });
                conversations.createIndex("type", "type", { unique: false });

                var groups = transaction.db.createObjectStore('groups');

                var sessions = transaction.db.createObjectStore('sessions');
                var identityKeys = transaction.db.createObjectStore('identityKeys');

                var preKeys = transaction.db.createObjectStore("preKeys");
                var signedPreKeys = transaction.db.createObjectStore("signedPreKeys");

                var items = transaction.db.createObjectStore("items");
                next();
            }
        },
        {
            version: "2.0",
            migrate: function(transaction, next) {
                console.log('migration 2.0');
                var conversations = transaction.objectStore("conversations");
                conversations.createIndex("search", "tokens", { unique: false, multiEntry: true });

                window.addEventListener('storage_ready', function() {
                    console.log('migrating search tokens');
                    var all = new Whisper.ConversationCollection();
                    all.fetch().then(function() {
                        all.each(function(model) {
                            model.updateTokens();
                            model.save();
                        });
                    });
                });
                next();
            }
        },
        {
            version: "3.0",
            migrate: function(transaction, next) {
                console.log('migration 3.0');
                var conversations = transaction.objectStore("items");

                window.addEventListener('storage_ready', function() {
                    console.log('migrating unread count');
                    var all = new Whisper.ConversationCollection();
                    all.fetch().then(function() {
                        var unreadCount = all.reduce(function(total, model) {
                            var count = model.get('unreadCount');
                            if (count === undefined) {
                                count = 0;
                            }
                            return total + count;
                        }, 0);
                        storage.remove('unreadCount');
                        storage.put('unreadCount', unreadCount);
                    });
                });
                next();
            }
        },
        {
            version: "4.0",
            migrate: function(transaction, next) {
                console.log('migration 4.0');
                window.addEventListener('storage_ready', function() {
                    console.log('migrating search tokens');
                    var all = new Whisper.ConversationCollection();
                    all.fetch().then(function() {
                        all.each(function(c) {
                            c.updateTokens();
                            c.save();
                        });
                    });
                });
                next();
            }
        },
        {
            version: "5.0",
            migrate: function(transaction, next) {
                console.log('migration 5.0');
                window.addEventListener('storage_ready', function() {
                    console.log('migrating registration flags');
                    if (storage.get("chromiumRegistrationDone") === "") {
                        storage.put("chromiumRegistrationDoneEver", "");
                    }
                });
                next();
            }
        },
        {
            version: "6.0",
            migrate: function(transaction, next) {
                console.log('migration 6.0');
                window.addEventListener('storage_ready', function() {
                    console.log('migrating registration flags');
                    storage.onready(function() {
                        if (storage.get("chromiumRegistrationDone") === "") {
                            storage.put("chromiumRegistrationDoneEver", "");
                            next();
                        }
                    });
                });
                next();
            }
        },
        {
            version: "7.0",
            migrate: function(transaction, next) {
                console.log('migration 7.0');
                console.log('creating debug log');
                transaction.db.createObjectStore("debug");
                next();
            }
        },
        {
            version: "8.0",
            migrate: function(transaction, next) {
                console.log('migration 8.0');
                console.log('creating unread message index');
                var conversations = transaction.objectStore('messages');
                conversations.createIndex('unread', ['conversationId', 'unread'], { unique: false });
                next();
            }
        },
        {
            version: "9.0",
            migrate: function(transaction, next) {
                console.log('migration 9.0');
                window.addEventListener('storage_ready', function() {
                    console.log('marking contacts and groups active');
                    var all = new Whisper.ConversationCollection();
                    var myNumber = textsecure.storage.user.getNumber();
                    all.fetch().then(function() {
                        var inactive = all.filter(function(model) {
                            return !model.get('active_at') && model.id !== myNumber;
                        });
                        inactive.sort(function(m1, m2) {
                            var title1 = m1.getTitle().toLowerCase();
                            var title2 = m2.getTitle().toLowerCase();
                            if (title1 ===  title2) {
                                return 0;
                            }
                            if (title1 < title2) {
                                return -1;
                            }
                            if (title1 > title2) {
                                return 1;
                            }
                        });
                        inactive.forEach(function(model) {
                            if (model.isPrivate() || !model.get('left')) {
                                model.save({ active_at: 1 });
                            }
                        });
                    });
                });
                next();
            }
        },
        {
            version: "10.0",
            migrate: function(transaction, next) {
                console.log('migration 10.0');
                console.log('creating expiring message index');
                var messages = transaction.objectStore('messages');
                messages.createIndex('expire', 'expireTimer', { unique: false });
                next();
            }
        },
        {
            version: "11.0",
            migrate: function(transaction, next) {
                console.log('migration 11.0');
                console.log('creating expires_at message index');
                var messages = transaction.objectStore('messages');
                messages.createIndex('expires_at', 'expires_at', { unique: false });
                next();
            }
        },
        {
            version: "12.0",
            migrate: function(transaction, next) {
                console.log('migration 12.0');
                console.log('cleaning up expiring messages with no expires_at');
                var messages = transaction.objectStore('messages');
                window.addEventListener('storage_ready', function() {
                    var messages = new Whisper.MessageCollection();
                    messages.fetch({
                      conditions: {expireTimer: {$gt: 0}},
                      addIndividually: true
                    });
                    messages.on('add', function(m) {
                      messages.remove(m);
                    });
                });
                next();
            }
        }
    ];
}());
<|endoftext|>


<commit_before>/**
 * Villa Distinct v0.8.0 (http://getvilla.org/)
 * Copyright 2013-2015 Noibe Developers
 * Licensed under MIT (https://github.com/noibe/villa/blob/master/LICENSE)
 */

+function ($) {
	'use strict';

	/* Constructor of distinct functions */
	$.fn.distinct = function (options, events) {

		var settings = $.extend({
			action: false,
			attrName: false,
			content: false,
			doDistinct: true,
			plusOne: false,
			prefix: false,
			selfAction: false,
			target: 'body',
			touchEvents: true
		}, options);

		var currentIndex;

		// Convert selfActions Object to Array
		// Happens when the user put a single object on selfAction var
		if (typeof settings.selfAction == 'object') {
			var self = settings.selfAction;
			settings.selfAction = Array();
			settings.selfAction.push(self);
		}

		// Add Touch and Mouse Listeners to elements
		this.each(function() {
			if (settings.touchEvents) {
				this.addEventListener('touchstart', handleController, false);
			}

			this.addEventListener('click', handleController, false);
		});

		// Handle Controller (start the actions with the listeners (touch or mouse))
		function handleController(evt) {

			evt.preventDefault();

			// Get the Index of element
			currentIndex = $(this).index();

			/* TODO - Remove Class */
			/* TODO - Add class */

			// Test if exists some self action
			if (settings.selfAction) selfAction(this);

			if (settings.action) {
				if (settings.plusOne) settings.action(currentIndex + 1);
				else settings.action(currentIndex);
			}

			if (settings.doDistinct) {
				doDistinct(this);
			}

		}

		// Self Action Controller
		function selfAction(el) {

			// init the self array
			var self = Array();

			// Find a index number at selfAction array and put on array 'self'
			// Obs: test for a fastest method to loop the array using the 'l' var
			for (var i = settings.selfAction.length; --i;) {

				// Internal Loop to pass in all index of SelfAction Array
				for (var j = 0; j < settings.selfAction[i].index.length; j++) {

					// Test if the current index is in some selfAction Object
					if (settings.selfAction[i].index[j] == currentIndex) {
						// Put the founded object to self array
						self.push(settings.selfAction[i]);
					}

				}

			}

			// Execute or not the rules declared on selfAction
			for (var i = 0; i < self.length; i++) {
				// Test if will pass the element (this) parameter
				// at function (self.action)
				if (self[i].passParam) {
					if (settings.plusOne) self[i].action(currentIndex + 1);
					else self[i].action(currentIndex);
				} else self[i].action();
			}

		}

		function doDistinct(el) {

			// Init var 'value'
			var prefix, value;

			// Get value based on currentIndex
			value = currentIndex;
			if (settings.plusOne) value++;

			// Update prefix based on classPrefix var of Settings Object
			if (settings.prefix) prefix = settings.prefix;
			else prefix = el.className;

			// Update value based on classPrefix var of Settings Object
			value = prefix + '-' + value;

			if (settings.attrName && settings.attrName != 'class') {
				$(settings.target).attr(settings.attrName, value);
			} else {
				// Remove class with prefix
				$(settings.target).removeClassLike(prefix);

				// Add new class based on value
				$(settings.target).addClass(value);
			}

		}

	}

}(jQuery);

/* external funcs */

// Return position (x or y) of element
function getPosition(element) {
	var xPosition = 0;
	var yPosition = 0;

	while (element) {
		xPosition += (element.offsetLeft - element.scrollLeft + element.clientLeft);
		yPosition += (element.offsetTop - element.scrollTop + element.clientTop);
		element = element.offsetParent;
	}
	return {x: xPosition, y: yPosition};
}

// get scroll position from top
function getScrollTop() {
	if (typeof pageYOffset != 'undefined') {
		//most browsers except IE before #9
		return pageYOffset;
	}
	else {
		var B = document.body; //IE 'quirks'
		var D = document.documentElement; //IE with doctype
		D = (D.clientHeight) ? D : B;
		return D.scrollTop;
	}
}

// removes class with prefix
jQuery.fn.removeClassLike = function (prefix) {
	if (this.attr("class")) {
		var classes = this.attr("class").split(" ").filter(function (c) {
			return c.lastIndexOf(prefix, 0) !== 0;
		});
		return this.attr("class", classes.join(" "));
	}
}<commit_msg>Create JS Append Found a bug at DistinctJS (just fixed)<commit_after>/**
 * Villa Distinct v0.9.0 (http://getvilla.org/)
 * Copyright 2013-2015 Noibe Developers
 * Licensed under MIT (https://github.com/noibe/villa/blob/master/LICENSE)
 */

+function ($) {
	'use strict';

	/* Constructor of distinct functions */
	$.fn.distinct = function (options, events) {

		var settings = $.extend({
			action: false,
			attrName: false,
			content: false,
			doDistinct: true,
			plusOne: false,
			prefix: false,
			selfAction: false,
			target: 'body',
			touchEvents: true
		}, options);

		var currentIndex;

		// Convert selfActions Object to Array
		// Happens when the user put a single object on selfAction var
		if (typeof settings.selfAction == 'object') {
			var self = settings.selfAction;
			settings.selfAction = Array();
			settings.selfAction.push(self);
		}

		// Add Touch and Mouse Listeners to elements
		this.each(function() {
			if (settings.touchEvents) {
				this.addEventListener('touchstart', handleController, false);
			}

			this.addEventListener('click', handleController, false);
		});

		// Handle Controller (start the actions with the listeners (touch or mouse))
		function handleController(evt) {

			evt.preventDefault();

			// Get the Index of element
			currentIndex = $(this).index();

			/* TODO - Remove Class */
			/* TODO - Add class */

			// Test if exists some self action
			if (settings.selfAction) selfAction(this);

			if (settings.action) {
				if (settings.plusOne) settings.action(currentIndex + 1);
				else settings.action(currentIndex);
			}

			if (settings.doDistinct) {
				doDistinct(this);
			}

		}

		// Self Action Controller
		function selfAction(el) {

			// init the self array
			var self = Array();

			// Find a index number at selfAction array and put on array 'self'
			// Obs: test for a fastest method to loop the array using the 'l' var
			for (var i = settings.selfAction.length; i--;) {

				// Internal Loop to pass in all index of SelfAction Array
				for (var j = 0; j < settings.selfAction[i].index.length; j++) {

					// Test if the current index is in some selfAction Object
					if (settings.selfAction[i].index[j] == currentIndex) {
						// Put the founded object to self array
						self.push(settings.selfAction[i]);
					}

				}

			}

			// Execute or not the rules declared on selfAction
			for (var i = 0; i < self.length; i++) {
				// Test if will pass the element (this) parameter
				// at function (self.action)
				if (self[i].passParam) {
					if (settings.plusOne) self[i].action(currentIndex + 1);
					else self[i].action(currentIndex);
				} else self[i].action();
			}

		}

		function doDistinct(el) {

			// Init var 'value'
			var prefix, value;

			// Get value based on currentIndex
			value = currentIndex;
			if (settings.plusOne) value++;

			// Update prefix based on classPrefix var of Settings Object
			if (settings.prefix) prefix = settings.prefix;
			else prefix = el.className;

			// Update value based on classPrefix var of Settings Object
			value = prefix + '-' + value;

			if (settings.attrName && settings.attrName != 'class') {
				$(settings.target).attr(settings.attrName, value);
			} else {
				// Remove class with prefix
				$(settings.target).removeClassLike(prefix);

				// Add new class based on value
				$(settings.target).addClass(value);
			}

		}

	}

}(jQuery);

/* external funcs */

// Return position (x or y) of element
function getPosition(element) {
	var xPosition = 0;
	var yPosition = 0;

	while (element) {
		xPosition += (element.offsetLeft - element.scrollLeft + element.clientLeft);
		yPosition += (element.offsetTop - element.scrollTop + element.clientTop);
		element = element.offsetParent;
	}
	return {x: xPosition, y: yPosition};
}

// get scroll position from top
function getScrollTop() {
	if (typeof pageYOffset != 'undefined') {
		//most browsers except IE before #9
		return pageYOffset;
	}
	else {
		var B = document.body; //IE 'quirks'
		var D = document.documentElement; //IE with doctype
		D = (D.clientHeight) ? D : B;
		return D.scrollTop;
	}
}

// removes class with prefix
jQuery.fn.removeClassLike = function (prefix) {
	if (this.attr("class")) {
		var classes = this.attr("class").split(" ").filter(function (c) {
			return c.lastIndexOf(prefix, 0) !== 0;
		});
		return this.attr("class", classes.join(" "));
	}
}<|endoftext|>


<commit_before>(function ($) {

  // Add posibility to scroll to selected option
  // usefull for select for example
  $.fn.scrollTo = function(elem) {
    $(this).scrollTop($(this).scrollTop() - $(this).offset().top + $(elem).offset().top);
    return this;
  };

  $.fn.dropdown = function (option) {
    var defaults = {
      inDuration: 300,
      outDuration: 225,
      constrain_width: true, // Constrains width of dropdown to the activator
      hover: false,
      gutter: 0, // Spacing from edge
      belowOrigin: false,
      alignment: 'left'
    };

    this.each(function(){
    var origin = $(this);
    var options = $.extend({}, defaults, option);

    // Dropdown menu
    var activates = $("#"+ origin.attr('data-activates'));

    function updateOptions() {
      if (origin.data('induration') !== undefined)
        options.inDuration = origin.data('inDuration');
      if (origin.data('outduration') !== undefined)
        options.outDuration = origin.data('outDuration');
      if (origin.data('constrainwidth') !== undefined)
        options.constrain_width = origin.data('constrainwidth');
      if (origin.data('hover') !== undefined)
        options.hover = origin.data('hover');
      if (origin.data('gutter') !== undefined)
        options.gutter = origin.data('gutter');
      if (origin.data('beloworigin') !== undefined)
        options.belowOrigin = origin.data('beloworigin');
      if (origin.data('alignment') !== undefined)
        options.alignment = origin.data('alignment');
    }

    updateOptions();

    // Attach dropdown to its activator
    origin.after(activates);

    /*
      Helper function to position and resize dropdown.
      Used in hover and click handler.
    */
    function placeDropdown() {
      // Check html data attributes
      updateOptions();

      // Set Dropdown state
      activates.addClass('active');

      // Constrain width
      if (options.constrain_width === true) {
        activates.css('width', origin.outerWidth());
      }
      var offset = 0;
      if (options.belowOrigin === true) {
        offset = origin.height();
      }

      // Handle edge alignment
      var offsetLeft = origin.offset().left;
      if (options.alignment === 'left') {
        var width_difference = 0;
        var gutter_spacing = options.gutter;

        if (offsetLeft + activates.innerWidth() > $(window).width()) {
          width_difference = origin.innerWidth() - activates.innerWidth();
          gutter_spacing *= -1;
        }

        // Position dropdown
        activates.css({
          position: 'absolute',
          top: origin.position().top + offset,
          left: origin.position().left + width_difference + gutter_spacing
        });
      } else if (options.alignment === 'right') {
        var offsetRight = $(window).width() - offsetLeft - origin.innerWidth();
        var width_difference = 0;
        var gutter_spacing = options.gutter;

        if (offsetRight + activates.innerWidth() > $(window).width()) {
          gutter_spacing *= -1;
        }

        // Position dropdown
        activates.css({
          position: 'absolute',
          top: origin.position().top + offset,
          right: ( $(window).width() - origin.position().left - origin.innerWidth() ) + gutter_spacing
        });
      }

      // Show dropdown
      activates.stop(true, true).css('opacity', 0)
        .slideDown({
        queue: false,
        duration: options.inDuration,
        easing: 'easeOutCubic',
        complete: function() {
          $(this).css('height', '');
        }
      })
        .animate( {opacity: 1}, {queue: false, duration: options.inDuration, easing: 'easeOutSine'});
    }

    function hideDropdown() {
      activates.fadeOut(options.outDuration);
      activates.removeClass('active');
    }

    // Hover
    if (options.hover) {
      var open = false;
      origin.unbind('click.' + origin.attr('id'));
      // Hover handler to show dropdown
      origin.on('mouseenter', function(e){ // Mouse over
        if (open === false) {
          placeDropdown();
          open = true;
        }
      });
      origin.on('mouseleave', function(e){
        // If hover on origin then to something other than dropdown content, then close
        var toEl = e.toElement || e.relatedTarget; // added browser compatibility for target element
        if(!$(toEl).closest('.dropdown-content').is(activates)) {
          activates.stop(true, true);
          hideDropdown();
          open = false;
        }
      });

      activates.on('mouseleave', function(e){ // Mouse out
        var toEl = e.toElement || e.relatedTarget;
        if(!$(toEl).closest('.dropdown-button').is(origin)) {
          activates.stop(true, true);
          hideDropdown();
          open = false;
        }
      });

    // Click
    } else {

      // Click handler to show dropdown
      origin.unbind('click.' + origin.attr('id'));
      origin.bind('click.'+origin.attr('id'), function(e){

        if ( origin[0] == e.currentTarget && ($(e.target).closest('.dropdown-content').length === 0) ) {
          e.preventDefault(); // Prevents button click from moving window
          placeDropdown();

        }
        // If origin is clicked and menu is open, close menu
        else {
          if (origin.hasClass('active')) {
            hideDropdown();
            $(document).unbind('click.' + activates.attr('id'));
          }
        }
        // If menu open, add click close handler to document
        if (activates.hasClass('active')) {
          $(document).bind('click.'+ activates.attr('id'), function (e) {
            if (!activates.is(e.target) && !origin.is(e.target) && (!origin.find(e.target).length > 0) ) {
              hideDropdown();
              $(document).unbind('click.' + activates.attr('id'));
            }
          });
        }
      });

    } // End else

    // Listen to open and close event - useful for select component
    origin.on('open', placeDropdown);
    origin.on('close', hideDropdown);

   });
  }; // End dropdown plugin

  $(document).ready(function(){
    $('.dropdown-button').dropdown();
  });
}( jQuery ));
<commit_msg>RHS-aligned dropdowns obey gutter even when overflowing.<commit_after>(function ($) {

  // Add posibility to scroll to selected option
  // usefull for select for example
  $.fn.scrollTo = function(elem) {
    $(this).scrollTop($(this).scrollTop() - $(this).offset().top + $(elem).offset().top);
    return this;
  };

  $.fn.dropdown = function (option) {
    var defaults = {
      inDuration: 300,
      outDuration: 225,
      constrain_width: true, // Constrains width of dropdown to the activator
      hover: false,
      gutter: 0, // Spacing from edge
      belowOrigin: false,
      alignment: 'left'
    };

    this.each(function(){
    var origin = $(this);
    var options = $.extend({}, defaults, option);

    // Dropdown menu
    var activates = $("#"+ origin.attr('data-activates'));

    function updateOptions() {
      if (origin.data('induration') !== undefined)
        options.inDuration = origin.data('inDuration');
      if (origin.data('outduration') !== undefined)
        options.outDuration = origin.data('outDuration');
      if (origin.data('constrainwidth') !== undefined)
        options.constrain_width = origin.data('constrainwidth');
      if (origin.data('hover') !== undefined)
        options.hover = origin.data('hover');
      if (origin.data('gutter') !== undefined)
        options.gutter = origin.data('gutter');
      if (origin.data('beloworigin') !== undefined)
        options.belowOrigin = origin.data('beloworigin');
      if (origin.data('alignment') !== undefined)
        options.alignment = origin.data('alignment');
    }

    updateOptions();

    // Attach dropdown to its activator
    origin.after(activates);

    /*
      Helper function to position and resize dropdown.
      Used in hover and click handler.
    */
    function placeDropdown() {
      // Check html data attributes
      updateOptions();

      // Set Dropdown state
      activates.addClass('active');

      // Constrain width
      if (options.constrain_width === true) {
        activates.css('width', origin.outerWidth());
      }
      var offset = 0;
      if (options.belowOrigin === true) {
        offset = origin.height();
      }

      // Handle edge alignment
      var offsetLeft = origin.offset().left;
      if (options.alignment === 'left') {
        var width_difference = 0;
        var gutter_spacing = options.gutter;

        if (offsetLeft + activates.innerWidth() > $(window).width()) {
          width_difference = origin.innerWidth() - activates.innerWidth();
          gutter_spacing *= -1;
        }

        // Position dropdown
        activates.css({
          position: 'absolute',
          top: origin.position().top + offset,
          left: origin.position().left + width_difference + gutter_spacing
        });
      } else if (options.alignment === 'right') {
        var offsetRight = $(window).width() - offsetLeft - origin.innerWidth();
        var width_difference = 0;
        var gutter_spacing = options.gutter;

        // Position dropdown
        activates.css({
          position: 'absolute',
          top: origin.position().top + offset,
          right: ( $(window).width() - origin.position().left - origin.innerWidth() ) + gutter_spacing
        });
      }

      // Show dropdown
      activates.stop(true, true).css('opacity', 0)
        .slideDown({
        queue: false,
        duration: options.inDuration,
        easing: 'easeOutCubic',
        complete: function() {
          $(this).css('height', '');
        }
      })
        .animate( {opacity: 1}, {queue: false, duration: options.inDuration, easing: 'easeOutSine'});
    }

    function hideDropdown() {
      activates.fadeOut(options.outDuration);
      activates.removeClass('active');
    }

    // Hover
    if (options.hover) {
      var open = false;
      origin.unbind('click.' + origin.attr('id'));
      // Hover handler to show dropdown
      origin.on('mouseenter', function(e){ // Mouse over
        if (open === false) {
          placeDropdown();
          open = true;
        }
      });
      origin.on('mouseleave', function(e){
        // If hover on origin then to something other than dropdown content, then close
        var toEl = e.toElement || e.relatedTarget; // added browser compatibility for target element
        if(!$(toEl).closest('.dropdown-content').is(activates)) {
          activates.stop(true, true);
          hideDropdown();
          open = false;
        }
      });

      activates.on('mouseleave', function(e){ // Mouse out
        var toEl = e.toElement || e.relatedTarget;
        if(!$(toEl).closest('.dropdown-button').is(origin)) {
          activates.stop(true, true);
          hideDropdown();
          open = false;
        }
      });

    // Click
    } else {

      // Click handler to show dropdown
      origin.unbind('click.' + origin.attr('id'));
      origin.bind('click.'+origin.attr('id'), function(e){

        if ( origin[0] == e.currentTarget && ($(e.target).closest('.dropdown-content').length === 0) ) {
          e.preventDefault(); // Prevents button click from moving window
          placeDropdown();

        }
        // If origin is clicked and menu is open, close menu
        else {
          if (origin.hasClass('active')) {
            hideDropdown();
            $(document).unbind('click.' + activates.attr('id'));
          }
        }
        // If menu open, add click close handler to document
        if (activates.hasClass('active')) {
          $(document).bind('click.'+ activates.attr('id'), function (e) {
            if (!activates.is(e.target) && !origin.is(e.target) && (!origin.find(e.target).length > 0) ) {
              hideDropdown();
              $(document).unbind('click.' + activates.attr('id'));
            }
          });
        }
      });

    } // End else

    // Listen to open and close event - useful for select component
    origin.on('open', placeDropdown);
    origin.on('close', hideDropdown);

   });
  }; // End dropdown plugin

  $(document).ready(function(){
    $('.dropdown-button').dropdown();
  });
}( jQuery ));
<|endoftext|>


<commit_before>// This file is required by the index.html file and will
// be executed in the renderer process for that window.
// All of the Node.js APIs are available in this process.

//var fs = require('fs'); // Load the File System to execute our common tasks (CRUD)
//var elect = require('electron');

const electron = require('electron');
const {remote} = electron;
const {dialog, BrowserWindow} = remote;
const fs = require('fs');

/*const //remote = require('remote'),
      app2 = remote.require('app');*/
var app = require('electron').remote;

//const appPath = process.env.NODE_ENV === 'production' ? remote.app.getAppPath() : __dirname
const basepath=process.env.NODE_ENV === 'production' ? remote.app.getAppPath() : __dirname;
//
var basepathDATA="";

var path = require('path');
path.join(__dirname, 'templates');
/*
path.join(__dirname, 'userData');
//console.log("#",path);
//console.log("#",path.normalize(basepathDATA));
*/
var	basepathTEMPLATES=basepath+"/templates/";
	basepathTEMPLATES=path.normalize(basepathTEMPLATES);
var datafileendung='.json';

var eleWin;

var AppBridge=function(){
	//var path = dialog.showOpenDialog({properties: ['openDirectory']});
	//console.log("elect",electron,fs);
	//console.log("elect",remote.systemPreferences);
	///console.log("elect",remote.process.resourcesPath);
	//console.log("basepath:",basepath);//"D:\elektron\PROSTd_lokal"

	//console.log("elect",{properties: ['openDirectory']});
	//console.log("elect",remote.process.platform);//win32
	//console.log("elect",remote.process.title);//C:\WINDOWS\system32\cmd.exe - electron   . //s
	//console.log(elect);
	//readFile(path+"optionen.txt");

	var projekttemplate={
			"id":"$ID",
			"titel":"$TITEL",
			"isnew":true,
			"info":{
				"isended":false,
				"auftraggeber":"",
				"projektleiter":"",
				"startdatum":"$HEUTE",
				"enddatum":"",
				"status":"",
				"projektart":[],
				"gruppe":[]
			},
			"stunden":[]
		};

	var refunction=undefined;
	var zurl="";
		//exists
		//mkdir
		//readdir

	var readFile=function(filepath){
		if(fs.existsSync(filepath)){
			fs.readFile(
				filepath,
				'utf-8',
				function (err, data) {
					var redata={};
					var sstatus="OK";
//console.log(filepath,data);
					if(err){
					  //alert("An error ocurred reading the file :" + err.message);
					  console.log("!!Error",err.message);
					  var dataERR={"user":"lokal",
								"lastaction":zurl,
								"status":"404:notfound",
								"dat":err.message};
					  sstatus="404:notfound";
					};

					if(zurl=="getoptionen"){
						if(sstatus=="404:notfound"){
							redata.dat="{\"tabaktiv\":0}";
							sstatus="OK";
						}
						redata={
							"user":"lokal",
							"dat":JSON.parse(data) ,
							"lastaction":zurl,
							"status":sstatus
						};

					}else
					if(zurl=="projektdata"){
						redata=JSON.parse(data);
					}

					if(refunction!=undefined)refunction(JSON.stringify(redata));
					//console.log(sstatus,zurl, data,refunction);

				}
			);
		}
		else{
			var dataERR={"user":"lokal",
								"lastaction":zurl,
								"status":"404:notfound",
								"dat":""};
			if(zurl=="getoptionen"){
				dataERR.dat={"tabaktiv":0};
				dataERR.status="OK";
				}

			console.log("ERROR:filenotexist",JSON.stringify(dataERR));
			if(refunction!=undefined)refunction(JSON.stringify(dataERR));
		}

	};

	var addStundeneintrag=function(id,stddata){
		var i,st,handlingstatus="";
		var filepath=basepathDATA+id+datafileendung;
		var redat={"user":"lokal",
					"id":id,
					"handlingstatus":"",
					"dateipfadname":filepath,
					"lastaction":zurl,
					"status":"OK"};

		stddata=JSON.parse( decodeURI(stddata));
//console.log(stddata);
		if(fs.existsSync(filepath)){
			var datei=fs.readFileSync(filepath, 'utf-8');
			datei=JSON.parse(datei);

			stundenliste=datei.stunden;
			var eintragen=true;
			var stundenlisteneu=[];
			for(i=0;i<stundenliste.length;i++){
				st=stundenliste[i];
				if(st.dat==stddata.dat){
					eintragen=false;
					if(stddata.deleting==true){
						redat.handlingstatus="deleting";
					}
					else{
						redat.handlingstatus="change";
						stundenlisteneu.push(stddata);
					}
					console.log("gefunden",stddata,redat.handlingstatus);
				}
				else{
					stundenlisteneu.push(stundenliste[i]);
				}
			}
			if(eintragen){
				stundenlisteneu.push(stddata);
				redat.handlingstatus="add";
			}
			datei.stunden=stundenlisteneu;

			fs.writeFile(filepath, JSON.stringify(datei),'utf-8' ,
				function(err) {
					if(err){
						console.log(">>",err);
						redat.status="404:notwrite";
					}
					else{
						console.log("The file "+filepath+" was saved!",err ,datei);
					}
					if(refunction!=undefined)refunction(JSON.stringify(redat));
				}
			);
		}
		else{
			redat.status="404:notfound";
			if(refunction!=undefined)refunction(JSON.stringify(redat));
		}
	}

	var refreshTitel=function(id,ddata){
		var i,st,handlingstatus="";
		var filepath=basepathDATA+id+datafileendung;
		var redat={"user":"lokal",
					"id":id,
					"handlingstatus":"",
					"dateipfadname":filepath,
					"lastaction":zurl,
					"status":"OK"};

		ddata=JSON.parse( decodeURI(ddata));
		if(fs.existsSync(filepath)){
			var datei=fs.readFileSync(filepath, 'utf-8');
			datei=JSON.parse(datei);
			datei.titel=ddata.titel;
			fs.writeFile(filepath, JSON.stringify(datei),'utf-8' ,
				function(err) {
					if(err){
						console.log("refreshTitel>>",err);
						redat.status="404:notwrite";
					}
					else{
						//console.log("The file was saved!",redat);
					}
					if(refunction!=undefined)refunction(JSON.stringify(redat));
				}
			);
		}
		else{
			redat.status="404:notfound";
			if(refunction!=undefined)refunction(JSON.stringify(redat));
		}

	}

	var refreshInfo=function(id,ddata){
		var i,st,handlingstatus="";
		var filepath=basepathDATA+id+datafileendung;
		var redat={"user":"lokal",
					"id":id,
					"handlingstatus":"projektinfoupdate",
					"dateipfadname":filepath,
					"lastaction":zurl,
					"status":"OK"};

		ddata=JSON.parse( decodeURI(ddata));
		if(fs.existsSync(filepath)){
			var datei=fs.readFileSync(filepath, 'utf-8');
			datei=JSON.parse(datei);
			//datei.titel=ddata.titel;
			datei.info=ddata;

			fs.writeFile(filepath, JSON.stringify(datei),'utf-8' ,
				function(err) {
					if(err){
						console.log("refreshTitel>>",err);
						redat.status="404:notwrite";
					}
					else{
						//console.log("The file was saved!",redat);
					}
					if(refunction!=undefined)refunction(JSON.stringify(redat));
				}
			);

		}
		else{
			redat.status="404:notfound";
			if(refunction!=undefined)refunction(JSON.stringify(redat));
		}

	}

	var getformdata=function(dat){
		var re=dat.getFullYear()+'-';
			if((dat.getMonth()+1)<10)re+='0';
			re+=(dat.getMonth()+1)+'-';
			if(dat.getDate()<10)re+='0';
			re+=dat.getDate()+' ';
			if(dat.getHours()<10)re+='0';
			re+=dat.getHours()+':';
			if(dat.getMinutes()<10)re+='0';
			re+=dat.getMinutes()+':';
			if(dat.getSeconds()<10)re+='0';
			re+=dat.getSeconds();
		return re;
	}

	var getFiles=function(myDir,filterend){
		var relist=[];
		var fdirectory=myDir;

		if(fdirectory.charCodeAt(fdirectory.length-1)==92){
			//console.log(">",fdirectory.charCodeAt(fdirectory.length-1))
			fdirectory=fdirectory.slice(0,fdirectory.length-1);
			}

		var redata=function(err,dir){
			var i,fsdat;
//console.log("getFiles",myDir,dir);
			for(i=0;i<dir.length;i++){
				if(filterend!=""){
					if(dir[i].indexOf(filterend)>0){
						fsdat=fs.lstatSync(myDir+dir[i]);
						relist.push({
							"name":(dir[i].split(filterend)[0]),
							"dat":getformdata(fsdat.mtime)
							});//"2017-12-11 11:11:11"
					}
				}
				else{
					fsdat=fs.lstatSync(myDir+dir[i]);
					relist.push({"name":dir[i],"dat":getformdata(fsdat.mtime)});//"2017-12-11 11:11:11"
					}
			}

			var data={"user":"lokal",
				"lastaction":"",
				"status":"OK",
				"dat":relist	//"name":"test","dat":"2017-12-11 11:11:11"
			}
			//
			if(refunction!=undefined)refunction(JSON.stringify(data));
			else{
				console.log("no refunction",relist);
			}
		};

		fs.readdir(fdirectory, redata );

	}

	var getSentvar=function(s){
		var i,v,re={},
			variabeln=(s+'').split('&');
		//id=fairydustrocket&data=%7B
		for(i=0;i<variabeln.length;i++){
			v=variabeln[i].split('=');
			re[v[0]]=v[1];
		}

		return re;
	}

	var clearfilename=function(sname){
		//sname = decodeURI(sname);
		sname = sname.split(" ").join("");//str_replace(' ', '', $string);
		sname = sname.split("ä").join("ae");//str_replace('ä', 'ae', $string);
		sname = sname.split("ö").join("oe");//str_replace('ö', 'oe', $string);
		sname = sname.split("ü").join("ue");//str_replace('ü', 'ue', $string);
		sname = sname.split("ß").join("ss");//str_replace('ß', 'ss', $string);
		sname = sname.split("Ä").join("ae");//str_replace('Ä', 'ae', $string);
		sname = sname.split("Ö").join("oe");//str_replace('Ö', 'oe', $string);
		sname = sname.split("Ü").join("ue");//str_replace('Ü', 'ue', $string);
		sname = sname.split(".").join("");//str_replace('Ü', 'ue', $string);
		sname = sname.split("$").join("");//str_replace('Ü', 'ue', $string);

		//$string = str_replace("%20", "", $string);
		// %...

		//$erlaubt = '/[a-z0-9\_\.\-]+/i';
		//preg_match_all($erlaubt, $string, $treffer);// "split"
		//$string = implode('', $treffer[0]); 		// "join"
		var match=sname.match(/[a-z0-9\_\.\-]+/i);
		if(match==null){
			sname="file";
		}
		else
			sname=match[0];

	 return sname;
	}

	var createnewProjektfile=function(pd){
		var filename=clearfilename(decodeURI(pd.newdata));
		var titel=decodeURI(pd.newdata);
		if(filename.length<10){//10
			filename=filename+"_";
			while(filename.length<10){
				filename+=Math.floor(Math.random()*9);
			}
		}
		var counter=0;
		while(fs.existsSync(basepathDATA+filename+datafileendung)){
			filename=filename+counter;
			$counter++;
			if($counter>20){
				filename+='br';
				break;}
		}

		var template=JSON.stringify(projekttemplate);
		if(fs.existsSync(basepathTEMPLATES+"proj_template.js")){
			template=fs.readFileSync(basepathTEMPLATES+"proj_template.js", 'utf-8');
		}
		var heute=new Date();
		var tmp=heute.getFullYear()+'-';
		if((heute.getMonth()+1)<10)tmp+='0';
		tmp+=(heute.getMonth()+1)+'-';
		if(heute.getDate()<10)tmp+='0';
		tmp+=heute.getDate();

		template=template.split('$ID').join(filename);//str_replace('$ID', $newProjektname, $buffer);
		template=template.split('$TITEL').join(titel);//htmlentities(urldecode($namedata));
		template=template.split('$HEUTE').join(tmp);//date("Y-m-d");
		var data={"user":"lokal",
			"dat":"",
			"dateiname":filename,
			"titel":pd.newdata,
			"lastaction":"newprojekt",
			"info":tmp,
			"status":"OK"
		};

		fs.writeFile(basepathDATA+filename+datafileendung, template,'utf-8' ,
			function(err) {
				if(err){
					console.log(">>",err);
					data.status="404:notwrite";
				}
				else{
					//console.log("The file was saved!",redat);
				}
				if(refunction!=undefined)refunction(JSON.stringify(data));
			}
		);
	};

	//system (loadDataAPP)<->elektron
	this.DataIO=function(url, auswertfunc,getorpost,daten){
		//console.log("DataIO",globaldata.user,url,getorpost,daten,fs);
		var pd=getSentvar(daten);
		var data={};

		if(basepathDATA=="")return;

		refunction=auswertfunc;
		zurl=url;
		if(url=="getoptionen"){//OK:Optionen laden
			readFile(basepathDATA+"optionen.txt");//id=lokal&data=%7B%22tabaktiv%22:0,%22showscramblebutt%22:false%7D
			//auswertfunc(JSON.stringify(data));
		}
		else
		if(url=="projektliste"){//OK:Liste der Projekte als Dateinamen + Dateiänerungsdatum
			//auswertfunc(JSON.stringify(data));
			getFiles(basepathDATA,datafileendung);
		}
		else
		if(url=="setoptionen"){//OK:Optionen speichern
			data={"user":"lokal",
				"lastaction":"",
				"status":"OK"
			}

			if(!fs.existsSync(basepathDATA+"optionen.txt")){
				console.log(":-(");
			}

			fs.writeFile(basepathDATA+"optionen.txt", decodeURI(pd.data),'utf-8',
				function(err) {
					if(err){
						console.log(">>",err);
						data.status="404:notwrite";
					}
					else{
						//console.log("The file was saved!",redat);
					}
					if(refunction!=undefined)refunction(JSON.stringify(data));
				}
			);
		}
		else
		if(url=="maindata"){//alive //OK
			data={"user":"lokal",
			"dat":"maindata",
			"lastaction":"maindata",
			"status":"OK"
			};
			auswertfunc(JSON.stringify(data));
		}
		else
		if(url=="projektdata"){//OK
			var filename=pd.name;
			readFile(basepathDATA+filename+datafileendung);
		}
		else
		if(url=="newprojekt"){//OK
			createnewProjektfile(pd);
		}
		else
		if(url=="projektstundenlisteupdate"){//OK
			addStundeneintrag(pd.id,pd.data);
		}
		else
		if(url=="projekttitelupdate"){//OK
			refreshTitel(pd.id,pd.data);
		}
		else
		if(url=="projektinfoupdate"){//OK
			refreshInfo(pd.id,pd.data);
		}
		else
			alert("load\n"+globaldata.user+'\n'+url+'\n'+getorpost+'\n'+daten);
	}

}

var AppeleWin=function(){
	var win=remote.getCurrentWindow();
	//console.log(win.getBounds());
	//win.setSize(900,900);

	var ini=function(){

		/*console.log('basepath',basepath);
		console.log('_dirname',__dirname);
		console.log('data',fs.existsSync(basepathDATA));
		console.log('templates',fs.existsSync(basepathTEMPLATES));
		console.log('getAppPath',remote.app.getAppPath());
		console.log('getAppPath.data',remote.app.getAppPath('data'));
		console.log('getAppPath.appData',remote.app.getAppPath('appData'));
		console.log('getAppPath.userData',remote.app.getAppPath('userData'));*/
		/*
		console.log(":Directory:",fs.readdirSync(basepath));
		console.log(":Directory:",fs.readdirSync(basepath+'/userData'));
		console.log(":Directory:",fs.readdirSync(basepathDATA));

		console.log(":documents:",app.app.getPath('documents'));
		*/
		//var r=fs.openSync(basepathDATA+"optionen.txt","a");
		//console.log(r);
		//fs.closeSync(r);

		var userdokumente=app.app.getPath('documents');// C:\Users\andreas\Documents !
		var tmp;
		var firststart=false;

		if(!fs.existsSync(userdokumente+"/PROSTd")){
			//create dir
			fs.mkdirSync(userdokumente+"/PROSTd");
		}
		if(!fs.existsSync(userdokumente+"/PROSTd/userData")){
			//create dir
			fs.mkdirSync(userdokumente+"/PROSTd/userData");
			firststart=true;
		}

		//create urlaub
		if(!fs.existsSync(userdokumente+"/PROSTd/userData/urlaub"+datafileendung)){
			if(fs.existsSync(basepathTEMPLATES+"urlaub"+datafileendung)){
				console.log("create urlaub");
				tmp=fs.readFileSync(basepathTEMPLATES+"urlaub"+datafileendung,'utf-8');
				fs.writeFileSync(userdokumente+"/PROSTd/userData/urlaub"+datafileendung,tmp,'utf-8');
			}
		}
		//create feiertage
		if(!fs.existsSync(userdokumente+"/PROSTd/userData/feiertage"+datafileendung)){
			if(fs.existsSync(basepathTEMPLATES+"feiertage"+datafileendung)){
				console.log("create feiertage");
				tmp=fs.readFileSync(basepathTEMPLATES+"feiertage"+datafileendung,'utf-8');
				fs.writeFileSync(userdokumente+"/PROSTd/userData/feiertage"+datafileendung,tmp,'utf-8');
			}
		}

		//usercss
		if(fs.existsSync(userdokumente+"/PROSTd/userData/style.css")){
			var newNode=document.createElement("link");
			newNode.type="text/css";
			newNode.rel="stylesheet";
			newNode.href=userdokumente+"/PROSTd/userData/style.css";
			document.head.appendChild(newNode);
		}

		//basepathDATA=basepath+"/userData/";
		basepathDATA=userdokumente+"/PROSTd/userData/";
		basepathDATA=path.normalize(basepathDATA);

		//console.log("!",fs.readFileSync(basepathDATA+"optionen.txt",'utf-8'));

		console.log("basepath",basepath);
		console.log("basepathDATA",basepathDATA);
		console.log("basepathTEMPLATES",basepathTEMPLATES);

		console.log(":Directory:",fs.readdirSync(basepath));
		console.log(":Directory:",fs.readdirSync(basepathDATA));
		//console.log(":Directory:",fs.readdirSync(basepath+'/userData'));

		/*console.log("##",app);
		app.app.on('move',resizer);
		app.app.on('moved',resizer);
		app.app.on('resize',resizer);
		*/
		//window.addEventListener('move',resizer );
		//window.addEventListener('moved',resizer );
		window.addEventListener('resize',resizer );

		if(firststart)
			alert("Deine Daten findest Du unter:\n"+basepathDATA);
	}

	var resizer=function(event){
		//console.log(">>",globaldata);
			//mainWindow.webContents.openDevTools()
			//app.BrowserWindow
			var win=remote.getCurrentWindow();
			var bereich=win.getBounds();// x: 279, y: 84, width: 1250, height: 640
			//console.log(bereich);
	}

	ini();
}

window.addEventListener('load', function (event) {
		//console.log(">>",globaldata);
		//mainWindow.webContents.openDevTools()
		//app.BrowserWindow
		eleWin=new AppeleWin();
	});<commit_msg>Delete electron.js<commit_after><|endoftext|>


<commit_before>'use strict';
Cryptodog.xmpp = {};
Cryptodog.xmpp.currentStatus = 'online';
Cryptodog.xmpp.connection = null;

Cryptodog.xmpp.defaultServer = {
	name: 'Cryptocat',
	domain: 'crypto.cat',
	conference: 'conference.crypto.cat',
	relay: 'https://crypto.cat/http-bind'
};

Cryptodog.xmpp.currentServer = {};

$(window).ready(function() {
// Load custom server settings
Cryptodog.storage.getItem('serverName', function(key){
	Cryptodog.xmpp.currentServer.name = key ? key : Cryptodog.xmpp.defaultServer.name;
});
Cryptodog.storage.getItem('domain', function(key){
	Cryptodog.xmpp.currentServer.domain = key ? key : Cryptodog.xmpp.defaultServer.domain;
});
Cryptodog.storage.getItem('conferenceServer', function(key){
	Cryptodog.xmpp.currentServer.conference = key ? key : Cryptodog.xmpp.defaultServer.conference;
});
Cryptodog.storage.getItem('relay', function(key){
	Cryptodog.xmpp.currentServer.relay = key ? key : Cryptodog.xmpp.defaultServer.relay;
});

// Prepares necessary encryption key operations before XMPP connection.
// Shows a progress bar while doing so.
Cryptodog.xmpp.showKeyPreparationDialog = function(callback) {
	// Key storage currently disabled as we are not yet sure if this is safe to do.
	// Cryptodog.storage.setItem('multiPartyKey', Cryptodog.multiParty.genPrivateKey())
	//else {
	Cryptodog.me.mpPrivateKey = Cryptodog.multiParty.genPrivateKey()
	//}
	Cryptodog.me.mpPublicKey = Cryptodog.multiParty.genPublicKey(
		Cryptodog.me.mpPrivateKey
	)
	Cryptodog.me.mpFingerprint = Cryptodog.multiParty.genFingerprint()
	// If we already have keys, just skip to the callback.
	if (Cryptodog.me.otrKey) {
		callback()
		return
	}
	$('#loginInfo').css({'background-color': '#bb7a20'})
	$('#loginInfo').text(Cryptodog.locale['loginMessage']['generatingKeys'])

	// Add delay to key generation when on the file protocol
	// Since the UI freezes when generating keys without WebWorkers
	if (window.location.protocol === 'file:'){
		setTimeout(function(){Cryptodog.xmpp.prepareKeys(callback)}, 100)
	}
	else {
		Cryptodog.xmpp.prepareKeys(callback)
	}
}

// See above.
Cryptodog.xmpp.prepareKeys = function(callback) {
	// Create DSA key for OTR.
	// file protocol doesn't support WebWorkers
	if (window.location.protocol === 'file:'){
		Cryptodog.me.otrKey = new DSA()
		if (callback) { callback() }
	}
	else {
		DSA.createInWebWorker({
			path: 'js/workers/dsa.js',
			seed: Cryptodog.random.generateSeed
		}, function(key) {
			Cryptodog.me.otrKey = key
			// Key storage currently disabled as we are not yet sure if this is safe to do.
			//	Cryptodog.storage.setItem('myKey', JSON.stringify(Cryptodog.me.otrKey))
			if (callback) { callback() }
		})
	}

}

// Connect anonymously and join conversation.
Cryptodog.xmpp.connect = function() {
	Cryptodog.me.conversation = Strophe.xmlescape($('#conversationName').val())
	Cryptodog.me.nickname = Strophe.xmlescape($('#nickname').val())
	Cryptodog.xmpp.connection = new Strophe.Connection(Cryptodog.xmpp.currentServer.relay)
	Cryptodog.xmpp.connection.connect(Cryptodog.xmpp.currentServer.domain, null, function(status) {
		if (status === Strophe.Status.CONNECTING) {
			$('#loginInfo').animate({'background-color': '#bb7a20'}, 200)
			$('#loginInfo').text(Cryptodog.locale['loginMessage']['connecting'])
		}
		else if (status === Strophe.Status.CONNECTED) {
			Cryptodog.xmpp.connection.muc.join(
				Cryptodog.me.conversation + '@' + Cryptodog.xmpp.currentServer.conference,
				Cryptodog.me.nickname,
				function(message) {
					if (Cryptodog.xmpp.onMessage(message)) { return true }
				},
				function(presence) {
					if (Cryptodog.xmpp.onPresence(presence)) { return true }
				}
			)
			Cryptodog.xmpp.onConnected()
			document.title = Cryptodog.me.nickname + '@' + Cryptodog.me.conversation
			$('.conversationName').text(document.title)
			Cryptodog.storage.setItem('nickname', Cryptodog.me.nickname)
		}
		else if ((status === Strophe.Status.CONNFAIL) || (status === Strophe.Status.DISCONNECTED)) {
			if (Cryptodog.loginError) {
				Cryptodog.xmpp.reconnect()
			}
		}
	})
}

// Executes on successfully completed XMPP connection.
Cryptodog.xmpp.onConnected = function() {
	afterConnect()
	$('#loginInfo').text('✓')
	$('#status').attr('src', 'img/icons/checkmark.svg');
	$('#buddy-groupChat,#status').show()
	$('#buddy-groupChat').insertBefore('#buddiesOnline')
	$('#fill').stop().animate({
		'width': '100%', 'opacity': '1'
	}, 250, 'linear')
	window.setTimeout(function() {
		$('#dialogBoxClose').click()
	}, 400)
	window.setTimeout(function() {
		$('#loginOptions,#languages,#customServerDialog').fadeOut(200)
		$('#version,#logoText,#loginInfo,#info').fadeOut(200)
		$('#header').animate({'background-color': '#444'})
		$('.logo').animate({'margin': '-11px 5px 0 0'})
		$('#login').fadeOut(200, function() {
			$('#conversationInfo').fadeIn()
			$('#buddy-groupChat').click(function() {
				Cryptodog.onBuddyClick($(this))
			})
			$('#buddy-groupChat').click()
			$('#conversationWrapper').fadeIn()
			$('#optionButtons').fadeIn()
			$('#footer').delay(200).animate({'height': 60}, function() {
				$('#userInput').fadeIn(200, function() {
					$('#userInputText').focus()
				})
			})
			$('#buddyWrapper').slideDown()
		})
	}, 800)
	Cryptodog.loginError = true
}

// Reconnect to the same chatroom, on accidental connection loss.
Cryptodog.xmpp.reconnect = function() {
	if (Cryptodog.xmpp.connection) {
	    Cryptodog.xmpp.connection.reset()
	}
	Cryptodog.xmpp.connection = new Strophe.Connection(Cryptodog.xmpp.currentServer.relay)
	Cryptodog.xmpp.connection.connect(Cryptodog.xmpp.currentServer.domain, null, function(status) {
		if (status === Strophe.Status.CONNECTING) {
			$('.conversationName').animate({'background-color': '#F00'})
		}
		else if (status === Strophe.Status.CONNECTED) {
			afterConnect()
			Cryptodog.xmpp.connection.muc.join(
				Cryptodog.me.conversation + '@' + Cryptodog.xmpp.currentServer.conference,
				Cryptodog.me.nickname
			)
		}
		else if ((status === Strophe.Status.CONNFAIL) || (status === Strophe.Status.DISCONNECTED)) {
			if (Cryptodog.loginError) {
				window.setTimeout(function() {
					Cryptodog.xmpp.reconnect()
				}, 5000)
			}
		}
	})
}

// Handle incoming messages from the XMPP server.
Cryptodog.xmpp.onMessage = function(message) {
	var nickname = cleanNickname($(message).attr('from'))
	var body = $(message).find('body').text()
	var type = $(message).attr('type')
	// If archived message, ignore.
	if ($(message).find('delay').length !== 0) {
		return true
	}
	//If message is from me, ignore.
	if (nickname === Cryptodog.me.nickname) {
		return true
	}
	// If message is from someone not on buddy list, ignore.
	if (!Cryptodog.buddies.hasOwnProperty(nickname)) {
		return true
	}
	// Check if message has a 'composing' notification.
	if ($(message).find('composing').length && !body.length) {
		$('#buddy-' + Cryptodog.buddies[nickname].id).addClass('composing')
		return true
	}
	// Check if message has a 'paused' (stopped writing) notification.
	if ($(message).find('paused').length) {
		$('#buddy-' + Cryptodog.buddies[nickname].id).removeClass('composing')
	}
	// Check if message is a group chat message.
	else if (type === 'groupchat' && body.length) {
		$('#buddy-' + Cryptodog.buddies[nickname].id).removeClass('composing')
		body = Cryptodog.multiParty.receiveMessage(nickname, Cryptodog.me.nickname, body)
		if (typeof(body) === 'string') {
			Cryptodog.addToConversation(body, nickname, 'groupChat', 'message')
		}
	}
	// Check if this is a private OTR message.
	else if (type === 'chat') {
		$('#buddy-' + Cryptodog.buddies[nickname].id).removeClass('composing')
		Cryptodog.buddies[nickname].otr.receiveMsg(body)
	}
	return true
}

// Handle incoming presence updates from the XMPP server.
Cryptodog.xmpp.onPresence = function(presence) {
	var status
	var nickname = cleanNickname($(presence).attr('from'))
	// If invalid nickname, do not process
	if ($(presence).attr('type') === 'error') {
		if ($(presence).find('error').attr('code') === '409') {
			// Delay logout in order to avoid race condition with window animation
			window.setTimeout(function() {
				Cryptodog.logout()
				Cryptodog.UI.loginFail(Cryptodog.locale['loginMessage']['nicknameInUse'])
			}, 3000)
			return false
		}
		return true
	}
	// Ignore if presence status is coming from myself
	if (nickname === Cryptodog.me.nickname) {
		return true
	}
	// Detect nickname change (which may be done by non-Cryptodog XMPP clients)
	if ($(presence).find('status').attr('code') === '303') {
		Cryptodog.removeBuddy(nickname)
		return true
	}
	// Detect buddy going offline.
	if ($(presence).attr('type') === 'unavailable') {
		Cryptodog.removeBuddy(nickname)
		return true
	}
	// Create buddy element if buddy is new.
	else if (!Cryptodog.buddies.hasOwnProperty(nickname)) {
		Cryptodog.addBuddy(nickname, null, 'online')
		for (var u = 0; u < 4000; u += 2000) {
			window.setTimeout(Cryptodog.xmpp.sendPublicKey, u, nickname)
		}
		Cryptodog.xmpp.sendStatus(); // Propagate away status to newcomers.
	}
	// Handle buddy status change to 'available'.
	else if (
		$(presence).find('show').text() === '' ||
		$(presence).find('show').text() === 'chat'
	) {
		status = 'online'
	}
	// Handle buddy status change to 'away'.
	else {
		status = 'away'
	}
	// Perform status change.
	Cryptodog.buddyStatus(nickname, status)
	return true
}

// Send your own multiparty public key to `nickname`, via XMPP-MUC.
Cryptodog.xmpp.sendPublicKey = function(nickname) {
	Cryptodog.xmpp.connection.muc.message(
		Cryptodog.me.conversation + '@' + Cryptodog.xmpp.currentServer.conference,
		null, Cryptodog.multiParty.sendPublicKey(nickname), null, 'groupchat', 'active'
	)
}

// Send your current status to the XMPP server.
Cryptodog.xmpp.sendStatus = function() {
    var status = ''
	if (Cryptodog.xmpp.currentStatus === 'away') {
    	status = 'away'
	}
	Cryptodog.xmpp.connection.muc.setStatus(
		Cryptodog.me.conversation + '@' + Cryptodog.xmpp.currentServer.conference,
		Cryptodog.me.nickname, status, status
	)
}

// Executed (manually) after connection.
var afterConnect = function() {
	$('.conversationName').animate({'background-color': '#bb7a20'})
	Cryptodog.xmpp.connection.ibb.addIBBHandler(Cryptodog.otr.ibbHandler)
	/* jshint -W106 */
	Cryptodog.xmpp.connection.si_filetransfer.addFileHandler(Cryptodog.otr.fileHandler)
	/* jshint +W106 */

	// Send status upon (re)connect.
	Cryptodog.xmpp.sendStatus();
}

// Clean nickname so that it's safe to use.
var cleanNickname = function(nickname) {
	var clean = nickname.match(/\/([\s\S]+)/)
	if (clean) {
		return clean[1]
	}
	return false
}

})
<commit_msg>Make cryptocrap default server<commit_after>'use strict';
Cryptodog.xmpp = {};
Cryptodog.xmpp.currentStatus = 'online';
Cryptodog.xmpp.connection = null;

Cryptodog.xmpp.defaultServer = {
	name: 'Cryptocrap',
	domain: 'cryptocrap.xyz',
	conference: 'conference.cryptocrap.xyz',
	relay: 'https://cryptocrap.xyz/http-bind'
};

Cryptodog.xmpp.currentServer = {};

$(window).ready(function() {
// Load custom server settings
Cryptodog.storage.getItem('serverName', function(key){
	Cryptodog.xmpp.currentServer.name = key ? key : Cryptodog.xmpp.defaultServer.name;
});
Cryptodog.storage.getItem('domain', function(key){
	Cryptodog.xmpp.currentServer.domain = key ? key : Cryptodog.xmpp.defaultServer.domain;
});
Cryptodog.storage.getItem('conferenceServer', function(key){
	Cryptodog.xmpp.currentServer.conference = key ? key : Cryptodog.xmpp.defaultServer.conference;
});
Cryptodog.storage.getItem('relay', function(key){
	Cryptodog.xmpp.currentServer.relay = key ? key : Cryptodog.xmpp.defaultServer.relay;
});

// Prepares necessary encryption key operations before XMPP connection.
// Shows a progress bar while doing so.
Cryptodog.xmpp.showKeyPreparationDialog = function(callback) {
	// Key storage currently disabled as we are not yet sure if this is safe to do.
	// Cryptodog.storage.setItem('multiPartyKey', Cryptodog.multiParty.genPrivateKey())
	//else {
	Cryptodog.me.mpPrivateKey = Cryptodog.multiParty.genPrivateKey()
	//}
	Cryptodog.me.mpPublicKey = Cryptodog.multiParty.genPublicKey(
		Cryptodog.me.mpPrivateKey
	)
	Cryptodog.me.mpFingerprint = Cryptodog.multiParty.genFingerprint()
	// If we already have keys, just skip to the callback.
	if (Cryptodog.me.otrKey) {
		callback()
		return
	}
	$('#loginInfo').css({'background-color': '#bb7a20'})
	$('#loginInfo').text(Cryptodog.locale['loginMessage']['generatingKeys'])

	// Add delay to key generation when on the file protocol
	// Since the UI freezes when generating keys without WebWorkers
	if (window.location.protocol === 'file:'){
		setTimeout(function(){Cryptodog.xmpp.prepareKeys(callback)}, 100)
	}
	else {
		Cryptodog.xmpp.prepareKeys(callback)
	}
}

// See above.
Cryptodog.xmpp.prepareKeys = function(callback) {
	// Create DSA key for OTR.
	// file protocol doesn't support WebWorkers
	if (window.location.protocol === 'file:'){
		Cryptodog.me.otrKey = new DSA()
		if (callback) { callback() }
	}
	else {
		DSA.createInWebWorker({
			path: 'js/workers/dsa.js',
			seed: Cryptodog.random.generateSeed
		}, function(key) {
			Cryptodog.me.otrKey = key
			// Key storage currently disabled as we are not yet sure if this is safe to do.
			//	Cryptodog.storage.setItem('myKey', JSON.stringify(Cryptodog.me.otrKey))
			if (callback) { callback() }
		})
	}

}

// Connect anonymously and join conversation.
Cryptodog.xmpp.connect = function() {
	Cryptodog.me.conversation = Strophe.xmlescape($('#conversationName').val())
	Cryptodog.me.nickname = Strophe.xmlescape($('#nickname').val())
	Cryptodog.xmpp.connection = new Strophe.Connection(Cryptodog.xmpp.currentServer.relay)
	Cryptodog.xmpp.connection.connect(Cryptodog.xmpp.currentServer.domain, null, function(status) {
		if (status === Strophe.Status.CONNECTING) {
			$('#loginInfo').animate({'background-color': '#bb7a20'}, 200)
			$('#loginInfo').text(Cryptodog.locale['loginMessage']['connecting'])
		}
		else if (status === Strophe.Status.CONNECTED) {
			Cryptodog.xmpp.connection.muc.join(
				Cryptodog.me.conversation + '@' + Cryptodog.xmpp.currentServer.conference,
				Cryptodog.me.nickname,
				function(message) {
					if (Cryptodog.xmpp.onMessage(message)) { return true }
				},
				function(presence) {
					if (Cryptodog.xmpp.onPresence(presence)) { return true }
				}
			)
			Cryptodog.xmpp.onConnected()
			document.title = Cryptodog.me.nickname + '@' + Cryptodog.me.conversation
			$('.conversationName').text(document.title)
			Cryptodog.storage.setItem('nickname', Cryptodog.me.nickname)
		}
		else if ((status === Strophe.Status.CONNFAIL) || (status === Strophe.Status.DISCONNECTED)) {
			if (Cryptodog.loginError) {
				Cryptodog.xmpp.reconnect()
			}
		}
	})
}

// Executes on successfully completed XMPP connection.
Cryptodog.xmpp.onConnected = function() {
	afterConnect()
	$('#loginInfo').text('✓')
	$('#status').attr('src', 'img/icons/checkmark.svg');
	$('#buddy-groupChat,#status').show()
	$('#buddy-groupChat').insertBefore('#buddiesOnline')
	$('#fill').stop().animate({
		'width': '100%', 'opacity': '1'
	}, 250, 'linear')
	window.setTimeout(function() {
		$('#dialogBoxClose').click()
	}, 400)
	window.setTimeout(function() {
		$('#loginOptions,#languages,#customServerDialog').fadeOut(200)
		$('#version,#logoText,#loginInfo,#info').fadeOut(200)
		$('#header').animate({'background-color': '#444'})
		$('.logo').animate({'margin': '-11px 5px 0 0'})
		$('#login').fadeOut(200, function() {
			$('#conversationInfo').fadeIn()
			$('#buddy-groupChat').click(function() {
				Cryptodog.onBuddyClick($(this))
			})
			$('#buddy-groupChat').click()
			$('#conversationWrapper').fadeIn()
			$('#optionButtons').fadeIn()
			$('#footer').delay(200).animate({'height': 60}, function() {
				$('#userInput').fadeIn(200, function() {
					$('#userInputText').focus()
				})
			})
			$('#buddyWrapper').slideDown()
		})
	}, 800)
	Cryptodog.loginError = true
}

// Reconnect to the same chatroom, on accidental connection loss.
Cryptodog.xmpp.reconnect = function() {
	if (Cryptodog.xmpp.connection) {
	    Cryptodog.xmpp.connection.reset()
	}
	Cryptodog.xmpp.connection = new Strophe.Connection(Cryptodog.xmpp.currentServer.relay)
	Cryptodog.xmpp.connection.connect(Cryptodog.xmpp.currentServer.domain, null, function(status) {
		if (status === Strophe.Status.CONNECTING) {
			$('.conversationName').animate({'background-color': '#F00'})
		}
		else if (status === Strophe.Status.CONNECTED) {
			afterConnect()
			Cryptodog.xmpp.connection.muc.join(
				Cryptodog.me.conversation + '@' + Cryptodog.xmpp.currentServer.conference,
				Cryptodog.me.nickname
			)
		}
		else if ((status === Strophe.Status.CONNFAIL) || (status === Strophe.Status.DISCONNECTED)) {
			if (Cryptodog.loginError) {
				window.setTimeout(function() {
					Cryptodog.xmpp.reconnect()
				}, 5000)
			}
		}
	})
}

// Handle incoming messages from the XMPP server.
Cryptodog.xmpp.onMessage = function(message) {
	var nickname = cleanNickname($(message).attr('from'))
	var body = $(message).find('body').text()
	var type = $(message).attr('type')
	// If archived message, ignore.
	if ($(message).find('delay').length !== 0) {
		return true
	}
	//If message is from me, ignore.
	if (nickname === Cryptodog.me.nickname) {
		return true
	}
	// If message is from someone not on buddy list, ignore.
	if (!Cryptodog.buddies.hasOwnProperty(nickname)) {
		return true
	}
	// Check if message has a 'composing' notification.
	if ($(message).find('composing').length && !body.length) {
		$('#buddy-' + Cryptodog.buddies[nickname].id).addClass('composing')
		return true
	}
	// Check if message has a 'paused' (stopped writing) notification.
	if ($(message).find('paused').length) {
		$('#buddy-' + Cryptodog.buddies[nickname].id).removeClass('composing')
	}
	// Check if message is a group chat message.
	else if (type === 'groupchat' && body.length) {
		$('#buddy-' + Cryptodog.buddies[nickname].id).removeClass('composing')
		body = Cryptodog.multiParty.receiveMessage(nickname, Cryptodog.me.nickname, body)
		if (typeof(body) === 'string') {
			Cryptodog.addToConversation(body, nickname, 'groupChat', 'message')
		}
	}
	// Check if this is a private OTR message.
	else if (type === 'chat') {
		$('#buddy-' + Cryptodog.buddies[nickname].id).removeClass('composing')
		Cryptodog.buddies[nickname].otr.receiveMsg(body)
	}
	return true
}

// Handle incoming presence updates from the XMPP server.
Cryptodog.xmpp.onPresence = function(presence) {
	var status
	var nickname = cleanNickname($(presence).attr('from'))
	// If invalid nickname, do not process
	if ($(presence).attr('type') === 'error') {
		if ($(presence).find('error').attr('code') === '409') {
			// Delay logout in order to avoid race condition with window animation
			window.setTimeout(function() {
				Cryptodog.logout()
				Cryptodog.UI.loginFail(Cryptodog.locale['loginMessage']['nicknameInUse'])
			}, 3000)
			return false
		}
		return true
	}
	// Ignore if presence status is coming from myself
	if (nickname === Cryptodog.me.nickname) {
		return true
	}
	// Detect nickname change (which may be done by non-Cryptodog XMPP clients)
	if ($(presence).find('status').attr('code') === '303') {
		Cryptodog.removeBuddy(nickname)
		return true
	}
	// Detect buddy going offline.
	if ($(presence).attr('type') === 'unavailable') {
		Cryptodog.removeBuddy(nickname)
		return true
	}
	// Create buddy element if buddy is new.
	else if (!Cryptodog.buddies.hasOwnProperty(nickname)) {
		Cryptodog.addBuddy(nickname, null, 'online')
		for (var u = 0; u < 4000; u += 2000) {
			window.setTimeout(Cryptodog.xmpp.sendPublicKey, u, nickname)
		}
		Cryptodog.xmpp.sendStatus(); // Propagate away status to newcomers.
	}
	// Handle buddy status change to 'available'.
	else if (
		$(presence).find('show').text() === '' ||
		$(presence).find('show').text() === 'chat'
	) {
		status = 'online'
	}
	// Handle buddy status change to 'away'.
	else {
		status = 'away'
	}
	// Perform status change.
	Cryptodog.buddyStatus(nickname, status)
	return true
}

// Send your own multiparty public key to `nickname`, via XMPP-MUC.
Cryptodog.xmpp.sendPublicKey = function(nickname) {
	Cryptodog.xmpp.connection.muc.message(
		Cryptodog.me.conversation + '@' + Cryptodog.xmpp.currentServer.conference,
		null, Cryptodog.multiParty.sendPublicKey(nickname), null, 'groupchat', 'active'
	)
}

// Send your current status to the XMPP server.
Cryptodog.xmpp.sendStatus = function() {
    var status = ''
	if (Cryptodog.xmpp.currentStatus === 'away') {
    	status = 'away'
	}
	Cryptodog.xmpp.connection.muc.setStatus(
		Cryptodog.me.conversation + '@' + Cryptodog.xmpp.currentServer.conference,
		Cryptodog.me.nickname, status, status
	)
}

// Executed (manually) after connection.
var afterConnect = function() {
	$('.conversationName').animate({'background-color': '#bb7a20'})
	Cryptodog.xmpp.connection.ibb.addIBBHandler(Cryptodog.otr.ibbHandler)
	/* jshint -W106 */
	Cryptodog.xmpp.connection.si_filetransfer.addFileHandler(Cryptodog.otr.fileHandler)
	/* jshint +W106 */

	// Send status upon (re)connect.
	Cryptodog.xmpp.sendStatus();
}

// Clean nickname so that it's safe to use.
var cleanNickname = function(nickname) {
	var clean = nickname.match(/\/([\s\S]+)/)
	if (clean) {
		return clean[1]
	}
	return false
}

})
<|endoftext|>


<commit_before>/*
		=========================================================================================
 		*
		*	FlipbookJS
 		*
 		=========================================================================================
		*----------------------------------------------------------------------------------------
 		*
 		*	slide animator that animates each slide leading to the target slide
 		*
 		=========================================================================================
		*
		*   author          >>  Christopher Miles
		*
		*   site            >>  http://ChristopherMil.es
		*   github          >>  http://github.com/creatologist
		*
		=========================================================================================
*/

//===============================================================================================
//----------------------------------------------------------------------------------------------- DO IT

var Flipbook = function( slides ) {

	slides = slides.toArray().reverse();

	this.atSlide = 0;
	this.currentSlide = slides[0];

	this.slides = slides;
	this.totalSlides = slides.length;

	for ( var i = 0, len = this.totalSlides; i < len; i++ ) {
		$( this.slides[i] ).attr( 'flipbookSlide', i );
	}
};

Flipbook.prototype = {

	flipTo : function( slideNum, duration, animationParams, finishCallback ) {

		if ( slideNum < this.atSlide ) slideNum -= 1;

		var totalSlides = slideNum - this.atSlide;

		var forward = true;
		if ( totalSlides < 0 ) forward = false;

		totalSlides = Math.abs( totalSlides );

		var t,
			pause = 0;

		if ( typeof duration == 'number' ) t = duration;
		else {
			t = duration.duration;
			pause = duration.pause;
		}

		var dTime = t / totalSlides;
		var delay = 0;

		var self = this;
		var last = false;

		for ( var i = 0, len = totalSlides; i < len; i++ ) {
			var n = i;
			if ( !forward ) n = -n;

			n = this.atSlide + n;

			if ( forward && i == len - 1 ) last = true;
			else if ( !forward && n == slideNum + 1 ) last = true;

			if ( last ) {
				$( this.slides[n] ).delay( delay + ( pause * i ) ).animate( animationParams, dTime, function() {
					if ( forward ) self.atSlide = Number( $( this ).attr( 'flipbookSlide' ) ) + 1;
					else self.atSlide = Number( $( this ).attr( 'flipbookSlide' ) );

					if ( finishCallback ) finishCallback();
				} );
			} else {
				$( this.slides[n] ).delay( delay + ( pause * i ) ).animate( animationParams, dTime, function() {
					if ( forward ) self.atSlide = Number( $( this ).attr( 'flipbookSlide' ) ) + 1;
					else self.atSlide = Number( $( this ).attr( 'flipbookSlide' ) );
				} );
			}

			delay += dTime;
		}

	}

};
<commit_msg>added a reset and onUpdate event listener<commit_after>/*
		=========================================================================================
 		*
		*	FlipbookJS
 		*
 		=========================================================================================
		*----------------------------------------------------------------------------------------
 		*
 		*	slide animator that animates each slide leading to the target slide
 		*
 		=========================================================================================
		*
		*   author          >>  Christopher Miles
		*
		*   site            >>  http://ChristopherMil.es
		*   github          >>  http://github.com/creatologist
		*
		=========================================================================================
*/

//===============================================================================================
//----------------------------------------------------------------------------------------------- DO IT

var Flipbook = function( slides, onUpdate ) {

	slides = slides.toArray().reverse();

	this.atSlide = 0;
	this.currentSlide = slides[0];

	this.slides = slides;
	this.totalSlides = slides.length;

	this.onUpdate;

	if ( onUpdate ) this.onUpdate = onUpdate;

	for ( var i = 0, len = this.totalSlides; i < len; i++ ) {
		$( this.slides[i] ).attr( 'flipbookSlide', i );
	}
};

Flipbook.prototype = {

	reset : function( style ) {
		this.atSlide = 0;
		for ( var i = 0, len = this.totalSlides; i < len; i++ ) {
			$( this.slides[i] ).css( style );
		}
	},

	flipTo : function( slideNum, duration, animationParams, finishCallback ) {

		if ( slideNum < this.atSlide ) slideNum -= 1;

		var totalSlides = slideNum - this.atSlide;

		var forward = true;
		if ( totalSlides < 0 ) forward = false;

		totalSlides = Math.abs( totalSlides );

		var t,
			pause = 0;

		if ( typeof duration == 'number' ) t = duration;
		else {
			t = duration.duration;
			pause = duration.pause;
		}

		var dTime = t / totalSlides;
		var delay = 0;

		var self = this;
		var last = false;

		for ( var i = 0, len = totalSlides; i < len; i++ ) {
			var n = i;
			if ( !forward ) n = -n;

			n = this.atSlide + n;

			if ( forward && i == len - 1 ) last = true;
			else if ( !forward && n == slideNum + 1 ) last = true;

			if ( last ) {
				$( this.slides[n] ).delay( delay + ( pause * i ) ).animate( animationParams, dTime, function() {

					var slideIndex = Number( $( this ).attr( 'flipbookSlide' ) );

					if ( forward ) self.atSlide = slideIndex + 1;
					else self.atSlide = slideIndex;

					if ( self.onUpdate ) self.onUpdate( self.atSlide, self.slides[ self.atSlide ], self );

					if ( finishCallback ) finishCallback();
				} );
			} else {
				$( this.slides[n] ).delay( delay + ( pause * i ) ).animate( animationParams, dTime, function() {
					var slideIndex = Number( $( this ).attr( 'flipbookSlide' ) );

					if ( forward ) self.atSlide = slideIndex + 1;
					else self.atSlide = slideIndex;

					if ( self.onUpdate ) self.onUpdate( self.atSlide, self.slides[ self.atSlide ], self );
				} );
			}

			delay += dTime;
		}

	}

};
<|endoftext|>


<commit_before>
/*global SessionDescription: false, webkitURL: false, webkitRTCPeerConnection: false*/

/**
 * @fileoverview SIP User Agent
 */

/**
 * @augments JsSIP
 * @class PeerConnection helper Class.
 * @param {JsSIP.OutgoingSession|JsSIP.IncomingSession} session
 * @param {HTMLVideoElement} selfView
 * @param {HTMLVideoElement} remoteView
 */
JsSIP.MediaSession = function(session, selfView, remoteView) {
  this.session = session;
  this.selfView = selfView || null;
  this.remoteView = remoteView || null;
  this.localMedia = null;
  this.peerConnection = null;
};

JsSIP.MediaSession.prototype = {
  /**
   * Stablish peerConnection for Caller.
   *
 - Prompt the user for permission to use the Web cam or other video or audio input.
   *
 -- If the user consents, create a peerConnection.
   *
 -- If the user doesn't consent, fire onFailure callback.
   *
   * @param {Object} mediaType {audio:true/false, video:true/false}
   * @param {Function} onSuccess
   * @param {Function} onFailure
   */
  startCaller: function(mediaType, onSuccess, onFailure) {
    var self = this;

    /** @private */
    function onGetUserMediaSuccess(stream) {
      var offer;

      // Start peerConnection
      self.start(onSuccess, onFailure);

      // add stream to peerConnection
      try {
        self.peerConnection.addStream(stream);
      } catch (e) {
        onFailure('addSstream',e);
      }

      // Set local description and start Ice.
      self.peerConnection.createOffer(function(sessionDescription){
        self.peerConnection.setLocalDescription(sessionDescription);
        console.log('Here the sessionDescription');
      });
    }

    /** @private */
    function onGetUserMediaFailure() {
      onFailure('getUserMedia');
    }

    this.getUserMedia(mediaType, onGetUserMediaSuccess, onGetUserMediaFailure);
  },

  /**
  * Stablish peerConnection for Callee.
  *
 - Prompt the user for permission to use the Web cam or other video or audio input.
  *
 -- If the user consents, create a peerConnection.
  *
 -- If the user doesn't consent, fire onMediaFailure callback.
  *

  *
 - Set the received SDP offer to the just created peerConnection.
  *
 -- If the SDP offer is not valid, fire onSdpFailure callback.
  *
 -- If the SDP offer is valid, fire onSuccess callback
  *
  * @param {Function} onSuccess
  * @param {Function} onMediaFailure
  * @param {Function} onSdpFailure
  * @param {String} sdp
  */
  startCallee: function(onSuccess, onMediaFailure, onSdpFailure, sdp) {
    var offer, mediaType,
      self = this;

    function onGetUserMediaSuccess(stream) {
      // add stream to peerConnection
      self.peerConnection.addStream(stream);

      // Create answer
      self.peerConnection.createAnswer(function(sessionDescription){
        self.peerConnection.setLocalDescription(sessionDescription);
      }, null, null);
    }

    function onGetUserMediaFailure() {
      onMediaFailure();
    }

    this.start(onSuccess);

    this.peerConnection.onaddstream = function(mediaStreamEvent) {
      var audio, video;

      audio = (mediaStreamEvent.stream.audioTracks.length > 0)? true: false;
      video = (mediaStreamEvent.stream.videoTracks.length > 0)? true: false;

      mediaType = {'audio':audio, 'video':video};

      // Attach stream to remoteView
      self.remoteView.src = webkitURL.createObjectURL(mediaStreamEvent.stream);

      self.getUserMedia(mediaType, onGetUserMediaSuccess, onGetUserMediaFailure);
    };

    try {
      this.peerConnection.setRemoteDescription(new window.RTCSessionDescription({type:'offer', sdp:sdp}));
    } catch (e) {
      onSdpFailure(e);
    }
  },

  /**
  * peerConnection creation.
  * @param {Function} onSuccess Fired when there are no more ICE candidates
  */
  start: function(onSuccess) {
    var
      session = this,
      sent = false,
      stun_config = 'stun: '+ this.session.ua.configuration.stun_server,
      servers = [{"url": stun_config}];

    this.peerConnection = new webkitRTCPeerConnection({iceServers: servers});

    this.peerConnection.onicecandidate = function(event) {
      if (event.candidate) {
        console.log(JsSIP.c.LOG_MEDIA_SESSION +'ICE candidate received: '+ event.candidate.candidate);
      } else {
        console.info(JsSIP.c.LOG_MEDIA_SESSION +'No more ICE candidate');
        console.log(JsSIP.c.LOG_MEDIA_SESSION +'Peerconnection status: '+ this.readyState);
        console.log(JsSIP.c.LOG_MEDIA_SESSION +'Ice Status: '+ this.iceState);
        if (!sent) { // Execute onSuccess just once.
          sent = true;
          onSuccess();
        }
      }
    };

    this.peerConnection.onopen = function() {
      console.log(JsSIP.c.LOG_MEDIA_SESSION +'Media session oppened');
    };

    this.peerConnection.onaddstream = function(mediaStreamEvent) {
      console.warn('stream added');

      if (session.remoteView && this.remoteStreams.length > 0) {
        session.remoteView.src = webkitURL.createObjectURL(mediaStreamEvent.stream);
      }
    };

    this.peerConnection.onremovestream = function(stream) {
      console.log(JsSIP.c.LOG_MEDIA_SESSION +'Stream rmeoved: '+ stream);
    };

    this.peerConnection.onstatechange = function() {
      console.warn('Status changed to: '+ this.readyState);
      console.warn('ICE state is: '+ this.iceState);
    };
  },

  close: function() {
    console.log(JsSIP.c.LOG_MEDIA_SESSION +'Closing peerConnection');
    if(this.peerConnection) {
      this.peerConnection.close();

      if(this.localMedia) {
        this.localMedia.stop();
      }
    }
  },

  /**
  * @param {Function} onSuccess
  * @param {Function} onFailure
  * @param {Object} mediaType
  */
  getUserMedia: function(mediaType, onSuccess, onFailure) {
    var self = this;

    function getSuccess(stream) {
      console.log(JsSIP.c.LOG_MEDIA_SESSION +"Got stream " + stream);

      //Save the localMedia in order to revoke access to devices later.
      self.localMedia = stream;

      // Attach the stream to the view if it exists.
      if (self.selfView){
        self.selfView.src = webkitURL.createObjectURL(stream);
      }

      onSuccess(stream);
    }

    function getFailure() {
      onFailure();
    }

    // Get User Media
    console.log(JsSIP.c.LOG_MEDIA_SESSION +"Requesting access to local media.");
    navigator.webkitGetUserMedia(mediaType, getSuccess, getFailure);

  },

  /**
  * Message reception once PeerConnection is active.
  * @param {String} type
  * @param {String} sdp
  * @param {Function} onSuccess
  * @param {Function} onFailure
  */
  onMessage: function(type, sdp, onSuccess, onFailure) {
    if (type === 'offer') {
      console.log(JsSIP.c.LOG_MEDIA_SESSION +'re-Invite received');
    } else if (type === 'answer') {
      try {
        this.peerConnection.setRemoteDescription(new window.RTCSessionDescription({type:'answer', sdp:sdp}));
        onSuccess();
      } catch (e) {
        onFailure(e);
      }
    }
  }
};<commit_msg>Make RTCPeerconnection work<commit_after>
/*global SessionDescription: false, webkitURL: false, webkitRTCPeerConnection: false*/

/**
 * @fileoverview SIP User Agent
 */

/**
 * @augments JsSIP
 * @class PeerConnection helper Class.
 * @param {JsSIP.OutgoingSession|JsSIP.IncomingSession} session
 * @param {HTMLVideoElement} selfView
 * @param {HTMLVideoElement} remoteView
 */
JsSIP.MediaSession = function(session, selfView, remoteView) {
  this.session = session;
  this.selfView = selfView || null;
  this.remoteView = remoteView || null;
  this.localMedia = null;
  this.peerConnection = null;
};

JsSIP.MediaSession.prototype = {
  /**
   * Stablish peerConnection for Caller.
   *
 - Prompt the user for permission to use the Web cam or other video or audio input.
   *
 -- If the user consents, create a peerConnection.
   *
 -- If the user doesn't consent, fire onFailure callback.
   *
   * @param {Object} mediaType {audio:true/false, video:true/false}
   * @param {Function} onSuccess
   * @param {Function} onFailure
   */
  startCaller: function(mediaType, onSuccess, onFailure) {
    var self = this;

    /** @private */
    function onGetUserMediaSuccess(stream) {
      var offer;

      // Start peerConnection
      self.start(onSuccess, onFailure);

      // add stream to peerConnection
      try {
        self.peerConnection.addStream(stream);
      } catch (e) {
        onFailure('addSstream',e);
      }

      // Set local description and start Ice.
      self.peerConnection.createOffer(function(sessionDescription){
        self.peerConnection.setLocalDescription(sessionDescription);
        console.log('Here the sessionDescription');
      });
    }

    /** @private */
    function onGetUserMediaFailure() {
      onFailure('getUserMedia');
    }

    this.getUserMedia(mediaType, onGetUserMediaSuccess, onGetUserMediaFailure);
  },

  /**
  * Stablish peerConnection for Callee.
  *
 - Prompt the user for permission to use the Web cam or other video or audio input.
  *
 -- If the user consents, create a peerConnection.
  *
 -- If the user doesn't consent, fire onMediaFailure callback.
  *

  *
 - Set the received SDP offer to the just created peerConnection.
  *
 -- If the SDP offer is not valid, fire onSdpFailure callback.
  *
 -- If the SDP offer is valid, fire onSuccess callback
  *
  * @param {Function} onSuccess
  * @param {Function} onMediaFailure
  * @param {Function} onSdpFailure
  * @param {String} sdp
  */
  startCallee: function(onSuccess, onMediaFailure, onSdpFailure, sdp) {
    var offer, mediaType,
      self = this;

    function onGetUserMediaSuccess(stream) {
      // add stream to peerConnection
      self.peerConnection.addStream(stream);

      self.peerConnection.setRemoteDescription(new window.RTCSessionDescription({type:'offer', sdp:sdp}));

      // Create answer
      self.peerConnection.createAnswer(function(sessionDescription){
        self.peerConnection.setLocalDescription(sessionDescription);
      }, null, {'has_audio':true, 'has_video':true});
    }

    function onGetUserMediaFailure() {
      onMediaFailure();
    }

    this.start(onSuccess);

    self.getUserMedia({'audio':true, 'video':true}, onGetUserMediaSuccess, onGetUserMediaFailure);
   },

  /**
  * peerConnection creation.
  * @param {Function} onSuccess Fired when there are no more ICE candidates
  */
  start: function(onSuccess) {
    var
      session = this,
      sent = false,
      stun_config = 'stun:'+this.session.ua.configuration.stun_server,
      servers = [{"url": stun_config}];

    this.peerConnection = new webkitRTCPeerConnection({"iceServers": servers});

    this.peerConnection.onicecandidate = function(event) {
      if (event.candidate) {
        console.log(JsSIP.c.LOG_MEDIA_SESSION +'ICE candidate received: '+ event.candidate.candidate);
      } else {
        console.info(JsSIP.c.LOG_MEDIA_SESSION +'No more ICE candidate');
        console.log(JsSIP.c.LOG_MEDIA_SESSION +'Peerconnection status: '+ this.readyState);
        console.log(JsSIP.c.LOG_MEDIA_SESSION +'Ice Status: '+ this.iceState);
        if (!sent) { // Execute onSuccess just once.
          sent = true;
          onSuccess();
        }
      }
    };

    this.peerConnection.onopen = function() {
      console.log(JsSIP.c.LOG_MEDIA_SESSION +'Media session oppened');
    };

    this.peerConnection.onaddstream = function(mediaStreamEvent) {
      console.warn('stream added');

      if (session.remoteView && this.remoteStreams.length > 0) {
        session.remoteView.src = webkitURL.createObjectURL(mediaStreamEvent.stream);
      }
    };

    this.peerConnection.onremovestream = function(stream) {
      console.log(JsSIP.c.LOG_MEDIA_SESSION +'Stream rmeoved: '+ stream);
    };

    this.peerConnection.onstatechange = function() {
      console.warn('Status changed to: '+ this.readyState);
      console.warn('ICE state is: '+ this.iceState);
    };
  },

  close: function() {
    console.log(JsSIP.c.LOG_MEDIA_SESSION +'Closing peerConnection');
    if(this.peerConnection) {
      this.peerConnection.close();

      if(this.localMedia) {
        this.localMedia.stop();
      }
    }
  },

  /**
  * @param {Function} onSuccess
  * @param {Function} onFailure
  * @param {Object} mediaType
  */
  getUserMedia: function(mediaType, onSuccess, onFailure) {
    var self = this;

    function getSuccess(stream) {
      console.log(JsSIP.c.LOG_MEDIA_SESSION +"Got stream " + stream);

      //Save the localMedia in order to revoke access to devices later.
      self.localMedia = stream;

      // Attach the stream to the view if it exists.
      if (self.selfView){
        self.selfView.src = webkitURL.createObjectURL(stream);
      }

      onSuccess(stream);
    }

    function getFailure() {
      onFailure();
    }

    // Get User Media
    console.log(JsSIP.c.LOG_MEDIA_SESSION +"Requesting access to local media.");
    navigator.webkitGetUserMedia(mediaType, getSuccess, getFailure);

  },

  /**
  * Message reception once PeerConnection is active.
  * @param {String} type
  * @param {String} sdp
  * @param {Function} onSuccess
  * @param {Function} onFailure
  */
  onMessage: function(type, sdp, onSuccess, onFailure) {
    if (type === 'offer') {
      console.log(JsSIP.c.LOG_MEDIA_SESSION +'re-Invite received');
    } else if (type === 'answer') {
      try {
        this.peerConnection.setRemoteDescription(new window.RTCSessionDescription({type:'answer', sdp:sdp}));
        onSuccess();
      } catch (e) {
        onFailure(e);
      }
    }
  }
};<|endoftext|>