<commit_before>/*
Copyright (c) 2014, EDINA.
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this
   list of conditions and the following disclaimer in the documentation and/or
   other materials provided with the distribution.
3. All advertising materials mentioning features or use of this software must
   display the following acknowledgement: This product includes software
   developed by the EDINA.
4. Neither the name of the EDINA nor the names of its contributors may be used to
   endorse or promote products derived from this software without specific prior
   written permission.

THIS SOFTWARE IS PROVIDED BY EDINA ''AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL EDINA BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
*/

"use strict";

/**
 * Module deals with download records/forms from the Personal Cloud.
 */
define(['records', 'map', 'utils', './login'], function(records, map, utils, login){

return {

    /**
     * Initialise upload module.
     * @param syncUtils common sync utilities.
     */
    init: function(syncUtils){
        this.syncUtils = syncUtils;
    },

    /**
     * Download editor from dropbox.
     * @param editor The editor name.
     * @param callback Function will be called when editor is successfully downloaded.
     */
    downloadEditor: function(editor, callback){
        var userId = login.getUser().id;
        var root = this.syncUtils.getCloudProviderUrl() + '/fs/dropbox/' + userId;
        var editorUrl = root + "/editors/" + editor;

        $.ajax({
            type: "GET",
            url: editorUrl,
            success: function(data){
                if(typeof(data.error) === 'undefined'){
                    var s = editor.lastIndexOf('/') + 1;
                    utils.writeToFile({"fileName":
                        editor,
                        "data": data},
                        records.getEditorsDir(),
                        callback
                    );
                }
                else{
                    console.error("Error returned with " + editorUrl +
                                  " : error = " + data.error);
                    callback(false);
                }
            },
            error: function(jqXHR, status, error){
                utils.inform('Editor Problem: ' + editor, 3000, error);
                console.error("Error downloading editor: " + editorUrl +
                              " : status=" + status + " : " + error);
                callback(false);
            },
            cache: false
        });
    },

    /**
     * Download editors from cloud provider.
     * @param callback Function executed after sync is complete.
     */
    downloadEditors: function(callback) {
        utils.inform("Sync editors ...");
        var userId = login.getUser().id;

        var finished = function(success){
            if(callback){
                callback(success);
            }
        };

        records.deleteAllEditors($.proxy(function(){
            var url = this.syncUtils.getCloudProviderUrl() + '/editors/dropbox/' +
                userId +'/';

            console.debug("Sync editors with " + url);

            $.ajax({
                type: "GET",
                dataType: "json",
                url: url,
                success: $.proxy(function(data){
                    if(data.error === 1 || data.metadata.length === 0){
                        // nothing to do
                        utils.inform('No editors to sync');
                        finished(true);
                    }
                    else{
                        var count = 0;
                        var noOfEditors = data.metadata.length;

                        //utils.printObj(data.metadata);

                        // do sync
                        $.each(data.metadata, $.proxy(function(i, editor){
                            // TODO work would correct filename and path
                            var s = editor.lastIndexOf('/') + 1;
                            var fileName = editor.substr(s, editor.lastIndexOf('.'));
                            this.downloadEditor(fileName, function(){
                                ++count;
                                if(count === noOfEditors){
                                    finished(true);
                                }
                            });

                            //utils.printObj(data);
                        }, this));
                    }
                }, this),
                error: function(jqXHR, status, error){
                    console.error("Problem with " + url + " : status=" +
                                  status + " : " + error);
                    finished(false);
                },
                cache: false
            });
        }, this));
    },

    /**
     * Sync records with cloud provider.
     * @param complete Function executed when sync is complete.
     * @param callback Function executed each time an annotation is added or deleted.
     */
    downloadRecords: function(complete, callback) {
        console.debug("Sync download all records");
        utils.inform("Sync records ...");

        var annotations = records.getSavedRecords();
        var userId = login.getUser().id;

        // all locally synced records will first be deleted
        $.each(annotations, function(id, annotation){
            if(annotation.isSynced){
                console.debug("Delete synced record: " + id);
                records.deleteAnnotation(id);

                if(callback){
                    callback(false, id);
                }
            }
        });

        var recordsDir = this.syncUtils.getCloudProviderUrl() +
            '/records/dropbox/' + userId + "/";
        var downloadQueue = [];
        var count = 0;

        console.debug("Fetch current records: " + recordsDir);

        // function for downloading next record in queue
        var _downloadNextRecord = $.proxy(function(){
            var recordName = downloadQueue.pop();
            if(recordName){
                utils.inform("Download " + recordName);

                this.downloadRecord(
                    recordName,
                    function(success, id, annotation){
                        --count;
                        // add new record
                        if(callback && success){
                            callback(true, id, annotation);
                        }

                        // get next in queue
                        _downloadNextRecord();
                    }
                );
            }

            if(count === 0){
                complete();
            }
        }, this);

        // fetch records
        $.ajax({
            type: "GET",
            dataType: "json",
            url: recordsDir,
            success: function(data){
                if(data.error === 0){
                    $.mobile.showPageLoadingMsg();
                    $.each(data.records, function(i, record){
                        // the first property of each object is the name
                        for(var name in record){
                            downloadQueue.push(name);
                            break;
                        };
                    });

                    if(downloadQueue.length === 0){
                        complete();
                    }
                    else{
                        count = downloadQueue.length;
                        console.debug(downloadQueue.length + " to download");
                        // create thread threads for downloading
                        var downloadThreads = 3;
                        for(var i = 0; i < downloadThreads; i++){
                            _downloadNextRecord();
                        }
                    }
                }
                else{
                    // TODO the user should be informed of a failure
                    // (when https://redmine.edina.ac.uk/issues/5812 is resolved)
                    console.error("Error with fetching records:" + data.msg);
                    $.mobile.hidePageLoadingMsg();
                    utils.inform("Sync Error " + data.msg, 5000);

                    complete();
                }
            },
            error: function(jqXHR, status, error){
                console.error("Problem fetching " + recordsDir + " : " +
                              status + " : " + error);
                complete();
            },
            cache: false
        });
    },

    /**
     * Download remote record from dropbox.
     * @param name Record name/title.
     * @param callback Function will be called when the new record is successfully
     * updated.
     * @param orgRecord Object containing id and original record, if record is to be
     * downloaded.
     */
    downloadRecord: function(name, callback, orgRecord){
        var rootUrl = this.syncUtils.getCloudProviderUrl() + '/records/dropbox/' +
            login.getUser().id + "/" + name;
        var recordUrl = rootUrl + "/record.json";

        var assetCount = 0;
        var finished = function(record, success){
            --assetCount;

            if(assetCount < 1){
                var id = undefined;
                var annotation = undefined;
                var delay = 0;

                if(success){
                    if(orgRecord === undefined){
                        // create brand new record
                        annotation = {
                            "record": record,
                            "isSynced": true
                        };
                    }
                    else{
                        // update existing record
                        annotation = orgRecord.annotation;
                        annotation.record = record;
                        id = orgRecord.id;
                    }

                    if(name !== annotation.record.name){
                        // update record name if they don't match, this is for cases
                        // where the record name (directory name) is different from
                        // the name inside the record
                        annotation.record.name = name;
                    }

                    id = records.saveAnnotation(id, annotation);
                }
                else{
                    // allow time to display any error
                    delay = 3000;
                }

                if(callback){
                    setTimeout(function(){
                        callback(success, id, annotation);
                    }, delay);
                }
            }
        };

        console.debug("Fetch " + recordUrl);
        $.ajax({
            type: "GET",
            dataType: "json",
            url: recordUrl,
            cache: false,
            success: $.proxy(function(record){
                //utils.printObj(record);

                // convert coordinates to national grid
                record.point = map.pointToInternal(record.point);

                //  fetch assets and convert URLs
                $.each(record.fields, $.proxy(function(i, field){
                    if(this.syncUtils.isAsset(field)){
                        ++assetCount;

                        var source = rootUrl + "/" + field.val;
                        var target = utils.getFilePath(records.getAssetsDir()) + "/" +
                            name + "/" + field.val;

                        console.debug("download: " + source + " to " + target);

                        new FileTransfer().download(
                            encodeURI(source),
                            target,
                            function(entry) {
                                console.debug("download complete: " + utils.getFilePath(entry));

                                // asset local path becomes new record field val
                                field.val = utils.getFilePath(entry);

                                finished(record, true);
                            },
                            function(error) {
                                // if this fails first check whitelist in cordova.xml
                                utils.informError("Problem syncing " + name);
                                console.error("Problem downloading asset: " + error.source +
                                              " to: " + error.target +
                                              " error: " + utils.getFileTransferErrorMsg(error) +
                                              "http status: " + error.http_status);
                                finished(record, false);
                            }
                        );
                    }
                }, this));

                if(assetCount === 0){
                    finished(record, true);
                }
            }, this),
            error: function(error){
                var msg = "Failed to fetch record " + name;
                console.error(msg);
                utils.informError(msg);
                finished(undefined, false);
            }
        });
    }
}

});
<commit_msg>ignore some jshint errors<commit_after>/*
Copyright (c) 2014, EDINA.
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this
   list of conditions and the following disclaimer in the documentation and/or
   other materials provided with the distribution.
3. All advertising materials mentioning features or use of this software must
   display the following acknowledgement: This product includes software
   developed by the EDINA.
4. Neither the name of the EDINA nor the names of its contributors may be used to
   endorse or promote products derived from this software without specific prior
   written permission.

THIS SOFTWARE IS PROVIDED BY EDINA ''AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL EDINA BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
*/

"use strict";

/**
 * Module deals with download records/forms from the Personal Cloud.
 */
define(['records', 'map', 'utils', './login'],
       function(records, map, utils, login){ // jshint ignore:line

return {

    /**
     * Initialise upload module.
     * @param syncUtils common sync utilities.
     */
    init: function(syncUtils){
        this.syncUtils = syncUtils;
    },

    /**
     * Download editor from dropbox.
     * @param editor The editor name.
     * @param callback Function will be called when editor is successfully downloaded.
     */
    downloadEditor: function(editor, callback){
        var userId = login.getUser().id;
        var root = this.syncUtils.getCloudProviderUrl() + '/fs/dropbox/' + userId;
        var editorUrl = root + "/editors/" + editor;

        $.ajax({
            type: "GET",
            url: editorUrl,
            success: function(data){
                if(typeof(data.error) === 'undefined'){
                    var s = editor.lastIndexOf('/') + 1;
                    utils.writeToFile({"fileName":
                        editor,
                        "data": data},
                        records.getEditorsDir(),
                        callback
                    );
                }
                else{
                    console.error("Error returned with " + editorUrl +
                                  " : error = " + data.error);
                    callback(false);
                }
            },
            error: function(jqXHR, status, error){
                utils.inform('Editor Problem: ' + editor, 3000, error);
                console.error("Error downloading editor: " + editorUrl +
                              " : status=" + status + " : " + error);
                callback(false);
            },
            cache: false
        });
    },

    /**
     * Download editors from cloud provider.
     * @param callback Function executed after sync is complete.
     */
    downloadEditors: function(callback) {
        utils.inform("Sync editors ...");
        var userId = login.getUser().id;

        var finished = function(success){
            if(callback){
                callback(success);
            }
        };

        records.deleteAllEditors($.proxy(function(){
            var url = this.syncUtils.getCloudProviderUrl() + '/editors/dropbox/' +
                userId +'/';

            console.debug("Sync editors with " + url);

            $.ajax({
                type: "GET",
                dataType: "json",
                url: url,
                success: $.proxy(function(data){
                    if(data.error === 1 || data.metadata.length === 0){
                        // nothing to do
                        utils.inform('No editors to sync');
                        finished(true);
                    }
                    else{
                        var count = 0;
                        var noOfEditors = data.metadata.length;

                        //utils.printObj(data.metadata);

                        // do sync
                        $.each(data.metadata, $.proxy(function(i, editor){
                            // TODO work would correct filename and path
                            var s = editor.lastIndexOf('/') + 1;
                            var fileName = editor.substr(s, editor.lastIndexOf('.'));
                            this.downloadEditor(fileName, function(){
                                ++count;
                                if(count === noOfEditors){
                                    finished(true);
                                }
                            });

                            //utils.printObj(data);
                        }, this));
                    }
                }, this),
                error: function(jqXHR, status, error){
                    console.error("Problem with " + url + " : status=" +
                                  status + " : " + error);
                    finished(false);
                },
                cache: false
            });
        }, this));
    },

    /**
     * Sync records with cloud provider.
     * @param complete Function executed when sync is complete.
     * @param callback Function executed each time an annotation is added or deleted.
     */
    downloadRecords: function(complete, callback) {
        console.debug("Sync download all records");
        utils.inform("Sync records ...");

        var annotations = records.getSavedRecords();
        var userId = login.getUser().id;

        // all locally synced records will first be deleted
        $.each(annotations, function(id, annotation){
            if(annotation.isSynced){
                console.debug("Delete synced record: " + id);
                records.deleteAnnotation(id);

                if(callback){
                    callback(false, id);
                }
            }
        });

        var recordsDir = this.syncUtils.getCloudProviderUrl() +
            '/records/dropbox/' + userId + "/";
        var downloadQueue = [];
        var count = 0;

        console.debug("Fetch current records: " + recordsDir);

        // function for downloading next record in queue
        var _downloadNextRecord = $.proxy(function(){
            var recordName = downloadQueue.pop();
            if(recordName){
                utils.inform("Download " + recordName);

                this.downloadRecord(
                    recordName,
                    function(success, id, annotation){
                        --count;
                        // add new record
                        if(callback && success){
                            callback(true, id, annotation);
                        }

                        // get next in queue
                        _downloadNextRecord();
                    }
                );
            }

            if(count === 0){
                complete();
            }
        }, this);

        // fetch records
        $.ajax({
            type: "GET",
            dataType: "json",
            url: recordsDir,
            success: function(data){
                if(data.error === 0){
                    $.mobile.showPageLoadingMsg();
                    $.each(data.records, function(i, record){
                        // the first property of each object is the name
                        for(var name in record){
                            downloadQueue.push(name);
                            break;
                        }
                    });

                    if(downloadQueue.length === 0){
                        complete();
                    }
                    else{
                        count = downloadQueue.length;
                        console.debug(downloadQueue.length + " to download");
                        // create thread threads for downloading
                        var downloadThreads = 3;
                        for(var i = 0; i < downloadThreads; i++){
                            _downloadNextRecord();
                        }
                    }
                }
                else{
                    // TODO the user should be informed of a failure
                    // (when https://redmine.edina.ac.uk/issues/5812 is resolved)
                    console.error("Error with fetching records:" + data.msg);
                    $.mobile.hidePageLoadingMsg();
                    utils.inform("Sync Error " + data.msg, 5000);

                    complete();
                }
            },
            error: function(jqXHR, status, error){
                console.error("Problem fetching " + recordsDir + " : " +
                              status + " : " + error);
                complete();
            },
            cache: false
        });
    },

    /**
     * Download remote record from dropbox.
     * @param name Record name/title.
     * @param callback Function will be called when the new record is successfully
     * updated.
     * @param orgRecord Object containing id and original record, if record is to be
     * downloaded.
     */
    downloadRecord: function(name, callback, orgRecord){
        var rootUrl = this.syncUtils.getCloudProviderUrl() + '/records/dropbox/' +
            login.getUser().id + "/" + name;
        var recordUrl = rootUrl + "/record.json";

        var assetCount = 0;
        var finished = function(record, success){
            --assetCount;

            if(assetCount < 1){
                var id, annotation;
                var delay = 0;

                if(success){
                    if(orgRecord === undefined){
                        // create brand new record
                        annotation = {
                            "record": record,
                            "isSynced": true
                        };
                    }
                    else{
                        // update existing record
                        annotation = orgRecord.annotation;
                        annotation.record = record;
                        id = orgRecord.id;
                    }

                    if(name !== annotation.record.name){
                        // update record name if they don't match, this is for cases
                        // where the record name (directory name) is different from
                        // the name inside the record
                        annotation.record.name = name;
                    }

                    id = records.saveAnnotation(id, annotation);
                }
                else{
                    // allow time to display any error
                    delay = 3000;
                }

                if(callback){
                    setTimeout(function(){
                        callback(success, id, annotation);
                    }, delay);
                }
            }
        };

        console.debug("Fetch " + recordUrl);
        $.ajax({
            type: "GET",
            dataType: "json",
            url: recordUrl,
            cache: false,
            success: $.proxy(function(record){
                //utils.printObj(record);

                // convert coordinates to national grid
                record.point = map.pointToInternal(record.point);

                //  fetch assets and convert URLs
                $.each(record.fields, $.proxy(function(i, field){
                    if(this.syncUtils.isAsset(field)){
                        ++assetCount;

                        var source = rootUrl + "/" + field.val;
                        var target = utils.getFilePath(records.getAssetsDir()) + "/" +
                            name + "/" + field.val;

                        console.debug("download: " + source + " to " + target);

                        new FileTransfer().download(
                            encodeURI(source),
                            target,
                            function(entry) {
                                console.debug("download complete: " + utils.getFilePath(entry));

                                // asset local path becomes new record field val
                                field.val = utils.getFilePath(entry);

                                finished(record, true);
                            },
                            function(error) {
                                // if this fails first check whitelist in cordova.xml
                                utils.informError("Problem syncing " + name);
                                console.error("Problem downloading asset: " + error.source +
                                              " to: " + error.target +
                                              " error: " + utils.getFileTransferErrorMsg(error) +
                                              "http status: " + error.http_status);// jshint ignore:line
                                finished(record, false);
                            }
                        );
                    }
                }, this));

                if(assetCount === 0){
                    finished(record, true);
                }
            }, this),
            error: function(error){
                var msg = "Failed to fetch record " + name;
                console.error(msg);
                utils.informError(msg);
                finished(undefined, false);
            }
        });
    }
};

});
<|endoftext|>


<commit_before>var jqEssentials={};!function(){"use strict";var e=function(e){function n(e){c.classList.contains(e)||(c.className+=" "+e)}function a(e){var n,a;for(a=0;a<c.length;a++)n=c[a],e.call(n,a,n);return this}function r(e,n){c.addEventListener(e,n,!1)}function t(e,n){return e?void(n?c.value=o[n](e):c.value=e):c.value}var c="."===e[0]?document.querySelectorAll(e):document.querySelector(e),o={slug:function(e){var n="ãàáäâẽèéëêìíïîõòóöôùúüûñç·/_,:;",a="aaaaaeeeeeiiiiooooouuuunc------";e=e.replace(/^\s+|\s+$/g,"").toLowerCase();for(var r=0,t=n.length;t>r;r++)e=e.replace(new RegExp(n.charAt(r),"g"),a.charAt(r));return e.replace(/[^a-z0-9 -]/g,"").replace(/\s+/g,"-").replace(/-+/g,"-")}};return{addClass:n,each:a,on:r,val:t}};jqEssentials=function(n){return new e(n)},window.$||(window.$=jqEssentials)}();
<commit_msg>Removing minified file<commit_after><|endoftext|>


<commit_before>/*
	Key Masher plugin for jQuery (https://github.com/digitalBush/jquery.keymasher)
	Copyright (c) 2010 Josh Bush (digitalbush.com)
	Licensed under the MIT license
	Version: 0.1
*/

(function($,undefined){
	var modifiers={shift:16,ctrl:17,meta:91,alt:18};
		//numberPad={'0':96,'1':97,'2':98,'3':99,'4':100,'5':101,'6':102,'7':103,'8':104,'9':105,'*':106,'+':107,'-':109,'.':110,'/':111},

	var keys=(function(){
		var keys    = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890`-=[]\\;',./ \t\n";
		var shifted = "abcdefghijklmnopqrstuvwxyz!@#$%^&*()~_+{}|:\"<>?";
		var noprint={f1:112,f2:113,f3:114,f4:115,f5:116,f6:117,f7:118,f8:119,f9:120,f10:121,f11:122,f12:123,
					capslock:20,numlock:144,scrolllock:145,pageup:33,pagedown:34,end:35,home:36,backspace:8,
					insert:45,del:46,pause:19,esc:27,left:37,up:38,right:39,down:40,printscreen:44};

		var defs={};
		$.each(keys,function(index,value){
			var keyCode=value.charCodeAt(0),shift=shifted[index];
			defs[value]={keyCode:keyCode,charCode:keyCode,shift:shift};
			if(shift)
				defs[shift]={keyCode:keyCode,charCode:shift.charCodeAt(0),shift:value,requiresShift:index>=26};
		});
		$.each(noprint,function(key,value){defs[key]={keyCode:value};});
		return defs;
	})();

	var KeyMasher=function(elm){
		var modifierState={alt: false, ctrl: false,	meta: false, shift: false};
		var forced={};
		var queueModifierEvent=function(direction,modifier,isForced){
			forced[modifier]=isForced;
			modifierState[modifier]=(direction=='down');
			var event=$.extend($.Event(), modifierState, {type:'key'+direction, keyCode: modifiers[modifier], charCode: 0});
			elm.queue('keymash',function(){
				elm.trigger(event);
				$(this).dequeue('keymash');
			});
		};

		var queueStroke=function(key){
			if($.type(key)==='string')
				key=keys[key];
			if(key.requiresShift && !modifierState.shift)
				queueModifierEvent('down','shift',true);
			else if(modifierState.shift && key.shift)
				key=keys[key.shift];

			var ignore = !key.charCode || modifierState.alt || modifierState.ctrl || modifierState.meta,
				down = $.extend($.Event('keydown'), modifierState, {keyCode: key.keyCode, charCode: 0}),
				press = $.extend($.Event('keypress'), modifierState, {keyCode: key.charCode, charCode: key.charCode}),
				up = $.extend($.Event('keyup'), modifierState, {keyCode: key.keyCode, charCode: 0});

			elm.queue('keymash',function(){
				elm.trigger(down);
				if(!down.isPropagationStopped() && !ignore){
					elm.trigger(press);
					if(!press.isPropagationStopped()){
						//need to do caret positioning
						elm.val(elm.val()+String.fromCharCode(key.charCode));
					}
				}
				elm.trigger(up);
				$(this).dequeue('keymash');
			});

			if(forced.shift)
				queueModifierEvent('up','shift');
		};

		var public={
			hold:function(holding,typing){
				var toks=holding.split(',');
				$.each(toks,function(index,value){queueModifierEvent('down',value);});
				public.type(typing);
				$.each(toks,function(index,value){queueModifierEvent('up',value);});
				return public;
			},
			type:function(){
				$.each(arguments,function(index,typing){
					if($.type(typing)==='string')
						$.each(typing,function(index,value){queueStroke(value);});
					else
						queueStroke(typing);
				});
				return public;
			}
		};
		return $.extend(public,keys);
	};

	$.fn.mashKeys=function(fn){
		if($.type(fn)==='string'){
			var typing=fn;
			fn=function(keys){keys.type(typing)};
		}
		return this.each(function(){
			var elm=$(this);
			fn(KeyMasher(elm));
		}).dequeue("keymash");
	};
})(jQuery);<commit_msg>moving modifiers into keyboard definition.<commit_after>/*
	Key Masher plugin for jQuery (https://github.com/digitalBush/jquery.keymasher)
	Copyright (c) 2010 Josh Bush (digitalbush.com)
	Licensed under the MIT license
	Version: 0.1
*/

(function($,undefined){
		//numberPad={'0':96,'1':97,'2':98,'3':99,'4':100,'5':101,'6':102,'7':103,'8':104,'9':105,'*':106,'+':107,'-':109,'.':110,'/':111},

	var keys=(function(){
		var keys    = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890`-=[]\\;',./ \t\n";
		var shifted = "abcdefghijklmnopqrstuvwxyz!@#$%^&*()~_+{}|:\"<>?";
		var noprint={shift:16,ctrl:17,meta:91,alt:18,f1:112,f2:113,f3:114,f4:115,f5:116,f6:117,f7:118,f8:119,f9:120,f10:121,f11:122,f12:123,
					capslock:20,numlock:144,scrolllock:145,pageup:33,pagedown:34,end:35,home:36,backspace:8,
					insert:45,del:46,pause:19,esc:27,left:37,up:38,right:39,down:40,printscreen:44};

		var defs={};
		$.each(keys,function(index,value){
			var keyCode=value.charCodeAt(0),shift=shifted[index];
			defs[value]={keyCode:keyCode,charCode:keyCode,shift:shift};
			if(shift)
				defs[shift]={keyCode:keyCode,charCode:shift.charCodeAt(0),shift:value,requiresShift:index>=26};
		});
		$.each(noprint,function(key,value){defs[key]={keyCode:value};});
		return defs;
	})();

	var KeyMasher=function(elm){
		var modifierState={alt: false, ctrl: false,	meta: false, shift: false};
		var forced={};
		var queueModifierEvent=function(direction,modifier,isForced){
			forced[modifier]=isForced;
			modifierState[modifier]=(direction=='down');
			var event=$.extend($.Event(), modifierState, {type:'key'+direction, keyCode: keys[modifier].keyCode, charCode: 0});
			elm.queue('keymash',function(){
				elm.trigger(event);
				$(this).dequeue('keymash');
			});
		};

		var queueStroke=function(key){
			if($.type(key)==='string')
				key=keys[key];
			if(key.requiresShift && !modifierState.shift)
				queueModifierEvent('down','shift',true);
			else if(modifierState.shift && key.shift)
				key=keys[key.shift];

			var ignore = !key.charCode || modifierState.alt || modifierState.ctrl || modifierState.meta,
				down = $.extend($.Event('keydown'), modifierState, {keyCode: key.keyCode, charCode: 0}),
				press = $.extend($.Event('keypress'), modifierState, {keyCode: key.charCode, charCode: key.charCode}),
				up = $.extend($.Event('keyup'), modifierState, {keyCode: key.keyCode, charCode: 0});

			elm.queue('keymash',function(){
				elm.trigger(down);
				if(!down.isPropagationStopped() && !ignore){
					elm.trigger(press);
					if(!press.isPropagationStopped()){
						//need to do caret positioning
						elm.val(elm.val()+String.fromCharCode(key.charCode));
					}
				}
				elm.trigger(up);
				$(this).dequeue('keymash');
			});

			if(forced.shift)
				queueModifierEvent('up','shift');
		};

		var public={
			hold:function(holding,typing){
				var toks=holding.split(',');
				$.each(toks,function(index,value){queueModifierEvent('down',value);});
				public.type(typing);
				$.each(toks,function(index,value){queueModifierEvent('up',value);});
				return public;
			},
			type:function(){
				$.each(arguments,function(index,typing){
					if($.type(typing)==='string')
						$.each(typing,function(index,value){queueStroke(value);});
					else
						queueStroke(typing);
				});
				return public;
			}
		};
		return $.extend(public,keys);
	};

	$.fn.mashKeys=function(fn){
		if($.type(fn)==='string'){
			var typing=fn;
			fn=function(keys){keys.type(typing)};
		}
		return this.each(function(){
			fn(KeyMasher($(this)));
		}).dequeue("keymash");
	};
})(jQuery);<|endoftext|>


<commit_before>var React = require('react')
var debug = require('debug')('holodex:graph-view:node-ui')
var r = require('r-dom')
var extend = require('xtend')

var Url = require('url')
var config = require('config')
var prefix = Url.format(config.api)

var memberTypeId = prefix + '/roleTypes/member'
var router = require('router')

function circumference (r) {
  return Math.PI*r
}

var style = {
  avatar: {
    cursor: 'pointer',
    border: '2px solid white',
    WebkitBoxShadow: '0px 0px 5px rgba(48,48,48,0.9)',
    MozBoxShadow: '0px 0px 5px rgba(48,48,48,0.9)',
    MsBoxShadow: '0px 0px 5px rgba(48,48,48,0.9)',
    boxShadow: '0px 0px 5px rgba(48,48,48,0.9)',
  },

  node: {
    position: 'absolute'
  }
}

module.exports = React.createClass({
  propTypes: {
    node: React.PropTypes.object.isRequired,
    handleClick: React.PropTypes.func
  },

  getInitialState: function () {
    return {
      activeHalos: {},
      haloWidth: 5,
      // roleIconRatio: 10,
      // startAngle: Math.PI/3 //radians
    }
  },

  render: function () {
    // debug('node', d)
    var d = this.props.node
    var activeRoleTypes = this.props.node.activeRoleTypes || []
    activeRoleTypes = activeRoleTypes.filter(function (roleTypeId) {
      return roleTypeId !== memberTypeId
    })

    debug('node', d)

    // var halos = (activeRoleTypes.length > 0) ? this.renderHalos(activeRoleTypes) : null
    // var roleIcons = (activeRoleTypes.length > 0) ? this.renderRoleIcons(activeRoleTypes, r) : null

    // debug('node', this.props)
    var isPerson = d.model.getType() === 'Person'

    return (
      React.createElement('g', { className: 'node' }, [
        isPerson ? React.createElement('circle', {
          cx: d.x,
          cy: d.y,
          r: Math.max(d.w / 2) + 2,
          fill: '#ECEFF1'
        }) : null /* React.createElement('rect', {
          x: d.x - d.w / 2 - 1,
          y: d.y - d.h / 2 - 1,
          width: d.w + 2,
          height: d.h + 2,
          fill: '#ECEFF1'
        })*/,
        React.createElement('clipPath', {
          id: d.model.getId() + '/node-clip-path',
        }, [
          isPerson ? React.createElement('circle', {
            cx: d.x,
            cy: d.y,
            r: Math.max(d.w, d.h) / 2
          }) : React.createElement('rect', {
            x: d.x - d.w / 2,
            y: d.y - d.h / 2,
            width: d.w,
            height: d.h
          })
        ]),
        React.createElement('image', {
          'xlink:href': d.model.image,
          onClick: this.handleClick,
          style: extend(style.avatar, {
            clipPath: 'url(#' + d.model.getId() + '/node-clip-path)'
          }),
          height: String(d.h),
          width: String(d.w),
          x: String(d.x - d.w / 2),
          y: String(d.y - d.h / 2)
        })
      ])
    )
  },

  handleClick: function () {
    this.props.handleClick(this.props.node.model)
  },

  // renderHalos: function (activeRoleTypes) {
  //   var self = this
  //   var w = self.props.node.w
  //   var x = self.props.node.x
  //   var y = self.props.node.y
  //   return activeRoleTypes.map(function (roleTypeId, i) {
  //     return React.createElement('circle', {
  //       cx: x,
  //       cy: y,
  //       r: w/2+((i+1)*self.state.haloWidth),
  //       fill: self.props.node.IdMap[roleTypeId].color
  //     })
  //   }).reverse()
  // },

  // renderRoleIcons: function (activeRoleTypes, radius) {
  //   var roleIconWidth = circumference(radius)/this.state.roleIconRatio
  //   var hypotenuse = radius + roleIconWidth/2
  //   var w = this.props.node.w
  //   var x = this.props.node.x
  //   var y = this.props.node.y
  //   return activeRoleTypes.map(function (roleTypeId, i) {
  //     var startAngle = this.state.startAngle
  //     var angle = startAngle + (i*startAngle)
  //
  //     return React.createElement('circle', {
  //       cx: x+Math.cos(angle)*hypotenuse,
  //       cy: y-Math.sin(angle)*hypotenuse,
  //       r: roleIconWidth,
  //       fill: this.props.node.IdMap[roleTypeId].color
  //     })
  //   }.bind(this))
  //
  // },

})
<commit_msg>remove unnecessary box-shadow vendor prefixes<commit_after>var React = require('react')
var debug = require('debug')('holodex:graph-view:node-ui')
var r = require('r-dom')
var extend = require('xtend')

var Url = require('url')
var config = require('config')
var prefix = Url.format(config.api)

var memberTypeId = prefix + '/roleTypes/member'
var router = require('router')

function circumference (r) {
  return Math.PI*r
}

var style = {
  avatar: {
    cursor: 'pointer',
    border: '2px solid white',
    WebkitBoxShadow: '0px 0px 5px rgba(48,48,48,0.9)',
    boxShadow: '0px 0px 5px rgba(48,48,48,0.9)'
  },

  node: {
    position: 'absolute'
  }
}

module.exports = React.createClass({
  propTypes: {
    node: React.PropTypes.object.isRequired,
    handleClick: React.PropTypes.func
  },

  getInitialState: function () {
    return {
      activeHalos: {},
      haloWidth: 5,
      // roleIconRatio: 10,
      // startAngle: Math.PI/3 //radians
    }
  },

  render: function () {
    // debug('node', d)
    var d = this.props.node
    var activeRoleTypes = this.props.node.activeRoleTypes || []
    activeRoleTypes = activeRoleTypes.filter(function (roleTypeId) {
      return roleTypeId !== memberTypeId
    })

    debug('node', d)

    // var halos = (activeRoleTypes.length > 0) ? this.renderHalos(activeRoleTypes) : null
    // var roleIcons = (activeRoleTypes.length > 0) ? this.renderRoleIcons(activeRoleTypes, r) : null

    // debug('node', this.props)
    var isPerson = d.model.getType() === 'Person'

    return (
      React.createElement('g', { className: 'node' }, [
        isPerson ? React.createElement('circle', {
          cx: d.x,
          cy: d.y,
          r: Math.max(d.w / 2) + 2,
          fill: '#ECEFF1'
        }) : null /* React.createElement('rect', {
          x: d.x - d.w / 2 - 1,
          y: d.y - d.h / 2 - 1,
          width: d.w + 2,
          height: d.h + 2,
          fill: '#ECEFF1'
        })*/,
        React.createElement('clipPath', {
          id: d.model.getId() + '/node-clip-path',
        }, [
          isPerson ? React.createElement('circle', {
            cx: d.x,
            cy: d.y,
            r: Math.max(d.w, d.h) / 2
          }) : React.createElement('rect', {
            x: d.x - d.w / 2,
            y: d.y - d.h / 2,
            width: d.w,
            height: d.h
          })
        ]),
        React.createElement('image', {
          'xlink:href': d.model.image,
          onClick: this.handleClick,
          style: extend(style.avatar, {
            clipPath: 'url(#' + d.model.getId() + '/node-clip-path)'
          }),
          height: String(d.h),
          width: String(d.w),
          x: String(d.x - d.w / 2),
          y: String(d.y - d.h / 2)
        })
      ])
    )
  },

  handleClick: function () {
    this.props.handleClick(this.props.node.model)
  },

  // renderHalos: function (activeRoleTypes) {
  //   var self = this
  //   var w = self.props.node.w
  //   var x = self.props.node.x
  //   var y = self.props.node.y
  //   return activeRoleTypes.map(function (roleTypeId, i) {
  //     return React.createElement('circle', {
  //       cx: x,
  //       cy: y,
  //       r: w/2+((i+1)*self.state.haloWidth),
  //       fill: self.props.node.IdMap[roleTypeId].color
  //     })
  //   }).reverse()
  // },

  // renderRoleIcons: function (activeRoleTypes, radius) {
  //   var roleIconWidth = circumference(radius)/this.state.roleIconRatio
  //   var hypotenuse = radius + roleIconWidth/2
  //   var w = this.props.node.w
  //   var x = this.props.node.x
  //   var y = this.props.node.y
  //   return activeRoleTypes.map(function (roleTypeId, i) {
  //     var startAngle = this.state.startAngle
  //     var angle = startAngle + (i*startAngle)
  //
  //     return React.createElement('circle', {
  //       cx: x+Math.cos(angle)*hypotenuse,
  //       cy: y-Math.sin(angle)*hypotenuse,
  //       r: roleIconWidth,
  //       fill: this.props.node.IdMap[roleTypeId].color
  //     })
  //   }.bind(this))
  //
  // },

})
<|endoftext|>


<commit_before>var Model = require('base/model')
var debug = require('debug')('holodex:relationship:model')

var roles = require('role/store')

module.exports = Model.extend({
  typeName: 'Relationship',
  collectionName: 'relationships',

  props: {
    type: 'link'
  },

  initialize: function (attrs, opts) {
    debug('initialize', this)
    Model.prototype.initialize.apply(this, arguments)

    this._roles = roles
    .addDynamicView(this.getId() + '/roles')
    .applyFind({
      relationship: this.getId()
    })
  },

  derived: {
    roles: {
      cache: false,
      fn: function () {
        return this._roles.data()
        .map(function (role) {
          return store.findById(role['@id'])
        })
      }
    },
    rolesByType: {
      cache: false,
      fn: function () {
        var rolesByType = {}
        this.roles.forEach(function (role) {

          // if role type is string,
          if (typeof role.type === 'string') {
            // get associated role type object
            var roleType = this.type.roles.find(function (roleType) {
              return roleType.name === role.type
            })
            role.type = roleType
          }

          rolesByType[role.type.name] = role
        }, this)
        return rolesByType
      },
    },
  },
})
<commit_msg>store yo<commit_after>var Model = require('base/model')
var debug = require('debug')('holodex:relationship:model')

var roles = require('role/store')

module.exports = Model.extend({
  typeName: 'Relationship',
  collectionName: 'relationships',

  props: {
    type: 'link'
  },

  initialize: function (attrs, opts) {
    debug('initialize', this)
    Model.prototype.initialize.apply(this, arguments)

    this._roles = roles
    .addDynamicView(this.getId() + '/roles')
    .applyFind({
      relationship: this.getId()
    })
  },

  derived: {
    roles: {
      cache: false,
      fn: function () {
        return this._roles.data()
        .map(function (role) {
          var store = require('base/store')
          return store.findById(role['@id'])
        })
      }
    },
    rolesByType: {
      cache: false,
      fn: function () {
        var rolesByType = {}
        this.roles.forEach(function (role) {

          // if role type is string,
          if (typeof role.type === 'string') {
            // get associated role type object
            var roleType = this.type.roles.find(function (roleType) {
              return roleType.name === role.type
            })
            role.type = roleType
          }

          rolesByType[role.type.name] = role
        }, this)
        return rolesByType
      },
    },
  },
})
<|endoftext|>


<commit_before>(function() {

var slide = function(ct, newView, oldView, direction) {
    var ctEl = ct.$(),
        newEl = newView.$(),
        oldEl = oldView.$();
    ctEl.addClass('ember-animated-container-slide-ct');
    newEl.addClass('ember-animated-container-slide-new');
    setTimeout(function() {
        ctEl.addClass('ember-animated-container-slide-ct-sliding-'+direction);
        ctEl.one('transitionend MSTransitionEnd webkitTransitionEnd oTransitionEnd', function() {
            ctEl.removeClass('ember-animated-container-slide-ct');
            ctEl.removeClass('ember-animated-container-slide-ct-sliding-'+direction);
            newEl.removeClass('ember-animated-container-slide-new');
            ct.removeObject(oldView);
            oldView.destroy();
        });
    }, 0);
};

Ember.AnimatedContainerView.registerEffect('slideLeft', function(ct, newView, oldView) {
    slide(ct, newView, oldView, 'left');
});

Ember.AnimatedContainerView.registerEffect('slideRight', function(ct, newView, oldView) {
    slide(ct, newView, oldView, 'right');
});

})();<commit_msg>Removed unused variable<commit_after>(function() {

var slide = function(ct, newView, oldView, direction) {
    var ctEl = ct.$(),
        newEl = newView.$();
    ctEl.addClass('ember-animated-container-slide-ct');
    newEl.addClass('ember-animated-container-slide-new');
    setTimeout(function() {
        ctEl.addClass('ember-animated-container-slide-ct-sliding-'+direction);
        ctEl.one('transitionend MSTransitionEnd webkitTransitionEnd oTransitionEnd', function() {
            ctEl.removeClass('ember-animated-container-slide-ct');
            ctEl.removeClass('ember-animated-container-slide-ct-sliding-'+direction);
            newEl.removeClass('ember-animated-container-slide-new');
            ct.removeObject(oldView);
            oldView.destroy();
        });
    }, 0);
};

Ember.AnimatedContainerView.registerEffect('slideLeft', function(ct, newView, oldView) {
    slide(ct, newView, oldView, 'left');
});

Ember.AnimatedContainerView.registerEffect('slideRight', function(ct, newView, oldView) {
    slide(ct, newView, oldView, 'right');
});

})();<|endoftext|>


<commit_before>'use strict'

class ElasticSlider {
    constructor(el, options) {
        this.slider = el;
        this.options = options;
        this.slidePromise = null;
        this.elementList = {};
        this.elementList.containerEl = this.slider.querySelector(`.ElasticSlider-container`);
        this.elementList.slideArr = this.elementList.containerEl.children;
        this.elementList.slideActiveEl = this.elementList.slideArr[options.activeSlide - 1];
        this.slideActiveIndex = options.activeSlide - 1;
        this._slideCount = this.elementList.slideArr.length;
        this.elementList.cloneEl = null;

        // Add classes
        // ====================================================================
        this.slider.classList.add('ElasticSlider');

        for (var i = 0; i < this.elementList.slideArr.length; i++) {
            var itemEl = this.elementList.slideArr[i]

            itemEl.classList.add('ElasticSlider-item');
        }

        this._setActiveSlide(this.slideActiveIndex);

        this.animateHash = {
            fade: function(self, index, cb) {
                // return function(this, index, cb) {
                    self.elementList.slideArr[index];
                    self.slideActiveIndex = index;
                    self.elementList.cloneEl.classList.add('ElasticSlider-item--animateFadeStart');

                    // Defer to force css transition onto start class
                    window.setTimeout(function() {
                        self.elementList.cloneEl.classList.add('ElasticSlider-item--animateFadeEnd');
                    }, 5);

                    window.setTimeout(function() {
                        if (typeof cb === 'function') cb(self, index);
                    }, 200)
                // }
            }
        }
    }

    destroy() {

    }

    startSlide(index, animateType) {
        // Index gets moved up one due to clone element
        this._createTransitionEl(index);

        // Handle odd index values
        if (index === 'next') index = this.slideActiveIndex + 1;
        if (index === 'prev') index = this.slideActiveIndex - 1;

        if (typeof index === 'undefined' || index > this._slideCount) {
            index = 0;
        } else if (index < 0) {
            index = this._slideCount;
        };

        if (animateType) {
            this.animateHash[animateType](this, index + 1, function(self, index){
                self.endSlide(index);
            })
        } else {
            this.endSlide(index);
        }
    }

    endSlide(index) {
        this._setActiveSlide(index);

        // Remove clone
        this.elementList.containerEl.removeChild(this.elementList.cloneEl);
        this.elementList.cloneEl = null;
    }

    _setActiveSlide(index) {
        for (var i = 0; i < this.elementList.slideArr.length; i++) {
            var slide = this.elementList.slideArr[i];

            slide.classList.remove('ElasticSlider-item--isActive');
        }

        this.elementList.slideArr[index].classList.add('ElasticSlider-item--isActive');
        this.slideActiveIndex = index;
    }

    _createTransitionEl(index) {
        if (this.elementList.cloneEl) {
            this.elementList.containerEl.removeChild(this.elementList.cloneEl);
        }
        this.elementList.cloneEl = this.elementList.slideArr[index].cloneNode(true);
        this.elementList.cloneEl.classList.add('ElasticSlider-item--clone')

        this.elementList.containerEl.insertBefore(this.elementList.cloneEl, this.elementList.slideArr[0]);
    }
}
<commit_msg>Updated timeout times<commit_after>'use strict'

class ElasticSlider {
    constructor(el, options) {
        this.slider = el;
        this.options = options;
        this.slidePromise = null;
        this.elementList = {};
        this.elementList.containerEl = this.slider.querySelector(`.ElasticSlider-container`);
        this.elementList.slideArr = this.elementList.containerEl.children;
        this.elementList.slideActiveEl = this.elementList.slideArr[options.activeSlide - 1];
        this.slideActiveIndex = options.activeSlide - 1;
        this._slideCount = this.elementList.slideArr.length;
        this.elementList.cloneEl = null;

        // Add classes
        // ====================================================================
        this.slider.classList.add('ElasticSlider');

        for (var i = 0; i < this.elementList.slideArr.length; i++) {
            var itemEl = this.elementList.slideArr[i]

            itemEl.classList.add('ElasticSlider-item');
        }

        this._setActiveSlide(this.slideActiveIndex);

        this.animateHash = {
            fade: function(self, index, cb) {
                // return function(this, index, cb) {
                    self.elementList.slideArr[index];
                    self.slideActiveIndex = index;
                    self.elementList.cloneEl.classList.add('ElasticSlider-item--animateFadeStart');

                    // Defer to force css transition onto start class
                    window.setTimeout(function() {
                        self.elementList.cloneEl.classList.add('ElasticSlider-item--animateFadeEnd');
                    }, 0);

                    window.setTimeout(function() {
                        if (typeof cb === 'function') cb(self, index);
                    }, 100)
            }
        }
    }

    destroy() {

    }

    startSlide(index, animateType) {
        // Index gets moved up one due to clone element
        this._createTransitionEl(index);

        // Handle odd index values
        if (index === 'next') index = this.slideActiveIndex + 1;
        if (index === 'prev') index = this.slideActiveIndex - 1;

        if (typeof index === 'undefined' || index > this._slideCount) {
            index = 0;
        } else if (index < 0) {
            index = this._slideCount;
        };

        if (animateType) {
            this.animateHash[animateType](this, index + 1, function(self, index){
                self.endSlide(index);
            })
        } else {
            this.endSlide(index);
        }
    }

    endSlide(index) {
        this._setActiveSlide(index);

        // Remove clone
        this.elementList.containerEl.removeChild(this.elementList.cloneEl);
        this.elementList.cloneEl = null;
    }

    _setActiveSlide(index) {
        for (var i = 0; i < this.elementList.slideArr.length; i++) {
            var slide = this.elementList.slideArr[i];

            slide.classList.remove('ElasticSlider-item--isActive');
        }

        this.elementList.slideArr[index].classList.add('ElasticSlider-item--isActive');
        this.slideActiveIndex = index;
    }

    _createTransitionEl(index) {
        if (this.elementList.cloneEl) {
            this.elementList.containerEl.removeChild(this.elementList.cloneEl);
        }
        this.elementList.cloneEl = this.elementList.slideArr[index].cloneNode(true);
        this.elementList.cloneEl.classList.add('ElasticSlider-item--clone')

        this.elementList.containerEl.insertBefore(this.elementList.cloneEl, this.elementList.slideArr[0]);
    }
}
<|endoftext|>


<commit_before>/*===============================================================================
************   Store and parse forms data   ************
===============================================================================*/
app.formsData = {};
app.formStoreData = function (formId, formJSON) {
    // Store form data in app.formsData
    app.formsData[formId] = formJSON;

    // Store form data in local storage also
    app.ls['f7form-' + formId] = JSON.stringify(formJSON);
};
app.formDeleteData = function (formId) {
    // Delete form data from app.formsData
    if (app.formsData[formId]) {
        app.formsData[formId] = '';
        delete app.formsData[formId];
    }

    // Delete form data from local storage also
    if (app.ls['f7form-' + formId]) {
        app.ls['f7form-' + formId] = '';
        app.ls.removeItem('f7form-' + formId);
    }
};
app.formGetData = function (formId) {
    // First of all check in local storage
    if (app.ls['f7form-' + formId]) {
        return JSON.parse(app.ls['f7form-' + formId]);
    }
    // Try to get it from formsData obj
    else if (app.formsData[formId]) return app.formsData[formId];
};
app.formToData = function (form) {
    form = $(form);
    if (form.length !== 1) return false;

    // Form data
    var formData = {};

    // Skip input types
    var skipTypes = ['submit', 'image', 'button', 'file'];
    var skipNames = [];
    form.find('input, select, textarea').each(function () {
        var input = $(this);
        var name = input.attr('name');
        var type = input.attr('type');
        var tag = this.nodeName.toLowerCase();
        if (skipTypes.indexOf(type) >= 0) return;
        if (skipNames.indexOf(name) >= 0 || !name) return;
        if (tag === 'select' && input.prop('multiple')) {
            skipNames.push(name);
            formData[name] = [];
            form.find('select[name="' + name + '"] option').each(function () {
                if (this.selected) formData[name].push(this.value);
            });
        }
        else {
            switch (type) {
                case 'checkbox' :
                    skipNames.push(name);
                    formData[name] = [];
                    form.find('input[name="' + name + '"]').each(function () {
                        if (this.checked) formData[name].push(this.value);
                    });
                    break;
                case 'radio' :
                    skipNames.push(name);
                    form.find('input[name="' + name + '"]').each(function () {
                        if (this.checked) formData[name] = this.value;
                    });
                    break;
                default :
                    formData[name] = input.val();
                    break;
            }
        }
    });
    form.trigger('formToJSON formToData form:todata', {formData: formData});

    return formData;
};
app.formToJSON = app.formToData;
app.formFromData = function (form, formData) {
    form = $(form);
    if (form.length !== 1) return false;

    // Skip input types
    var skipTypes = ['submit', 'image', 'button', 'file'];
    var skipNames = [];

    form.find('input, select, textarea').each(function () {
        var input = $(this);
        var name = input.attr('name');
        var type = input.attr('type');
        var tag = this.nodeName.toLowerCase();
        if (!formData[name]) return;
        if (skipTypes.indexOf(type) >= 0) return;
        if (skipNames.indexOf(name) >= 0 || !name) return;
        if (tag === 'select' && input.prop('multiple')) {
            skipNames.push(name);
            form.find('select[name="' + name + '"] option').each(function () {
                if (formData[name].indexOf(this.value) >= 0) this.selected = true;
                else this.selected = false;
            });
        }
        else {
            switch (type) {
                case 'checkbox' :
                    skipNames.push(name);
                    form.find('input[name="' + name + '"]').each(function () {
                        if (formData[name].indexOf(this.value) >= 0) this.checked = true;
                        else this.checked = false;
                    });
                    break;
                case 'radio' :
                    skipNames.push(name);
                    form.find('input[name="' + name + '"]').each(function () {
                        if (formData[name] === this.value) this.checked = true;
                        else this.checked = false;
                    });
                    break;
                default :
                    input.val(formData[name]);
                    break;
            }
        }
        if (tag === 'select' && input.parents('.smart-select').length > 0) {
            input.trigger('change');
        }
    });
    form.trigger('formFromJSON formFromData form:fromdata', {formData: formData});
};
app.formFromJSON = app.formFromData;

app.initFormsStorage = function (pageContainer) {
    pageContainer = $(pageContainer);
    var forms = pageContainer.find('form.store-data');
    if (forms.length === 0) return;

    // Parse forms data and fill form if there is such data
    forms.each(function () {
        var id = this.getAttribute('id');
        if (!id) return;
        var formData = app.formGetData(id);
        if (formData) app.formFromData(this, formData);
    });
    // Update forms data on inputs change
    function storeForm() {
        /*jshint validthis:true */
        var form = $(this);
        var formId = form[0].id;
        if (!formId) return;
        var formJSON = app.formToData(form);
        if (!formJSON) return;
        app.formStoreData(formId, formJSON);
        form.trigger('store form:storedata', {data: formJSON});
    }
    forms.on('change submit', storeForm);

    // Detach Listeners
    function pageBeforeRemove() {
        forms.off('change submit', storeForm);
        pageContainer.off('page:beforeremove', pageBeforeRemove);
    }
    pageContainer.on('page:beforeremove', pageBeforeRemove);
};<commit_msg>formFromJSON set field empty<commit_after>/*===============================================================================
************   Store and parse forms data   ************
===============================================================================*/
app.formsData = {};
app.formStoreData = function (formId, formJSON) {
    // Store form data in app.formsData
    app.formsData[formId] = formJSON;

    // Store form data in local storage also
    app.ls['f7form-' + formId] = JSON.stringify(formJSON);
};
app.formDeleteData = function (formId) {
    // Delete form data from app.formsData
    if (app.formsData[formId]) {
        app.formsData[formId] = '';
        delete app.formsData[formId];
    }

    // Delete form data from local storage also
    if (app.ls['f7form-' + formId]) {
        app.ls['f7form-' + formId] = '';
        app.ls.removeItem('f7form-' + formId);
    }
};
app.formGetData = function (formId) {
    // First of all check in local storage
    if (app.ls['f7form-' + formId]) {
        return JSON.parse(app.ls['f7form-' + formId]);
    }
    // Try to get it from formsData obj
    else if (app.formsData[formId]) return app.formsData[formId];
};
app.formToData = function (form) {
    form = $(form);
    if (form.length !== 1) return false;

    // Form data
    var formData = {};

    // Skip input types
    var skipTypes = ['submit', 'image', 'button', 'file'];
    var skipNames = [];
    form.find('input, select, textarea').each(function () {
        var input = $(this);
        var name = input.attr('name');
        var type = input.attr('type');
        var tag = this.nodeName.toLowerCase();
        if (skipTypes.indexOf(type) >= 0) return;
        if (skipNames.indexOf(name) >= 0 || !name) return;
        if (tag === 'select' && input.prop('multiple')) {
            skipNames.push(name);
            formData[name] = [];
            form.find('select[name="' + name + '"] option').each(function () {
                if (this.selected) formData[name].push(this.value);
            });
        }
        else {
            switch (type) {
                case 'checkbox' :
                    skipNames.push(name);
                    formData[name] = [];
                    form.find('input[name="' + name + '"]').each(function () {
                        if (this.checked) formData[name].push(this.value);
                    });
                    break;
                case 'radio' :
                    skipNames.push(name);
                    form.find('input[name="' + name + '"]').each(function () {
                        if (this.checked) formData[name] = this.value;
                    });
                    break;
                default :
                    formData[name] = input.val();
                    break;
            }
        }
    });
    form.trigger('formToJSON formToData form:todata', {formData: formData});

    return formData;
};
app.formToJSON = app.formToData;
app.formFromData = function (form, formData) {
    form = $(form);
    if (form.length !== 1) return false;

    // Skip input types
    var skipTypes = ['submit', 'image', 'button', 'file'];
    var skipNames = [];

    form.find('input, select, textarea').each(function () {
        var input = $(this);
        var name = input.attr('name');
        var type = input.attr('type');
        var tag = this.nodeName.toLowerCase();
        if (typeof formData[name] === 'undefined' || formData[name] === null) return;
        if (skipTypes.indexOf(type) >= 0) return;
        if (skipNames.indexOf(name) >= 0 || !name) return;
        if (tag === 'select' && input.prop('multiple')) {
            skipNames.push(name);
            form.find('select[name="' + name + '"] option').each(function () {
                if (formData[name].indexOf(this.value) >= 0) this.selected = true;
                else this.selected = false;
            });
        }
        else {
            switch (type) {
                case 'checkbox' :
                    skipNames.push(name);
                    form.find('input[name="' + name + '"]').each(function () {
                        if (formData[name].indexOf(this.value) >= 0) this.checked = true;
                        else this.checked = false;
                    });
                    break;
                case 'radio' :
                    skipNames.push(name);
                    form.find('input[name="' + name + '"]').each(function () {
                        if (formData[name] === this.value) this.checked = true;
                        else this.checked = false;
                    });
                    break;
                default :
                    input.val(formData[name]);
                    break;
            }
        }
        if (tag === 'select' && input.parents('.smart-select').length > 0) {
            input.trigger('change');
        }
    });
    form.trigger('formFromJSON formFromData form:fromdata', {formData: formData});
};
app.formFromJSON = app.formFromData;

app.initFormsStorage = function (pageContainer) {
    pageContainer = $(pageContainer);
    var forms = pageContainer.find('form.store-data');
    if (forms.length === 0) return;

    // Parse forms data and fill form if there is such data
    forms.each(function () {
        var id = this.getAttribute('id');
        if (!id) return;
        var formData = app.formGetData(id);
        if (formData) app.formFromData(this, formData);
    });
    // Update forms data on inputs change
    function storeForm() {
        /*jshint validthis:true */
        var form = $(this);
        var formId = form[0].id;
        if (!formId) return;
        var formJSON = app.formToData(form);
        if (!formJSON) return;
        app.formStoreData(formId, formJSON);
        form.trigger('store form:storedata', {data: formJSON});
    }
    forms.on('change submit', storeForm);

    // Detach Listeners
    function pageBeforeRemove() {
        forms.off('change submit', storeForm);
        pageContainer.off('page:beforeremove', pageBeforeRemove);
    }
    pageContainer.on('page:beforeremove', pageBeforeRemove);
};<|endoftext|>


<commit_before>{
    'use strict';

    window.addEventListener('load', function () {
        getmdlSelect.init('.getmdl-select');
        document.addEventListener("DOMNodeInserted", function (ev) {
            if (ev.relatedNode.querySelectorAll(".getmdl-select").length > 0) {
                componentHandler.upgradeDom();
            }
        }, false);
    });

    var getmdlSelect = {
        defaultValue : {
            width: 300
        },
        addEventListeners: function (dropdown) {
            var input = dropdown.querySelector('input');
            var list = dropdown.querySelectorAll('li');
            var menu = dropdown.querySelector('.mdl-js-menu');

            //show menu on mouse down or mouse up
            input.onkeydown = function (event) {
                if (event.keyCode == 38 || event.keyCode == 40) {
                    menu['MaterialMenu'].show();
                }
            };

            //return focus to input
            menu.onkeydown = function (event) {
                if (event.keyCode == 13) {
                    input.focus();
                }
            };

            [].forEach.call(list, function (li) {
                li.onclick = function () {
                    input.value = li.textContent;
                    dropdown.MaterialTextfield.change(li.textContent); // handles css class changes
                    setTimeout( function() {
                        dropdown.MaterialTextfield.updateClasses_(); //update css class
                    }, 250 );

                    // update input with the "id" value
                    input.dataset.val = li.dataset.val || '';

                    if ("createEvent" in document) {
                        var evt = document.createEvent("HTMLEvents");
                        evt.initEvent("change", false, true);
                        input.dispatchEvent(evt);
                    } else {
                        input.fireEvent("onchange");
                    }
                };
            });
        },
        init: function (selector) {
            var dropdowns = document.querySelectorAll(selector);
            [].forEach.call(dropdowns, function (i) {
                getmdlSelect.addEventListeners(i);
            });
        }
    };
}
<commit_msg>menu not hiding<commit_after>{
    'use strict';

    window.addEventListener('load', function () {
        getmdlSelect.init('.getmdl-select');
        document.addEventListener("DOMNodeInserted", function (ev) {
            if (ev.relatedNode.querySelectorAll(".getmdl-select").length > 0) {
                componentHandler.upgradeDom();
            }
        }, false);
    });

    var getmdlSelect = {
        defaultValue : {
            width: 300
        },
        addEventListeners: function (dropdown) {
            var input = dropdown.querySelector('input');
            var list = dropdown.querySelectorAll('li');
            var menu = dropdown.querySelector('.mdl-js-menu');

            //show menu on mouse down or mouse up
            input.onkeydown = function (event) {
                if (event.keyCode == 38 || event.keyCode == 40) {
                    menu['MaterialMenu'].show();
                }
            };

            //return focus to input
            menu.onkeydown = function (event) {
                if (event.keyCode == 13) {
                    input.focus();
                }
            };

            [].forEach.call(list, function (li) {
                li.onclick = function () {
                    input.value = li.textContent;
                    dropdown.MaterialTextfield.change(li.textContent); // handles css class changes
                    setTimeout( function() {
                        dropdown.MaterialTextfield.updateClasses_(); //update css class
                    }, 250 );

                    // update input with the "id" value
                    input.dataset.val = li.dataset.val || '';

                    if ("createEvent" in document) {
                        var evt = document.createEvent("HTMLEvents");
                        evt.initEvent("change", false, true);
                        menu['MaterialMenu'].hide()
                        input.dispatchEvent(evt);
                    } else {
                        input.fireEvent("onchange");
                    }
                };
            });
        },
        init: function (selector) {
            var dropdowns = document.querySelectorAll(selector);
            [].forEach.call(dropdowns, function (i) {
                getmdlSelect.addEventListeners(i);
            });
        }
    };
}
<|endoftext|>


<commit_before>var initialized = false;
var interval;
var lat1 = 0;
var lon1 = 0;
var lat2;
var lon2;
var prevHead = 0;
var prevDist = 0;
var head = 0;
var dist = 0;
var token = '-';
var units = "metric";
var sens = 5;
var R = 6371000; // m
var locationWatcher;
var locationInterval;
var locationOptions = {timeout: 15000, maximumAge: 1000, enableHighAccuracy: true };
var serverAddress = 'http://getback.pebbletime.io/';

Pebble.addEventListener("ready", function(e) {
  lat2 = parseFloat(localStorage.getItem("lat2")) || null;
  lon2 = parseFloat(localStorage.getItem("lon2")) || null;
  interval = parseInt(localStorage.getItem("interval")) || 0;
  units = localStorage.getItem("units") || "metric";
  sens = parseInt(localStorage.getItem("sens")) || 5;
  token = localStorage.getItem("token") || token;
  if ((lat2 === null) || (lon2 === null)) {
    storeCurrentPosition();
  }
  else {
    // console.log("Target location known:" + lon2 + ',' + lat2);
  }
  startWatcher();
  if (Pebble.getTimelineToken) {
    Pebble.getTimelineToken(
      function (timelineToken) {
        token = timelineToken;
        console.log('Got timeline token ' + token);
        localStorage.setItem("token", token);
      },
      function (error) {
        console.log('Error getting timeline token: ' + error);
      }
    );
  }
  console.log("JavaScript app ready and running!");
  initialized = true;
});

Pebble.addEventListener("appmessage",
  function(e) {
    if (e && e.payload && e.payload.cmd) {
      console.log("Got command: " + e.payload.cmd);
      switch (e.payload.cmd) {
        case 'set':
          if (!e.payload.id || (e.payload.id < 0)) {
            storeCurrentPosition();
          }
          else {
            getPositionFromServer(e.payload.id);
          }
          break;
        case 'clear':
          lat2 = null;
          lon2 = null;
          break;
        case 'quit':
          navigator.geolocation.clearWatch(locationWatcher);
          break;
        default:
          console.log("Unknown command!");
      }
    }
  }
);

Pebble.addEventListener("showConfiguration",
  function() {
    var uri = serverAddress + token + '/configure';
    console.log("Configuration url: " + uri);
    Pebble.openURL(uri);
  }
);

Pebble.addEventListener("webviewclosed",
  function(e) {
    console.log(e.response);
    var options = JSON.parse(decodeURIComponent(e.response));
    console.log("Webview window returned: " + JSON.stringify(options));
    units = (options["units"] === 1) ? 'imperial' : 'metric';
    localStorage.setItem("units", units);
    console.log("Units set to: " + units);
    interval = parseInt(options["interval"]) || 0;
    localStorage.setItem("interval", interval);
    console.log("Interval set to: " + interval);
    sens = parseInt(options["sens"]) || 5;
    localStorage.setItem("sens", sens);
    console.log("Sentitivity set to: " + sens);
    var msg = {"units": units,
               "sens": parseInt(sens)};
    sendMessage(msg);
    calculate();
    startWatcher();
  }
);

function sendMessage(dict) {
  Pebble.sendAppMessage(dict, appMessageAck, appMessageNack);
  console.log("Sent message to Pebble! " + JSON.stringify(dict));
}

function appMessageAck(e) {
  console.log("Message accepted by Pebble!");
}

function appMessageNack(e) {
  console.log("Message rejected by Pebble! " + e.error);
}

function locationSuccess(position) {
  // console.log("Got location " + position.coords.latitude + ',' + position.coords.longitude + ', heading at ' + position.coords.heading);
  lat1 = position.coords.latitude;
  lon1 = position.coords.longitude;
  calculate();
}

function addLocation(position) {
  storeLocation(position);
  // add place to server
  var obj = {position: position};
  var url = serverAddress + token + '/place/new';
  var req = new XMLHttpRequest();
  req.onload = function(res) {
    console.log(res);
  };
  req.open("post", url, true);
  req.send(obj);
}

function storeLocation(position) {
  lat2 = position.coords.latitude;
  lon2 = position.coords.longitude;
  localStorage.setItem("lat2", lat2);
  localStorage.setItem("lon2", lon2);
  // console.log("Stored location " + position.coords.latitude + ',' + position.coords.longitude);
  calculate();
}

function calculate() {
  var msg;
  if (lat2 || lon2) {
    if (!lat2) {
      lat2 = 0;
    }
    if (!lon2) {
      lon2 = 0;
    }
    var dLat = toRad(lat2-lat1);
    var dLon = toRad(lon2-lon1);
    var l1 = toRad(lat1);
    var l2 = toRad(lat2);
    var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
            Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(l1) * Math.cos(l2);
    var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
    dist = Math.round(R * c);
    var y = Math.sin(dLon) * Math.cos(l2);
    var x = Math.cos(l1)*Math.sin(l2) -
            Math.sin(l1)*Math.cos(l2)*Math.cos(dLon);
    head = toDeg(Math.round(Math.atan2(y, x)));
    if ((dist != prevDist) || (head != prevHead)) {
      msg = {"dist": dist,
             "head": head,
             "units": units,
             "sens": parseInt(sens)};
      sendMessage(msg);
      prevDist = dist;
      prevHead = head;
    }
  }
}

function locationError(error) {
  console.warn('location error (' + error.code + '): ' + error.message);
}

function storeCurrentPosition() {
  // console.log("Attempting to store current position.");
  var msg = {"dist": 0,
             "head": 0};
  sendMessage(msg);
  navigator.geolocation.getCurrentPosition(addLocation, locationError, locationOptions);
}

function getPositionFromServer(id) {
  var url = serverAddress + token + '/place/' + id;
  var req = new XMLHttpRequest();
  req.onload = parseServerResponse;
  req.open("get", url, true);
  req.send();
}

function parseServerResponse(res) {
  if (!res.position) {
    console.warn('No position from server');
    return false;
  }
  console.log('Got position from server: ' + res.position.latitude + ', ' + res.position.longitude);
  storeLocation(res.position);
}

function startWatcher() {
  if (locationInterval) {
    clearInterval(locationInterval);
  }
  if (locationWatcher) {
    navigator.geolocation.clearWatch(locationWatcher);
  }
  if (interval > 0) {
    console.log('Interval is ' + interval + ', using getCurrentPosition and setInterval');
    locationInterval = setInterval(function() {
      navigator.geolocation.getCurrentPosition(locationSuccess, locationError, locationOptions);
    }, interval * 1000);
  }
  else {
    console.log('Interval not set, using watchPosition');
    navigator.geolocation.getCurrentPosition(locationSuccess, locationError, locationOptions);
    locationWatcher = navigator.geolocation.watchPosition(locationSuccess, locationError, locationOptions);
  }
  // for testing: randomize movement!
  /*
  window.navigator.geolocation.getCurrentPosition(locationSuccess, locationError, locationOptions);
  locationWatcher = window.setInterval(function() {
    lat1 = lat1 + Math.random()/100;
    lon1 = lon1 - Math.random()/100;
    calculate();
  }, 5000);
  */
  console.log("Started location watcher: " + locationWatcher);
}
function toRad(num) {
  return num * Math.PI / 180;
}
function toDeg(num) {
  return num * 180 / Math.PI;
}
<commit_msg>pass existing config to config screen<commit_after>var initialized = false;
var interval;
var lat1 = 0;
var lon1 = 0;
var lat2;
var lon2;
var prevHead = 0;
var prevDist = 0;
var head = 0;
var dist = 0;
var token = '-';
var units = "metric";
var sens = 5;
var R = 6371000; // m
var locationWatcher;
var locationInterval;
var locationOptions = {timeout: 15000, maximumAge: 1000, enableHighAccuracy: true };
var serverAddress = 'http://getback.pebbletime.io/';

Pebble.addEventListener("ready", function(e) {
  lat2 = parseFloat(localStorage.getItem("lat2")) || null;
  lon2 = parseFloat(localStorage.getItem("lon2")) || null;
  interval = parseInt(localStorage.getItem("interval")) || 0;
  units = localStorage.getItem("units") || "metric";
  sens = parseInt(localStorage.getItem("sens")) || 5;
  token = localStorage.getItem("token") || token;
  if ((lat2 === null) || (lon2 === null)) {
    storeCurrentPosition();
  }
  else {
    // console.log("Target location known:" + lon2 + ',' + lat2);
  }
  startWatcher();
  if (Pebble.getTimelineToken) {
    Pebble.getTimelineToken(
      function (timelineToken) {
        token = timelineToken;
        console.log('Got timeline token ' + token);
        localStorage.setItem("token", token);
      },
      function (error) {
        console.log('Error getting timeline token: ' + error);
      }
    );
  }
  console.log("JavaScript app ready and running!");
  initialized = true;
});

Pebble.addEventListener("appmessage",
  function(e) {
    if (e && e.payload && e.payload.cmd) {
      console.log("Got command: " + e.payload.cmd);
      switch (e.payload.cmd) {
        case 'set':
          if (!e.payload.id || (e.payload.id < 0)) {
            storeCurrentPosition();
          }
          else {
            getPositionFromServer(e.payload.id);
          }
          break;
        case 'clear':
          lat2 = null;
          lon2 = null;
          break;
        case 'quit':
          navigator.geolocation.clearWatch(locationWatcher);
          break;
        default:
          console.log("Unknown command!");
      }
    }
  }
);

Pebble.addEventListener("showConfiguration",
  function() {
    var conf = {
      'units': units,
      'interval': interval,
      'sens': sens};
    // var uri = serverAddress + token + '/configure?conf=' +
    var uri = serverAddress + '/configure#' +
      encodeURIComponent(JSON.stringify(conf));
    console.log("Configuration url: " + uri);
    Pebble.openURL(uri);
  }
);

Pebble.addEventListener("webviewclosed",
  function(e) {
    console.log(e.response);
    var options = JSON.parse(decodeURIComponent(e.response));
    console.log("Webview window returned: " + JSON.stringify(options));
    units = (options.units == 'imperial') ? 'imperial' : 'metric';
    localStorage.setItem("units", units);
    console.log("Units set to: " + units);
    interval = parseInt(options.interval) || 0;
    localStorage.setItem("interval", interval);
    console.log("Interval set to: " + interval);
    sens = parseInt(options.sens) || 5;
    localStorage.setItem("sens", sens);
    console.log("Sentitivity set to: " + sens);
    var msg = {"units": units,
               "sens": parseInt(sens)};
    sendMessage(msg);
    calculate();
    startWatcher();
  }
);

function sendMessage(dict) {
  Pebble.sendAppMessage(dict, appMessageAck, appMessageNack);
  console.log("Sent message to Pebble! " + JSON.stringify(dict));
}

function appMessageAck(e) {
  console.log("Message accepted by Pebble!");
}

function appMessageNack(e) {
  console.log("Message rejected by Pebble! " + e.error);
}

function locationSuccess(position) {
  // console.log("Got location " + position.coords.latitude + ',' + position.coords.longitude + ', heading at ' + position.coords.heading);
  lat1 = position.coords.latitude;
  lon1 = position.coords.longitude;
  calculate();
}

function addLocation(position) {
  storeLocation(position);
  // add place to server
  var obj = {position: position};
  var url = serverAddress + token + '/place/new';
  var req = new XMLHttpRequest();
  req.onload = function(res) {
    console.log(res);
  };
  req.open("post", url, true);
  req.send(obj);
}

function storeLocation(position) {
  lat2 = position.coords.latitude;
  lon2 = position.coords.longitude;
  localStorage.setItem("lat2", lat2);
  localStorage.setItem("lon2", lon2);
  // console.log("Stored location " + position.coords.latitude + ',' + position.coords.longitude);
  calculate();
}

function calculate() {
  var msg;
  if (lat2 || lon2) {
    if (!lat2) {
      lat2 = 0;
    }
    if (!lon2) {
      lon2 = 0;
    }
    var dLat = toRad(lat2-lat1);
    var dLon = toRad(lon2-lon1);
    var l1 = toRad(lat1);
    var l2 = toRad(lat2);
    var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
            Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(l1) * Math.cos(l2);
    var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
    dist = Math.round(R * c);
    var y = Math.sin(dLon) * Math.cos(l2);
    var x = Math.cos(l1)*Math.sin(l2) -
            Math.sin(l1)*Math.cos(l2)*Math.cos(dLon);
    head = toDeg(Math.round(Math.atan2(y, x)));
    if ((dist != prevDist) || (head != prevHead)) {
      msg = {"dist": dist,
             "head": head,
             "units": units,
             "sens": parseInt(sens)};
      sendMessage(msg);
      prevDist = dist;
      prevHead = head;
    }
  }
}

function locationError(error) {
  console.warn('location error (' + error.code + '): ' + error.message);
}

function storeCurrentPosition() {
  // console.log("Attempting to store current position.");
  var msg = {"dist": 0,
             "head": 0};
  sendMessage(msg);
  navigator.geolocation.getCurrentPosition(addLocation, locationError, locationOptions);
}

function getPositionFromServer(id) {
  var url = serverAddress + token + '/place/' + id;
  var req = new XMLHttpRequest();
  req.onload = parseServerResponse;
  req.open("get", url, true);
  req.send();
}

function parseServerResponse(res) {
  if (!res.position) {
    console.warn('No position from server');
    return false;
  }
  console.log('Got position from server: ' + res.position.latitude + ', ' + res.position.longitude);
  storeLocation(res.position);
}

function startWatcher() {
  if (locationInterval) {
    clearInterval(locationInterval);
  }
  if (locationWatcher) {
    navigator.geolocation.clearWatch(locationWatcher);
  }
  if (interval > 0) {
    console.log('Interval is ' + interval + ', using getCurrentPosition and setInterval');
    navigator.geolocation.getCurrentPosition(locationSuccess, locationError, locationOptions);
    locationInterval = setInterval(function() {
      navigator.geolocation.getCurrentPosition(locationSuccess, locationError, locationOptions);
    }, interval * 1000);
  }
  else {
    console.log('Interval not set, using watchPosition');
    navigator.geolocation.getCurrentPosition(locationSuccess, locationError, locationOptions);
    locationWatcher = navigator.geolocation.watchPosition(locationSuccess, locationError, locationOptions);
    console.log("Started location watcher: " + locationWatcher);
  }
  // for testing: randomize movement!
  /*
  window.navigator.geolocation.getCurrentPosition(locationSuccess, locationError, locationOptions);
  if (!interval) {
    interval = 10;
  }
  locationWatcher = setInterval(function() {
    lat1 = lat1 + Math.random()/100;
    lon1 = lon1 - Math.random()/100;
    calculate();
  }, interval * 1000);
  console.log("Started fake location watcher: " + locationWatcher);
  */
}
function toRad(num) {
  return num * Math.PI / 180;
}
function toDeg(num) {
  return num * 180 / Math.PI;
}
<|endoftext|>