<commit_before>//tabs.js are the events and functions associated with UI tabs.
Meteor.tabsFunctions = {
	toggleTabs : function(){
		event.preventDefault();
	    // Tabs Variables
	    if(event.target.hasAttribute('aria-controls') && event.target.getAttribute('aria-expanded') == 'false'){
			var thisToggleMenu = event.target.parentNode.parentNode;
			var thisToggleMenuButtons = thisToggleMenu.querySelectorAll('[aria-controls][data-toggle=tabs]');
			var thisTabsContent = thisToggleMenu.parentNode.querySelector('div.tabs');
			var thisTabsContentElement = thisTabsContent.querySelectorAll('[aria-hidden]');
			for (var i = 0, e; e = thisToggleMenuButtons[i]; i++) {
				h.active(e,false);
			}
			h.active(event.target, true);
			for (var i = 0, e; e = thisTabsContentElement[i]; i++) {
				h.hidden(e, true);
	            if ('#' + e.getAttribute('id') == event.target.getAttribute('aria-controls')){ //If Sidebar ID matches toggles' data-sidebar
	                h.hidden(e,false); //Add active class to given sidebar
	            }
			}
			//If filter active
			if (event.target.getAttribute('aria-controls') == '#library'){
				event.target.parentNode.parentNode.parentNode.querySelector('aside.filter').classList.add('active-filter');
			}
			if (event.target.getAttribute('aria-controls') == '#infosheets' || event.target.getAttribute('aria-controls') == '#stats-data' || event.target.getAttribute('aria-controls') == '#webinars'){
				event.target.parentNode.parentNode.parentNode.querySelector('aside.filter').classList.remove('active-filter');
			}
	    }
	}
}

//Define Usage
t = Meteor.tabsFunctions;

Template.body.events({
    //Tabs
    'click [data-toggle=tabs]': function (event) { t.toggleTabs(); },
});

Template.tabs.onRendered(function() {
	if (window.innerWidth > 767){
		var toggleMenus = document.querySelectorAll('menu.tabs');
		//alert(toggleMenus);
		for (var i = 0, e; e = toggleMenus[i]; i++) {
			//alert(e);
			var menuItem = e.querySelectorAll('[data-toggle="tabs"]');
			menuItem[0].click();
		}
	}
	if (window.innerWidth < 768){
		var toggleMenus = document.querySelectorAll('#main menu.tabs');
		//alert(toggleMenus);
		for (var i = 0, e; e = toggleMenus[i]; i++) {
			//alert(e);
			var menuItem = e.querySelectorAll('[data-toggle="tabs"]');
			menuItem[0].click();
		}
	}
	/*$(window).resize(function() {
		if (window.innerWidth > 767){
			var toggleMenus = document.querySelectorAll('menu.tabs');
			//alert(toggleMenus);
			for (var i = 0, e; e = toggleMenus[i]; i++) {
				//alert(e);
				var menuItem = e.querySelectorAll('[data-toggle="tabs"]');
				menuItem[0].click();
			}
		}
	});*/
});
<commit_msg>Collapse main tabs on mobile except the masthead.<commit_after>//tabs.js are the events and functions associated with UI tabs.
Meteor.tabsFunctions = {
	toggleTabs : function(){
		event.preventDefault();
	    // Tabs Variables
	    if(event.target.hasAttribute('aria-controls') && event.target.getAttribute('aria-expanded') == 'false'){
			var thisToggleMenu = event.target.parentNode.parentNode;
			var thisToggleMenuButtons = thisToggleMenu.querySelectorAll('[aria-controls][data-toggle=tabs]');
			var thisTabsContent = thisToggleMenu.parentNode.querySelector('div.tabs');
			var thisTabsContentElement = thisTabsContent.querySelectorAll('[aria-hidden]');
			for (var i = 0, e; e = thisToggleMenuButtons[i]; i++) {
				h.active(e,false);
			}
			h.active(event.target, true);
			for (var i = 0, e; e = thisTabsContentElement[i]; i++) {
				h.hidden(e, true);
	            if ('#' + e.getAttribute('id') == event.target.getAttribute('aria-controls')){ //If Sidebar ID matches toggles' data-sidebar
	                h.hidden(e,false); //Add active class to given sidebar
	            }
			}
			//If filter active
			if (event.target.getAttribute('aria-controls') == '#library'){
				event.target.parentNode.parentNode.parentNode.querySelector('aside.filter').classList.add('active-filter');
			}
			if (event.target.getAttribute('aria-controls') == '#infosheets' || event.target.getAttribute('aria-controls') == '#stats-data' || event.target.getAttribute('aria-controls') == '#webinars'){
				event.target.parentNode.parentNode.parentNode.querySelector('aside.filter').classList.remove('active-filter');
			}
	    }
	}
}

//Define Usage
t = Meteor.tabsFunctions;

Template.body.events({
    //Tabs
    'click [data-toggle=tabs]': function (event) { t.toggleTabs(); },
});

Template.tabs.onRendered(function() {
	if (window.innerWidth > 767){
		var toggleMenus = document.querySelectorAll('menu.tabs');
		//alert(toggleMenus);
		for (var i = 0, e; e = toggleMenus[i]; i++) {
			//alert(e);
			var menuItem = e.querySelectorAll('[data-toggle="tabs"]');
			menuItem[0].click();
		}
	}
	if (window.innerWidth < 768){
		var toggleMenus = document.querySelectorAll('#main #masthead menu.tabs');
		//alert(toggleMenus);
		for (var i = 0, e; e = toggleMenus[i]; i++) {
			//alert(e);
			var menuItem = e.querySelectorAll('[data-toggle="tabs"]');
			menuItem[0].click();
		}
	}
	/*$(window).resize(function() {
		if (window.innerWidth > 767){
			var toggleMenus = document.querySelectorAll('menu.tabs');
			//alert(toggleMenus);
			for (var i = 0, e; e = toggleMenus[i]; i++) {
				//alert(e);
				var menuItem = e.querySelectorAll('[data-toggle="tabs"]');
				menuItem[0].click();
			}
		}
	});*/
});
<|endoftext|>


<commit_before>import React, { Component } from "react";

class UpdateAccount extends Component {
  render() {
    return (

Update Account Details

        <form>
          Email:
          <input type="text" name="email"></input>
          Organization:
          <input type="text" name="org"></input>
          <input type="submit" value="save" className="btn-primary"></input>
        </form>

    );
  }
}

export default UpdateAccount;
<commit_msg>init states for UpdateAccount component<commit_after>import React, { Component } from "react";
import { isEmail } from "validator";
import ErrorList from "./ErrorList";

class UpdateAccount extends Component {
  state = {
    fields: {
      email: "",
      org: "",
      neworg: "",
    },
    fieldErrors: [],
  }

  validate(fields) {
    const errors = [];
    if (!fields.email) errors.push("Email Required!");
    if (!isEmail(fields.email)) errors.push("Invalid email!");
    return errors;
  }

  onInputChange(event) {
    const value = event.target.value;
    const name = event.target.name;
    const fields = this.state.fields;
    fields[name] = value;
    this.setState({ fields });

    const hiddenForm = document.querySelector(".change");

    if (value === "new" && name === "org") {
      hiddenForm.classList.remove("hidden");
    } else {
      hiddenForm.classList.add("hidden");
    }
  }

  onFormSubmit(event) {
    event.preventDefault();
    const fieldErrors = this.validate(this.state.fields);
    this.setState({ fieldErrors });

    // Return on Errors
    if (fieldErrors.length) return;

    this.setState({fields: {
      email: "",
      org: "",
      neworg: "",
    }})
  }

  render() {
    return (

Update Account Details

        <form onSubmit={this.onFormSubmit.bind(this)}>
          Email:
          <input type="text" name="email" value={this.state.fields.email} onChange={this.onInputChange.bind(this)}></input>
          Organization:
          <select
            name="org"
            onChange={this.onInputChange.bind(this)}
            value={this.state.fields.org}>
            <option>NordVisa</option>
            <option value="new">New Organization</option>
            <option defaultValue>No Organization</option>
          </select>

            New Organization:
            <input
              name="neworg"
              value={this.state.fields.neworg}
              onChange={this.onInputChange.bind(this)}
              type="text">
            </input>

          <ErrorList errors={this.state.fieldErrors}/>
          <input type="submit" value="save" className="btn-primary"></input>
        </form>

    );
  }
}

export default UpdateAccount;
<|endoftext|>


<commit_before>import { Minutes } from '/imports/minutes'
import { Topic } from '/imports/topic'
import { InfoItem } from '/imports/infoitem'

let _minutesId;

Template.topicElement.onCreated(function () {
    _minutesId = Template.instance().data.minutesID;
});

Template.topicElement.helpers({

    checkedState: function () {
        if (this.topic.isOpen) {
            return "";
        } else {
            return {checked: "checked"};
        }
    },

    disabledState: function () {
        if (this.isEditable) {
            return "";
        } else {
            return {disabled: "disabled"};
        }
    },

    // helper will be called within the each-infoItem block
    // so this refers to the current infoItem
    getInfoItem: function (index) {
        let parentTopicId = Template.instance().data.topic._id;
        let parentElement = (Template.instance().data.minutesID)
            ? Template.instance().data.minutesID : Template.instance().data.parentMeetingSeriesId;

        return {
            infoItem: this,
            parentTopicId: parentTopicId,
            isEditable: Template.instance().data.isEditable,
            minutesID: parentElement,//Template.instance().data.minutesID,
            currentCollapseId: parentTopicId+"_"+index  // each topic item gets its own collapseID
        };
    },

    // determine if this topic shall be rendered collapsed
    isCollapsed() {
        let collapseState = Session.get("minutesedit.collapsetopics."+_minutesId);
        return collapseState ? collapseState[this.topic._id] : false;
    },

    showRecurringIcon() {
        return (this.isEditable || this.topic.isRecurring);
    },

    responsiblesHelper() {
        let parentElement = (this.minutesID) ? this.minutesID : this.parentMeetingSeriesId;

        let aTopic = new Topic(parentElement, this.topic._id);
        if (aTopic.hasResponsibles()) {
            return "("+aTopic.getResponsiblesString()+")";
        }
        return "";
    }
});

Template.topicElement.events({
    'click #btnDelTopic'(evt) {
        evt.preventDefault();

        if (!this.minutesID) {
            return;
        }
        console.log("Delete topics: "+this.topic._id+" from minutes "+this.minutesID);

        let aMin = new Minutes(this.minutesID);

        let dialogContent = "
Do you really want to delete the topic " + this.topic.subject + "?
";

        confirmationDialog(
            /* callback called if user wants to continue */
            () => {
                aMin.removeTopic(this.topic._id);
            },
            /* Dialog content */
            dialogContent
        );
    },

    'click .btnToggleState'(evt) {
        evt.preventDefault();
        if (!this.minutesID) {
            return;
        }

        console.log("Toggle topic state ("+this.topic.isOpen+"): "+this.topic._id+" from minutes "+this.minutesID);
        let aTopic = new Topic(this.minutesID, this.topic._id);
        if (aTopic) {
            aTopic.toggleState();
            aTopic.save();
        }
    },

    'click .js-toggle-recurring'(evt) {
        evt.preventDefault();
        if (!this.isEditable) {
            return;
        }

        if (!this.minutesID) {
            return;
        }

        let aTopic = new Topic(this.minutesID, this.topic._id);
        if (aTopic) {
            aTopic.toggleRecurring();
            aTopic.save();
        }
    },

    'click #btnEditTopic'(evt) {
        evt.preventDefault();

        if (!this.minutesID) {
            return;
        }

        Session.set("topicEditTopicId", this.topic._id);
    },

    'click .addTopicInfoItem'(evt) {
        evt.preventDefault();
        // will be called before the modal dialog is shown

        Session.set("topicInfoItemEditTopicId", this.topic._id);
    },

    'click #btnTopicExpandCollapse'(evt) {
        console.log("btnTopicExpandCollapse()"+this.topic._id);
        evt.preventDefault();
        let collapseState = Session.get("minutesedit.collapsetopics."+_minutesId);
        console.log("1. JSON: "+JSON.stringify(collapseState,null,2));
        if (!collapseState) {
            collapseState = {};
        }
        collapseState[this.topic._id] = ! collapseState[this.topic._id];
        Session.set("minutesedit.collapsetopics."+_minutesId, collapseState);
        console.log("2. JSON: "+JSON.stringify(collapseState,null,2));
    }
});<commit_msg>Fix: Deletion of topic always threw a blaze exception in the browser. Fixes #88<commit_after>import { Minutes } from '/imports/minutes'
import { Topic } from '/imports/topic'
import { InfoItem } from '/imports/infoitem'

let _minutesId;

Template.topicElement.onCreated(function () {
    _minutesId = Template.instance().data.minutesID;
});

Template.topicElement.helpers({

    checkedState: function () {
        if (this.topic.isOpen) {
            return "";
        } else {
            return {checked: "checked"};
        }
    },

    disabledState: function () {
        if (this.isEditable) {
            return "";
        } else {
            return {disabled: "disabled"};
        }
    },

    // helper will be called within the each-infoItem block
    // so this refers to the current infoItem
    getInfoItem: function (index) {
        let parentTopicId = Template.instance().data.topic._id;
        let parentElement = (Template.instance().data.minutesID)
            ? Template.instance().data.minutesID : Template.instance().data.parentMeetingSeriesId;

        return {
            infoItem: this,
            parentTopicId: parentTopicId,
            isEditable: Template.instance().data.isEditable,
            minutesID: parentElement,//Template.instance().data.minutesID,
            currentCollapseId: parentTopicId+"_"+index  // each topic item gets its own collapseID
        };
    },

    // determine if this topic shall be rendered collapsed
    isCollapsed() {
        let collapseState = Session.get("minutesedit.collapsetopics."+_minutesId);
        return collapseState ? collapseState[this.topic._id] : false;
    },

    showRecurringIcon() {
        return (this.isEditable || this.topic.isRecurring);
    },

    responsiblesHelper() {
        try {
            let parentElement = (this.minutesID) ? this.minutesID : this.parentMeetingSeriesId;

            let aTopic = new Topic(parentElement, this.topic._id);
            if (aTopic.hasResponsibles()) {
                return "("+aTopic.getResponsiblesString()+")";
            }
        } catch (e) {
            // intentionally left blank.
            // on deletion of a topic blaze once calls this method on the just deleted topic
            // we handle this gracefully with this empty exception handler
        }
        return "";
    }
});

Template.topicElement.events({
    'click #btnDelTopic'(evt) {
        evt.preventDefault();

        if (!this.minutesID) {
            return;
        }
        console.log("Delete topics: "+this.topic._id+" from minutes "+this.minutesID);

        let aMin = new Minutes(this.minutesID);

        let dialogContent = "
Do you really want to delete the topic " + this.topic.subject + "?
";

        confirmationDialog(
            /* callback called if user wants to continue */
            () => {
                aMin.removeTopic(this.topic._id);
            },
            /* Dialog content */
            dialogContent
        );
    },

    'click .btnToggleState'(evt) {
        evt.preventDefault();
        if (!this.minutesID) {
            return;
        }

        console.log("Toggle topic state ("+this.topic.isOpen+"): "+this.topic._id+" from minutes "+this.minutesID);
        let aTopic = new Topic(this.minutesID, this.topic._id);
        if (aTopic) {
            aTopic.toggleState();
            aTopic.save();
        }
    },

    'click .js-toggle-recurring'(evt) {
        evt.preventDefault();
        if (!this.isEditable) {
            return;
        }

        if (!this.minutesID) {
            return;
        }

        let aTopic = new Topic(this.minutesID, this.topic._id);
        if (aTopic) {
            aTopic.toggleRecurring();
            aTopic.save();
        }
    },

    'click #btnEditTopic'(evt) {
        evt.preventDefault();

        if (!this.minutesID) {
            return;
        }

        Session.set("topicEditTopicId", this.topic._id);
    },

    'click .addTopicInfoItem'(evt) {
        evt.preventDefault();
        // will be called before the modal dialog is shown

        Session.set("topicInfoItemEditTopicId", this.topic._id);
    },

    'click #btnTopicExpandCollapse'(evt) {
        console.log("btnTopicExpandCollapse()"+this.topic._id);
        evt.preventDefault();
        let collapseState = Session.get("minutesedit.collapsetopics."+_minutesId);
        console.log("1. JSON: "+JSON.stringify(collapseState,null,2));
        if (!collapseState) {
            collapseState = {};
        }
        collapseState[this.topic._id] = ! collapseState[this.topic._id];
        Session.set("minutesedit.collapsetopics."+_minutesId, collapseState);
        console.log("2. JSON: "+JSON.stringify(collapseState,null,2));
    }
});<|endoftext|>


<commit_before>export { default as AppHolder } from './app-holder';
export { default as GennyForm } from './genny-form';
export { default as GennyTable } from './genny-table';
export { default as GennyTreeView } from './genny-tree-view';<commit_msg>fix sidebar<commit_after>export { default as AppHolder } from './app-holder';
export { default as GennyForm } from './genny-form';
export { default as GennyTable } from './genny-table';
export { default as GennyTreeView } from './genny-tree-view';
export { default as GennyImageView } from './genny-image-view';
<|endoftext|>


<commit_before>/*
Gradebook from Names and Scores

I worked on this challenge [by myself, with:]
This challenge took me [#] hours.

You will work with the following two variables.  The first, students, holds the names of four students.
The second, scores, holds groups of test scores.  The relative positions of elements within the two
variables match (i.e., 'Joseph' is the first element in students; his scores are the first value in scores.).

Do not alter the students and scores code.

*/

var students = ["Joseph", "Susan", "William", "Elizabeth"]

var scores = [ [80, 70, 70, 100],
               [85, 80, 90, 90],
               [75, 70, 80, 75],
               [100, 90, 95, 85] ]

// __________________________________________
// Write your code below.

// __________________________________________
// Refactored Solution

// __________________________________________
// Reflect

// __________________________________________
// Test Code:  Do not alter code below this line.

function assert(test, message, test_number) {
  if (!test) {
    console.log(test_number + "false");
    throw "ERROR: " + message;
  }
  console.log(test_number + "true");
  return true;
}

assert(
  (gradebook instanceof Object),
  "The value of gradebook should be an Object.\n",
  "1. "
)

assert(
  (gradebook["Elizabeth"] instanceof Object),
  "gradebook's Elizabeth property should be an object.",
  "2. "
)

assert(
  (gradebook.William.testScores === scores[2]),
  "William's testScores should equal the third element in scores.",
  "3. "
)

assert(
  (gradebook.addScore instanceof Function),
  "The value of gradebook's addScore property should be a Function.",
  "4. "
)

gradebook.addScore("Susan", 80)

assert(
  (gradebook.Susan.testScores.length === 5
   && gradebook.Susan.testScores[4] === 80),
  "Susan's testScores should have a new score of 80 added to the end.",
  "5. "
)

assert(
  (gradebook.getAverage instanceof Function),
  "The value of gradebook's getAverage property should be a Function.",
  "6. "
)

assert(
  (average instanceof Function),
  "The value of average should be a Function.\n",
  "7. "
)
assert(
  average([1, 2, 3]) === 2,
  "average should return the average of the elements in the array argument.\n",
  "8. "
)

assert(
  (gradebook.getAverage("Joseph") === 80),
  "gradebook's getAverage should return 80 if passed 'Joseph'.",
  "9. "
)
<commit_msg>complete 8.2<commit_after>/*
Gradebook from Names and Scores
I worked on this challenge [by myself, with:]
This challenge took me [#] hours.
You will work with the following two variables.  The first, students, holds the names of four students.
The second, scores, holds groups of test scores.  The relative positions of elements within the two
variables match (i.e., 'Joseph' is the first element in students; his scores are the first value in scores.).
Do not alter the students and scores code.
*/

var students = ["Joseph", "Susan", "William", "Elizabeth"]

var scores = [ [80, 70, 70, 100],
               [85, 80, 90, 90],
               [75, 70, 80, 75],
               [100, 90, 95, 85] ]

// __________________________________________
// Write your code below.
// var gradebook = {
//   "Joseph": {},
//   "Susan": {},
//   "William": {},
//   "Elizabeth": {}
// };

// gradebook["Joseph"]["testScores"] = scores[0];
// gradebook["Susan"]["testScores"] = scores[1];
// gradebook["William"]["testScores"] = scores[2];
// gradebook["Elizabeth"]["testScores"] = scores[3];

// gradebook["addScore"] = function(name, score) {
//   gradebook[name]["testScores"].push(score);
// };

// gradebook["getAverage"] = function(name) {
//   return average(gradebook[name]["testScores"]);
// };

// var average = function(array) {
//   var counter = 0;

//   var answer = 0;

//   while (counter < array.length) {
//     answer += array[counter];
//     counter++;
//   };

//   return (answer / array.length);
// };

// __________________________________________
// Refactored Solution

var gradebook = {};

for (var i = 0; i < students.length; i++) {
  gradebook[students[i]] = {};
  gradebook[students[i]]["testScores"] = scores[i];
};

gradebook["addScore"] = function(name, score) {
  gradebook[name]["testScores"].push(score);
};

gradebook["getAverage"] = function(name) {
  return average(gradebook[name]["testScores"]);
};

var average = function(array) {
  var result = 0;
  for (var counter = 0; counter < array.length; counter++) {
    result += array[counter];
  };
  return (result / array.length);
};

// __________________________________________
// Reflect
// What did you learn about adding functions to objects?
// This was more of a refresher for us, and we didn't run into any trouble adding functions, so there wasn't much that we really learned.
// How did you iterate over nested arrays in JavaScript?
// First was using a while loop, and then in the refactor we changed it to a for loop with a counter.
// Were there any new methods you were able to incorporate? If so, what were they and how did they work?
// No we didn't use any new methods.

// __________________________________________
// Test Code:  Do not alter code below this line.

function assert(test, message, test_number) {
  if (!test) {
    console.log(test_number + "false");
    throw "ERROR: " + message;
  }
  console.log(test_number + "true");
  return true;
}

assert(
  (gradebook instanceof Object),
  "The value of gradebook should be an Object.\n",
  "1. "
)

assert(
  (gradebook["Elizabeth"] instanceof Object),
  "gradebook's Elizabeth property should be an object.",
  "2. "
)

assert(
  (gradebook.William.testScores === scores[2]),
  "William's testScores should equal the third element in scores.",
  "3. "
)

assert(
  (gradebook.addScore instanceof Function),
  "The value of gradebook's addScore property should be a Function.",
  "4. "
)

gradebook.addScore("Susan", 80)

assert(
  (gradebook.Susan.testScores.length === 5
   && gradebook.Susan.testScores[4] === 80),
  "Susan's testScores should have a new score of 80 added to the end.",
  "5. "
)

assert(
  (gradebook.getAverage instanceof Function),
  "The value of gradebook's getAverage property should be a Function.",
  "6. "
)

assert(
  (average instanceof Function),
  "The value of average should be a Function.\n",
  "7. "
)
assert(
  average([1, 2, 3]) === 2,
  "average should return the average of the elements in the array argument.\n",
  "8. "
)

assert(
  (gradebook.getAverage("Joseph") === 80),
  "gradebook's getAverage should return 80 if passed 'Joseph'.",
  "9. "
)<|endoftext|>


<commit_before>"use strict";
var gConnections = {};

function Connection(key) {
	this.key = key;
	this.connection = null;
	this.buffer = "";
	return this;
}

Connection.get = function(credentials, name, terminal) {
	var key = JSON.stringify([credentials.user, name]);
	return imports.network.getConnection(credentials, name).then(function(connection) {
		if (!gConnections[key]) {
			gConnections[key] = new Connection(key);
		}
		gConnections[key].connection = connection;
		gConnections[key].terminal = terminal;
		return gConnections[key];
	});
};

Connection.parseFrom = function(from) {
	var result = {full: from};
	var match = new RegExp(/:?(?:(.*)\!(.*)@)?(.*)/).exec(from);
	if (match) {
		result.nick = match[1];
		result.user = match[2];
		result.host = match[3];
	}
	return result;
};

Connection.prototype.connect = function(host, port) {
	var connection = this;
	return this.connection.connect(host, port).then(function() {
		return connection.refresh();
	});
};

Connection.prototype.onRead = function(data) {
	this.buffer += data;
	while (true) {
		var lineEnd = this.buffer.indexOf('\r\n');
		var nextStart = lineEnd + 2;
		if (lineEnd == -1) {
			lineEnd = this.buffer.indexOf('\n');
			nextStart = lineEnd + 1;
		}
		if (lineEnd != -1) {
			var line = this.buffer.substring(0, lineEnd);
			this.onReadLine(line);
			this.buffer = this.buffer.substring(nextStart);
		} else {
			break;
		}
	}
};

Connection.prototype.onError = function(data) {
	this.terminal.print("Read error: " + data);
};

Connection.prototype.write = function(command) {
	return this.connection.write(command + "\r\n");
};

Connection.prototype.status = function() {
	var connection = this;
	return this.connection.isConnected().then(function(status) {
		return connection.terminal.print("Status: " + (status ? "connected" : "not connected"));
	});
};

Connection.prototype.refresh = function() {
	var connection = this;
	this.connection.onError(this.onError.bind(this));
	this.connection.isConnected().then(function(status) {
		if (status) {
			connection.write("PONG :" + new Date().getTime());
		}
	});
	return this.connection.read(this.onRead.bind(this));
};

Connection.prototype.printMessage = function(nick, target, message) {
	if (message.charCodeAt(0) === 1 && message.charCodeAt(message.length - 1) === 1) {
		message = message.substring(1, message.length - 1);
		var space = message.indexOf(' ');
		var command = message;
		var payload = "";
		if (space != -1) {
			command = message.substring(0, space);
			payload = message.substring(space + 1);
		}
		if (command == "ACTION") {
			this.terminal.print({styled: [
				{style: "color: #888", value: new Date().toString()},
				{style: "color: #448", value: " ["},
				{style: "color: #fff", value: target},
				{style: "color: #448", value: "] "},
				{style: "color: #44f", value: "* "},
				{style: "color: #fff", value: nick},
				{style: "color: #44f", value: " "},
				{style: "color: #ccc", value: payload},
			]});
		} else {
			this.terminal.print({styled: [
				{style: "color: #888", value: new Date().toString()},
				{style: "color: #448", value: " ["},
				{style: "color: #fff", value: target},
				{style: "color: #448", value: "] "},
				{style: "color: #44f", value: " <"},
				{style: "color: #fff", value: nick},
				{style: "color: #44f", value: "> "},
				{style: "color: #4f4", value: "CTCP "},
				{style: "color: #ccc", value: message},
			]});
		}
	} else {
		this.terminal.print({styled: [
			{style: "color: #888", value: new Date().toString()},
			{style: "color: #448", value: " ["},
			{style: "color: #fff", value: target},
			{style: "color: #448", value: "] "},
			{style: "color: #44f", value: "<"},
			{style: "color: #fff", value: nick},
			{style: "color: #44f", value: "> "},
			{style: "color: #ccc", value: message},
		]});
	}
};

Connection.prototype.onReadLine = function(line) {
	var colon = line.indexOf(' :');
	var argv;
	if (colon != -1) {
		argv = line.substring(0, colon).split(" ");
		argv.push(line.substring(colon + 2));
	} else {
		argv = line.split(" ");
	}
	if (argv[0] == "PING") {
		this.write("PONG :" + argv[1]);
	} else if (argv[1] == "PRIVMSG") {
		var from = Connection.parseFrom(argv[0]);
		this.printMessage(from.nick, argv[2], argv[3]);
	} else {
		this.terminal.print(line);
	}
};

function irc(terminal, argv, credentials) {
	return imports.auth.transferCredentials(credentials, "network").then(function(networkCredentials) {
		var connectionName = argv[1];
		argv = argv.slice(2);

		if (argv[0] == "connect") {
			return Connection.get(networkCredentials, connectionName, terminal).then(function(connection) {
				return connection.connect(argv[1], parseInt(argv[2]) || 6667);
			}).then(function() {
				terminal.print("Connected to " + argv[1] + ":" + (parseInt(argv[2]) || 6667));
			});
		} else if (argv[0] == "msg") {
			return Connection.get(networkCredentials, connectionName, terminal).then(function(connection) {
				return connection.write("PRIVMSG " + argv[1] + " :" + argv.slice(2).join(" ")).then(function() {
					connection.printMessage("you???", argv[1], argv.slice(2).join(" "));
				});
			});
		} else if (argv[0] == "send") {
			return Connection.get(networkCredentials, connectionName, terminal).then(function(connection) {
				return connection.write(argv[1]);
			}).then(function() {
				terminal.print("=> " + argv[1]);
			});
		} else if (argv[0] == "close") {
			return Connection.get(networkCredentials, connectionName, terminal).then(function(connection) {
				return connection.close();
			}).then(function() {
				terminal.print("Closed connection.");
			});
		} else if (argv[0] == "status") {
			return Connection.get(networkCredentials, connectionName, terminal).then(function(connection) {
				return connection.status();
			});
		} else if (argv[0] == "refresh") {
			return Connection.get(networkCredentials, connectionName, terminal).then(function(connection) {
				return connection.refresh().then(function() {
					terminal.print("Connection refreshed.");
				});
			});
		} else {
			terminal.print("Unsupported IRC command: " + argv[0]);
		}
	});
}

imports.shell.register("irc", irc);<commit_msg>Remember and display the current user's nickname.  Reply to CTCP version requests.<commit_after>"use strict";
var gConnections = {};

function Connection(key) {
	this.key = key;
	this.connection = null;
	this.buffer = "";
	this.nickname = null;
	return this;
}

Connection.get = function(credentials, name, terminal) {
	var key = JSON.stringify([credentials.user, name]);
	return imports.network.getConnection(credentials, name).then(function(connection) {
		if (!gConnections[key]) {
			gConnections[key] = new Connection(key);
		}
		gConnections[key].connection = connection;
		gConnections[key].terminal = terminal;
		return gConnections[key];
	});
};

Connection.parseFrom = function(from) {
	var result = {full: from};
	var match = new RegExp(/:?(?:(.*)\!(.*)@)?(.*)/).exec(from);
	if (match) {
		result.nick = match[1];
		result.user = match[2];
		result.host = match[3];
	}
	return result;
};

Connection.prototype.connect = function(host, port) {
	var connection = this;
	return this.connection.connect(host, port).then(function() {
		return connection.refresh();
	});
};

Connection.prototype.onRead = function(data) {
	this.buffer += data;
	while (true) {
		var lineEnd = this.buffer.indexOf('\r\n');
		var nextStart = lineEnd + 2;
		if (lineEnd == -1) {
			lineEnd = this.buffer.indexOf('\n');
			nextStart = lineEnd + 1;
		}
		if (lineEnd != -1) {
			var line = this.buffer.substring(0, lineEnd);
			this.onReadLine(line);
			this.buffer = this.buffer.substring(nextStart);
		} else {
			break;
		}
	}
};

Connection.prototype.onError = function(data) {
	this.terminal.print("Read error: " + data);
};

Connection.prototype.write = function(command) {
	return this.connection.write(command + "\r\n");
};

Connection.prototype.status = function() {
	var connection = this;
	return this.connection.isConnected().then(function(status) {
		return connection.terminal.print("Status: " + (status ? "connected" : "not connected"));
	});
};

Connection.prototype.refresh = function() {
	var connection = this;
	this.connection.onError(this.onError.bind(this));
	this.connection.isConnected().then(function(status) {
		if (status) {
			connection.write("PONG :" + new Date().getTime());
		}
	});
	return this.connection.read(this.onRead.bind(this));
};

Connection.prototype.printMessage = function(nick, target, message) {
	if (message.charCodeAt(0) === 1 && message.charCodeAt(message.length - 1) === 1) {
		message = message.substring(1, message.length - 1);
		var space = message.indexOf(' ');
		var command = message;
		var payload = "";
		if (space != -1) {
			command = message.substring(0, space);
			payload = message.substring(space + 1);
		}
		if (command == "ACTION") {
			this.terminal.print({styled: [
				{style: "color: #888", value: new Date().toString()},
				{style: "color: #448", value: " ["},
				{style: "color: #fff", value: target},
				{style: "color: #448", value: "] "},
				{style: "color: #44f", value: "* "},
				{style: "color: #fff", value: nick},
				{style: "color: #44f", value: " "},
				{style: "color: #ccc", value: payload},
			]});
		} else {
			this.terminal.print({styled: [
				{style: "color: #888", value: new Date().toString()},
				{style: "color: #448", value: " ["},
				{style: "color: #fff", value: target},
				{style: "color: #448", value: "] "},
				{style: "color: #44f", value: " <"},
				{style: "color: #fff", value: nick},
				{style: "color: #44f", value: "> "},
				{style: "color: #4f4", value: "CTCP "},
				{style: "color: #ccc", value: message},
			]});
		}
	} else {
		this.terminal.print({styled: [
			{style: "color: #888", value: new Date().toString()},
			{style: "color: #448", value: " ["},
			{style: "color: #fff", value: target},
			{style: "color: #448", value: "] "},
			{style: "color: #44f", value: "<"},
			{style: "color: #fff", value: nick},
			{style: "color: #44f", value: "> "},
			{style: "color: #ccc", value: message},
		]});
	}
};

Connection.prototype.onCtcp = function(from, to, message) {
	if (message == "VERSION") {
		this.write("NOTICE " + from.nick + " :\u0001VERSION SandboxOS IRC 0.1\u0001");
	}
}

Connection.prototype.onReadLine = function(line) {
	var colon = line.indexOf(' :');
	var argv;
	if (colon != -1) {
		argv = line.substring(0, colon).split(" ");
		argv.push(line.substring(colon + 2));
	} else {
		argv = line.split(" ");
	}
	if (parseInt(argv[1]) || argv[1] == "NICK") {
		this.nickname = argv[2];
	}
	if (argv[0] == "PING") {
		this.write("PONG :" + argv[1]);
	} else if (argv[1] == "PRIVMSG") {
		var from = Connection.parseFrom(argv[0]);
		this.printMessage(from.nick, argv[2], argv[3]);
		if (argv[3].charCodeAt(0) === 1 && argv[3].charCodeAt(argv[3].length - 1) === 1) {
			this.onCtcp(from, argv[2], argv[3].substring(1, argv[3].length - 1));
		}
	} else {
		this.terminal.print(line);
	}
};

function irc(terminal, argv, credentials) {
	return imports.auth.transferCredentials(credentials, "network").then(function(networkCredentials) {
		var connectionName = argv[1];
		argv = argv.slice(2);

		if (argv[0] == "connect") {
			return Connection.get(networkCredentials, connectionName, terminal).then(function(connection) {
				return connection.connect(argv[1], parseInt(argv[2]) || 6667);
			}).then(function() {
				terminal.print("Connected to " + argv[1] + ":" + (parseInt(argv[2]) || 6667));
			});
		} else if (argv[0] == "msg") {
			return Connection.get(networkCredentials, connectionName, terminal).then(function(connection) {
				return connection.write("PRIVMSG " + argv[1] + " :" + argv.slice(2).join(" ")).then(function() {
					connection.printMessage(connection.nickname, argv[1], argv.slice(2).join(" "));
				});
			});
		} else if (argv[0] == "send") {
			return Connection.get(networkCredentials, connectionName, terminal).then(function(connection) {
				return connection.write(argv[1]);
			}).then(function() {
				terminal.print("=> " + argv[1]);
			});
		} else if (argv[0] == "close") {
			return Connection.get(networkCredentials, connectionName, terminal).then(function(connection) {
				return connection.close();
			}).then(function() {
				terminal.print("Closed connection.");
			});
		} else if (argv[0] == "status") {
			return Connection.get(networkCredentials, connectionName, terminal).then(function(connection) {
				return connection.status();
			});
		} else if (argv[0] == "refresh") {
			return Connection.get(networkCredentials, connectionName, terminal).then(function(connection) {
				return connection.refresh().then(function() {
					terminal.print("Connection refreshed.");
				});
			});
		} else {
			terminal.print("Unsupported IRC command: " + argv[0]);
		}
	});
}

imports.shell.register("irc", irc);<|endoftext|>


<commit_before>(function() {

  // have to inject CSS since new-issues and issues conflicts and
  // Chrome doesn't correctly exclude injected CSS using exclude_matches
  // see http://stackoverflow.com/questions/20784654/excluding-domains-from-content-scripts-in-manifest-json-doesnt-work-for-css-fil

  var link = document.createElement('link');
  link.href = chrome.extension.getURL('new-issue.css');
  link.type = 'text/css';
  link.rel = 'stylesheet';
  document.documentElement.insertBefore(link);

  var config = {
      insertBefore : ['button:contains(Submit new issue)'],
      bodySelector : '#issue_body',
      buttonHTML   : (
        '<button id="totallyAwesomeSelfieButton" type="button" class="button">' +
          '' +
          'Selfie!' +
        '</button>'
      ),
      placeVideo    : function (video, canvas) { $('.form-actions').prepend(video); }
    }
    , client = new GitHubSelfies(config);
  client.setupSelfieStream();
})();
<commit_msg>Github textbox id with numeric suffix.<commit_after>(function() {

  // have to inject CSS since new-issues and issues conflicts and
  // Chrome doesn't correctly exclude injected CSS using exclude_matches
  // see http://stackoverflow.com/questions/20784654/excluding-domains-from-content-scripts-in-manifest-json-doesnt-work-for-css-fil

  var link = document.createElement('link');
  link.href = chrome.extension.getURL('new-issue.css');
  link.type = 'text/css';
  link.rel = 'stylesheet';
  document.documentElement.insertBefore(link);

  var config = {
      insertBefore : ['button:contains(Submit new issue)'],
      bodySelector : '[id^=issue_body]',
      buttonHTML   : (
        '<button id="totallyAwesomeSelfieButton" type="button" class="button">' +
          '' +
          'Selfie!' +
        '</button>'
      ),
      placeVideo    : function (video, canvas) { $('.form-actions').prepend(video); }
    }
    , client = new GitHubSelfies(config);
  client.setupSelfieStream();
})();
<|endoftext|>


<commit_before>"use strict";

// ==UserScript==
// @name        Wide Github
// @namespace   https://github.com/xthexder/wide-github
// @description Change all Github repository and gist pages to be full width and dynamically sized.
// @author      xthexder
// @copyright   2013+, xthexder (https://github.com/xthexder)
// @contributor Jason Frey (https://github.com/Fryguy)
// @contributor Marti Martz (https://github.com/Martii)
// @license     MIT; https://raw.githubusercontent.com/xthexder/wide-github/master/LICENSE
// @version     1.2.0
// @icon        https://raw.githubusercontent.com/xthexder/wide-github/master/icon.png
// @homepageURL https://github.com/xthexder/wide-github
// @supportURL  https://github.com/xthexder/wide-github/issues
// @include     *github.com*
// @grant       none
// ==/UserScript==

var styleSheet = "" +
".header .container {" +
  "width: auto !important;" +
  "margin-left: 20px !important;" +
  "margin-right: 20px !important;" +
  "min-width: 980px;" +
"}" +
"#js-repo-pjax-container .container {" +
  "width: auto !important;" +
  "margin-left: 20px !important;" +
  "margin-right: 20px !important;" +
  "min-width: 980px;" +
"}" +
".full-width .container {" +
  "padding-left: 0px !important;" +
  "padding-right: 0px !important;" +
"}" +

// New PR split diff
".full-width .new-pr-form {" +
  "max-width: none !important;" +
"}" +

// Repository Issues
"#js-repo-pjax-container .repository-content .discussion-timeline {" +  // Issue body
  "margin-left: -220px;" +
  "padding-left: 220px;" +
  "width: 100% !important;" +
"}" +
".repository-content .discussion-sidebar {" +
  "width: 200px !important;" +
"}" +
".repository-content .timeline-new-comment {" + // New Issue / issue comment form
  "max-width: 100% !important;" +
"}" +
".repository-content .inline-comments .comment-holder {" + // Diff / code comments
  "max-width: 960px !important;" +
"}" +
".repository-content .inline-comments .inline-comment-form-container {" +
  "max-width: 960px !important;" +
"}" +
".repository-content .inline-comments .inline-comment-form {" +
  "max-width: 960px !important;" +
"}" +

// Repository pulse page
".repository-content .authors-and-code .section {" + // Contributors bar graph
  "width: 50%;" +
  "height: 180px;" +
"}" +
".repository-content .authors-and-code .section svg {" +
  "height: 180px;" +
"}" +

// Repository graph page
".repository-content .capped-card {" + // Graph cards on contributors / graph list
  "margin:10px 10px 0 0 !important;" +
"}" +

// Gists
".gist-content-wrapper .container {" +
  "width: auto !important;" +
  "margin-left: 20px !important;" +
  "margin-right: 20px !important;" +
  "min-width: 980px;" +
"}" +

"";

(function () {
  var s = document.createElement('style');
  s.type = "text/css";
  s.innerHTML = styleSheet;
  (document.head || document.documentElement).appendChild(s);
})();
<commit_msg>Fix the vertical line that runs through PR commits<commit_after>"use strict";

// ==UserScript==
// @name        Wide Github
// @namespace   https://github.com/xthexder/wide-github
// @description Change all Github repository and gist pages to be full width and dynamically sized.
// @author      xthexder
// @copyright   2013+, xthexder (https://github.com/xthexder)
// @contributor Jason Frey (https://github.com/Fryguy)
// @contributor Marti Martz (https://github.com/Martii)
// @contributor Paul "Joey" Clark (https://github.com/joeytwiddle)
// @license     MIT; https://raw.githubusercontent.com/xthexder/wide-github/master/LICENSE
// @version     1.2.1
// @icon        https://raw.githubusercontent.com/xthexder/wide-github/master/icon.png
// @homepageURL https://github.com/xthexder/wide-github
// @supportURL  https://github.com/xthexder/wide-github/issues
// @include     *github.com*
// @grant       none
// ==/UserScript==

var styleSheet = "" +
".header .container {" +
  "width: auto !important;" +
  "margin-left: 20px !important;" +
  "margin-right: 20px !important;" +
  "min-width: 980px;" +
"}" +
"#js-repo-pjax-container .container {" +
  "width: auto !important;" +
  "margin-left: 20px !important;" +
  "margin-right: 20px !important;" +
  "min-width: 980px;" +
"}" +
".full-width .container {" +
  "padding-left: 0px !important;" +
  "padding-right: 0px !important;" +
"}" +

// New PR split diff
".full-width .new-pr-form {" +
  "max-width: none !important;" +
"}" +

// Repository Issues
"#js-repo-pjax-container .repository-content .discussion-timeline {" +  // Issue body
  "margin-left: -220px;" +
  "padding-left: 220px;" +
  "width: 100% !important;" +
"}" +
".discussion-timeline::before {" + // The vertical line running through the commit list on PRs
  "margin-left: 220px;" +
"}" +
".repository-content .discussion-sidebar {" +
  "width: 200px !important;" +
"}" +
".repository-content .timeline-new-comment {" + // New Issue / issue comment form
  "max-width: 100% !important;" +
"}" +
".repository-content .inline-comments .comment-holder {" + // Diff / code comments
  "max-width: 960px !important;" +
"}" +
".repository-content .inline-comments .inline-comment-form-container {" +
  "max-width: 960px !important;" +
"}" +
".repository-content .inline-comments .inline-comment-form {" +
  "max-width: 960px !important;" +
"}" +

// Repository pulse page
".repository-content .authors-and-code .section {" + // Contributors bar graph
  "width: 50%;" +
  "height: 180px;" +
"}" +
".repository-content .authors-and-code .section svg {" +
  "height: 180px;" +
"}" +

// Repository graph page
".repository-content .capped-card {" + // Graph cards on contributors / graph list
  "margin:10px 10px 0 0 !important;" +
"}" +

// Gists
".gist-content-wrapper .container {" +
  "width: auto !important;" +
  "margin-left: 20px !important;" +
  "margin-right: 20px !important;" +
  "min-width: 980px;" +
"}" +

"";

(function () {
  var s = document.createElement('style');
  s.type = "text/css";
  s.innerHTML = styleSheet;
  (document.head || document.documentElement).appendChild(s);
})();
<|endoftext|>


<commit_before>import Head from 'components/head';
import Layout from 'components/Layout';
import Spacer from 'components/Spacer';
import getPosts from 'lib/get-posts';
import Link from 'next/link';
import Router from 'next/router';
import Padding from 'components/padding';

const Blog = ({ posts }) => {
  return (
    <>

        <title>Blog | Reaper</title>

      <Layout>
        <Padding y={3}>

              {posts.map(({ meta }, index) => {
                return (

                    <Link href={`blog/${meta.slug}`}>
                      {meta.title}
                    </Link>

                );
              })}

            <Spacer y={1} />
            <button
              className="margin-top-sm  align-start button black outline-btn"
              onClick={() => Router.push('/')}
            >
              Back
            </button>
            <Spacer y={2} />

        </Padding>
      </Layout>
    </>
  );
};

export async function getStaticProps() {
  const posts = await getPosts();
  return {
    props: {
      posts,
    },
  };
}

export default Blog;
<commit_msg>:robot: Formatted!<commit_after>import Head from 'components/head'
import Layout from 'components/Layout'
import Spacer from 'components/Spacer'
import getPosts from 'lib/get-posts'
import Link from 'next/link'
import Router from 'next/router'
import Padding from 'components/padding'

const Blog = ({ posts }) => {
  return (
    <>

        <title>Blog | Reaper</title>

      <Layout>
        <Padding y={3}>

              {posts.map(({ meta }, index) => {
                return (

                    <Link href={`blog/${meta.slug}`}>
                      {meta.title}
                    </Link>

                )
              })}

            <Spacer y={1} />
            <button
              className='margin-top-sm  align-start button black outline-btn'
              onClick={() => Router.push('/')}
            >
              Back
            </button>
            <Spacer y={2} />

        </Padding>
      </Layout>
    </>
  )
}

export async function getStaticProps () {
  const posts = await getPosts()
  return {
    props: {
      posts
    }
  }
}

export default Blog
<|endoftext|>


<commit_before><commit_msg>Sorting content types and menus in settings sidebar<commit_after><|endoftext|>


<commit_before>;(function() {
  "use strict";

  var BaseController = require("BaseController");

  new BaseController({
    siteName: "Tidal",
    play: "[data-test-id=play]",
    pause: "[data-test-id=pause]",
    playNext: "[data-test-id=next]",
    playPrev: "[data-test-id=previous]",

    song: "[data-test-id=track-title]",
    artist: "[data-test-id=artist-title]",
    buttonSwitch : true
  });
})();
<commit_msg>update Tidal controller (#488)<commit_after>;(function() {
  "use strict";

  var BaseController = require("BaseController");

  new BaseController({
    siteName: "Tidal",
    play: "[data-test=play]",
    pause: "[data-test=pause]",
    playNext: "[data-test=next]",
    playPrev: "[data-test=previous]",

    song: "[data-test=track-title]",
    artist: "[data-test=artist-title]",
    buttonSwitch : true
  });
})();
<|endoftext|>


<commit_before><commit_msg>chore(cypress): fix menu navigation (#1005)<commit_after><|endoftext|>


<commit_before>var searchTimeout = 0.5; //timeout for search box in seconds.
var timer = 0;

function searchFriends()
{
    var searchTerm = $('#friendSearch').val();

    //make the ajax call to search for friends.
    $.ajax({
        type: 'POST',
        url: Routing.generate('WishlistUserBundle_friendSearch'),
        data: {searchTerm: searchTerm},
        success: function(data, textStatus, jqXHR) {
            updateFriendList(jQuery.parseJSON(data));
        }
    });
}

function timerEnd()
{
    window.clearTimeout(timer);
}

function timerRestart()
{
    timerEnd();
    timer = window.setTimeout(searchFriends, searchTimeout*1000);
}

function modifyAddButton(response, textStatus, jqXHR, row)
{
    console.log('Promoting friend!');
    $('.addFriendButtonDiv',row).fadeOut(400, function(){
        $(this).html("Request sent").addClass("requestSentNotification");
        $(this).fadeIn(400);
    });
}

function addFriend(personId)
{
    var row = $("input.userId[value|='"+ personId + "']").parent();
    ajaxPost({personId: personId}, Routing.generate('WishlistUserBundle_friendAdd'), modifyAddButton, row);
}

function updateFriendList(results)
{
    var friends = results.friends;
    var persons = results.persons;
    var friendlist = $('div.friendlist');

    if(friendlist.size() == 0)
    {
        $('#friendsContainer').append('

');
        friendlist = $('div.friendlist');
        friendlist.addClass('friendlist');
    }
    //Empty out the whole friendlist
    friendlist.empty();

    //TODO: This HTML is a hack, it should really be moved to the server.
    if( friends.length >= 1 ) {
        var friendRowArray = [];
        friendlist.append('
My Friends

');

        friends.forEach(function(friend) {
            friendRowArray.push("

" + friend.name +"

");
        });

        $('#div_friendlist_div ul').append(friendRowArray.join(""));
    }

    if( persons.length >= 1) {
        var personRowArray = [];
        friendlist.append('
People on Wishenda

');

        persons.forEach(function(person) {
            personRowArray.push("
"
                                + "<input class='userId' type='hidden' value='"+ person.wishlistuser_id + "' />"
                                + "
"
                                    + "<button class='addFriendButton'>Add Friend</button>"
                                + "
"
                                + "
"
                                    + ""
                                    + ""
                                    + person.name
                                + "
"
                                + "
");
        });

        $('#div_personlist_div ul').append(personRowArray.join(""));
        $('.addFriendButton').button({
            icons: {
                primary: "ui-icon-plusthick"
            }
        }).click(function(e){
            var userRow = $(this).parents("li");
            var personId = userRow.children("input.userId").val();
            addFriend(personId);
        });
    }

    //Finally make all of the newly created search results into button links.
    createButtonLinks();
}

function keyTrigger(e)
{
    if( (e.keyCode >= 65 && e.keyCode <= 90) || e.keyCode === 8 || e.keyCode === 16)
    {
        //if it was a normal character just restart the timer for the search.
        timerRestart();
    }
    else if( e.keyCode === 13 )
    {
        //If enter was pressed cancel the timer and search for friends.
        timerEnd();
        searchFriends();
    }
    else {
        var val = removeSpecialChars($(e.srcElement).val());
        $(e.srcElement).val(val);
    }
}

function createButtonLinks()
{
    $('.userButton').click(function(){
       window.location = $(this).find("a").attr("href");
    });

    $('#addFriendButton').button();
    $('#addFriendButton').css('height', '30').css('font-size','10');

    $('#inviteFriendButton').button();
    $('#inviteFriendButton').css('height', '30').css('font-size','10');
}

function displayFriendInviteStatus(inviteStatus)
{
    var title = '';
    var message = '';

    if(true == inviteStatus) {
        title = 'Success';
        message = 'Your friend has been invited to Wishenda!';
    }
    else {
        title = 'Failure';
        message = 'A problem occurred, is your friend already a member of Wishenda?';
    }

    popupMessage(title, message);
}

function submitFriendInvite(email)
{
    var retval = false;
    var inviteUrl = Routing.generate('WishlistUserBundle_friendInvite');

    ajaxPost({email: email}, inviteUrl, function(responseText) {
        if (responseText.toLowerCase() == 'success') {
            retval = true;
        }
        else {
            retval = false;
        }

        displayFriendInviteStatus(retval);
        $('#friendInviteDialog').dialog('close');
    });
}

$(document).ready(function(){

    createButtonLinks();

    $('#friendSearch').keyup(keyTrigger);

    $('#friendInviteDialog').dialog({
            autoOpen: false,
            position: 'top',
            resizable: false,
            height:300,
            width:500,
            modal: true,
            buttons: {
                'Invite': function(){
                    $('#friendInviteFormSubmit').click();
                }
            }
    });

    $('#friendInviteForm').submit(function(e) {
        e.preventDefault();

        submitFriendInvite($('#newFriendEmail').val());
    });

    $('#inviteFriendButton').click(function(){
        $('#friendInviteDialog').dialog('open');
    });
});
<commit_msg>added logic that clears the friend invite email input field when the dialog is opened. this way no old data is displayed from a previous time that the dialog was opened.<commit_after>var searchTimeout = 0.5; //timeout for search box in seconds.
var timer = 0;

function searchFriends()
{
    var searchTerm = $('#friendSearch').val();

    //make the ajax call to search for friends.
    $.ajax({
        type: 'POST',
        url: Routing.generate('WishlistUserBundle_friendSearch'),
        data: {searchTerm: searchTerm},
        success: function(data, textStatus, jqXHR) {
            updateFriendList(jQuery.parseJSON(data));
        }
    });
}

function timerEnd()
{
    window.clearTimeout(timer);
}

function timerRestart()
{
    timerEnd();
    timer = window.setTimeout(searchFriends, searchTimeout*1000);
}

function modifyAddButton(response, textStatus, jqXHR, row)
{
    console.log('Promoting friend!');
    $('.addFriendButtonDiv',row).fadeOut(400, function(){
        $(this).html("Request sent").addClass("requestSentNotification");
        $(this).fadeIn(400);
    });
}

function addFriend(personId)
{
    var row = $("input.userId[value|='"+ personId + "']").parent();
    ajaxPost({personId: personId}, Routing.generate('WishlistUserBundle_friendAdd'), modifyAddButton, row);
}

function updateFriendList(results)
{
    var friends = results.friends;
    var persons = results.persons;
    var friendlist = $('div.friendlist');

    if(friendlist.size() == 0)
    {
        $('#friendsContainer').append('

');
        friendlist = $('div.friendlist');
        friendlist.addClass('friendlist');
    }
    //Empty out the whole friendlist
    friendlist.empty();

    //TODO: This HTML is a hack, it should really be moved to the server.
    if( friends.length >= 1 ) {
        var friendRowArray = [];
        friendlist.append('
My Friends

');

        friends.forEach(function(friend) {
            friendRowArray.push("

" + friend.name +"

");
        });

        $('#div_friendlist_div ul').append(friendRowArray.join(""));
    }

    if( persons.length >= 1) {
        var personRowArray = [];
        friendlist.append('
People on Wishenda

');

        persons.forEach(function(person) {
            personRowArray.push("
"
                                + "<input class='userId' type='hidden' value='"+ person.wishlistuser_id + "' />"
                                + "
"
                                    + "<button class='addFriendButton'>Add Friend</button>"
                                + "
"
                                + "
"
                                    + ""
                                    + ""
                                    + person.name
                                + "
"
                                + "
");
        });

        $('#div_personlist_div ul').append(personRowArray.join(""));
        $('.addFriendButton').button({
            icons: {
                primary: "ui-icon-plusthick"
            }
        }).click(function(e){
            var userRow = $(this).parents("li");
            var personId = userRow.children("input.userId").val();
            addFriend(personId);
        });
    }

    //Finally make all of the newly created search results into button links.
    createButtonLinks();
}

function keyTrigger(e)
{
    if( (e.keyCode >= 65 && e.keyCode <= 90) || e.keyCode === 8 || e.keyCode === 16)
    {
        //if it was a normal character just restart the timer for the search.
        timerRestart();
    }
    else if( e.keyCode === 13 )
    {
        //If enter was pressed cancel the timer and search for friends.
        timerEnd();
        searchFriends();
    }
    else {
        var val = removeSpecialChars($(e.srcElement).val());
        $(e.srcElement).val(val);
    }
}

function createButtonLinks()
{
    $('.userButton').click(function(){
       window.location = $(this).find("a").attr("href");
    });

    $('#addFriendButton').button();
    $('#addFriendButton').css('height', '30').css('font-size','10');

    $('#inviteFriendButton').button();
    $('#inviteFriendButton').css('height', '30').css('font-size','10');
}

function displayFriendInviteStatus(inviteStatus)
{
    var title = '';
    var message = '';

    if(true == inviteStatus) {
        title = 'Success';
        message = 'Your friend has been invited to Wishenda!';
    }
    else {
        title = 'Failure';
        message = 'A problem occurred, is your friend already a member of Wishenda?';
    }

    popupMessage(title, message);
}

function submitFriendInvite(email)
{
    var retval = false;
    var inviteUrl = Routing.generate('WishlistUserBundle_friendInvite');

    ajaxPost({email: email}, inviteUrl, function(responseText) {
        if (responseText.toLowerCase() == 'success') {
            retval = true;
        }
        else {
            retval = false;
        }

        displayFriendInviteStatus(retval);
        $('#friendInviteDialog').dialog('close');
    });
}

$(document).ready(function(){
    var friendInviteDialog = $('#friendInviteDialog');
    var friendInviteEmail = $('#newFriendEmail');

    createButtonLinks();

    $('#friendSearch').keyup(keyTrigger);

    friendInviteDialog.dialog({
            autoOpen: false,
            position: 'top',
            resizable: false,
            height:300,
            width:500,
            modal: true,
            buttons: {
                'Invite': function(){
                    $('#friendInviteFormSubmit').click();
                }
            }
    });

    $('#friendInviteForm').submit(function(e) {
        e.preventDefault();

        submitFriendInvite(friendInviteEmail.val());
    });

    $('#inviteFriendButton').click(function(){
        friendInviteDialog.dialog('open');
        friendInviteEmail.val('');
    });
});
<|endoftext|>


<commit_before>$(function () {
    var logLevelInputFactory = function (item) {
        return '' + item.name + '' +
            '<select class="config-item" data-field="' + item.name + '">' +
            '<option value="">None</option>' +
            '<option value="error">Error</option>' +
            '<option value="warning">Warning</option>' +
            '<option value="info">Info</option>' +
            '<option value="debug">Debug</option>' +
            '</select>' +
            '' + item.help + '';
    };

    var inputFieldFactory = function (item) {
        return '' + item.name + '' +
            '<input type="text" class="pure-input-1 config-item" id="' + item.name + '" name="' + item.name + '" data-field="' + item.name + '">' +
            '' + item.help + '';
    };

    var passwordFieldFactory = function (item) {
        return '' + item.name + '' +
            '<input type="password" class="pure-input-1 config-item" id="' + item.name + '" name="' + item.name + '" data-field="' + item.name + '">' +
            '' + item.help + '';
    };

    var checkboxFactory = function (item) {
        return '' +
            '<input class=" config-item " type="checkbox" value="' + item.name + '" data-field="' + item.name + '" name="' + item.name + '"> ' +
            item.name +
            '' + item.help + '' +
            '';
    };

    var legendFactory = function (item) {
        return '<legend>' + item.name + '</legend>';
    };

    var protocolInputField = function (item) {
        return '

';
    };

    var inputApply = function (item_id, data) {
        $('.config-item[data-field="' + item_id + '"]').val(data);
    };

    var checkboxApply = function (item_id, data) {
        $('.config-item[data-field="' + item_id + '"]').prop("checked", data);
    };

    var protocolApply = function (item_id, data) {

        var fillProtocolData = function (protos) {
            $("#rfProtocols").empty();
            protos.forEach(function (value) {
                var elem = '' +
                    '<input class=" config-item protocols-item" id="proto_check_' + value + '" type="checkbox" value="' + value + '" data-field="' + item_id + '" name="' + item_id + '">' +
                    ' Protocol ' + value +
                    '';
                $("#rfProtocols").append(elem);
                registerConfigUi('#proto_check_' + value);
            });
            if (data.length > 0) {
                data.forEach(function (value) {
                    $('#proto_check_' + value).prop('checked', true);
                });
            } else {
                $(".protocols-item").each(function (_, value) {
                    $(value).prop("checked", true);
                });
            }
        };

        $.ajax({
                   url: "/protocols",
                   type: "GET",
                   contentType: 'application/json',
                   success: fillProtocolData
               });
    };

    var inputGet = function (item_id) {
        return $('.config-item[data-field="' + item_id + '"]').val();
    };

    var inputGetInt = function (item_id) {
        return parseInt(inputGet(item_id));
    };

    var checkboxGet = function (item_id) {
        return $('.config-item[data-field="' + item_id + '"]').prop("checked");
    };

    var protocolGet = function (item_id) {
        var checked = $('.protocols-item:checked');
        if ($('.protocols-item').length === checked.length) {
            return [];
        }
        return $.map(checked, function (x) {
            return $(x).val();
        });
    };

    function ConfigItem(name, factory, apply, fetch, help) {
        this.name = name;
        this.factory = factory;
        this.apply = apply;
        this.fetch = fetch;
        this.help = help;
    }

    function GroupItem(name, factory) {
        this.name = name;
        this.factory = factory;
    }

    var CONFIG_ITEMS = [
        new GroupItem("General Config", legendFactory),
        new ConfigItem("deviceName", inputFieldFactory, inputApply, inputGet, "The general name of the device"),
        new ConfigItem("configPassword", passwordFieldFactory, inputApply, inputGet, "The admin password for the web UI"),

        new GroupItem("MQTT Config", legendFactory),
        new ConfigItem("mqttBroker", inputFieldFactory, inputApply, inputGet, "MQTT Broker host"),
        new ConfigItem("mqttBrokerPort", inputFieldFactory, inputApply, inputGetInt, "MQTT Broker port"),
        new ConfigItem("mqttUser", inputFieldFactory, inputApply, inputGet, "MQTT username (optional)"),
        new ConfigItem("mqttPassword", passwordFieldFactory, inputApply, inputGet, "MQTT password (optional)"),
        new ConfigItem("mqttRetain", checkboxFactory, checkboxApply, checkboxGet, "Retain MQTT messages"),

        new GroupItem("MQTT Topic Config", legendFactory),
        new ConfigItem("mqttReceiveTopic", inputFieldFactory, inputApply, inputGet, "Topic to publish received signal"),
        new ConfigItem("mqttSendTopic", inputFieldFactory, inputApply, inputGet, "Topic to get signals to send from"),

        new GroupItem("433MHz RF Config", legendFactory),
        new ConfigItem("rfEchoMessages", checkboxFactory, checkboxApply, checkboxGet, "Echo sent rf messages back"),
        new ConfigItem("rfReceiverPin", inputFieldFactory, inputApply, inputGetInt, "The pin used for the rf receiver"),
        new ConfigItem("rfTransmitterPin", inputFieldFactory, inputApply, inputGetInt, "The pin used for the RF transmitter"),

        new GroupItem("Enabled RF protocols", legendFactory),
        new ConfigItem("rfProtocols", protocolInputField, protocolApply, protocolGet, ""),

        new GroupItem("Log Config", legendFactory),
        new ConfigItem("serialLogLevel", logLevelInputFactory, inputApply, inputGet, "Level for serial logging"),
        new ConfigItem("webLogLevel", logLevelInputFactory, inputApply, inputGet, "Level for logging to the web UI"),
        new ConfigItem("syslogLevel", logLevelInputFactory, inputApply, inputGet, "Level for syslog logging"),
        new ConfigItem("syslogHost", inputFieldFactory, inputApply, inputGet, "Syslog server (optional)"),
        new ConfigItem("syslogPort", inputFieldFactory, inputApply, inputGetInt, "Syslog port (optional)")
    ];

    var ui_map = {};
    CONFIG_ITEMS.forEach(function (value) {
        if (value.fetch !== undefined) {
            ui_map[value.name] = value;
        }
    });

    var closeWebSocket = function () {
    };

    var openWebSocket = function () {
        var container = $('#log-container');
        var pre = container.find('pre');

        var webSocket = new WebSocket("ws://" + location.hostname + ":81");
        var tm;

        closeWebSocket = function () {
            clearTimeout(tm);
            webSocket.close();
        };

        var ping = function () {
            tm = setTimeout(function () {
                webSocket.send("__PING__");

                tm = setTimeout(function () {
                    webSocket.close();
                    openWebSocket();
                }, 2000);
            }, 5000);
        };

        webSocket.onmessage = function (e) {
            var message = e.data;

            if (message === "__PONG__") {
                clearTimeout(tm);
                ping();
                return;
            }

            pre.append(message);
            if (message === '\n' || (typeof message === "string" && message.indexOf('\n') !== -1)) {
                container.scrollTop(pre.get(0).scrollHeight);
            }
        };

        webSocket.onerror = function (ev) {
            webSocket.close();
            setTimeout(function () {
                openWebSocket();
            });
        };

        webSocket.onopen = function (ev) {
            ping();
        };
    };

    var last_cfg = {};
    var changes = {};

    function throttle(callback, limit) {
        var wait = false;
        return function (args) {
            if (!wait) {
                callback.apply(this, arguments);
                wait = true;
                setTimeout(function () {
                    wait = false;
                }, limit);
            }
        };
    }

    var registerConfigUi = function (item) {
        var _item = $(item);
        _item.change(function () {
            var name = _item.data("field");
            var new_data = ui_map[name].fetch(name);
            if (JSON.stringify(last_cfg[name]) !== JSON.stringify(new_data)) {
                changes[name] = new_data;
            }
        });
    };

    var loadConfig = function () {
        var applyConfig = function (data) {
            $.each(data, function (key, value) {
                ui_map[key].apply(key, value);
            });
            changes = {};
        };

        $.ajax({
                   url: '/config',
                   type: 'GET',
                   contentType: 'application/json',
                   success: applyConfig
               });
    };

    var SystemCommandActions = {
        restart: function () {
            var _body = $("body");
            _body.empty();
            _body.append("
Device will reboot!

Try to reconnect in 15 seconds.
");
            setTimeout(function () {
                window.location.reload(true);
            }, 15000);
        },
        reset_wifi: function () {
            var _body = $("body");
            _body.empty();
            _body.append("
Devices WIFI settings where cleared!

Please reconfigure it.
");
        },
        reset_config: function () {
            var _body = $("body");
            _body.empty();
            _body.append("
Devices Config was reset!

Reload page ...
");
            setTimeout(function () {
                window.location.reload(true);
            }, 2000);
        }
    };

    var sendCommand = throttle(
        function (params) {
            $.ajax({
                       url: '/system',
                       type: 'POST',
                       data: JSON.stringify(params),
                       contentType: 'application/json',
                       success: function () {
                           SystemCommandActions[params.command]();
                       }
                   }
            );
        },
        1000
    );

    var initUi = function () {
        var settings = "";
        CONFIG_ITEMS.forEach(function (item) {
            settings += item.factory(item);
        });
        $("#settings").prepend(settings);
        CONFIG_ITEMS.forEach(function (item) {
            registerConfigUi('.config-item[data-field="' + item.name + '"]');
        });
        loadConfig();
        loadDebug();
    };

    var loadDebug = function () {
        var applyDebug = function (data) {
            $.each(data, function (key, value) {
                $('.debug-item[data-dbg-field="' + key + '"]').prop("checked", value);
            });
        };

        $.ajax({
                   url: "/debug",
                   type: "GET",
                   contentType: 'application/json',
                   success: applyDebug
               });
    };

    var saveDebug = function () {
        var data = {};
        $(".debug-item").each(function (_, item) {
            var _item = $(item);
            data[_item.attr("name")] = _item.prop("checked");
        });

        $.ajax({
                   url: '/debug',
                   type: "PUT",
                   data: JSON.stringify(data),
                   contentType: 'application/json',
                   success: loadConfig
               });
    };

    var loadFwVersion = function () {
        $.ajax({
                   url: "/firmware",
                   type: "GET",
                   contentType: 'application/json',
                   success: function (data) {
                       $('#current-fw-version').append('Current version: ' + data["version"]);
                   }
               })
    };

    $('.system-btn').click(function () {
        sendCommand({command: $(this).data('command')});
    });

    $('#settings-form').submit(function (e) {
        e.preventDefault();

        $.ajax({
                   url: "/config",
                   type: 'PUT',
                   contentType: 'application/json',
                   data: JSON.stringify(changes),
                   success: loadConfig

               });

        return false;
    });

    $('#cfg-form-reset').click(function (e) {
        e.preventDefault();
        loadConfig();
        return false;
    });

    $("#debugging-form").submit(function (e) {
        e.preventDefault();

        saveDebug();
        return false;
    });

    $('#dbg-form-reset').click(function (e) {
        e.preventDefault();
        loadDebug();
        return false;
    });

    // Clear log
    $('#btn-clear-log').click(function (e) {
        $('#log-container').find('pre').empty();
    });

    $('#update-form').submit(function () {
        closeWebSocket();
    });

    initUi();
    loadFwVersion();
    openWebSocket();
});
<commit_msg>Frontend: make clear that we deal with GPIO pins<commit_after>$(function () {
    var logLevelInputFactory = function (item) {
        return '' + item.name + '' +
            '<select class="config-item" data-field="' + item.name + '">' +
            '<option value="">None</option>' +
            '<option value="error">Error</option>' +
            '<option value="warning">Warning</option>' +
            '<option value="info">Info</option>' +
            '<option value="debug">Debug</option>' +
            '</select>' +
            '' + item.help + '';
    };

    var inputFieldFactory = function (item) {
        return '' + item.name + '' +
            '<input type="text" class="pure-input-1 config-item" id="' + item.name + '" name="' + item.name + '" data-field="' + item.name + '">' +
            '' + item.help + '';
    };

    var passwordFieldFactory = function (item) {
        return '' + item.name + '' +
            '<input type="password" class="pure-input-1 config-item" id="' + item.name + '" name="' + item.name + '" data-field="' + item.name + '">' +
            '' + item.help + '';
    };

    var checkboxFactory = function (item) {
        return '' +
            '<input class=" config-item " type="checkbox" value="' + item.name + '" data-field="' + item.name + '" name="' + item.name + '"> ' +
            item.name +
            '' + item.help + '' +
            '';
    };

    var legendFactory = function (item) {
        return '<legend>' + item.name + '</legend>';
    };

    var protocolInputField = function (item) {
        return '

';
    };

    var inputApply = function (item_id, data) {
        $('.config-item[data-field="' + item_id + '"]').val(data);
    };

    var checkboxApply = function (item_id, data) {
        $('.config-item[data-field="' + item_id + '"]').prop("checked", data);
    };

    var protocolApply = function (item_id, data) {

        var fillProtocolData = function (protos) {
            $("#rfProtocols").empty();
            protos.forEach(function (value) {
                var elem = '' +
                    '<input class=" config-item protocols-item" id="proto_check_' + value + '" type="checkbox" value="' + value + '" data-field="' + item_id + '" name="' + item_id + '">' +
                    ' Protocol ' + value +
                    '';
                $("#rfProtocols").append(elem);
                registerConfigUi('#proto_check_' + value);
            });
            if (data.length > 0) {
                data.forEach(function (value) {
                    $('#proto_check_' + value).prop('checked', true);
                });
            } else {
                $(".protocols-item").each(function (_, value) {
                    $(value).prop("checked", true);
                });
            }
        };

        $.ajax({
                   url: "/protocols",
                   type: "GET",
                   contentType: 'application/json',
                   success: fillProtocolData
               });
    };

    var inputGet = function (item_id) {
        return $('.config-item[data-field="' + item_id + '"]').val();
    };

    var inputGetInt = function (item_id) {
        return parseInt(inputGet(item_id));
    };

    var checkboxGet = function (item_id) {
        return $('.config-item[data-field="' + item_id + '"]').prop("checked");
    };

    var protocolGet = function (item_id) {
        var checked = $('.protocols-item:checked');
        if ($('.protocols-item').length === checked.length) {
            return [];
        }
        return $.map(checked, function (x) {
            return $(x).val();
        });
    };

    function ConfigItem(name, factory, apply, fetch, help) {
        this.name = name;
        this.factory = factory;
        this.apply = apply;
        this.fetch = fetch;
        this.help = help;
    }

    function GroupItem(name, factory) {
        this.name = name;
        this.factory = factory;
    }

    var CONFIG_ITEMS = [
        new GroupItem("General Config", legendFactory),
        new ConfigItem("deviceName", inputFieldFactory, inputApply, inputGet, "The general name of the device"),
        new ConfigItem("configPassword", passwordFieldFactory, inputApply, inputGet, "The admin password for the web UI"),

        new GroupItem("MQTT Config", legendFactory),
        new ConfigItem("mqttBroker", inputFieldFactory, inputApply, inputGet, "MQTT Broker host"),
        new ConfigItem("mqttBrokerPort", inputFieldFactory, inputApply, inputGetInt, "MQTT Broker port"),
        new ConfigItem("mqttUser", inputFieldFactory, inputApply, inputGet, "MQTT username (optional)"),
        new ConfigItem("mqttPassword", passwordFieldFactory, inputApply, inputGet, "MQTT password (optional)"),
        new ConfigItem("mqttRetain", checkboxFactory, checkboxApply, checkboxGet, "Retain MQTT messages"),

        new GroupItem("MQTT Topic Config", legendFactory),
        new ConfigItem("mqttReceiveTopic", inputFieldFactory, inputApply, inputGet, "Topic to publish received signal"),
        new ConfigItem("mqttSendTopic", inputFieldFactory, inputApply, inputGet, "Topic to get signals to send from"),

        new GroupItem("433MHz RF Config", legendFactory),
        new ConfigItem("rfEchoMessages", checkboxFactory, checkboxApply, checkboxGet, "Echo sent rf messages back"),
        new ConfigItem("rfReceiverPin", inputFieldFactory, inputApply, inputGetInt, "The GPIO pin used for the rf receiver"),
        new ConfigItem("rfTransmitterPin", inputFieldFactory, inputApply, inputGetInt, "The GPIO pin used for the RF transmitter"),

        new GroupItem("Enabled RF protocols", legendFactory),
        new ConfigItem("rfProtocols", protocolInputField, protocolApply, protocolGet, ""),

        new GroupItem("Log Config", legendFactory),
        new ConfigItem("serialLogLevel", logLevelInputFactory, inputApply, inputGet, "Level for serial logging"),
        new ConfigItem("webLogLevel", logLevelInputFactory, inputApply, inputGet, "Level for logging to the web UI"),
        new ConfigItem("syslogLevel", logLevelInputFactory, inputApply, inputGet, "Level for syslog logging"),
        new ConfigItem("syslogHost", inputFieldFactory, inputApply, inputGet, "Syslog server (optional)"),
        new ConfigItem("syslogPort", inputFieldFactory, inputApply, inputGetInt, "Syslog port (optional)")
    ];

    var ui_map = {};
    CONFIG_ITEMS.forEach(function (value) {
        if (value.fetch !== undefined) {
            ui_map[value.name] = value;
        }
    });

    var closeWebSocket = function () {
    };

    var openWebSocket = function () {
        var container = $('#log-container');
        var pre = container.find('pre');

        var webSocket = new WebSocket("ws://" + location.hostname + ":81");
        var tm;

        closeWebSocket = function () {
            clearTimeout(tm);
            webSocket.close();
        };

        var ping = function () {
            tm = setTimeout(function () {
                webSocket.send("__PING__");

                tm = setTimeout(function () {
                    webSocket.close();
                    openWebSocket();
                }, 2000);
            }, 5000);
        };

        webSocket.onmessage = function (e) {
            var message = e.data;

            if (message === "__PONG__") {
                clearTimeout(tm);
                ping();
                return;
            }

            pre.append(message);
            if (message === '\n' || (typeof message === "string" && message.indexOf('\n') !== -1)) {
                container.scrollTop(pre.get(0).scrollHeight);
            }
        };

        webSocket.onerror = function (ev) {
            webSocket.close();
            setTimeout(function () {
                openWebSocket();
            });
        };

        webSocket.onopen = function (ev) {
            ping();
        };
    };

    var last_cfg = {};
    var changes = {};

    function throttle(callback, limit) {
        var wait = false;
        return function (args) {
            if (!wait) {
                callback.apply(this, arguments);
                wait = true;
                setTimeout(function () {
                    wait = false;
                }, limit);
            }
        };
    }

    var registerConfigUi = function (item) {
        var _item = $(item);
        _item.change(function () {
            var name = _item.data("field");
            var new_data = ui_map[name].fetch(name);
            if (JSON.stringify(last_cfg[name]) !== JSON.stringify(new_data)) {
                changes[name] = new_data;
            }
        });
    };

    var loadConfig = function () {
        var applyConfig = function (data) {
            $.each(data, function (key, value) {
                ui_map[key].apply(key, value);
            });
            changes = {};
        };

        $.ajax({
                   url: '/config',
                   type: 'GET',
                   contentType: 'application/json',
                   success: applyConfig
               });
    };

    var SystemCommandActions = {
        restart: function () {
            var _body = $("body");
            _body.empty();
            _body.append("
Device will reboot!

Try to reconnect in 15 seconds.
");
            setTimeout(function () {
                window.location.reload(true);
            }, 15000);
        },
        reset_wifi: function () {
            var _body = $("body");
            _body.empty();
            _body.append("
Devices WIFI settings where cleared!

Please reconfigure it.
");
        },
        reset_config: function () {
            var _body = $("body");
            _body.empty();
            _body.append("
Devices Config was reset!

Reload page ...
");
            setTimeout(function () {
                window.location.reload(true);
            }, 2000);
        }
    };

    var sendCommand = throttle(
        function (params) {
            $.ajax({
                       url: '/system',
                       type: 'POST',
                       data: JSON.stringify(params),
                       contentType: 'application/json',
                       success: function () {
                           SystemCommandActions[params.command]();
                       }
                   }
            );
        },
        1000
    );

    var initUi = function () {
        var settings = "";
        CONFIG_ITEMS.forEach(function (item) {
            settings += item.factory(item);
        });
        $("#settings").prepend(settings);
        CONFIG_ITEMS.forEach(function (item) {
            registerConfigUi('.config-item[data-field="' + item.name + '"]');
        });
        loadConfig();
        loadDebug();
    };

    var loadDebug = function () {
        var applyDebug = function (data) {
            $.each(data, function (key, value) {
                $('.debug-item[data-dbg-field="' + key + '"]').prop("checked", value);
            });
        };

        $.ajax({
                   url: "/debug",
                   type: "GET",
                   contentType: 'application/json',
                   success: applyDebug
               });
    };

    var saveDebug = function () {
        var data = {};
        $(".debug-item").each(function (_, item) {
            var _item = $(item);
            data[_item.attr("name")] = _item.prop("checked");
        });

        $.ajax({
                   url: '/debug',
                   type: "PUT",
                   data: JSON.stringify(data),
                   contentType: 'application/json',
                   success: loadConfig
               });
    };

    var loadFwVersion = function () {
        $.ajax({
                   url: "/firmware",
                   type: "GET",
                   contentType: 'application/json',
                   success: function (data) {
                       $('#current-fw-version').append('Current version: ' + data["version"]);
                   }
               })
    };

    $('.system-btn').click(function () {
        sendCommand({command: $(this).data('command')});
    });

    $('#settings-form').submit(function (e) {
        e.preventDefault();

        $.ajax({
                   url: "/config",
                   type: 'PUT',
                   contentType: 'application/json',
                   data: JSON.stringify(changes),
                   success: loadConfig

               });

        return false;
    });

    $('#cfg-form-reset').click(function (e) {
        e.preventDefault();
        loadConfig();
        return false;
    });

    $("#debugging-form").submit(function (e) {
        e.preventDefault();

        saveDebug();
        return false;
    });

    $('#dbg-form-reset').click(function (e) {
        e.preventDefault();
        loadDebug();
        return false;
    });

    // Clear log
    $('#btn-clear-log').click(function (e) {
        $('#log-container').find('pre').empty();
    });

    $('#update-form').submit(function () {
        closeWebSocket();
    });

    initUi();
    loadFwVersion();
    openWebSocket();
});
<|endoftext|>


<commit_before>/*
 * Given a ContentNode, returns the thumbnail URL of the first file (if any) with a thumbnail
 */
export function getContentNodeThumbnail(contentnode) {
  const fileWithThumbnail = contentnode.files.find(file => file.thumbnail && file.available);
  if (fileWithThumbnail) {
    return fileWithThumbnail.storage_url;
  }
  return null;
}
<commit_msg>Account for all possible API response types when retrieving thumbnail<commit_after>/*
 * Given a ContentNode, returns the thumbnail URL.
 * A thumbnail URL is commonly saved in file objects of `files` attribute
 * however some simplified endpoints return it only in `thumbnail` attribute.
 * Therefore, if `thumbnail` attribute is availabe, its value is returned.
 * If it's not available, then the first file (if any) with a thumbnail
 * from `files` is returned.
 */
export function getContentNodeThumbnail(contentnode) {
  if (contentnode.thumbnail) {
    return contentnode.thumbnail;
  }
  if (!contentnode.files || !contentnode.files.length) {
    return null;
  }
  const fileWithThumbnail = contentnode.files.find(file => file.thumbnail && file.available);
  if (fileWithThumbnail) {
    return fileWithThumbnail.storage_url;
  }
  return null;
}
<|endoftext|>