+
+ Class:{{work 'class'}}
+
Due Date:
diff --git a/hourglass/client/main/main.js b/hourglass/client/main/main.js
index 33f611c..da04805 100644
--- a/hourglass/client/main/main.js
+++ b/hourglass/client/main/main.js
@@ -8,6 +8,9 @@ import './main.html';
var load = true;
var calWorkOpen = null;
var calWorkDate = null;
+var dragging = false;
+var clicked = false;
+
var defaultWork = {
name: "Name | Click here to edit...",
@@ -20,6 +23,7 @@ var defaultWork = {
Session.set("user", {}); // Stores user preferences.
Session.set("calendarEvents", []); // Stores calendar classes.
Session.set("myClasses", []); // Stores user classes.
+Session.set("myWork", []); // Stores user related work.
Session.set("requests", false); // Status of requests.
Session.set("sidebarMode", ""); // Status of sidebars.
Session.set("newWork", null); // If user creating new work.
@@ -31,8 +35,6 @@ Session.set("classDispHover", null); // Stores current hovered class filter.
Session.set("restrictText", {}); // Stores text for comment character restriction.
Session.set("confirmText", ""); // Stores text for confirmations.
-var dragging = false;
-
// On render actions
Template.login.rendered = function() {
@@ -47,6 +49,18 @@ Template.main.created = function() {
$(".overlay").fadeOut(150);
}
});
+ getClasses();
+ work.find().observeChanges({
+ added: function (id, fields) {
+ updateWork(id, fields, "added");
+ },
+ changed: function (id, fields) {
+ updateWork(id, fields, "changed");
+ },
+ removed: function (id) {
+ updateWork(id, null, "remove");
+ }
+ });
/*if (Notification.permission !== "granted") {
Notification.requestPermission().then(function(result) {
@@ -75,12 +89,11 @@ Template.classesMode.rendered = function() {
$(".mainClass .slimScrollBar").css("display", "none");
var area = $("#classesMode");
- var clicked = false;
var clickX = 0;
area.on({
'mousemove': function(e) {
- if(clicked) area.scrollLeft(area.scrollLeft() + (clickX - e.pageX)/25);
+ if(clicked && !dragging) area.scrollLeft(area.scrollLeft() + (clickX - e.pageX)/70);
},
'mousedown': function(e) {
clicked = true;
@@ -130,19 +143,171 @@ Template.registerHelper('overlayDim', (part) => { // Gets size of the overlay co
});
Template.registerHelper('myClasses', () => { // Gets all classes and respective works.
- if (Session.get("user").classes.length === 0) { // Null checking.
+ /*var myClasses = Session.get("user").classes;
+ var classDisp = Session.get("classDisp");
+ if (myClasses.length === 0) { // Null checking.
return [];
} else {
- var array = myClasses();
+ var array = [];
+ for(var i = 0; i < myClasses.length; i++) {
+ var classObj;
+ if(myClasses[i] === Meteor.userId()) {
+ classObj.name = "Personal";
+ classObj.box = " owned";
+ classObj.mine = false; // Actual value is reversed.
+ classObj.subscribers = 1;
+ } else {
+ classObj = classes.findOne({_id: myClasses[i]});
+ if(classObj === undefined) return;
+ var isAdmin = classObj.admin === Meteor.userId();
+ classObj.box = (isAdmin) ? " owned" : "";
+ classObj.mine = (isAdmin) ? false : true; // Actual value is reversed
+ classObj.subscribers = classObj.subscribers.length;
+ classObj.teachershort = (found.teacher === undefined) ? "" : found.teacher.split(" ").slice(1).reduce(function(a,b) { return a+ " " + b;});
+ }
+
+ classObj.selected = ((classDisp.indexOf(myClasses[i]) !== -1)) ? Session.get("user").preferences.theme.modeHighlight : "rgba(0,0,0,0)"; // Filter selected.
+ array.push(classObj);
+ }*/
+/* var array = myClasses();
if(Meteor.Device.isPhone()) mobileWork();
Session.set("myClasses", array);
calendarEvents(array);
$("#fullcalendar").fullCalendar("removeEvents");
- $("#fullcalendar").fullCalendar("addEventSource", Session.get("calendarEvents"))
- return array;
- }
+ $("#fullcalendar").fullCalendar("addEventSource", Session.get("calendarEvents"))*/
+ return Session.get("myClasses");
+
});
+Template.registerHelper('myWork', () => {
+ return Session.get("myWork");
+});
+
+getClasses = function() {
+ var array = [];
+ var myClasses = Session.get("user").classes;
+ var classDisp = Session.get("classDisp");
+ for(var i = 0; i < myClasses.length; i++) {
+ var classObj = {};
+ if(myClasses[i] === Meteor.userId()) {
+ classObj.name = "Personal";
+ classObj.box = " owned";
+ classObj.mine = false; // Actual value is reversed.
+ classObj.subscribers = 1;
+ classObj.admin = Meteor.userId();
+ classObj._id = Meteor.userId();
+ } else {
+ classObj = classes.findOne({_id: myClasses[i]});
+ if(classObj === undefined) return;
+ var isAdmin = classObj.admin === Meteor.userId();
+ classObj.box = (isAdmin) ? " owned" : "";
+ classObj.mine = (isAdmin) ? false : true; // Actual value is reversed
+ classObj.subscribers = classObj.subscribers.length;
+ classObj.teachershort = (classObj.teacher === undefined) ? "" : classObj.teacher.split(" ").slice(1).reduce(function(a,b) { return a+ " " + b;});
+ }
+
+ classObj.selected = ((classDisp.indexOf(myClasses[i]) !== -1)) ? Session.get("user").preferences.theme.modeHighlight : "rgba(0,0,0,0)"; // Filter selected.
+ array.push(classObj);
+ }
+ Session.set("myClasses", array);
+}
+
+updateWork = function(id, fields, type) {
+ if(type === "remove" && Session.get("myWork").filter(function(work) { // Removed work and exists in user data.
+ return work._id === id;
+ }).length !== 0) {
+ Session.set("myWork", Session.get("myWork").filter(function(work) {
+ return work._id !== id;
+ }));
+ return;
+ }
+
+ var classDisp = Session.get("classDisp");
+ var sideFilter = Session.get("typeFilter"); // Get sidebar type filter.
+ var hideTime = Session.get("user").preferences.timeHide;
+ var workObj;
+
+ if(type === "added") {
+ workObj = Object.assign({}, fields, {_id: id})
+ } else if(type === "changed") {
+ workObj = Object.assign(Session.get("myWork").filter(function(work) {
+ return work._id === id;
+ }), fields);
+ }
+
+ workObj.classid = workObj.class;
+ workObj.realDate = workObj.dueDate;
+ workObj.dueDate = moment(workObj.dueDate).calendar(null, {
+ sameDay: '[Today]',
+ nextDay: '[Tomorrow]',
+ nextWeek: 'dddd',
+ lastDay: '[Yesterday]',
+ lastWeek: '[Last] dddd',
+ sameElse: 'MMMM Do'
+ });
+
+ if (workObj.dueDate === "Today") { // Font weight based on date proximity.
+ workObj.cardDate = "600";
+ } else if (workObj.dueDate === "Tomorrow") {
+ workObj.cardDate = "400";
+ }
+
+ workObj.typeColor = workColors[workObj.type];
+ workObj.confirmationLength = workObj.confirmations.length; // Counts the number of confirmations and reports for a particular work.
+ workObj.reportLength = workObj.reports.length;
+
+ workObj.creatorname = Meteor.users.findOne({
+ _id: workObj.creator
+ }).profile.name;
+
+ workObj.hide = false;
+
+ //Filters
+ var notInClassFilter = classDisp.length !== 0 && !_.contains(classDisp, workObj.classid);
+ var pastHideDate = hideTime !== 0 && (moment().subtract(hideTime, 'days'))._d > (moment(workObj.realDate))._d;
+ var markedDone = Session.get("user").preferences.done && !Meteor.Device.isPhone() && _.contains(workObj.done, Meteor.userId());
+ var reported = (workObj.reportLength / (workObj.reportLength + workObj.confirmationLength)) > 0.7; // Over 70% are reports
+
+ if(notInClassFilter || pastHideDate || markedDone) workObj.hide = true;
+
+ var normalColor = Session.get("user").preferences.theme.text;
+ // Ratio color handling
+ /*var conf = workObj.confirmations.length;
+ var repo = workObj.reports.length;
+ var ratio = conf / repo;
+
+ if (Math.abs(conf - repo)) {
+ if ((conf + repo) <= 1) {
+ thisWork[j].doneRatio = normalColor;
+ } else {
+ thisWork[j].doneRatio = "#F9F906";
+ }
+ } else if (ratio >= 2) {
+ thisWork[j].doneRatio = "#33DD33";
+ } else if (ratio <= 0.9) {
+ thisWork[j].doneRatio = "#FF1A1A";
+ }*/
+
+ workObj.doneRatio = normalColor;
+
+ var myWork;
+ if(type === "added") {
+ myWork = Session.get("myWork");
+ } else if(type === "changed") {
+ myWork = Session.get("myWork").filter(function(work) {
+ return work._id !== id;
+ });
+ }
+ myWork.push(workObj);
+ Session.set("myWork", myWork.sort(function(a,b) {
+ return Date.parse(a.realDate) - Date.parse(b.realDate);
+ }));
+
+ calendarEvents();
+ $("#fullcalendar").fullCalendar("removeEvents");
+ $("#fullcalendar").fullCalendar("addEventSource", Session.get("calendarEvents"));
+}
+
Template.registerHelper('pref', (val) => { // Obtains all user preferences.
try {
if(val === "school") return Session.get("user").school;
@@ -215,7 +380,9 @@ Template.main.helpers({
return " - " + Session.get("user").school;
},
avatar() { // Returns avatar.
- return Meteor.user().services.google.picture;
+ try {
+ return Meteor.user().services.google.picture;
+ } catch(err) {}
},
username() { // Returns user name.
return Session.get("user").name;
@@ -681,11 +848,11 @@ Template.main.events({
},
'click .cWorkBottom .fa-thumbs-up' (event) {
serverData = [event.target.parentNode.parentNode.parentNode.parentNode.getAttribute("workid"), "confirmations"]
- sendData("toggleWork")
+ sendData("toggleWork");
},
'click .cWorkBottom .fa-exclamation-triangle' (event) {
serverData = [event.target.parentNode.parentNode.parentNode.parentNode.getAttribute("workid"), "reports"]
- sendData("toggleWork")
+ sendData("toggleWork");
},
'click #signout' () {
$(".noScroll").velocity("fadeOut", 50);
@@ -694,6 +861,15 @@ Template.main.events({
}
});
+Template.classesMode.helpers({
+ thisClassWork() {
+ var id = this._id;
+ return Session.get("myWork").filter(function(work) {
+ return work.classid === id;
+ });
+ }
+});
+
// Other Functions
toggleOptionMenu = function(toggle, menu) {
@@ -960,6 +1136,7 @@ startDragula = function() {
var els = document.getElementsByClassName("classWrapper");
if($(els[0]).hasClass("gu-transit")) return;
dragging = false;
+ clicked = false;
var final = [];
for (var i = 0; i < els.length; i++) {
var classid = els[i].getElementsByClassName("creWork")[0].getAttribute("classid");
@@ -991,7 +1168,7 @@ myClasses = function() {
});
if(found === undefined) return;
found.subscribers = found.subscribers.length;
- found.teachershort = found.teacher.split(" ").slice(1).reduce(function(a,b) { return a+ " " + b;});
+ found.teachershort = (found.teacher === undefined) ? "" : found.teacher.split(" ").slice(1).reduce(function(a,b) { return a+ " " + b;});
found.mine = true;
if (found.admin === Meteor.userId()) { // If user owns this class.
found.box = " owned";
@@ -1089,35 +1266,30 @@ myClasses = function() {
return array;
}
-function calendarEvents(array) {
+function calendarEvents() {
var events = [];
- var userClasses = array;
- if(userClasses === undefined) return;
- for (var i = 0; i < userClasses.length; i++) {
- var works = userClasses[i].thisClassWork;
- for (var j = 0; j < works.length; j++) {
- var work = works[j];
- var currClass = classes.findOne({
- _id: work.class
- });
- var inRole = false;
+ var myWork = Session.get("myWork");
+ for(var i = 0; i < myWork.length; i++) {
+ var work = myWork[i];
+ var currClass = classes.findOne({ _id: work.classid});
+ var inRole = false;
- if (work.class === Meteor.userId() ||
- Meteor.userId() === work.creator ||
- Roles.userIsInRole(Meteor.userId(), ['superadmin', 'admin']) ||
- currClass.moderators.indexOf(Meteor.userId()) !== -1 ||
- currClass.banned.indexOf(Meteor.userId()) !== -1
- ) inRole = true;
- events.push({
- id: work._id,
- start: work.realDate.toISOString().slice(0, 10),
- title: work.name,
- backgroundColor: workColors[work.type],
- borderColor: "#444",
- startEditable: inRole,
- className: work.type + " workevent " + work.class
- });
- }
+ if (work.class === Meteor.userId() ||
+ Meteor.userId() === work.creator ||
+ Roles.userIsInRole(Meteor.userId(), ['superadmin', 'admin']) ||
+ currClass.moderators.indexOf(Meteor.userId()) !== -1 ||
+ currClass.banned.indexOf(Meteor.userId()) !== -1
+ ) inRole = true;
+
+ events.push({
+ id: work._id,
+ start: work.realDate.toISOString().slice(0, 10),
+ title: work.name,
+ backgroundColor: workColors[work.type],
+ borderColor: "#444",
+ startEditable: inRole,
+ className: work.type + " workevent " + work.class
+ });
}
Session.set("calendarEvents", events);
}
diff --git a/hourglass/client/menus/menus.css b/hourglass/client/menus/menus.css
index c41e2de..23cecdc 100644
--- a/hourglass/client/menus/menus.css
+++ b/hourglass/client/menus/menus.css
@@ -346,6 +346,7 @@
#code {
margin: 0;
+ padding: 2%;
width: auto;
background-color: rgba(255,255,255,0.3);
@@ -361,9 +362,10 @@
}
#copyHolder {
- visibility: hidden;
pointer-events: none;
position: absolute;
+
+ right: -500px;
}
#changeAdminWrapper {
diff --git a/hourglass/client/menus/menus.html b/hourglass/client/menus/menus.html
index caa2a1b..5a731d1 100644
--- a/hourglass/client/menus/menus.html
+++ b/hourglass/client/menus/menus.html
@@ -411,7 +411,8 @@
{{/if}}
{{/unless}}
- {{> classInfoCode classInfo 'code'}}
+
+ {{> classInfoCode}}
Change Admin:
@@ -484,13 +485,14 @@
- {{#if exists}}
-
+ {{classInfo 'code'}}
+ {{#if code 'exists'}}
+
Code
-
{{code}}
-
+
{{code 'code'}}
+
-
Copied!
+
Copied!
{{/if}}
diff --git a/hourglass/client/menus/menus.js b/hourglass/client/menus/menus.js
index b6ebe08..9010581 100644
--- a/hourglass/client/menus/menus.js
+++ b/hourglass/client/menus/menus.js
@@ -220,15 +220,12 @@ Template.registerHelper("classInfo", (info) => {
_id: (isYou) ? Meteor.userId() : thisClass.admin
});
case "code":
- if (isYou) return {
- exists: false
- };
- return (isYou || Meteor.userId() !== this.admin) ? {
- exists: false
- } : {
- exists: true,
- code: Meteor.call('getCode', thisClass._id)
- };
+ if(isYou || Meteor.userId() !== thisClass.admin) return false;
+ var exist;
+ Meteor.call('getCode', thisClass._id, function(err, result) {
+ Session.set("code", [(result === undefined || result === "") ? false : true, result]);
+ });
+ break;
case "mine":
return (isYou) ? true : Meteor.userId() === thisClass.admin;
case "moderators":
@@ -376,7 +373,7 @@ Template.joinClass.helpers({
for (var i = 0; i < array.length; i++) {
array[i].join = true;
array[i].subscribers = array[i].subscribers.length;
- array[i].teachershort = array[i].teacher.split(" ").slice(1).reduce(function(a, b) {
+ if(array[i].teacher !== undefined) array[i].teachershort = array[i].teacher.split(" ").slice(1).reduce(function(a, b) {
return a + " " + b;
});
}
@@ -489,10 +486,11 @@ Template.joinClass.events({
Meteor.call("joinPrivateClass", input.value, function(error, result) {
if (result) {
sAlert.success("Joined!", {
- effect: 'genie',
+ effect: 'stackslide',
position: 'bottom-right',
timeout: 1500
});
+ $("#privateCode").velocity("fadeOut",100);
} else {
sAlert.error("Invalid code!", {
effect: 'stackslide',
@@ -500,7 +498,9 @@ Template.joinClass.events({
timeout: 1500
});
}
+
});
+
}
});
@@ -547,13 +547,14 @@ Template.createClass.events({
return;
}
values.privacy = (values.privacy === "Public") ? false : true;
- values.status = false;
+ values.status = false;
values.category = values.category.toLowerCase();
values.code = "";
serverData = values;
+
if (!teachers.findOne({
name: values.teacher
- })) {
+ }) && values.teacher !== "") {
Meteor.call("createTeacher", values.teacher, values.school, function(error, result) {
if (error !== undefined) {
sAlert.error(error.message, {
@@ -570,6 +571,30 @@ Template.createClass.events({
}
});
+Template.classInfoCode.events({
+ 'click .fa' (event) {
+ document.getElementById("copyHolder").select();
+ document.execCommand("copy");
+ $(event.target.parentNode.childNodes[9]).fadeIn(100, function() {
+ setTimeout(function() {
+ $(event.target.parentNode.childNodes[9]).fadeOut(250);
+ }, 500);
+ });
+ }
+});
+
+Template.classInfoCode.helpers({
+ code(info) {
+ try {
+ if(info === "exists") {
+ return Session.get("code")[0];
+ } else {
+ return Session.get("code")[1];
+ }
+ } catch(err) {}
+ }
+})
+
Template.classInfoUsers.events({
'click .userAdder .fa' (event) {
var type = event.target.getAttribute("user");
@@ -621,18 +646,6 @@ Template.classInfoUsers.events({
}
});
-Template.classInfoCode.events({
- 'click .fa' (event) {
- document.getElementById("copyHolder").select();
- document.execCommand("copy");
- $(event.target.parentNode.childNodes[9]).fadeIn(100, function() {
- setTimeout(function() {
- $(event.target.parentNode.childNodes[9]).fadeOut(250);
- }, 500);
- });
- }
-});
-
toggleToMode = function(mode) {
$("#mainBody").fadeOut(250, function() {
(Session.equals("sidebarMode", "option")) ? Session.set("settingMode", mode): Session.set("mode", mode);
diff --git a/hourglass/client/mobile/mobile.js b/hourglass/client/mobile/mobile.js
index 1b75669..d83d5cc 100644
--- a/hourglass/client/mobile/mobile.js
+++ b/hourglass/client/mobile/mobile.js
@@ -7,6 +7,7 @@ Session.set("select", "none");
Session.set("options", null);
var filterOpen = [false, true, true];
+var timeout;
Template.registerHelper('optionInfo', (type) => {
var op = Session.get("options")
@@ -116,7 +117,7 @@ Template.mobile.rendered = function() {
Template.mobile.events({
'click #mOverlay' () {
- toggleSidebar(false);
+ if(timeout) toggleSidebar(false);
}
});
@@ -604,6 +605,10 @@ addMobileButton = function(element, lighten, animateType, completeFunction) {
ele.on('touchend', function(e) {
if(!care) return;
ele.velocity("stop");
+ timeout = false;
+ setTimeout(function() {
+ timeout = true;
+ }, 100);
switch(type) {
case "color":
ele.velocity(
diff --git a/hourglass/server/main.js b/hourglass/server/main.js
index 18ee71c..9abcd3b 100644
--- a/hourglass/server/main.js
+++ b/hourglass/server/main.js
@@ -312,7 +312,7 @@ function securityCheck(checklist, input) {
break;
// Incorrect teacher format
case 28:
- if (input.teachername.split(" ").length < 2) error = 20;
+ if (input.teachername.split(" ").length < 2 && teachername !== "") error = 20;
break;
}
results.push(error);
@@ -373,17 +373,17 @@ Meteor.methods({
if (!security) {
input.status = Roles.userIsInRole(Meteor.userId(), ['superadmin', 'admin']);
input.admin = Meteor.userId();
- Meteor.call('genCode', function(error, result) {
+ Meteor.call('genCode', input.privacy, function(error, result) {
input.code = result;
- });
- if (input.category != "class" && input.category != "club") {
- input.category = "other";
- }
- input.subscribers = [];
- input.moderators = [];
- input.banned = [];
- classes.insert(input, function(err, result) {
- Meteor.call('joinClass', [result, input.code]);
+ if (input.category != "class" && input.category != "club") {
+ input.category = "other";
+ }
+ input.subscribers = [];
+ input.moderators = [];
+ input.banned = [];
+ classes.insert(input, function(err, result) {
+ Meteor.call('joinClass', [result, input.code]);
+ });
});
} else {
throw new Meteor.Error(errors[security]);
@@ -754,11 +754,9 @@ Meteor.methods({
var current = Meteor.user().profile;
var index = current.classes.indexOf(change);
if (index >= 0) {
- console.log("hi");
if (classes.findOne({
_id: change
}).admin != Meteor.userId()) {
- console.log("f");
current.classes.splice(index, 1);
Meteor.users.update({
_id: Meteor.userId()