<commit_before>frappe.provide("jasper");

jasper.dialog_upload = frappe.ui.form.ControlData.extend({
	init: function(opts) {
		this.docname = opts.docname;
		this._super(opts);
		this.input_area = this.wrapper;
		this.make_input();

	},
	make_input: function() {
		var me = this;
		this.$value = $('
' +
			'
' +
				'' +
				'' +
			'
' +
			'×
')
			.prependTo(me.input_area)
			.toggle(false);

		this.$value.find(".close").on("click", function() {
			if(me.frm) {
				me.frm.attachments.remove_attachment_by_filename(me.value, function() {
					me.parse_validate_and_set_in_model(null);
					me.set_input(null);
					me.refresh();
				});
			} else {
				me.dataurl = null;
				me.fileobj = null;
				me.set_input(null);
				me.refresh();
			}
		})
	},
	show: function(){
		if(!this.dialog) {
			this.dialog = new frappe.ui.Dialog({
				title: __(this.df.label || "Upload"),
			});
		}

		$(this.dialog.body).empty();

		this.set_upload_options();
		jasper.upload.make(this.upload_options);
		this.dialog.show();
	},
	on_attach: function(){
		var me = this;
		var msgbox = msgprint(__("Uploading..."));
		this.args["method"] = "jasper_erpnext_report.utils.file.file_upload";
		return frappe.call({
			"method": "uploadfile",
			args: me.args,
			callback: function(r) {
				if(!r._server_messages)
					msgbox.hide();
				if(r.exc) {
					// if no onerror, assume callback will handle errors
					opts.onerror ? opts.onerror(r) : opts.callback(null, null, r);
					return;
				}
				var attachment = r.message;
				$(document).trigger("upload_complete", attachment);
			}
		});
	},
	set_upload_options: function() {
		var me = this;
		this.upload_options = {
			parent: me.dialog.body,
			args: {},
			max_width: me.df.max_width,
			max_height: me.df.max_height,
			callback: function(attachment, r) {
				me.dialog.hide();
				me.on_upload_complete(attachment);
				me.set_input(attachment.file_url, this.dataurl);
			},
			onerror: function() {
				me.dialog.hide();
			},
		}

		if(this.frm) {
			this.upload_options.args = {
				doctype: me.frm.doctype,
				docname: me.frm.docname,
				method:  "jasper_erpnext_report.utils.file.file_upload"
			}
		};
		this.upload_options.on_attachs = function(args, dataurl) {
				me.dialog.hide();
				me.args = args;
				me.dataurl = dataurl;
				if(me.on_attach) {
					me.on_attach()
				}
				if(me.df.on_attach) {
					me.df.on_attach(args, dataurl);
				}
				me.on_upload_complete();
		}
	},
	on_upload_complete: function(attachment) {
		if(this.frm) {
			this.parse_validate_and_set_in_model(attachment.file_url);
			this.refresh();
			this.frm.attachments.update_attachment(attachment);
		} else {
			this.set_input(attachment.file_url, this.dataurl);
			this.refresh();
		}
	},
	set_input: function(value, dataurl) {
			this.value = $.trim(value);
			if(this.value) {
			}
	},
	clear_input: function(){
		this.$value.toggle(true).find(".attached-file").empty();
	},
	get_value: function() {
			if(this.frm) {
				return this.value;
			} else {
				return this.fileobj ? (this.fileobj.filename + "," + this.dataurl) : null;
			}
	},
	set_model_value: function(value, fieldname, fieldtype) {
			if(frappe.model.set_value(this.doctype, this.docname, fieldname,
				value, fieldtype)) {
				this.last_value = value;
			}
	},
});

jasper.dialog_upload_tree = frappe.ui.form.Control.extend({
	init: function(opts) {
		this._super(opts);
		this.maked = false;
	},
	make: function(){
		return;
	},
	make_wrapper: function() {
		return;
	},
	make_input: function() {
		var me = this;

		if(this.maked === false){
			this.value = this.$wrapper.html('

');

			this.get_instance_tree();
			this.maked = true;
		};

	},
	get_instance_tree: function(){
		var me = this;
		$('#jasper_upload_tree').jstree({
			'core' : {
			  'check_callback' : true,
			  'multiple' : false
			},
		    "types" : {
		       "default" : {
		         "icon" : "icon-paper-clip"
		       }
		     },
			"plugins" : ["state", "wholerow", "contextmenu", "types"],
			"contextmenu": {items: me.set_context()},

		});
		this.instance = $('#jasper_upload_tree').jstree(true);
	},
	show: function(){
		var me = this;
		this.make_input();
		if(!this.dialog) {
			this.dialog = new frappe.ui.Dialog({
				title: __(me.df.label || "Upload"),
			});
		}

		$(this.dialog.body).empty();

		this.set_upload_options();
		jasper.upload.make(this.upload_options);
		this.dialog.show();
	},
	set_upload_options: function() {
		var me = this;
		this.selected = this.instance.get_selected();
		this.data = this.instance.get_node(this.selected).data;
		this.root = this.instance.get_node("#").children[0] || "#";
		this.upload_options = {
			parent: me.dialog.body,
			args: {},
			max_width: me.df.max_width,
			max_height: me.df.max_height,
			callback: function(attachment, r) {
				me.dialog.hide();
				if (!r._server_messages){
					me.instance.create_node(me.selected.length > 0 ? me.selected[0]: me.root,{"id": attachment.name, "text":attachment.file_url,
					"data":{name: attachment.file_name.slice(0,-6)}});
				}
				me.on_upload_complete(attachment);
			},
			onerror: function() {
				me.dialog.hide();
			},
		}

		if(this.frm) {
			this.upload_options.args = {
				//from_form: 1,
				parent_report: this.selected[0] || (this.root==="#"? "root":this.root),
				doctype: me.frm.doctype,
				docname: me.frm.docname,
				method:  "jasper_erpnext_report.utils.upload.file_upload"
			}
		};
		this.upload_options.on_attachs = function(args, dataurl) {
				me.dialog.hide();
				me.args = args;
				me.dataurl = dataurl;
				if(me.on_attach) {
					me.on_attach()
				}
				if(me.df.on_attach) {
					me.df.on_attach(args, dataurl);
				}
				me.on_upload_complete();
		}
	},
	on_upload_complete: function(attachment) {
		if(this.frm) {
			this.parse_validate_and_set_in_model(attachment.file_url);
			this.refresh();
			this.frm.attachments.update_attachment(attachment);
		} else {
			this.refresh();
		}
	},
	set_model_value: function(value) {
		if(frappe.model.set_value(this.doctype, this.docname, this.df.fieldname,
			value, this.df.fieldtype)) {
			this.last_value = value;
		}
	},
	set_input: function(name, file_name, url, parent_report) {
			if(url) {
				this.make_input();
				if (parent_report === "root")
					parent_report = null;
				this.instance.create_node(parent_report || "#",{"id": name, "text":url, "data":{"name": file_name.split(".")[0]}});
			}
	},
	clear_input: function(){
		$('#jasper_upload_tree').jstree("destroy").empty();
		$('#jasper_upload_tree').remove();
		this.maked = false;
	},
	set_context: function(){
		var me = this;
		return function(node) {
		    // The default set of all items
		    var items = {
		        deleteItem: { // The "delete" menu item
		            label: "Delete",
		            action: function (d) {
						var inst = $.jstree.reference(d.reference);
	                    obj = inst.get_node(d.reference);
						me.delete_item(obj);
						inst.delete_node(obj);
		            }
		        }
		    };
			//delete items.deleteItem;
		    return items;
		};
	},
	delete_item: function(obj){
		var me = this;
		if(me.frm) {
			for (var i=0; i < obj.children.length; i++){
				var node = me.instance.get_node(obj.children[i]);
				me.frm.attachments.remove_attachment_by_filename(node.text, function() {
					me.parse_validate_and_set_in_model(null);
				});
			};
			me.frm.attachments.remove_attachment_by_filename(obj.text, function() {
				me.parse_validate_and_set_in_model(null);
			});
		} else {
			me.dataurl = null;
			me.fileobj = null;
		}
	}
});

jasper.upload = {
	make: function(opts) {
		if(!opts.args) opts.args = {};
		var $upload = $('
\

 '
				+ __('Upload a file') + '
\

\
				<input class="alert alert-info" style="padding: 7px; margin: 7px 0px;" \
					type="file" name="filedata" />\

\
			<button class="btn btn-info btn-upload"> ' +__('Upload')
				+'</button>
').appendTo(opts.parent);

		$upload.find(".action-attach").click(function() {
			$upload.find(".action-link").removeClass("disabled");
			$upload.find(".action-attach").addClass("disabled");
			$upload.find(".action-link-input").toggle(false);
			$upload.find(".action-attach-input").toggle(true);
			$upload.find(".btn-upload").html(' ' +__('Upload'))
			return false;
		})

		// get the first file
		$upload.find(".btn-upload").click(function() {
			// convert functions to values
			for(key in opts.args) {
				if(typeof val==="function")
					opt.args[key] = opts.args[key]();
			}

			// add other inputs in the div as arguments
			opts.args.params = {};
			$upload.find("input[name]").each(function() {
				var key = $(this).attr("name");
				var type = $(this).attr("type");
				if(key!="filedata" && key!="file_url") {
					if(type === "checkbox") {
						opts.args.params[key] = $(this).is(":checked");
					} else {
						opts.args.params[key] = $(this).val();
					}
				}
			})

			var fileobj = $upload.find(":file").get(0).files[0];
			jasper.upload.upload_file(fileobj, opts.args, opts);
		})
	},
	upload_file: function(fileobj, args, opts) {
		if(!fileobj && !args.file_url) {
			msgprint(__("Please attach a file."));
			return;
		}

		var dataurl = null;
		var _upload_file = function() {
			if(opts.on_attach) {
				opts.on_attach(args, dataurl)
			} else {
				var msgbox = msgprint(__("Uploading..."));
				return frappe.call({
					"method": "uploadfile",
					args: args,
					callback: function(r) {
						if(!r._server_messages)
							msgbox.hide();
						if(r.exc) {
							// if no onerror, assume callback will handle errors
							opts.onerror ? opts.onerror(r) : opts.callback(null, null, r);
							return;
						}
						var attachment = r.message;
						opts.callback(attachment, r);
						$(document).trigger("upload_complete", attachment);
					}
				});
			}
		}

		if(args.file_url) {
			_upload_file();
		} else {
			var freader = new FileReader();

			freader.onload = function() {
				args.filename = fileobj.name;
				if((opts.max_width || opts.max_height) && (/\.(gif|jpg|jpeg|tiff|png)$/i).test(args.filename)) {
					frappe.utils.resize_image(freader, function(_dataurl) {
						dataurl = _dataurl;
						args.filedata = _dataurl.split(",")[1];
						_upload_file();
					})
				} else {
					dataurl = freader.result;
					args.filedata = freader.result.split(",")[1];
					_upload_file();
				}
			};

			freader.readAsDataURL(fileobj);
		}
	}
}
<commit_msg>Clean code.<commit_after>frappe.provide("jasper");

jasper.dialog_upload = frappe.ui.form.ControlData.extend({
	init: function(opts) {
		this.docname = opts.docname;
		this._super(opts);
		this.input_area = this.wrapper;
		this.make_input();

	},
	make_input: function() {
		var me = this;
		this.$value = $('
' +
			'
' +
				'' +
				'' +
			'
' +
			'×
')
			.prependTo(me.input_area)
			.toggle(false);

		this.$value.find(".close").on("click", function() {
			if(me.frm) {
				me.frm.attachments.remove_attachment_by_filename(me.value, function() {
					me.parse_validate_and_set_in_model(null);
					me.set_input(null);
					me.refresh();
				});
			} else {
				me.dataurl = null;
				me.fileobj = null;
				me.set_input(null);
				me.refresh();
			}
		})
	},
	show: function(){
		if(!this.dialog) {
			this.dialog = new frappe.ui.Dialog({
				title: __(this.df.label || "Upload"),
			});
		}

		$(this.dialog.body).empty();

		this.set_upload_options();
		jasper.upload.make(this.upload_options);
		this.dialog.show();
	},
	on_attach: function(){
		var me = this;
		var msgbox = msgprint(__("Uploading..."));
		this.args["method"] = "jasper_erpnext_report.utils.file.file_upload";
		return frappe.call({
			"method": "uploadfile",
			args: me.args,
			callback: function(r) {
				if(!r._server_messages)
					msgbox.hide();
				if(r.exc) {
					// if no onerror, assume callback will handle errors
					opts.onerror ? opts.onerror(r) : opts.callback(null, null, r);
					return;
				}
				var attachment = r.message;
				$(document).trigger("upload_complete", attachment);
			}
		});
	},
	set_upload_options: function() {
		var me = this;
		this.upload_options = {
			parent: me.dialog.body,
			args: {},
			max_width: me.df.max_width,
			max_height: me.df.max_height,
			callback: function(attachment, r) {
				me.dialog.hide();
				me.on_upload_complete(attachment);
				me.set_input(attachment.file_url, this.dataurl);
			},
			onerror: function() {
				me.dialog.hide();
			},
		}

		if(this.frm) {
			this.upload_options.args = {
				doctype: me.frm.doctype,
				docname: me.frm.docname,
				method:  "jasper_erpnext_report.utils.file.file_upload"
			}
		};
		this.upload_options.on_attachs = function(args, dataurl) {
				me.dialog.hide();
				me.args = args;
				me.dataurl = dataurl;
				if(me.on_attach) {
					me.on_attach()
				}
				if(me.df.on_attach) {
					me.df.on_attach(args, dataurl);
				}
				me.on_upload_complete();
		}
	},
	on_upload_complete: function(attachment) {
		if(this.frm) {
			this.parse_validate_and_set_in_model(attachment.file_url);
			this.refresh();
			this.frm.attachments.update_attachment(attachment);
		} else {
			this.set_input(attachment.file_url, this.dataurl);
			this.refresh();
		}
	},
	set_input: function(value, dataurl) {
			this.value = $.trim(value);
			if(this.value) {
			}
	},
	clear_input: function(){
		this.$value.toggle(true).find(".attached-file").empty();
	},
	get_value: function() {
			if(this.frm) {
				return this.value;
			} else {
				return this.fileobj ? (this.fileobj.filename + "," + this.dataurl) : null;
			}
	},
	set_model_value: function(value, fieldname, fieldtype) {
			if(frappe.model.set_value(this.doctype, this.docname, fieldname,
				value, fieldtype)) {
				this.last_value = value;
			}
	},
});

jasper.dialog_upload_tree = frappe.ui.form.Control.extend({
	init: function(opts) {
		this._super(opts);
		this.maked = false;
	},
	make: function(){
		return;
	},
	make_wrapper: function() {
		return;
	},
	make_input: function() {
		var me = this;

		if(this.maked === false){
			this.value = this.$wrapper.html('

');

			this.get_instance_tree();
			this.maked = true;
		};

	},
	get_instance_tree: function(){
		var me = this;
		$('#jasper_upload_tree').jstree({
			'core' : {
			  'check_callback' : true,
			  'multiple' : false
			},
		    "types" : {
		       "default" : {
		         "icon" : "icon-paper-clip"
		       }
		     },
			"plugins" : ["state", "wholerow", "contextmenu", "types"],
			"contextmenu": {items: me.set_context()},

		});
		this.instance = $('#jasper_upload_tree').jstree(true);
	},
	show: function(){
		var me = this;
		this.make_input();
		if(!this.dialog) {
			this.dialog = new frappe.ui.Dialog({
				title: __(me.df.label || "Upload"),
			});
		}

		$(this.dialog.body).empty();

		this.set_upload_options();
		jasper.upload.make(this.upload_options);
		this.dialog.show();
	},
	set_upload_options: function() {
		var me = this;
		this.selected = this.instance.get_selected();
		this.data = this.instance.get_node(this.selected).data;
		this.root = this.instance.get_node("#").children[0] || "#";
		this.upload_options = {
			parent: me.dialog.body,
			args: {},
			max_width: me.df.max_width,
			max_height: me.df.max_height,
			callback: function(attachment, r) {
				me.dialog.hide();
				if (!r._server_messages){
					me.instance.create_node(me.selected.length > 0 ? me.selected[0]: me.root,{"id": attachment.name, "text":attachment.file_url,
					"data":{name: attachment.file_name.slice(0,-6)}});
				}
				me.on_upload_complete(attachment);
			},
			onerror: function() {
				me.dialog.hide();
			},
		}

		if(this.frm) {
			this.upload_options.args = {
				//from_form: 1,
				parent_report: this.selected[0] || (this.root==="#"? "root":this.root),
				doctype: me.frm.doctype,
				docname: me.frm.docname,
				method:  "jasper_erpnext_report.utils.upload.file_upload"
			}
		};
		this.upload_options.on_attachs = function(args, dataurl) {
				me.dialog.hide();
				me.args = args;
				me.dataurl = dataurl;
				if(me.on_attach) {
					me.on_attach()
				}
				if(me.df.on_attach) {
					me.df.on_attach(args, dataurl);
				}
				me.on_upload_complete();
		}
	},
	on_upload_complete: function(attachment) {
		if(this.frm) {
			this.parse_validate_and_set_in_model(attachment.file_url);
			this.refresh();
			this.frm.attachments.update_attachment(attachment);
		} else {
			this.refresh();
		}
	},
	set_model_value: function(value) {
		if(frappe.model.set_value(this.doctype, this.docname, this.df.fieldname,
			value, this.df.fieldtype)) {
			this.last_value = value;
		}
	},
	set_input: function(name, file_name, url, parent_report) {
			if(url) {
				this.make_input();
				if (parent_report === "root")
					parent_report = null;
				this.instance.create_node(parent_report || "#",{"id": name, "text":url, "data":{"name": file_name.split(".")[0]}});
			}
	},
	clear_input: function(){
		$('#jasper_upload_tree').jstree("destroy").empty();
		$('#jasper_upload_tree').remove();
		this.maked = false;
	},
	set_context: function(){
		var me = this;
		return function(node) {
		    // The default set of all items
		    var items = {
		        deleteItem: { // The "delete" menu item
		            label: "Delete",
		            action: function (d) {
						var inst = $.jstree.reference(d.reference);
	                    obj = inst.get_node(d.reference);
						me.delete_item(obj);
						inst.delete_node(obj);
		            }
		        }
		    };
			//delete items.deleteItem;
		    return items;
		};
	},
	delete_item: function(obj){
		var me = this;
		if(me.frm) {
			for (var i=0; i < obj.children.length; i++){
				var node = me.instance.get_node(obj.children[i]);
				me.frm.attachments.remove_attachment_by_filename(node.text, function() {
					me.parse_validate_and_set_in_model(null);
				});
			};
			me.frm.attachments.remove_attachment_by_filename(obj.text, function() {
				me.parse_validate_and_set_in_model(null);
			});
		} else {
			me.dataurl = null;
			me.fileobj = null;
		}
	}
});

jasper.upload = {
	make: function(opts) {
		if(!opts.args) opts.args = {};
		var $upload = $('
' +
			'
 ' +
				__('Upload a file') + '
' +
			'
' +
				'<input class="alert alert-info" style="padding: 7px; margin: 7px 0px;" type="file" name="filedata" />' +
			'
' +
			'<button class="btn btn-info btn-upload"> ' +__('Upload') + '</button>' +
			'
')
			.appendTo(opts.parent);
		$upload.find(".action-attach").click(function() {
			$upload.find(".action-link").removeClass("disabled");
			$upload.find(".action-attach").addClass("disabled");
			$upload.find(".action-link-input").toggle(false);
			$upload.find(".action-attach-input").toggle(true);
			$upload.find(".btn-upload").html(' ' +__('Upload'))
			return false;
		})

		// get the first file
		$upload.find(".btn-upload").click(function() {
			// convert functions to values
			for(key in opts.args) {
				if(typeof val==="function")
					opt.args[key] = opts.args[key]();
			}

			// add other inputs in the div as arguments
			opts.args.params = {};
			$upload.find("input[name]").each(function() {
				var key = $(this).attr("name");
				var type = $(this).attr("type");
				if(key!="filedata" && key!="file_url") {
					if(type === "checkbox") {
						opts.args.params[key] = $(this).is(":checked");
					} else {
						opts.args.params[key] = $(this).val();
					}
				}
			})

			var fileobj = $upload.find(":file").get(0).files[0];
			jasper.upload.upload_file(fileobj, opts.args, opts);
		})
	},
	upload_file: function(fileobj, args, opts) {
		if(!fileobj && !args.file_url) {
			msgprint(__("Please attach a file."));
			return;
		}

		var dataurl = null;
		var _upload_file = function() {
			if(opts.on_attach) {
				opts.on_attach(args, dataurl)
			} else {
				var msgbox = msgprint(__("Uploading..."));
				return frappe.call({
					"method": "uploadfile",
					args: args,
					callback: function(r) {
						if(!r._server_messages)
							msgbox.hide();
						if(r.exc) {
							// if no onerror, assume callback will handle errors
							opts.onerror ? opts.onerror(r) : opts.callback(null, null, r);
							return;
						}
						var attachment = r.message;
						opts.callback(attachment, r);
						$(document).trigger("upload_complete", attachment);
					}
				});
			}
		}

		if(args.file_url) {
			_upload_file();
		} else {
			var freader = new FileReader();

			freader.onload = function() {
				args.filename = fileobj.name;
				if((opts.max_width || opts.max_height) && (/\.(gif|jpg|jpeg|tiff|png)$/i).test(args.filename)) {
					frappe.utils.resize_image(freader, function(_dataurl) {
						dataurl = _dataurl;
						args.filedata = _dataurl.split(",")[1];
						_upload_file();
					})
				} else {
					dataurl = freader.result;
					args.filedata = freader.result.split(",")[1];
					_upload_file();
				}
			};

			freader.readAsDataURL(fileobj);
		}
	}
}
<|endoftext|>


<commit_before>/**
 * Copyright 2014 IBM Corp.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 **/

module.exports = function(RED) {

    "use strict";
    var request = require('request');

    /**
     * Swarm input node - will return the most recent check-in since
     * the node has been initialized. The node will only populate msg.payload
     * with the JSON of the check-in if a new check-in has been made within
     * the polling interval.
     */
    function SwarmInNode(n) {
        RED.nodes.createNode(this, n);
        var node = this;
        var credentials = RED.nodes.getCredentials(n.foursquare);
        var credentialsOk = checkCredentials(node, credentials);
        if (credentialsOk) {
            var repeat = 900000; // 15 minutes
            var now = Math.floor(((new Date()).getTime())/1000); // time now, in seconds, since epoch
            var afterTimestamp = now; // means that only new check-ins (after initialization) are sent
            var lastcheckin = null;

            var interval = setInterval(function() {
                node.emit("input", {});
            }, repeat );

            this.on("input", function(msg) {
                getCheckinsAfterTimestamp(node, "self", afterTimestamp, credentials, msg, function(msg) {
                    var latestcheckin = JSON.stringify(msg);
                    if (latestcheckin !== lastcheckin) {
                        lastcheckin = latestcheckin;
                        afterTimestamp = msg.payload.createdAt; // createdAt is received via Swarm API's JSON
                        node.send(msg);
                    }
                });
            });

            this.on("close", function() {
                if (interval !== null) {
                    clearInterval(interval);
                }
            });

        }
    }

    RED.nodes.registerType("swarm in", SwarmInNode);

    /**
     * Swarm query node - will return the most recent check-in
     * If a check-in exists the node will always return
     * the most recent even if no new check-ins have happened since the previous query.
     * If no check-ins are found, a null msg.payload is returned.
     */
    function SwarmQueryNode(n) {
        RED.nodes.createNode(this, n);
        var node = this;
        this.request = n.request || "get-most-recent-checkin";
        var credentials = RED.nodes.getCredentials(n.foursquare);
        var credentialsOk = checkCredentials(node, credentials);
        if (credentialsOk) {
          this.on("input", function(msg) {
              if (node.request === "get-most-recent-checkin") {
                  getCheckinsAfterTimestamp(node, "self", null, credentials, msg, function(msg) {
                      node.send(msg);
                  });
              }
          });
        }
    }

    RED.nodes.registerType("swarm", SwarmQueryNode);

    function checkCredentials(node, credentials) {
        if (credentials && credentials.clientid && credentials.clientsecret && credentials.accesstoken) {
           return true;
        } else {
            node.error("problem with credentials being set: " + credentials + ", ");
            node.status({fill:"red",shape:"ring",text:"failed"});
            return false;
        }
    }

    function getCheckinsAfterTimestamp(node, userid, afterTimestamp, credentials, msg, callback) {
        var version = "&v=20141016"; // Mandatory for Foursquare API!
        var apiUrl = "https://api.foursquare.com/v2/users/" + userid + "/checkins?oauth_token=" + credentials.accesstoken  + "&sort=newestfirst&m=swarm" + version;
        if(afterTimestamp !== null) {
            apiUrl = apiUrl + "&afterTimestamp=" + afterTimestamp;
        }
        request.get(apiUrl,function(err, httpResponse, body) {
            if (err) {
                node.error(err.toString());
                node.status({fill:"red",shape:"ring",text:"failed"});
            } else {
                var result = JSON.parse(body);
                if (result.meta.code != 200) {
                    node.error("Error code: " + result.meta.code + ", errorDetail: " + result.meta.errorDetail);
                    node.status({fill:"red",shape:"ring",text:"failed"});
                } else {
                    if (result.response.checkins.items.length !== 0) {
                      var latest = result.response.checkins.items[0];
                      msg.payload = {};
                      msg.payload = latest;
                      msg.location = {};

                      if (latest.location && (latest.location !== 'undefined')) {
                          msg.location.lat = latest.location.lat;
                          msg.location.lon = latest.location.lng;
                          msg.location.name = latest.location.name;
                          msg.name = latest.location.name;
                      }
                      if (latest.venue && (latest.venue !== 'undefined')) {
                          // this is ok to overwrite anything set before because the location property
                          // may or may not be there, and the same with the venue property
                         msg.location.lat = latest.venue.location.lat;
                         msg.location.lon = latest.venue.location.lng;
                         msg.location.city = latest.venue.location.city;
                         msg.location.country = latest.venue.location.country;
                         msg.location.name = latest.venue.name;
                         msg.name = latest.venue.name;
                      }
                      callback(msg);
                  } else {
                      if(afterTimestamp === null) { // if query node, always return something, when no check-ins, return empty payload
                          msg.payload = null;
                          callback(msg);
                      }
                  }
                }
            }
        });
    }
}
<commit_msg>Make swarm query node support credentials in msg.<commit_after>/**
 * Copyright 2014 IBM Corp.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 **/

module.exports = function(RED) {

    "use strict";
    var request = require('request');

    /**
     * Swarm input node - will return the most recent check-in since
     * the node has been initialized. The node will only populate msg.payload
     * with the JSON of the check-in if a new check-in has been made within
     * the polling interval.
     */
    function SwarmInNode(n) {
        RED.nodes.createNode(this, n);
        var node = this;
        var credentials = RED.nodes.getCredentials(n.foursquare);
        var credentialsOk = checkCredentials(node, credentials);
        if (credentialsOk) {
            var repeat = 900000; // 15 minutes
            var now = Math.floor(((new Date()).getTime())/1000); // time now, in seconds, since epoch
            var afterTimestamp = now; // means that only new check-ins (after initialization) are sent
            var lastcheckin = null;

            var interval = setInterval(function() {
                node.emit("input", {});
            }, repeat );

            this.on("input", function(msg) {
                getCheckinsAfterTimestamp(node, "self", afterTimestamp, credentials, msg, function(msg) {
                    var latestcheckin = JSON.stringify(msg);
                    if (latestcheckin !== lastcheckin) {
                        lastcheckin = latestcheckin;
                        afterTimestamp = msg.payload.createdAt; // createdAt is received via Swarm API's JSON
                        node.send(msg);
                    }
                });
            });

            this.on("close", function() {
                if (interval !== null) {
                    clearInterval(interval);
                }
            });

        }
    }

    RED.nodes.registerType("swarm in", SwarmInNode);

    /**
     * Swarm query node - will return the most recent check-in
     * If a check-in exists the node will always return
     * the most recent even if no new check-ins have happened since the previous query.
     * If no check-ins are found, a null msg.payload is returned.
     */
    function SwarmQueryNode(n) {
        RED.nodes.createNode(this, n);
        var node = this;
        this.request = n.request || "get-most-recent-checkin";
        var nodeCredentials = RED.nodes.getCredentials(n.foursquare);
        checkCredentials(node, nodeCredentials);
        this.on("input", function(msg) {
            var credentials = nodeCredentials && nodeCredentials.accesstoken ? nodeCredentials : msg.credentials || {};
            if (!credentials.accesstoken) {
                node.warn("No credentials available");
                delete msg.payload;
                msg.error = "no access token provided";
                node.send(msg);
                return;
            }
            if (node.request === "get-most-recent-checkin") {
                getCheckinsAfterTimestamp(node, "self", null, credentials, msg, function(msg) {
                    node.send(msg);
                });
            }
        });
    }

    RED.nodes.registerType("swarm", SwarmQueryNode);

    function checkCredentials(node, credentials) {
        if (credentials && credentials.clientid && credentials.clientsecret && credentials.accesstoken) {
           return true;
        } else {
            node.warn("no credentials for node");
            return false;
        }
    }

    function getCheckinsAfterTimestamp(node, userid, afterTimestamp, credentials, msg, callback) {
        var version = "&v=20141016"; // Mandatory for Foursquare API!
        var apiUrl = "https://api.foursquare.com/v2/users/" + userid + "/checkins?oauth_token=" + credentials.accesstoken  + "&sort=newestfirst&m=swarm" + version;
        if(afterTimestamp !== null) {
            apiUrl = apiUrl + "&afterTimestamp=" + afterTimestamp;
        }
        request.get(apiUrl,function(err, httpResponse, body) {
            if (err) {
                node.error(err.toString());
                node.status({fill:"red",shape:"ring",text:"failed"});
            } else {
                var result = JSON.parse(body);
                if (result.meta.code != 200) {
                    node.error("Error code: " + result.meta.code + ", errorDetail: " + result.meta.errorDetail);
                    node.status({fill:"red",shape:"ring",text:"failed"});
                } else {
                    if (result.response.checkins.items.length !== 0) {
                      var latest = result.response.checkins.items[0];
                      msg.payload = {};
                      msg.payload = latest;
                      msg.location = {};

                      if (latest.location && (latest.location !== 'undefined')) {
                          msg.location.lat = latest.location.lat;
                          msg.location.lon = latest.location.lng;
                          msg.location.name = latest.location.name;
                          msg.name = latest.location.name;
                      }
                      if (latest.venue && (latest.venue !== 'undefined')) {
                          // this is ok to overwrite anything set before because the location property
                          // may or may not be there, and the same with the venue property
                         msg.location.lat = latest.venue.location.lat;
                         msg.location.lon = latest.venue.location.lng;
                         msg.location.city = latest.venue.location.city;
                         msg.location.country = latest.venue.location.country;
                         msg.location.name = latest.venue.name;
                         msg.name = latest.venue.name;
                      }
                      callback(msg);
                  } else {
                      if(afterTimestamp === null) { // if query node, always return something, when no check-ins, return empty payload
                          msg.payload = null;
                          callback(msg);
                      }
                  }
                }
            }
        });
    }
}
<|endoftext|>


<commit_before>/**
 * @module  camera
 * @author  Flavio De Stefano <flavio.destefano@caffeinalab.com>
 */

/*
Include methods used in this module dynamically to avoid that Titanium
static analysis doesn't include native-language methods.
 */
Ti.Media;

var MODULE_NAME = 'camera';

var Dialog = require('T/dialog');
var Util = require('T/util');
var Permissions = require('T/permissions/camera');

/**
 * Call showCamera or openPhotoGallery using same options
 * @private
 * @param  {String}   method    Must be one of showCamera or openPhotoGallery
 * @param  {Object}   opt       Options passed to `Ti.Media.FUNC`
 * @param  {Function} callback  Success callback
 */
function getPhoto(method, opt, callback) {
	Permissions.request(function() {

		opt = _.extend({}, opt, {
			mediaTypes: [ Ti.Media.MEDIA_TYPE_PHOTO ],
			saveToPhotoGallery: true,
			success: callback,
			cancel: function(e) {
				Ti.API.warn(MODULE_NAME + ': Cancelled', e);
			},
			error: function(err) {
				Ti.API.error(MODULE_NAME + ': Error', err);
				Util.errorAlert(L('unexpected_error', 'Unexpected error'));
			}
		});
		if (method == Ti.Media.showCamera) {
			Ti.Media.showCamera(opt);
		} else if (method == Ti.Media.openPhotoGallery) {
			Ti.Media.openPhotoGallery(opt);
		}

	}, function(err) {
		Ti.API.error(MODULE_NAME + ': Error', err);
		Util.errorAlert(L('error_camera_permissions', 'Missing camera permissions'));
	});
}

/**
 * Open the Camera to take a photo
 *
 * @param  {Object}   opt           Options passed to `Ti.Media.showCamera`
 * @param  {Function} callback      Success callback
 */
exports.takePhoto = function(opt, callback) {
	getPhoto(Titanium.Media.showCamera, opt, callback);
};

/**
 * Open the Gallery to chooose a photo
 *
 * @param  {Object}   opt           Options passed to `Ti.Media.showCamera`
 * @param  {Function} callback      Success callback
 */
exports.choosePhoto = function(opt, callback) {
	getPhoto(Titanium.Media.openPhotoGallery, opt, callback);
};

/**
 * Display an option dialog to prompt the user to take a photo with the camera or select a photo from the gallery
 *
 * @param  {Object}   opt           Options passed to `Ti.Media.showCamera`
 * @param  {Function} callback      Success callback
 */
exports.selectPhoto = function(opt, callback) {
	Dialog.option(L('select_photo_source'), [
	{
		title: L('take_photo', 'Take photo'),
		callback: function() { exports.takePhoto(opt, callback); }
	},
	{
		title: L('choose_existing_photo', 'Choose existing photo'),
		callback: function() { exports.choosePhoto(opt, callback); }
	},
	{
		title: L('cancel'),
		cancel: true
	}
	]);
};<commit_msg>Better eq for methods<commit_after>/**
 * @module  camera
 * @author  Flavio De Stefano <flavio.destefano@caffeinalab.com>
 */

/*
Include methods used in this module dynamically to avoid that Ti
static analysis doesn't include native-language methods.
 */
Ti.Media;

var MODULE_NAME = 'camera';

var Dialog = require('T/dialog');
var Util = require('T/util');
var Permissions = require('T/permissions/camera');

/**
 * Call showCamera or openPhotoGallery using same options
 * @private
 * @param  {String}   method    Must be one of showCamera or openPhotoGallery
 * @param  {Object}   opt       Options passed to `Ti.Media.FUNC`
 * @param  {Function} callback  Success callback
 */
function getPhoto(method, opt, callback) {
	Permissions.request()
	.then(function() {

		opt = _.extend({}, opt, {
			mediaTypes: [ Ti.Media.MEDIA_TYPE_PHOTO ],
			saveToPhotoGallery: true,
			success: callback,
			cancel: function(e) {
				Ti.API.warn(MODULE_NAME + ': Cancelled', e);
			},
			error: function(err) {
				Ti.API.error(MODULE_NAME + ': Error', err);
				Util.errorAlert(L('unexpected_error', 'Unexpected error'));
			}
		});

		if (method === Ti.Media.showCamera) {
			Ti.Media.showCamera(opt);
		} else if (method === Ti.Media.openPhotoGallery) {
			Ti.Media.openPhotoGallery(opt);
		} else {
			throw new Error(MODULE_NAME + ': invalid method');
		}

	});
}

/**
 * Open the Camera to take a photo
 *
 * @param  {Object}   opt           Options passed to `Ti.Media.showCamera`
 * @param  {Function} callback      Success callback
 */
exports.takePhoto = function(opt, callback) {
	getPhoto(Ti.Media.showCamera, opt, callback);
};

/**
 * Open the Gallery to chooose a photo
 *
 * @param  {Object}   opt           Options passed to `Ti.Media.showCamera`
 * @param  {Function} callback      Success callback
 */
exports.choosePhoto = function(opt, callback) {
	getPhoto(Ti.Media.openPhotoGallery, opt, callback);
};

/**
 * Display an option dialog to prompt the user to take a photo with the camera or select a photo from the gallery
 *
 * @param  {Object}   opt           Options passed to `Ti.Media.showCamera`
 * @param  {Function} callback      Success callback
 */
exports.selectPhoto = function(opt, callback) {
	Dialog.option(L('select_photo_source'), [
	{
		title: L('take_photo', 'Take photo'),
		callback: function() { exports.takePhoto(opt, callback); }
	},
	{
		title: L('choose_existing_photo', 'Choose existing photo'),
		callback: function() { exports.choosePhoto(opt, callback); }
	},
	{
		title: L('cancel'),
		cancel: true
	}
	]);
};<|endoftext|>


<commit_before>/*globals ko */
ko.validation.rules['areSame'] = {
    getValue: function (o) {
        return (typeof o === 'function' ? o() : o);
    },
    validator: function (val, otherField) {
        return val === this.getValue(otherField);
    }
};<commit_msg>Fixing build<commit_after>/*globals ko */
ko.validation.rules.areSame = {
    getValue: function (o) {
        return (typeof o === 'function' ? o() : o);
    },
    validator: function (val, otherField) {
        return val === this.getValue(otherField);
    }
};<|endoftext|>


<commit_before>/* globals describe, it, document, console */
/*
 * no idea...   nothing working on this side.  maybe a jsdom issue?
 *
 * works in the browser
 *
 * https://github.com/tmpvar/jsdom/issues/1517
 */
import BaseWidget   from '/baseWidget';

import assert       from 'assert';
import sinon        from 'sinon';

const stylaWidget = new BaseWidget( {
    target : document.body,
    slug   : 'braunhamburg',
    domain : 'test'
} );

const refs = stylaWidget.refs;

/**
 * ## attach
 *
 * adds the styla widget to the DOM
 *
 * @return _Void_
 */
describe( 'attach', () =>
{
    it( 'should add the widget to it\'s previous target', () =>
    {
        stylaWidget.attach();

        const parent  = refs.wrapper.parentNode;
        assert.equal( parent.nodeType, 1 );

        refs.styles.forEach( el =>
        {
            const parent  = el.parentNode;
            assert.equal( parent.nodeType, 1 );
        } );
    } );

    it( 'should add the widget to a specified target', () =>
    {
        stylaWidget.attach( 'div' );

        const parent  = refs.wrapper.parentNode;
        assert.equal( parent.nodeType, 1 );

        refs.styles.forEach( el =>
        {
            const parent  = el.parentNode;
            assert.equal( parent.nodeType, 1 );
        } );
    } );
} );

/**
 * ## checkTarget
 *
 * makes sure the target is a DOMelement and wide enough
 *
 * @return _Void_
 */
describe( 'checkTarget', () =>
{
    it( 'should change a string into a DOM element', () =>
    {
        const target = stylaWidget.checkTarget( 'body' );
        assert.deepEqual( document.body, target );
    } );

    it( 'should fallback to the body when no other element is supplied', () =>
    {
        sinon.stub( console, 'error', () =>
        {
        } );

        const target = stylaWidget.checkTarget( 'moon' );
        assert.deepEqual( document.body, target );

        console.error.restore();
    } );

    it( 'should fail if the element width is under the min width', () =>
    {
        document.body.offsetWidth = 149;
        assert.throws( () => stylaWidget.checkTarget( document.body, 250 ),
                    `Styla Widget error: Target element too small
                                    to render widget ¯\\_(ツ)_/¯` );
        document.body.offsetWidth = 260;
    } );
} );

/**
 * ## constructor
 *
 * grabs the feed from the api and starts everything
 *
 * @param {String} domain target domain to grab products from
 *
 * @return _Object_ this
 */
describe( 'constructor', () =>
{
    it( 'should not build without a slug', () =>
    {
        assert.throws( () => new BaseWidget(),
                'Styla Widget error: No slug defined, cannot render widget' );
    } );

    it( 'should adds one to the limit if there is a story to ignore', () =>
    {
        const stylaWidget = new BaseWidget( {
            slug   : 'braunhamburg',
            ignore : 'khfvk'
        } );
        assert.equal( stylaWidget.limit, 6 );
    } );

    it( 'should be able to build using the tag feed', () =>
    {
        const stylaWidget = new BaseWidget( {
            slug : 'braunhamburg',
            tag  : 'moon'
        } );
        assert.equal( stylaWidget.url, 'https://live.styla.com/api/feeds/tags/moon?offset=0&limit=5&domain=braunhamburg' );
    } );

    it( 'should be able to build using the category feed', () =>
    {
        const stylaWidget = new BaseWidget( {
            slug     : 'braunhamburg',
            category : '2262'
        } );
        assert.equal( stylaWidget.url, 'https://live.styla.com/api/feeds/boards/2262/user/braunhamburg?domain=braunhamburg&offset=0' );
    } );

    it( 'should throw a console error if both tag and category is set', () =>
    {
        sinon.stub( console, 'error', () =>
        {
        } );

        new BaseWidget( {
            slug     : 'braunhamburg',
            tag      : 'fussball',
            category : '2262'
        } );

        assert.equal( console.error.callCount, 1 );

        console.error.restore();

    } );

    it( 'should be able to randomize the results slightly', () =>
    {
        const stylaWidget = new BaseWidget( {
            slug        : 'braunhamburg',
            tag         : 'moon',
            randomize   : 10,
            limit       : 5
        } );

        assert.equal( stylaWidget.url, 'https://live.styla.com/api/feeds/tags/moon?offset=0&limit=10&domain=braunhamburg' );
    } );

    it( 'should set the correct defaults', () =>
    {
        const stylaWidget = new BaseWidget( {
            slug : 'braunhamburg'
        } );

        assert.equal( stylaWidget.api, 'https://live.styla.com' );
        assert.equal( stylaWidget.ignore, false );
        assert.equal( stylaWidget.limit, 5 );
        assert.equal( stylaWidget.linkDomain, false );
        assert.equal( stylaWidget.minWidth, 250 );
        assert.equal( stylaWidget.offset, 0 );
        assert.equal( stylaWidget.imageSize, 400 );
        assert.equal( stylaWidget.storiesApi, false );
        assert.equal( stylaWidget.tag, false );
        assert.equal( stylaWidget.category, false );
        assert.equal( stylaWidget.target, document.body );
        assert.equal( stylaWidget.cta, false );
    } );
} );

/**
 * ## destroy
 *
 * removes the styla widget from the DOM
 *
 * @return _Void_
 */
describe( 'destroy', () =>
{
    it( 'should remove the widget from the DOM', () =>
    {
        stylaWidget.destroy();

        const parent  = refs.wrapper.parentNode;
        assert.equal( parent, null );

        refs.styles.forEach( el =>
        {
            const parent  = el.parentNode;
            assert.equal( parent, null );
        } );
    } );
} );
<commit_msg>tests all pass<commit_after>/* globals describe, it, document, console */
/*
 * no idea...   nothing working on this side.  maybe a jsdom issue?
 *
 * works in the browser
 *
 * https://github.com/tmpvar/jsdom/issues/1517
 */
import BaseWidget   from '/baseWidget';

import assert       from 'assert';
import sinon        from 'sinon';

const stylaWidget = new BaseWidget( {
    target : document.body,
    slug   : 'braunhamburg',
    domain : 'test'
} );

const refs = stylaWidget.refs;

/**
 * ## attach
 *
 * adds the styla widget to the DOM
 *
 * @return _Void_
 */
describe( 'attach', () =>
{
    it( 'should add the widget to it\'s previous target', () =>
    {
        stylaWidget.attach();

        const parent  = refs.wrapper.parentNode;
        assert.equal( parent.nodeType, 1 );

        refs.styles.forEach( el =>
        {
            const parent  = el.parentNode;
            assert.equal( parent.nodeType, 1 );
        } );
    } );

    it( 'should add the widget to a specified target', () =>
    {
        stylaWidget.attach( 'div' );

        const parent  = refs.wrapper.parentNode;
        assert.equal( parent.nodeType, 1 );

        refs.styles.forEach( el =>
        {
            const parent  = el.parentNode;
            assert.equal( parent.nodeType, 1 );
        } );
    } );
} );

/**
 * ## checkTarget
 *
 * makes sure the target is a DOMelement and wide enough
 *
 * @return _Void_
 */
describe( 'checkTarget', () =>
{
    it( 'should change a string into a DOM element', () =>
    {
        const target = stylaWidget.checkTarget( 'body' );
        assert.deepEqual( document.body, target );
    } );

    it( 'should fallback to the body when no other element is supplied', () =>
    {
        sinon.stub( console, 'error', () =>
        {
        } );

        const target = stylaWidget.checkTarget( 'moon' );
        assert.deepEqual( document.body, target );

        console.error.restore();
    } );

    it( 'should fail if the element width is under the min width', () =>
    {
        document.body.offsetWidth = 149;
        assert.throws( () => stylaWidget.checkTarget( document.body, 250 ),
                    `Styla Widget error: Target element too small
                                    to render widget ¯\\_(ツ)_/¯` );
        document.body.offsetWidth = 260;
    } );
} );

/**
 * ## constructor
 *
 * grabs the feed from the api and starts everything
 *
 * @param {String} domain target domain to grab products from
 *
 * @return _Object_ this
 */
describe( 'constructor', () =>
{
    it( 'should not build without a slug', () =>
    {
        assert.throws( () => new BaseWidget(),
                'Styla Widget error: No slug defined, cannot render widget' );
    } );

    it( 'should adds one to the limit if there is a story to ignore', () =>
    {
        const stylaWidget = new BaseWidget( {
            slug   : 'braunhamburg',
            ignore : 'khfvk'
        } );
        assert.equal( stylaWidget.limit, 6 );
    } );

    it( 'should be able to build using the tag feed', () =>
    {
        const stylaWidget = new BaseWidget( {
            slug : 'braunhamburg',
            tag  : 'moon'
        } );
        assert.equal( stylaWidget.url, 'https://live.styla.com/api/feeds/tags/moon?limit=5&domain=braunhamburg' );
    } );

    it( 'should be able to build using the category feed', () =>
    {
        const stylaWidget = new BaseWidget( {
            slug     : 'braunhamburg',
            category : '2262'
        } );
        assert.equal( stylaWidget.url, 'https://live.styla.com/api/feeds/boards/2262/user/braunhamburg?domain=braunhamburg' );
    } );

    it( 'should throw a console error if both tag and category is set', () =>
    {
        sinon.stub( console, 'error', () =>
        {
        } );

        new BaseWidget( {
            slug     : 'braunhamburg',
            tag      : 'fussball',
            category : '2262'
        } );

        assert.equal( console.error.callCount, 1 );

        console.error.restore();

    } );

    it( 'should be able to randomize the results slightly', () =>
    {
        const stylaWidget = new BaseWidget( {
            slug        : 'braunhamburg',
            tag         : 'moon',
            randomize   : 10,
            limit       : 5
        } );

        assert.equal( stylaWidget.url, 'https://live.styla.com/api/feeds/tags/moon?limit=10&domain=braunhamburg' );
    } );

    it( 'should set the correct defaults', () =>
    {
        const stylaWidget = new BaseWidget( {
            slug : 'braunhamburg'
        } );

        assert.equal( stylaWidget.api, 'https://live.styla.com' );
        assert.equal( stylaWidget.ignore, false );
        assert.equal( stylaWidget.limit, 5 );
        assert.equal( stylaWidget.linkDomain, false );
        assert.equal( stylaWidget.minWidth, 250 );
        assert.equal( stylaWidget.offset, 0 );
        assert.equal( stylaWidget.imageSize, 400 );
        assert.equal( stylaWidget.storiesApi, false );
        assert.equal( stylaWidget.tag, false );
        assert.equal( stylaWidget.category, false );
        assert.equal( stylaWidget.target, document.body );
        assert.equal( stylaWidget.cta, false );
    } );
} );

/**
 * ## destroy
 *
 * removes the styla widget from the DOM
 *
 * @return _Void_
 */
describe( 'destroy', () =>
{
    it( 'should remove the widget from the DOM', () =>
    {
        stylaWidget.destroy();

        const parent  = refs.wrapper.parentNode;
        assert.equal( parent, null );

        refs.styles.forEach( el =>
        {
            const parent  = el.parentNode;
            assert.equal( parent, null );
        } );
    } );
} );
<|endoftext|>


<commit_before>// View model for the courses page
function pageViewModel(gvm) {
    // Page specific i18n bindings
    gvm.app  = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ProjectRapportName")}, gvm);
    gvm.title = ko.computed(function(){i18n.setLocale(gvm.lang()); return gvm.app() + ' - ' + i18n.__("CourseTitle2");}, gvm);
    gvm.pageHeader = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("CourseTitle2");}, gvm);
    gvm.projectname = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ProjectRapportName");}, gvm);

    gvm.availableLocations = ko.observableArray([]);
    gvm.availableTrainings = ko.observableArray([]);
    gvm.availableCourses = ko.observableArray([]);

    /*Teacher*/
    gvm.availableTeacher = ko.observableArray([]);
    gvm.currentteacherid = null;
    /*teacher*/

    // Pagination i18n bindings
    gvm.addBtn = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("AddBtn")}, gvm);

    gvm.codeTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("CodeTableTitle");}, gvm);
    gvm.nameTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("NameTableTitle");}, gvm);
    gvm.descTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("DescTableTitle");}, gvm);
    gvm.actionTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ActionTableTitle");}, gvm);

    // The table data observable array
    gvm.tabledata = ko.observableArray([]);

    // Add data to the table
    gvm.addTableData = function(id, code, name, desc) {
        console.log(id + ", " + code + ", " + name + ", " + desc);
        // Push data
        var tblOject = {tid: id, tcode: code, tname: name, tdesc: desc};
        gvm.tabledata.push(tblOject);

        // Attach delete handler to delete button
        $('#removebtn-' + id).bind('click', function(event, data){
            // Delete the table item
            deleteTableItem(id, tblOject);
            event.stopPropagation();
        });

        // Attach edit handler to edit button
        $('#editbtn-' + id).bind('click', function(event, data){
            // Edit the table item
            showEditProjectTypeModal(code, name, desc, id);
            event.stopPropagation();
        });

        //Attach manage handler to manage competences, subcompetences and indicators to manage button
        $('#managebtn-' + id).bind('click', function(event, data) {
            //TODO
        });

        /*$('#studentbtn-' + id).bind('click', function(event, data) {
            showCoupleStudentListModal(id);
            gvm.currentprojectid = id;
            gvm.currentselectedlist = -1;
            event.stopPropagation();
            loadCoupleDropdown();
        });*/
    }

    gvm.clearTable = function() {
        gvm.tabledata.removeAll();
    }

    gvm.updateTeacher = function(id) {
        console.log("updateteacherfunctie1");
    $.getJSON('/api/teacherrapport/' + id, function(data) {
        gvm.availableTeacher.removeAll();
        $.each(data, function(i, item) {
            gvm.availableTeacher.push(item);
                console.log("updateteacherfunctie")
            /* Add listener to listitem */
            $("#teacherbtn-" + item.id).click(function(){
                $(".btn-teacher span:first").text($(this).text());
                gvm.currentteacherid = item.id;
                gvm.saveLastSelectedDropdowns();
                loadTablePage(item.id, 1);
            });
        });
    });
    }
    }
/*
 * Delete item from table given the id.
 */
function deleteTableItem(id, tblOject) {
    showYesNoModal("Bent u zeker dat u dit item wil verwijderen? \r\n Let op: verwijderde items blijven in het systeem en kunnen weer actief gezet worden door een administrator. \r\n Gelieve de administrator te contacteren om een vak definitief te verwijderen.", function(val){
        if(val){
            $.ajax({
                url: "/api/coursedelete/" + id,
                type: "DELETE",
                success: function() {
                    viewModel.tabledata.remove(tblOject);
                }
            });
        }
    });
}

/*
 * Add a new projecttype
 */
function addNewProjecttypeForm(serialData, callback) {
    $.ajax({
            url: "/api/courserapport",
            type: "POST",
            data: serialData,
            success: function(data) {
                viewModel.addTableData(data['id'], data['code'], data['name'], data['description']);
                callback(true);
            },
            error: function(data) {
                callback(false);
            }
        });
}

/*
 * Add a new projecttype
 */
function addNewProjecttypeRaw(code, name, description, callback) {
    addNewProjecttypeForm("code=" + encodeURIComponent(code) + "&name=" + encodeURIComponent(name) + "&description=" + encodeURIComponent(description), callback);
}

/*
 * Update the projecttype
 * @param {type} id
 * @param {type} code
 * @param {type} name
 * @param {type} description
 * @param {type} callback
 * @returns {undefined}
 */
function updateProjecttypeForm(id, serialData, callback) {
    $.ajax({
        url: "/api/courseupdate/" + id,
        type: "PUT",
        data: serialData,
        success: function(data) {
            //viewModel.addTableData(data['id'], data['code'], data['name'], data['description']);
            loadTablePage(1); //TODO now it is refreshing table after updating but it redirects to pagenr 1     WERKT NIET
            callback(true);
        },
        error: function(data) {
            callback(false);
        }
    });
}

/**
 * update project type
 * @param {type} id
 * @param {type} code
 * @param {type} name
 * @param {type} description
 * @param {type} callback
 * @returns {undefined}
 */
function updateProjecttypeRaw(id, code, name, description, callback) {
    updateProjecttypeForm(id, "code=" + encodeURIComponent(code) + "&name=" + encodeURIComponent(name) + "&description=" + encodeURIComponent(description), callback);
}

/*
 * Load page of the table
 */
function loadTablePage(pagenr)
{
    $.getJSON('/api/coursesrapport/page/' + pagenr, function(data){

        /* Clear current table page */
        viewModel.clearTable();

        // Load table data
        $.each(data.data, function(i, item) {
            console.log(item.name);
            viewModel.addTableData(item.id, item.code, item.name, item.description);
        });

        /* Let previous en next buttons work */
        if(data.prev == "none"){
            $('#pager-prev-btn').addClass('disabled');
        } else {
            $('#pager-prev-btn').removeClass('disabled');
            $('#pager-prev-btn a').click(function(){
                loadTablePage(data.prev);
            });
        }

        if(data.next == "none"){
            $('#pager-next-btn').addClass('disabled');
        } else {
            $('#pager-next-btn').removeClass('disabled');
            $('#pager-next-btn a').click(function(){
                loadTablePage(data.next);
            });
        }

        // Number of pager buttons
        var numItems = $('.pager-nr-btn').length;

        /* Calculate for the pager buttons */
        var lowPage = Math.floor(pagenr/numItems) + 1;

        $('.pager-nr-btn').each(function() {
            /* calculate current page number */
            var thispagenr = lowPage++;

            /* Add the page number */
            $(this).html('' + thispagenr + '');

            /* Add active class to current page */
            if(thispagenr == pagenr) {
                $(this).addClass('active');
            } else {
                $(this).removeClass('active');
            }

            /* Disable inactive classes and bind handlers to active classes */
            if(thispagenr > data.pagecount) {
                $(this).addClass('disabled');
            } else {
                /* Add click listener for button */
                $(this).click(function() {
                    loadTablePage(thispagenr);
                });
            }
        });
    });

}

/**
 * Show a new projecttype modal.
 * @returns {undefined}
 */
function showNewProjectTypeModal()
{
    resetGeneralModal();
    setGeneralModalTitle(i18n.__("AddNewCourse"));
    setGeneralModalBody('<form id="newprojectform"> \

 \
                <input type="text" class="form-control input-lg" placeholder="' + i18n.__('CodeTableTitle') + '" " name="code"> \

 \

 \
                <input type="text" class="form-control input-lg" placeholder="' + i18n.__('NameTableTitle') + '" name="name"> \

 \

 \
                <input type="text" class="form-control input-lg" placeholder="' + i18n.__('DescTableTitle') + '" name="description"> \

 \

' +
                '<button class="btn btn-default dropdown-toggle" type="button" id="availableTeacher" data-toggle="dropdown" aria-expanded="true" placeholder="' + i18n.__('TeacherTableTitle') + '">' +
                    'Teacher' +
                '</button>' +
                '
' +
                '
' +
            '
' +
            '</form>' );

    addGeneralModalButton(i18n.__("AddBtn"), function(){
        console.log($('#newprojectform').serialize());
       addNewProjecttypeForm($('#newprojectform').serialize(), function(result){
            hideModal();
        });
    });

    showGeneralModal();
}

/**
 * Show the edit projecttype modal.
 * @param {type} code
 * @param {type} name
 * @param {type} description
 * @param {type} tid
 * @returns {undefined}
 */
function showEditProjectTypeModal(code, name, description, tid)
{
  resetGeneralModal();
    setGeneralModalTitle(i18n.__("EditProjectTitle2"));
    setGeneralModalBody('<form id="updateprojectform"> \

 \
                <input type="text" class="form-control input-lg" placeholder="' + i18n.__('CodeTableTitle') + '" " name="code" value="' + code + '"> \

 \

 \
                <input type="text" class="form-control input-lg" placeholder="' + i18n.__('NameTableTitle') + '" name="name" value="' + name + '"> \

 \

 \
                <input type="text" class="form-control input-lg" placeholder="' + i18n.__('DescTableTitle') + '" name="description" value="' + description + '"> \

 \
        </form>');
    $.getJSON()

    addGeneralModalButton(i18n.__("SaveBtn"), function(){
        updateProjecttypeForm(tid, $('#updateprojectform').serialize(), function(result){
            hideModal();
        });
    });

    addGeneralModalButton(i18n.__("CancelBtn"), function(){
        hideModal();
    })

    showGeneralModal();
}

function showCoupleStudentListModal(projectid) {
    viewModel.currentselectedlist = -1;
    resetGeneralModal();
    setGeneralModalTitle(i18n.__("CoupleStudentList"));
    setGeneralModalBody(
        '
' +
            '<button class="btn btn-default dropdown-toggle" type="button" id="dropdownStudLists" data-toggle="dropdown" aria-expanded="true">' +
                'Dropdown' +
                '' +
            '</button>' +
            '
' +
            '
' +
        '
');

    addGeneralModalButton(i18n.__("SaveBtn"), function() {
        updateListForm(viewModel.currentselectedlist, $('#coupleform').serialize(), function(result){
            hideModal();
        });
    });

    addGeneralModalButton(i18n.__("CancelBtn"), function(){
        hideModal();
    })
    showGeneralModal();
}
function loadCoupleDropdown() {
    $.getJSON('/api/studentlists/' + viewModel.userId, function(data) {
        $.each(data, function(i, item) {
            $("#ddlLists").append('
' + item.name + '
')
            $("#dropdownitem-" + item.id).click(function(){
                $(this).parent().parent().parent().removeClass("open");
                $(this).parent().parent().parent().find(".btn").html($(this).text() + '');
                viewModel.currentselectedlist = item.id;
            });
        });
    });
    $("#dropdownStudLists").click(function() {
        $(this).parent().toggleClass("open");
    });
}

function updateListForm(id, serialData, callback) {
    $.ajax({
        url: "/api/project/" + viewModel.currentprojectid + "/studentlist/" + id,
        type: "POST",
        data: serialData,
        success: function(data) {
            callback(true);
        },
        error: function(data) {
            callback(false);
        }
    });
}

function initPage() {
    // Add button handlers
    $('#addProjectTypeBtn').click(function(){
        showNewProjectTypeModal();
    });

    $.getJSON('/api/currentuser', function(data) {
        viewModel.userId = data.id;
    });

    loadTablePage(1);
}
<commit_msg>coursesrapportenviewmodel teacher<commit_after>// View model for the courses page
function pageViewModel(gvm) {
    // Page specific i18n bindings
    gvm.app  = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ProjectRapportName")}, gvm);
    gvm.title = ko.computed(function(){i18n.setLocale(gvm.lang()); return gvm.app() + ' - ' + i18n.__("CourseTitle2");}, gvm);
    gvm.pageHeader = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("CourseTitle2");}, gvm);
    gvm.projectname = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ProjectRapportName");}, gvm);

    gvm.availableLocations = ko.observableArray([]);
    gvm.availableTrainings = ko.observableArray([]);
    gvm.availableCourses = ko.observableArray([]);

    /*Teacher*/
    gvm.availableTeacher = ko.observableArray([]);
    gvm.currentteacherid = null;
    /*teacher*/

    // Pagination i18n bindings
    gvm.addBtn = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("AddBtn")}, gvm);

    gvm.codeTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("CodeTableTitle");}, gvm);
    gvm.nameTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("NameTableTitle");}, gvm);
    gvm.descTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("DescTableTitle");}, gvm);
    gvm.actionTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ActionTableTitle");}, gvm);

    // The table data observable array
    gvm.tabledata = ko.observableArray([]);

    // Add data to the table
    gvm.addTableData = function(id, code, name, desc) {
        console.log(id + ", " + code + ", " + name + ", " + desc);
        // Push data
        var tblOject = {tid: id, tcode: code, tname: name, tdesc: desc};
        gvm.tabledata.push(tblOject);

        // Attach delete handler to delete button
        $('#removebtn-' + id).bind('click', function(event, data){
            // Delete the table item
            deleteTableItem(id, tblOject);
            event.stopPropagation();
        });

        // Attach edit handler to edit button
        $('#editbtn-' + id).bind('click', function(event, data){
            // Edit the table item
            showEditProjectTypeModal(code, name, desc, id);
            event.stopPropagation();
        });

        //Attach manage handler to manage competences, subcompetences and indicators to manage button
        $('#managebtn-' + id).bind('click', function(event, data) {
            //TODO
        });

        /*$('#studentbtn-' + id).bind('click', function(event, data) {
            showCoupleStudentListModal(id);
            gvm.currentprojectid = id;
            gvm.currentselectedlist = -1;
            event.stopPropagation();
            loadCoupleDropdown();
        });*/
    }

    gvm.clearTable = function() {
        gvm.tabledata.removeAll();
    }

    gvm.updateTeacher = function(id) {
        console.log("updateteacherfunctie1");
    $.getJSON('/api/teacherrapport/' + id, function(data) {
        gvm.availableTeacher.removeAll();
        $.each(data, function(i, item) {
            gvm.availableTeacher.push(item);
                console.log("updateteacherfunctie")
            /* Add listener to listitem */
            $("#teacherbtn-" + item.id).click(function(){
                $(".btn-teacher span:first").text($(this).text());
                gvm.currentteacherid = item.id;
                gvm.saveLastSelectedDropdowns();
                loadTablePage(item.id, 1);
            });
        });
    });
    }
    }
/*
 * Delete item from table given the id.
 */
function deleteTableItem(id, tblOject) {
    showYesNoModal("Bent u zeker dat u dit item wil verwijderen? \r\n Let op: verwijderde items blijven in het systeem en kunnen weer actief gezet worden door een administrator. \r\n Gelieve de administrator te contacteren om een vak definitief te verwijderen.", function(val){
        if(val){
            $.ajax({
                url: "/api/coursedelete/" + id,
                type: "DELETE",
                success: function() {
                    viewModel.tabledata.remove(tblOject);
                }
            });
        }
    });
}

/*
 * Add a new projecttype
 */
function addNewProjecttypeForm(serialData, callback) {
    $.ajax({
            url: "/api/courserapport",
            type: "POST",
            data: serialData,
            success: function(data) {
                viewModel.addTableData(data['id'], data['code'], data['name'], data['description']);
                callback(true);
            },
            error: function(data) {
                callback(false);
            }
        });
}

/*
 * Add a new projecttype
 */
function addNewProjecttypeRaw(code, name, description, callback) {
    addNewProjecttypeForm("code=" + encodeURIComponent(code) + "&name=" + encodeURIComponent(name) + "&description=" + encodeURIComponent(description), callback);
}

/*
 * Update the projecttype
 * @param {type} id
 * @param {type} code
 * @param {type} name
 * @param {type} description
 * @param {type} callback
 * @returns {undefined}
 */
function updateProjecttypeForm(id, serialData, callback) {
    $.ajax({
        url: "/api/courseupdate/" + id,
        type: "PUT",
        data: serialData,
        success: function(data) {
            //viewModel.addTableData(data['id'], data['code'], data['name'], data['description']);
            loadTablePage(1); //TODO now it is refreshing table after updating but it redirects to pagenr 1     WERKT NIET
            callback(true);
        },
        error: function(data) {
            callback(false);
        }
    });
}

/**
 * update project type
 * @param {type} id
 * @param {type} code
 * @param {type} name
 * @param {type} description
 * @param {type} callback
 * @returns {undefined}
 */
function updateProjecttypeRaw(id, code, name, description, callback) {
    updateProjecttypeForm(id, "code=" + encodeURIComponent(code) + "&name=" + encodeURIComponent(name) + "&description=" + encodeURIComponent(description), callback);
}

/*
 * Load page of the table
 */
function loadTablePage(pagenr)
{
    $.getJSON('/api/coursesrapport/page/' + pagenr, function(data){

        /* Clear current table page */
        viewModel.clearTable();

        // Load table data
        $.each(data.data, function(i, item) {
            console.log(item.name);
            viewModel.addTableData(item.id, item.code, item.name, item.description);
        });

        /* Let previous en next buttons work */
        if(data.prev == "none"){
            $('#pager-prev-btn').addClass('disabled');
        } else {
            $('#pager-prev-btn').removeClass('disabled');
            $('#pager-prev-btn a').click(function(){
                loadTablePage(data.prev);
            });
        }

        if(data.next == "none"){
            $('#pager-next-btn').addClass('disabled');
        } else {
            $('#pager-next-btn').removeClass('disabled');
            $('#pager-next-btn a').click(function(){
                loadTablePage(data.next);
            });
        }

        // Number of pager buttons
        var numItems = $('.pager-nr-btn').length;

        /* Calculate for the pager buttons */
        var lowPage = Math.floor(pagenr/numItems) + 1;

        $('.pager-nr-btn').each(function() {
            /* calculate current page number */
            var thispagenr = lowPage++;

            /* Add the page number */
            $(this).html('' + thispagenr + '');

            /* Add active class to current page */
            if(thispagenr == pagenr) {
                $(this).addClass('active');
            } else {
                $(this).removeClass('active');
            }

            /* Disable inactive classes and bind handlers to active classes */
            if(thispagenr > data.pagecount) {
                $(this).addClass('disabled');
            } else {
                /* Add click listener for button */
                $(this).click(function() {
                    loadTablePage(thispagenr);
                });
            }
        });
    });

}

/**
 * Show a new projecttype modal.
 * @returns {undefined}
 */
function showNewProjectTypeModal()
{
    resetGeneralModal();
    setGeneralModalTitle(i18n.__("AddNewCourse"));
    setGeneralModalBody('<form id="newprojectform"> \

 \
                <input type="text" class="form-control input-lg" placeholder="' + i18n.__('CodeTableTitle') + '" " name="code"> \

 \

 \
                <input type="text" class="form-control input-lg" placeholder="' + i18n.__('NameTableTitle') + '" name="name"> \

 \

 \
                <input type="text" class="form-control input-lg" placeholder="' + i18n.__('DescTableTitle') + '" name="description"> \

 \

' +
                '<button class="btn btn-default dropdown-toggle" type="button" id="availableTeacher" data-toggle="dropdown" aria-expanded="true" placeholder="' + i18n.__('TeacherTableTitle') + '">' +
                    'Teacher' +
                '</button>' +
                '
' +
                '

' +
                '
' +
            '
' +
            '</form>' );

    addGeneralModalButton(i18n.__("AddBtn"), function(){
        console.log($('#newprojectform').serialize());
       addNewProjecttypeForm($('#newprojectform').serialize(), function(result){
            hideModal();
        });
    });

    showGeneralModal();
}

/**
 * Show the edit projecttype modal.
 * @param {type} code
 * @param {type} name
 * @param {type} description
 * @param {type} tid
 * @returns {undefined}
 */
function showEditProjectTypeModal(code, name, description, tid)
{
  resetGeneralModal();
    setGeneralModalTitle(i18n.__("EditProjectTitle2"));
    setGeneralModalBody('<form id="updateprojectform"> \

 \
                <input type="text" class="form-control input-lg" placeholder="' + i18n.__('CodeTableTitle') + '" " name="code" value="' + code + '"> \

 \

 \
                <input type="text" class="form-control input-lg" placeholder="' + i18n.__('NameTableTitle') + '" name="name" value="' + name + '"> \

 \

 \
                <input type="text" class="form-control input-lg" placeholder="' + i18n.__('DescTableTitle') + '" name="description" value="' + description + '"> \

 \
        </form>');
    $.getJSON()

    addGeneralModalButton(i18n.__("SaveBtn"), function(){
        updateProjecttypeForm(tid, $('#updateprojectform').serialize(), function(result){
            hideModal();
        });
    });

    addGeneralModalButton(i18n.__("CancelBtn"), function(){
        hideModal();
    })

    showGeneralModal();
}

function showCoupleStudentListModal(projectid) {
    viewModel.currentselectedlist = -1;
    resetGeneralModal();
    setGeneralModalTitle(i18n.__("CoupleStudentList"));
    setGeneralModalBody(
        '
' +
            '<button class="btn btn-default dropdown-toggle" type="button" id="dropdownStudLists" data-toggle="dropdown" aria-expanded="true">' +
                'Dropdown' +
                '' +
            '</button>' +
            '
' +
            '
' +
        '
');

    addGeneralModalButton(i18n.__("SaveBtn"), function() {
        updateListForm(viewModel.currentselectedlist, $('#coupleform').serialize(), function(result){
            hideModal();
        });
    });

    addGeneralModalButton(i18n.__("CancelBtn"), function(){
        hideModal();
    })
    showGeneralModal();
}
function loadCoupleDropdown() {
    $.getJSON('/api/studentlists/' + viewModel.userId, function(data) {
        $.each(data, function(i, item) {
            $("#ddlLists").append('
' + item.name + '
')
            $("#dropdownitem-" + item.id).click(function(){
                $(this).parent().parent().parent().removeClass("open");
                $(this).parent().parent().parent().find(".btn").html($(this).text() + '');
                viewModel.currentselectedlist = item.id;
            });
        });
    });
    $("#dropdownStudLists").click(function() {
        $(this).parent().toggleClass("open");
    });
}

function updateListForm(id, serialData, callback) {
    $.ajax({
        url: "/api/project/" + viewModel.currentprojectid + "/studentlist/" + id,
        type: "POST",
        data: serialData,
        success: function(data) {
            callback(true);
        },
        error: function(data) {
            callback(false);
        }
    });
}

function initPage() {
    // Add button handlers
    $('#addProjectTypeBtn').click(function(){
        showNewProjectTypeModal();
    });

    $.getJSON('/api/currentuser', function(data) {
        viewModel.userId = data.id;
    });

    loadTablePage(1);
}
<|endoftext|>


<commit_before>const tap = require('tap');
const path = require('path');
const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer;
const VirtualMachine = require('../../src/virtual-machine');
const Runtime = require('../../src/engine/runtime');
const MonitorRecord = require('../../src/engine/monitor-record');
const {Map} = require('immutable');

tap.tearDown(() => process.nextTick(process.exit));

const test = tap.test;

test('spec', t => {
    const r = new Runtime();

    t.type(Runtime, 'function');
    t.type(r, 'object');

    // Test types of cloud data managing functions
    t.type(r.hasCloudData, 'function');
    t.type(r.canAddCloudVariable, 'function');
    t.type(r.addCloudVariable, 'function');
    t.type(r.removeCloudVariable, 'function');

    t.ok(r instanceof Runtime);

    t.end();
});

test('monitorStateEquals', t => {
    const r = new Runtime();
    const id = 'xklj4#!';
    const prevMonitorState = MonitorRecord({
        id,
        opcode: 'turtle whereabouts',
        value: '25'
    });
    const newMonitorDelta = Map({
        id,
        value: String(25)
    });
    r.requestAddMonitor(prevMonitorState);
    r.requestUpdateMonitor(newMonitorDelta);

    t.equals(true, prevMonitorState === r._monitorState.get(id));
    t.equals(String(25), r._monitorState.get(id).get('value'));
    t.end();
});

test('monitorStateDoesNotEqual', t => {
    const r = new Runtime();
    const id = 'xklj4#!';
    const params = {seven: 7};
    const prevMonitorState = MonitorRecord({
        id,
        opcode: 'turtle whereabouts',
        value: '25'
    });

    // Value change
    let newMonitorDelta = Map({
        id,
        value: String(24)
    });
    r.requestAddMonitor(prevMonitorState);
    r.requestUpdateMonitor(newMonitorDelta);

    t.equals(false, prevMonitorState.equals(r._monitorState.get(id)));
    t.equals(String(24), r._monitorState.get(id).get('value'));

    // Prop change
    newMonitorDelta = Map({
        id: 'xklj4#!',
        params: params
    });
    r.requestUpdateMonitor(newMonitorDelta);

    t.equals(false, prevMonitorState.equals(r._monitorState.get(id)));
    t.equals(String(24), r._monitorState.get(id).value);
    t.equals(params, r._monitorState.get(id).params);

    t.end();
});

test('getLabelForOpcode', t => {
    const r = new Runtime();

    const fakeExtension = {
        id: 'fakeExtension',
        name: 'Fake Extension',
        blocks: [
            {
                info: {
                    opcode: 'foo',
                    json: {},
                    text: 'Foo',
                    xml: ''
                }
            },
            {
                info: {
                    opcode: 'foo_2',
                    json: {},
                    text: 'Foo 2',
                    xml: ''
                }
            }
        ]
    };

    r._blockInfo.push(fakeExtension);

    const result1 = r.getLabelForOpcode('fakeExtension_foo');
    t.type(result1.category, 'string');
    t.type(result1.label, 'string');
    t.equals(result1.label, 'Fake Extension: Foo');

    const result2 = r.getLabelForOpcode('fakeExtension_foo_2');
    t.type(result2.category, 'string');
    t.type(result2.label, 'string');
    t.equals(result2.label, 'Fake Extension: Foo 2');

    t.end();
});

test('Project loaded emits runtime event', t => {
    const vm = new VirtualMachine();
    const projectUri = path.resolve(__dirname, '../fixtures/default.sb2');
    const project = readFileToBuffer(projectUri);
    let projectLoaded = false;

    vm.runtime.addListener('PROJECT_LOADED', () => {
        projectLoaded = true;
    });

    vm.loadProject(project).then(() => {
        t.equal(projectLoaded, true, 'Project load event emitted');
        t.end();
    });
});

test('Cloud variable limit allows only 8 cloud variables', t => {
    // This is a test of just the cloud variable limit mechanism
    // The functions being tested below need to be used when
    // creating and deleting cloud variables in the runtime.

    const rt = new Runtime();

    t.equal(rt.hasCloudData(), false);

    for (let i = 0; i < 8; i++) {
        t.equal(rt.canAddCloudVariable(), true);
        rt.addCloudVariable();
        // Adding a cloud variable should change the
        // result of the hasCloudData check
        t.equal(rt.hasCloudData(), true);
    }

    // We should be at the cloud variable limit now
    t.equal(rt.canAddCloudVariable(), false);

    // Removing a cloud variable should allow the addition of exactly one more
    // when we are at the cloud variable limit
    rt.removeCloudVariable();

    t.equal(rt.canAddCloudVariable(), true);
    rt.addCloudVariable();
    t.equal(rt.canAddCloudVariable(), false);

    // Disposing of the runtime should reset the cloud variable limitations
    rt.dispose();
    t.equal(rt.hasCloudData(), false);

    for (let i = 0; i < 8; i++) {
        t.equal(rt.canAddCloudVariable(), true);
        rt.addCloudVariable();
        t.equal(rt.hasCloudData(), true);
    }

    // We should be at the cloud variable limit now
    t.equal(rt.canAddCloudVariable(), false);

    t.end();

});

test('Starting the runtime emits an event', t => {
    let started = false;
    const rt = new Runtime();
    rt.addListener('RUNTIME_STARTED', () => {
        started = true;
    });
    rt.start();
    t.equal(started, true);
    t.end();
});

test('Runtime cannot be started while already running', t => {
    const rt = new Runtime();
    rt.start(); // Start the first time

    // Set up a flag/listener to check if it can be started again
    let started = false;
    rt.addListener('RUNTIME_STARTED', () => {
        started = true;
    });

    // Starting again should not emit another event
    rt.start();
    t.equal(started, false);
    t.end();
});

test('setCompatibilityMode restarts if it was already running', t => {
    const rt = new Runtime();
    rt.start(); // Start the first time

    // Set up a flag/listener to check if it gets started again
    let started = false;
    rt.addListener('RUNTIME_STARTED', () => {
        started = true;
    });

    rt.setCompatibilityMode(true);
    t.equal(started, true);
    t.end();
});

test('setCompatibilityMode does not restart if it was not running', t => {
    const rt = new Runtime();

    let started = false;
    rt.addListener('RUNTIME_STARTED', () => {
        started = true;
    });

    rt.setCompatibilityMode(true);
    t.equal(started, false);
    t.end();
});

test('Disposing the runtime emits an event', t => {
    let disposed = false;
    const rt = new Runtime();
    rt.addListener('RUNTIME_DISPOSED', () => {
        disposed = true;
    });
    rt.start();
    t.equal(disposed, true);
    t.end();
});
<commit_msg>Update test/unit/engine_runtime.js<commit_after>const tap = require('tap');
const path = require('path');
const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer;
const VirtualMachine = require('../../src/virtual-machine');
const Runtime = require('../../src/engine/runtime');
const MonitorRecord = require('../../src/engine/monitor-record');
const {Map} = require('immutable');

tap.tearDown(() => process.nextTick(process.exit));

const test = tap.test;

test('spec', t => {
    const r = new Runtime();

    t.type(Runtime, 'function');
    t.type(r, 'object');

    // Test types of cloud data managing functions
    t.type(r.hasCloudData, 'function');
    t.type(r.canAddCloudVariable, 'function');
    t.type(r.addCloudVariable, 'function');
    t.type(r.removeCloudVariable, 'function');

    t.ok(r instanceof Runtime);

    t.end();
});

test('monitorStateEquals', t => {
    const r = new Runtime();
    const id = 'xklj4#!';
    const prevMonitorState = MonitorRecord({
        id,
        opcode: 'turtle whereabouts',
        value: '25'
    });
    const newMonitorDelta = Map({
        id,
        value: String(25)
    });
    r.requestAddMonitor(prevMonitorState);
    r.requestUpdateMonitor(newMonitorDelta);

    t.equals(true, prevMonitorState === r._monitorState.get(id));
    t.equals(String(25), r._monitorState.get(id).get('value'));
    t.end();
});

test('monitorStateDoesNotEqual', t => {
    const r = new Runtime();
    const id = 'xklj4#!';
    const params = {seven: 7};
    const prevMonitorState = MonitorRecord({
        id,
        opcode: 'turtle whereabouts',
        value: '25'
    });

    // Value change
    let newMonitorDelta = Map({
        id,
        value: String(24)
    });
    r.requestAddMonitor(prevMonitorState);
    r.requestUpdateMonitor(newMonitorDelta);

    t.equals(false, prevMonitorState.equals(r._monitorState.get(id)));
    t.equals(String(24), r._monitorState.get(id).get('value'));

    // Prop change
    newMonitorDelta = Map({
        id: 'xklj4#!',
        params: params
    });
    r.requestUpdateMonitor(newMonitorDelta);

    t.equals(false, prevMonitorState.equals(r._monitorState.get(id)));
    t.equals(String(24), r._monitorState.get(id).value);
    t.equals(params, r._monitorState.get(id).params);

    t.end();
});

test('getLabelForOpcode', t => {
    const r = new Runtime();

    const fakeExtension = {
        id: 'fakeExtension',
        name: 'Fake Extension',
        blocks: [
            {
                info: {
                    opcode: 'foo',
                    json: {},
                    text: 'Foo',
                    xml: ''
                }
            },
            {
                info: {
                    opcode: 'foo_2',
                    json: {},
                    text: 'Foo 2',
                    xml: ''
                }
            }
        ]
    };

    r._blockInfo.push(fakeExtension);

    const result1 = r.getLabelForOpcode('fakeExtension_foo');
    t.type(result1.category, 'string');
    t.type(result1.label, 'string');
    t.equals(result1.label, 'Fake Extension: Foo');

    const result2 = r.getLabelForOpcode('fakeExtension_foo_2');
    t.type(result2.category, 'string');
    t.type(result2.label, 'string');
    t.equals(result2.label, 'Fake Extension: Foo 2');

    t.end();
});

test('Project loaded emits runtime event', t => {
    const vm = new VirtualMachine();
    const projectUri = path.resolve(__dirname, '../fixtures/default.sb2');
    const project = readFileToBuffer(projectUri);
    let projectLoaded = false;

    vm.runtime.addListener('PROJECT_LOADED', () => {
        projectLoaded = true;
    });

    vm.loadProject(project).then(() => {
        t.equal(projectLoaded, true, 'Project load event emitted');
        t.end();
    });
});

test('Cloud variable limit allows only 8 cloud variables', t => {
    // This is a test of just the cloud variable limit mechanism
    // The functions being tested below need to be used when
    // creating and deleting cloud variables in the runtime.

    const rt = new Runtime();

    t.equal(rt.hasCloudData(), false);

    for (let i = 0; i < 8; i++) {
        t.equal(rt.canAddCloudVariable(), true);
        rt.addCloudVariable();
        // Adding a cloud variable should change the
        // result of the hasCloudData check
        t.equal(rt.hasCloudData(), true);
    }

    // We should be at the cloud variable limit now
    t.equal(rt.canAddCloudVariable(), false);

    // Removing a cloud variable should allow the addition of exactly one more
    // when we are at the cloud variable limit
    rt.removeCloudVariable();

    t.equal(rt.canAddCloudVariable(), true);
    rt.addCloudVariable();
    t.equal(rt.canAddCloudVariable(), false);

    // Disposing of the runtime should reset the cloud variable limitations
    rt.dispose();
    t.equal(rt.hasCloudData(), false);

    for (let i = 0; i < 8; i++) {
        t.equal(rt.canAddCloudVariable(), true);
        rt.addCloudVariable();
        t.equal(rt.hasCloudData(), true);
    }

    // We should be at the cloud variable limit now
    t.equal(rt.canAddCloudVariable(), false);

    t.end();

});

test('Starting the runtime emits an event', t => {
    let started = false;
    const rt = new Runtime();
    rt.addListener('RUNTIME_STARTED', () => {
        started = true;
    });
    rt.start();
    t.equal(started, true);
    t.end();
});

test('Runtime cannot be started while already running', t => {
    const rt = new Runtime();
    rt.start(); // Start the first time

    // Set up a flag/listener to check if it can be started again
    let started = false;
    rt.addListener('RUNTIME_STARTED', () => {
        started = true;
    });

    // Starting again should not emit another event
    rt.start();
    t.equal(started, false);
    t.end();
});

test('setCompatibilityMode restarts if it was already running', t => {
    const rt = new Runtime();
    rt.start(); // Start the first time

    // Set up a flag/listener to check if it gets started again
    let started = false;
    rt.addListener('RUNTIME_STARTED', () => {
        started = true;
    });

    rt.setCompatibilityMode(true);
    t.equal(started, true);
    t.end();
});

test('setCompatibilityMode does not restart if it was not running', t => {
    const rt = new Runtime();

    let started = false;
    rt.addListener('RUNTIME_STARTED', () => {
        started = true;
    });

    rt.setCompatibilityMode(true);
    t.equal(started, false);
    t.end();
});

test('Disposing the runtime emits an event', t => {
    let disposed = false;
    const rt = new Runtime();
    rt.addListener('RUNTIME_DISPOSED', () => {
        disposed = true;
    });
    rt.dispose();
    t.equal(disposed, true);
    t.end();
});
<|endoftext|>


<commit_before>describe('Game module', function() {
    describe('GameManager', function() {
        // Inject the Game module into this test
        beforeEach(module('Game'));

        var provide;

        var _gridManager;
        beforeEach(module(function($provide) {
            // Create mocked gridService for this test
            _gridManager = {
                isAnyCellAvailable: angular.noop,
                isTileMatchesAvailable: angular.noop,
                generateEmptyGameBoard: angular.noop,
                initGameBoard: angular.noop
            };

            // Replace real GridManager with mocked one
            $provide.value('GridManager', _gridManager);

            provide = $provide;
        }));

        var gameManager; // Instance of the GameManager
        beforeEach(inject(function(GameManager) {
            gameManager = GameManager;
        }));

        it('should have a GameManage', function() {
            expect(gameManager).toBeDefined();
        });

        describe('.reinit', function() {
            beforeEach(function() {
                gameManager.reinit();
            });

            it('should initialize current score to 0', function() {
                   expect(gameManager.currentScore).toEqual(0);
            });
            it('should initialize best score to 0', function() {
                    expect(gameManager.bestScore).toEqual(0);
            });
        });

        describe('.newGame', function() {
            it('should call the GridManager to generate an empty game board', function() {
               spyOn(_gridManager, 'generateEmptyGameBoard').andCallThrough();
               gameManager.newGame();
               expect(_gridManager.generateEmptyGameBoard).toHaveBeenCalled();
           });
            it('should call the GridManager to place initial pieces', function() {
                spyOn(_gridManager, 'initGameBoard').andCallThrough();
                gameManager.newGame();
                expect(_gridManager.initGameBoard).toHaveBeenCalled();
            });
            it('should call reinit at the end', function() {
                spyOn(gameManager, 'reinit').andCallThrough();
                gameManager.newGame();
                expect(gameManager.reinit).toHaveBeenCalled();
            });
        });

        describe('.updateScore', function() {
            it('should update current score', function() {
                gameManager.updateScore(1);
                expect(gameManager.currentScore).toEqual(1);
            });

            it('should update best score when new score is higher than best score', function() {
                gameManager.bestScore = 10;
                gameManager.updateScore(50);
                expect(gameManager.getBestScore()).toEqual(50);
            });
        });

        describe('.movesAvailable', function() {
            it('should report true if there are cells available', function() {
                spyOn(_gridManager, 'isAnyCellAvailable').andReturn(true);
                expect(gameManager.moveAvailable()).toBeTruthy();
            });

            it('should report true if there are matched available', function() {
                spyOn(_gridManager, 'isAnyCellAvailable').andReturn(false);
                spyOn(_gridManager, 'isTileMatchesAvailable').andReturn(true);
                expect(gameManager.moveAvailable()).toBeTruthy();
            });

            it('should report false if there are no cells nor matched available', function() {
                spyOn(_gridManager, 'isAnyCellAvailable').andReturn(false);
                spyOn(_gridManager, 'isTileMatchesAvailable').andReturn(false);
                expect(gameManager.moveAvailable()).toBeFalsy();
            });
        });
    });
});<commit_msg>fix typo<commit_after>describe('Game module', function() {
    describe('GameManager', function() {
        // Inject the Game module into this test
        beforeEach(module('Game'));

        var provide;

        var _gridManager;
        beforeEach(module(function($provide) {
            // Create mocked gridService for this test
            _gridManager = {
                isAnyCellAvailable: angular.noop,
                isTileMatchesAvailable: angular.noop,
                generateEmptyGameBoard: angular.noop,
                initGameBoard: angular.noop
            };

            // Replace real GridManager with mocked one
            $provide.value('GridManager', _gridManager);

            provide = $provide;
        }));

        var gameManager; // Instance of the GameManager
        beforeEach(inject(function(GameManager) {
            gameManager = GameManager;
        }));

        it('should have a GameManager', function() {
            expect(gameManager).toBeDefined();
        });

        describe('.reinit', function() {
            beforeEach(function() {
                gameManager.reinit();
            });

            it('should initialize current score to 0', function() {
                   expect(gameManager.currentScore).toEqual(0);
            });
            it('should initialize best score to 0', function() {
                    expect(gameManager.bestScore).toEqual(0);
            });
        });

        describe('.newGame', function() {
            it('should call the GridManager to generate an empty game board', function() {
               spyOn(_gridManager, 'generateEmptyGameBoard').andCallThrough();
               gameManager.newGame();
               expect(_gridManager.generateEmptyGameBoard).toHaveBeenCalled();
           });
            it('should call the GridManager to place initial pieces', function() {
                spyOn(_gridManager, 'initGameBoard').andCallThrough();
                gameManager.newGame();
                expect(_gridManager.initGameBoard).toHaveBeenCalled();
            });
            it('should call reinit at the end', function() {
                spyOn(gameManager, 'reinit').andCallThrough();
                gameManager.newGame();
                expect(gameManager.reinit).toHaveBeenCalled();
            });
        });

        describe('.updateScore', function() {
            it('should update current score', function() {
                gameManager.updateScore(1);
                expect(gameManager.currentScore).toEqual(1);
            });

            it('should update best score when new score is higher than best score', function() {
                gameManager.bestScore = 10;
                gameManager.updateScore(50);
                expect(gameManager.getBestScore()).toEqual(50);
            });
        });

        describe('.movesAvailable', function() {
            it('should report true if there are cells available', function() {
                spyOn(_gridManager, 'isAnyCellAvailable').andReturn(true);
                expect(gameManager.moveAvailable()).toBeTruthy();
            });

            it('should report true if there are matched available', function() {
                spyOn(_gridManager, 'isAnyCellAvailable').andReturn(false);
                spyOn(_gridManager, 'isTileMatchesAvailable').andReturn(true);
                expect(gameManager.moveAvailable()).toBeTruthy();
            });

            it('should report false if there are no cells nor matched available', function() {
                spyOn(_gridManager, 'isAnyCellAvailable').andReturn(false);
                spyOn(_gridManager, 'isTileMatchesAvailable').andReturn(false);
                expect(gameManager.moveAvailable()).toBeFalsy();
            });
        });
    });
});<|endoftext|>