From 33def5a7dd8ee81e7766c50f1666ece60fbd25ab Mon Sep 17 00:00:00 2001 From: Pawan Rawal Date: Tue, 8 Nov 2016 15:06:23 +0530 Subject: [PATCH 1/6] Add ability to cancel, resend invites --- admin/candidate/candidate.go | 22 +- admin/mail/mail.go | 6 +- admin/webUI/app/app.module.js | 2 + admin/webUI/app/app.route.js | 1 + .../app/components/invite/inviteController.js | 67 ++- .../app/components/invite/inviteService.js | 58 ++ .../invite/views/invite-dashboard.html | 54 +- admin/webUI/assets/js/gru.js | 2 - .../webUI/assets/lib/js/angular-moment.min.js | 2 + admin/webUI/assets/lib/js/moment.min.js | 548 ++++++++++++++++++ main.go | 1 + quiz/quiz.go | 6 +- 12 files changed, 743 insertions(+), 26 deletions(-) create mode 100644 admin/webUI/assets/lib/js/angular-moment.min.js create mode 100644 admin/webUI/assets/lib/js/moment.min.js diff --git a/admin/candidate/candidate.go b/admin/candidate/candidate.go index f871eeb..0978e55 100644 --- a/admin/candidate/candidate.go +++ b/admin/candidate/candidate.go @@ -46,6 +46,7 @@ func index(quizId string) string { email validity complete + cancel quiz_start invite_sent candidate.question { @@ -125,7 +126,7 @@ func Add(w http.ResponseWriter, r *http.Request) { } // Token sent in mail is uid + the random string. - go mail.Send(c.Name, c.Email, t.Format("Mon Jan 2 15:04:05 MST 2006"), + go mail.Send(c.Email, t.Format("Mon Jan 2 15:04:05 MST 2006"), uid+c.Token) sr.Message = "Candidate added successfully." sr.Success = true @@ -186,8 +187,6 @@ func Edit(w http.ResponseWriter, r *http.Request) { http.StatusInternalServerError) return } - go mail.Send(c.Name, c.Email, t.Format("Mon Jan 2 15:04:05 MST 2006"), - c.Uid+c.Token) sr.Success = true sr.Message = "Candidate info updated successfully." w.Write(server.MarshalResponse(sr)) @@ -222,3 +221,20 @@ func Get(w http.ResponseWriter, r *http.Request) { } w.Write(res) } + +func ResendInvite(w http.ResponseWriter, r *http.Request) { + sr := server.Response{} + vars := mux.Vars(r) + cid := vars["id"] + + email := r.PostFormValue("email") + token := r.PostFormValue("token") + validity := r.PostFormValue("validity") + if email == "" || token == "" || validity == "" { + sr.Write(w, "", "Email/token/validity can't be empty.", http.StatusBadRequest) + return + } + + go mail.Send(email, validity, cid+token) + sr.Write(w, "", "Invite has been resent.", http.StatusOK) +} diff --git a/admin/mail/mail.go b/admin/mail/mail.go index 4083105..b50a7e3 100644 --- a/admin/mail/mail.go +++ b/admin/mail/mail.go @@ -14,14 +14,14 @@ var SENDGRID_API_KEY = flag.String("sendgrid", "", "Sendgrid API Key") // TODO - Later just have one IP address with port info. var Ip = flag.String("ip", "http://localhost:2020", "Public IP address of server") -func Send(name, email, validity, token string) { +func Send(email, validity, token string) { if *SENDGRID_API_KEY == "" { fmt.Println(*Ip + "/#/quiz/" + token) return } from := mail.NewEmail("Dgraph", "join@dgraph.io") subject := "Invitation for screening quiz from Dgraph" - to := mail.NewEmail(name, email) + to := mail.NewEmail("", email) // TODO - Move this to a template. url := fmt.Sprintf("%v/#/quiz/%v", *Ip, token) body := ` @@ -30,7 +30,7 @@ func Send(name, email, validity, token string) { -Hello ` + name + `, +Hello!

You have been invited to take the screening quiz by Dgraph.
diff --git a/admin/webUI/app/app.module.js b/admin/webUI/app/app.module.js index 0654e2e..a286780 100644 --- a/admin/webUI/app/app.module.js +++ b/admin/webUI/app/app.module.js @@ -121,6 +121,8 @@ angular.module('GruiApp').constant('APP_REQUIRES', { 'javascript': ['assets/lib/js/javascript.js'], 'marked': ['https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.2/marked.min.js'], 'highlight': ['assets/lib/js/highlight.pack.js'], + 'moment': ['assets/lib/js/moment.min.js'], + 'angular-moment': ['assets/lib/js/angular-moment.min.js'] }, }); diff --git a/admin/webUI/app/app.route.js b/admin/webUI/app/app.route.js index fd5d096..4c2ea82 100644 --- a/admin/webUI/app/app.route.js +++ b/admin/webUI/app/app.route.js @@ -127,6 +127,7 @@ parent: 'invite', templateUrl: inviteDashboardTemplate, authenticate: true, + resolve: helper.resolveFor('moment', 'angular-moment') }) .state('invite.add', { url: '/invite-user', diff --git a/admin/webUI/app/components/invite/inviteController.js b/admin/webUI/app/components/invite/inviteController.js index de54290..1b21a26 100644 --- a/admin/webUI/app/components/invite/inviteController.js +++ b/admin/webUI/app/components/invite/inviteController.js @@ -254,10 +254,13 @@ } } - function candidatesController($rootScope, $stateParams, $state, inviteService) { + function candidatesController($rootScope, $stateParams, $state, inviteService, moment) { candidatesVm = this; candidatesVm.sortType = 'score'; candidatesVm.sortReverse = true; + candidatesVm.expires = expires; + candidatesVm.cancel = cancel; + candidatesVm.resend = resend; candidatesVm.quizID = $stateParams.quizID; @@ -299,6 +302,67 @@ }, function(err) { console.log(err); }); + + angular.element(document).ready(function() { + var dialog = document.querySelector('dialog'); + var $delete = $('.delete-cand'); + if (!dialog.showModal) { + dialogPolyfill.registerDialog(dialog); + } + $delete.on('click', function() { + console.log("here") + dialog.showModal(); + }); + dialog.querySelector('.close').addEventListener('click', function() { + dialog.close(); + }); + }); + + function expires(validity) { + var numDays = moment(validity).diff(moment(), 'days') + if (numDays == 0) { + return "Today" + } else if (numDays > 0) { + return numDays + } + return "Expired" + } + + function cancel(candidateID) { + inviteService.cancelInvite(candidateID).then(function(cancelled) { + if (!cancelled) { + SNACKBAR({ + message: "Invite could not be cancelled.", + messageType: "error", + }) + return + } + SNACKBAR({ + message: "Invite cancelled successfully.", + }) + $state.transitionTo("invite.dashboard", { + quizID: candidatesVm.quizID, + }) + }) + } + + function resend(candidateID) { + inviteService.resendInvite(candidateID).then(function(response) { + if (!response.success) { + SNACKBAR({ + message: response.message, + messageType: "error", + }) + return + } + SNACKBAR({ + message: response.message + }) + $state.transitionTo("invite.dashboard", { + quizID: candidatesVm.quizID, + }) + }) + } } function candidateReportController($rootScope, $stateParams, $state, inviteService) { @@ -372,6 +436,7 @@ "$stateParams", "$state", "inviteService", + "moment", candidatesController ]; angular.module('GruiApp').controller('candidatesController', candidatesDependency); diff --git a/admin/webUI/app/components/invite/inviteService.js b/admin/webUI/app/components/invite/inviteService.js index 1675717..c0f7a1e 100644 --- a/admin/webUI/app/components/invite/inviteService.js +++ b/admin/webUI/app/components/invite/inviteService.js @@ -30,6 +30,7 @@ var query = "{\ quiz(_uid_: " + quizId + ") {\ quiz.candidate {\ + cancel\ email\ }\ }\ @@ -39,6 +40,9 @@ var candidates = data.quiz[0]["quiz.candidate"]; if (candidates) { for (var i = 0; i < candidates.length; i++) { + if (candidates[i].cancel === 'true') { + continue + } if (candidates[i].email === email) { return deferred.resolve(true); } @@ -49,6 +53,60 @@ return deferred.promise; } + services.resendInvite = function(candidateID) { + var deferred = $q.defer(); + // TODO - User filter on email after incorporating Dgraph schema. + var query = "{\ + quiz.candidate(_uid_: " + candidateID + ") {\ + email\ + token\ + validity\ + }\ + }" + + services.proxy(query).then(function(data) { + var candidate = data["quiz.candidate"][0]; + if (candidate == null) { + return deferred.resolve({ + success: false, + message: "No candidate found." + }); + } + return candidate + }).then(function(candidate) { + var paylaod = { + "email": candidate.email, + "token": candidate.token, + "validity": candidate.validity + } + MainService.post('/candidate/invite/' + candidateID, paylaod).then(function(data) { + return deferred.resolve({ + sucess: true, + message: data.Message + }) + }) + }); + return deferred.promise; + } + + services.cancelInvite = function(candidateID) { + var deferred = $q.defer(); + var mutation = "mutation {\ + set {\ + <_uid_:" + candidateID + "> \"true\" .\ + }\ + }" + + services.proxy(mutation).then(function(data) { + if (data.code == "ErrorOk") { + return deferred.resolve(true); + } + return deferred.resolve(false); + }); + return deferred.promise; + } + + // TODO - Move to a location where other services can access this. services.proxy = function(data) { return MainService.post('/proxy', data); diff --git a/admin/webUI/app/components/invite/views/invite-dashboard.html b/admin/webUI/app/components/invite/views/invite-dashboard.html index 033ba19..35ad8ef 100644 --- a/admin/webUI/app/components/invite/views/invite-dashboard.html +++ b/admin/webUI/app/components/invite/views/invite-dashboard.html @@ -28,29 +28,30 @@
Candidate List for Quiz
Email - Score - arrow_drop_up - arrow_drop_down - + Score + arrow_drop_up + arrow_drop_down + - Quiz Start - arrow_drop_up - arrow_drop_down - + Quiz Start + arrow_drop_up + arrow_drop_down + Actions - + {{candidate.name}} {{candidate.email}} {{candidate.score | number: 2}} {{candidate.quiz_start | date : 'MMM dd, yyyy'}} - VIEW REPORT + VIEW REPORT  |  + DELETE @@ -63,8 +64,8 @@
Candidate List for Quiz
- - + +
@@ -78,17 +79,25 @@
Candidate List for Quiz
arrow_drop_down - + - + - + @@ -98,3 +107,16 @@
Candidate List for Quiz
+ +

Are you sure you wan't to delete candidate information for?

+ +
+ + +
+
diff --git a/admin/webUI/assets/js/gru.js b/admin/webUI/assets/js/gru.js index 9ef7350..2dfdcf9 100644 --- a/admin/webUI/assets/js/gru.js +++ b/admin/webUI/assets/js/gru.js @@ -1,4 +1,3 @@ -// MATERIAL DESIGN SNACKBAR (function() { $(document).ready(function() { @@ -18,7 +17,6 @@ ); } - (function() { setTimeout(function() { $mdl_input = $(".mdl-textfield__input") diff --git a/admin/webUI/assets/lib/js/angular-moment.min.js b/admin/webUI/assets/lib/js/angular-moment.min.js new file mode 100644 index 0000000..e800ee7 --- /dev/null +++ b/admin/webUI/assets/lib/js/angular-moment.min.js @@ -0,0 +1,2 @@ +"format amd";!function(){"use strict";function a(a){return angular.isUndefined(a)||null===a}function b(){try{return require("moment")}catch(a){throw new Error("Please install moment via npm. Please reference to: https://github.com/urish/angular-moment")}}function c(c,d){if("undefined"==typeof d){if("function"!=typeof require)throw new Error("Moment cannot be found by angular-moment! Please reference to: https://github.com/urish/angular-moment");d=b()}return c.module("angularMoment",[]).constant("angularMomentConfig",{preprocess:null,timezone:null,format:null,statefulFilters:!0}).constant("moment",d).constant("amTimeAgoConfig",{withoutSuffix:!1,serverTime:null,titleFormat:null,fullDateThreshold:null,fullDateFormat:null,fullDateThresholdUnit:"day"}).directive("amTimeAgo",["$window","moment","amMoment","amTimeAgoConfig",function(b,d,e,f){return function(g,h,i){function j(){var a;if(p)a=p;else if(f.serverTime){var b=(new Date).getTime(),c=b-w+f.serverTime;a=d(c)}else a=d();return a}function k(){q&&(b.clearTimeout(q),q=null)}function l(a){var c=j().diff(a,v),d=t&&c>=t;if(d?h.text(a.format(u)):h.text(a.from(j(),r)),s&&z&&h.attr("title",a.format(s)),!d){var e=Math.abs(j().diff(a,"minute")),f=3600;e<1?f=1:e<60?f=30:e<180&&(f=300),q=b.setTimeout(function(){l(a)},1e3*f)}}function m(a){y&&h.attr("datetime",a)}function n(){if(k(),o){var a=e.preprocessDate(o);l(a),m(a.toISOString())}}var o,p,q=null,r=f.withoutSuffix,s=f.titleFormat,t=f.fullDateThreshold,u=f.fullDateFormat,v=f.fullDateThresholdUnit,w=(new Date).getTime(),x=i.amTimeAgo,y="TIME"===h[0].nodeName.toUpperCase(),z=!h.attr("title");g.$watch(x,function(b){return a(b)||""===b?(k(),void(o&&(h.text(""),m(""),o=null))):(o=b,void n())}),c.isDefined(i.amFrom)&&g.$watch(i.amFrom,function(b){p=a(b)||""===b?null:d(b),n()}),c.isDefined(i.amWithoutSuffix)&&g.$watch(i.amWithoutSuffix,function(a){"boolean"==typeof a?(r=a,n()):r=f.withoutSuffix}),i.$observe("amFullDateThreshold",function(a){t=a,n()}),i.$observe("amFullDateFormat",function(a){u=a,n()}),i.$observe("amFullDateThresholdUnit",function(a){v=a,n()}),g.$on("$destroy",function(){k()}),g.$on("amMoment:localeChanged",function(){n()})}}]).service("amMoment",["moment","$rootScope","$log","angularMomentConfig",function(a,b,d,e){var f=null;this.changeLocale=function(d,e){var f=a.locale(d,e);return c.isDefined(d)&&b.$broadcast("amMoment:localeChanged"),f},this.changeTimezone=function(c){a.tz&&a.tz.setDefault?(a.tz.setDefault(c),b.$broadcast("amMoment:timezoneChanged")):d.warn("angular-moment: changeTimezone() works only with moment-timezone.js v0.3.0 or greater."),e.timezone=c,f=c},this.preprocessDate=function(b){return f!==e.timezone&&this.changeTimezone(e.timezone),e.preprocess?e.preprocess(b):a(!isNaN(parseFloat(b))&&isFinite(b)?parseInt(b,10):b)}}]).filter("amParse",["moment",function(a){return function(b,c){return a(b,c)}}]).filter("amFromUnix",["moment",function(a){return function(b){return a.unix(b)}}]).filter("amUtc",["moment",function(a){return function(b){return a.utc(b)}}]).filter("amUtcOffset",["amMoment",function(a){function b(b,c){return a.preprocessDate(b).utcOffset(c)}return b}]).filter("amLocal",["moment",function(a){return function(b){return a.isMoment(b)?b.local():null}}]).filter("amTimezone",["amMoment","angularMomentConfig","$log",function(a,b,c){function d(b,d){var e=a.preprocessDate(b);return d?e.tz?e.tz(d):(c.warn("angular-moment: named timezone specified but moment.tz() is undefined. Did you forget to include moment-timezone.js ?"),e):e}return d}]).filter("amCalendar",["moment","amMoment","angularMomentConfig",function(b,c,d){function e(b,d,e){if(a(b))return"";var f=c.preprocessDate(b);return f.isValid()?f.calendar(d,e):""}return e.$stateful=d.statefulFilters,e}]).filter("amDifference",["moment","amMoment","angularMomentConfig",function(b,c,d){function e(d,e,f,g){if(a(d))return"";var h=c.preprocessDate(d),i=a(e)?b():c.preprocessDate(e);return h.isValid()&&i.isValid()?h.diff(i,f,g):""}return e.$stateful=d.statefulFilters,e}]).filter("amDateFormat",["moment","amMoment","angularMomentConfig",function(b,c,d){function e(b,d){if(a(b))return"";var e=c.preprocessDate(b);return e.isValid()?e.format(d):""}return e.$stateful=d.statefulFilters,e}]).filter("amDurationFormat",["moment","angularMomentConfig",function(b,c){function d(c,d,e){return a(c)?"":b.duration(c,d).humanize(e)}return d.$stateful=c.statefulFilters,d}]).filter("amTimeAgo",["moment","amMoment","angularMomentConfig",function(b,c,d){function e(d,e,f){var g,h;return a(d)?"":(d=c.preprocessDate(d),g=b(d),g.isValid()?(h=b(f),!a(f)&&h.isValid()?g.from(h,e):g.fromNow(e)):"")}return e.$stateful=d.statefulFilters,e}]).filter("amSubtract",["moment","angularMomentConfig",function(b,c){function d(c,d,e){return a(c)?"":b(c).subtract(parseInt(d,10),e)}return d.$stateful=c.statefulFilters,d}]).filter("amAdd",["moment","angularMomentConfig",function(b,c){function d(c,d,e){return a(c)?"":b(c).add(parseInt(d,10),e)}return d.$stateful=c.statefulFilters,d}]).filter("amStartOf",["moment","angularMomentConfig",function(b,c){function d(c,d){return a(c)?"":b(c).startOf(d)}return d.$stateful=c.statefulFilters,d}]).filter("amEndOf",["moment","angularMomentConfig",function(b,c){function d(c,d){return a(c)?"":b(c).endOf(d)}return d.$stateful=c.statefulFilters,d}]),"angularMoment"}var d=window&&window.process&&window.process.type;"function"==typeof define&&define.amd?define(["angular","moment"],c):"undefined"!=typeof module&&module&&module.exports&&"function"==typeof require&&!d?module.exports=c(require("angular"),require("moment")):c(angular,("undefined"!=typeof global?global:window).moment)}(); +//# sourceMappingURL=angular-moment.min.js.map \ No newline at end of file diff --git a/admin/webUI/assets/lib/js/moment.min.js b/admin/webUI/assets/lib/js/moment.min.js new file mode 100644 index 0000000..6ea916a --- /dev/null +++ b/admin/webUI/assets/lib/js/moment.min.js @@ -0,0 +1,548 @@ +//! moment.js +//! version : 2.15.2 +//! authors : Tim Wood, Iskren Chernev, Moment.js contributors +//! license : MIT +//! momentjs.com +!function(a,b){"object"==typeof exports&&"undefined"!=typeof module?module.exports=b():"function"==typeof define&&define.amd?define(b):a.moment=b()}(this,function(){"use strict";function a(){return md.apply(null,arguments)} +// This is done to register the method called with moment() +// without creating circular dependencies. +function b(a){md=a}function c(a){return a instanceof Array||"[object Array]"===Object.prototype.toString.call(a)}function d(a){ +// IE8 will treat undefined and null as object if it wasn't for +// input != null +return null!=a&&"[object Object]"===Object.prototype.toString.call(a)}function e(a){var b;for(b in a) +// even if its not own property I'd still call it non-empty +return!1;return!0}function f(a){return a instanceof Date||"[object Date]"===Object.prototype.toString.call(a)}function g(a,b){var c,d=[];for(c=0;c0)for(c in od)d=od[c],e=b[d],o(e)||(a[d]=e);return a} +// Moment prototype object +function q(b){p(this,b),this._d=new Date(null!=b._d?b._d.getTime():NaN), +// Prevent infinite loop in case updateOffset creates new moment +// objects. +pd===!1&&(pd=!0,a.updateOffset(this),pd=!1)}function r(a){return a instanceof q||null!=a&&null!=a._isAMomentObject}function s(a){return a<0?Math.ceil(a)||0:Math.floor(a)}function t(a){var b=+a,c=0;return 0!==b&&isFinite(b)&&(c=s(b)),c} +// compare two arrays, return the number of differences +function u(a,b,c){var d,e=Math.min(a.length,b.length),f=Math.abs(a.length-b.length),g=0;for(d=0;d0?"future":"past"];return y(c)?c(b):c.replace(/%s/i,b)}function I(a,b){var c=a.toLowerCase();zd[c]=zd[c+"s"]=zd[b]=a}function J(a){return"string"==typeof a?zd[a]||zd[a.toLowerCase()]:void 0}function K(a){var b,c,d={};for(c in a)h(a,c)&&(b=J(c),b&&(d[b]=a[c]));return d}function L(a,b){Ad[a]=b}function M(a){var b=[];for(var c in a)b.push({unit:c,priority:Ad[c]});return b.sort(function(a,b){return a.priority-b.priority}),b}function N(b,c){return function(d){return null!=d?(P(this,b,d),a.updateOffset(this,c),this):O(this,b)}}function O(a,b){return a.isValid()?a._d["get"+(a._isUTC?"UTC":"")+b]():NaN}function P(a,b,c){a.isValid()&&a._d["set"+(a._isUTC?"UTC":"")+b](c)} +// MOMENTS +function Q(a){return a=J(a),y(this[a])?this[a]():this}function R(a,b){if("object"==typeof a){a=K(a);for(var c=M(a),d=0;d=0;return(f?c?"+":"":"-")+Math.pow(10,Math.max(0,e)).toString().substr(1)+d} +// token: 'M' +// padded: ['MM', 2] +// ordinal: 'Mo' +// callback: function () { this.month() + 1 } +function T(a,b,c,d){var e=d;"string"==typeof d&&(e=function(){return this[d]()}),a&&(Ed[a]=e),b&&(Ed[b[0]]=function(){return S(e.apply(this,arguments),b[1],b[2])}),c&&(Ed[c]=function(){return this.localeData().ordinal(e.apply(this,arguments),a)})}function U(a){return a.match(/\[[\s\S]/)?a.replace(/^\[|\]$/g,""):a.replace(/\\/g,"")}function V(a){var b,c,d=a.match(Bd);for(b=0,c=d.length;b=0&&Cd.test(a);)a=a.replace(Cd,c),Cd.lastIndex=0,d-=1;return a}function Y(a,b,c){Wd[a]=y(b)?b:function(a,d){return a&&c?c:b}}function Z(a,b){return h(Wd,a)?Wd[a](b._strict,b._locale):new RegExp($(a))} +// Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript +function $(a){return _(a.replace("\\","").replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(a,b,c,d,e){return b||c||d||e}))}function _(a){return a.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function aa(a,b){var c,d=b;for("string"==typeof a&&(a=[a]),"number"==typeof b&&(d=function(a,c){c[b]=t(a)}),c=0;c=0&&isFinite(h.getFullYear())&&h.setFullYear(a),h}function sa(a){var b=new Date(Date.UTC.apply(null,arguments)); +//the Date.UTC function remaps years 0-99 to 1900-1999 +return a<100&&a>=0&&isFinite(b.getUTCFullYear())&&b.setUTCFullYear(a),b} +// start-of-first-week - start-of-year +function ta(a,b,c){var// first-week day -- which january is always in the first week (4 for iso, 1 for other) +d=7+b-c, +// first-week day local weekday -- which local weekday is fwd +e=(7+sa(a,0,d).getUTCDay()-b)%7;return-e+d-1} +//http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday +function ua(a,b,c,d,e){var f,g,h=(7+c-d)%7,i=ta(a,d,e),j=1+7*(b-1)+h+i;return j<=0?(f=a-1,g=oa(f)+j):j>oa(a)?(f=a+1,g=j-oa(a)):(f=a,g=j),{year:f,dayOfYear:g}}function va(a,b,c){var d,e,f=ta(a.year(),b,c),g=Math.floor((a.dayOfYear()-f-1)/7)+1;return g<1?(e=a.year()-1,d=g+wa(e,b,c)):g>wa(a.year(),b,c)?(d=g-wa(a.year(),b,c),e=a.year()+1):(e=a.year(),d=g),{week:d,year:e}}function wa(a,b,c){var d=ta(a,b,c),e=ta(a+1,b,c);return(oa(a)-d+e)/7} +// HELPERS +// LOCALES +function xa(a){return va(a,this._week.dow,this._week.doy).week}function ya(){return this._week.dow}function za(){return this._week.doy} +// MOMENTS +function Aa(a){var b=this.localeData().week(this);return null==a?b:this.add(7*(a-b),"d")}function Ba(a){var b=va(this,1,4).week;return null==a?b:this.add(7*(a-b),"d")} +// HELPERS +function Ca(a,b){return"string"!=typeof a?a:isNaN(a)?(a=b.weekdaysParse(a),"number"==typeof a?a:null):parseInt(a,10)}function Da(a,b){return"string"==typeof a?b.weekdaysParse(a)%7||7:isNaN(a)?null:a}function Ea(a,b){return a?c(this._weekdays)?this._weekdays[a.day()]:this._weekdays[this._weekdays.isFormat.test(b)?"format":"standalone"][a.day()]:this._weekdays}function Fa(a){return a?this._weekdaysShort[a.day()]:this._weekdaysShort}function Ga(a){return a?this._weekdaysMin[a.day()]:this._weekdaysMin}function Ha(a,b,c){var d,e,f,g=a.toLocaleLowerCase();if(!this._weekdaysParse)for(this._weekdaysParse=[],this._shortWeekdaysParse=[],this._minWeekdaysParse=[],d=0;d<7;++d)f=j([2e3,1]).day(d),this._minWeekdaysParse[d]=this.weekdaysMin(f,"").toLocaleLowerCase(),this._shortWeekdaysParse[d]=this.weekdaysShort(f,"").toLocaleLowerCase(),this._weekdaysParse[d]=this.weekdays(f,"").toLocaleLowerCase();return c?"dddd"===b?(e=sd.call(this._weekdaysParse,g),e!==-1?e:null):"ddd"===b?(e=sd.call(this._shortWeekdaysParse,g),e!==-1?e:null):(e=sd.call(this._minWeekdaysParse,g),e!==-1?e:null):"dddd"===b?(e=sd.call(this._weekdaysParse,g),e!==-1?e:(e=sd.call(this._shortWeekdaysParse,g),e!==-1?e:(e=sd.call(this._minWeekdaysParse,g),e!==-1?e:null))):"ddd"===b?(e=sd.call(this._shortWeekdaysParse,g),e!==-1?e:(e=sd.call(this._weekdaysParse,g),e!==-1?e:(e=sd.call(this._minWeekdaysParse,g),e!==-1?e:null))):(e=sd.call(this._minWeekdaysParse,g),e!==-1?e:(e=sd.call(this._weekdaysParse,g),e!==-1?e:(e=sd.call(this._shortWeekdaysParse,g),e!==-1?e:null)))}function Ia(a,b,c){var d,e,f;if(this._weekdaysParseExact)return Ha.call(this,a,b,c);for(this._weekdaysParse||(this._weekdaysParse=[],this._minWeekdaysParse=[],this._shortWeekdaysParse=[],this._fullWeekdaysParse=[]),d=0;d<7;d++){ +// test the regex +if( +// make the regex if we don't have it already +e=j([2e3,1]).day(d),c&&!this._fullWeekdaysParse[d]&&(this._fullWeekdaysParse[d]=new RegExp("^"+this.weekdays(e,"").replace(".",".?")+"$","i"),this._shortWeekdaysParse[d]=new RegExp("^"+this.weekdaysShort(e,"").replace(".",".?")+"$","i"),this._minWeekdaysParse[d]=new RegExp("^"+this.weekdaysMin(e,"").replace(".",".?")+"$","i")),this._weekdaysParse[d]||(f="^"+this.weekdays(e,"")+"|^"+this.weekdaysShort(e,"")+"|^"+this.weekdaysMin(e,""),this._weekdaysParse[d]=new RegExp(f.replace(".",""),"i")),c&&"dddd"===b&&this._fullWeekdaysParse[d].test(a))return d;if(c&&"ddd"===b&&this._shortWeekdaysParse[d].test(a))return d;if(c&&"dd"===b&&this._minWeekdaysParse[d].test(a))return d;if(!c&&this._weekdaysParse[d].test(a))return d}} +// MOMENTS +function Ja(a){if(!this.isValid())return null!=a?this:NaN;var b=this._isUTC?this._d.getUTCDay():this._d.getDay();return null!=a?(a=Ca(a,this.localeData()),this.add(a-b,"d")):b}function Ka(a){if(!this.isValid())return null!=a?this:NaN;var b=(this.day()+7-this.localeData()._week.dow)%7;return null==a?b:this.add(a-b,"d")}function La(a){if(!this.isValid())return null!=a?this:NaN; +// behaves the same as moment#day except +// as a getter, returns 7 instead of 0 (1-7 range instead of 0-6) +// as a setter, sunday should belong to the previous week. +if(null!=a){var b=Da(a,this.localeData());return this.day(this.day()%7?b:b-7)}return this.day()||7}function Ma(a){return this._weekdaysParseExact?(h(this,"_weekdaysRegex")||Pa.call(this),a?this._weekdaysStrictRegex:this._weekdaysRegex):(h(this,"_weekdaysRegex")||(this._weekdaysRegex=pe),this._weekdaysStrictRegex&&a?this._weekdaysStrictRegex:this._weekdaysRegex)}function Na(a){return this._weekdaysParseExact?(h(this,"_weekdaysRegex")||Pa.call(this),a?this._weekdaysShortStrictRegex:this._weekdaysShortRegex):(h(this,"_weekdaysShortRegex")||(this._weekdaysShortRegex=qe),this._weekdaysShortStrictRegex&&a?this._weekdaysShortStrictRegex:this._weekdaysShortRegex)}function Oa(a){return this._weekdaysParseExact?(h(this,"_weekdaysRegex")||Pa.call(this),a?this._weekdaysMinStrictRegex:this._weekdaysMinRegex):(h(this,"_weekdaysMinRegex")||(this._weekdaysMinRegex=re),this._weekdaysMinStrictRegex&&a?this._weekdaysMinStrictRegex:this._weekdaysMinRegex)}function Pa(){function a(a,b){return b.length-a.length}var b,c,d,e,f,g=[],h=[],i=[],k=[];for(b=0;b<7;b++) +// make the regex if we don't have it already +c=j([2e3,1]).day(b),d=this.weekdaysMin(c,""),e=this.weekdaysShort(c,""),f=this.weekdays(c,""),g.push(d),h.push(e),i.push(f),k.push(d),k.push(e),k.push(f);for( +// Sorting makes sure if one weekday (or abbr) is a prefix of another it +// will match the longer piece. +g.sort(a),h.sort(a),i.sort(a),k.sort(a),b=0;b<7;b++)h[b]=_(h[b]),i[b]=_(i[b]),k[b]=_(k[b]);this._weekdaysRegex=new RegExp("^("+k.join("|")+")","i"),this._weekdaysShortRegex=this._weekdaysRegex,this._weekdaysMinRegex=this._weekdaysRegex,this._weekdaysStrictRegex=new RegExp("^("+i.join("|")+")","i"),this._weekdaysShortStrictRegex=new RegExp("^("+h.join("|")+")","i"),this._weekdaysMinStrictRegex=new RegExp("^("+g.join("|")+")","i")} +// FORMATTING +function Qa(){return this.hours()%12||12}function Ra(){return this.hours()||24}function Sa(a,b){T(a,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),b)})} +// PARSING +function Ta(a,b){return b._meridiemParse} +// LOCALES +function Ua(a){ +// IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays +// Using charAt should be more compatible. +return"p"===(a+"").toLowerCase().charAt(0)}function Va(a,b,c){return a>11?c?"pm":"PM":c?"am":"AM"}function Wa(a){return a?a.toLowerCase().replace("_","-"):a} +// pick the locale from the array +// try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each +// substring from most specific to least, but move to the next array item if it's a more specific variant than the current root +function Xa(a){for(var b,c,d,e,f=0;f0;){if(d=Ya(e.slice(0,b).join("-")))return d;if(c&&c.length>=b&&u(e,c,!0)>=b-1) +//the next array item is better than a shallower substring of this one +break;b--}f++}return null}function Ya(a){var b=null; +// TODO: Find a better way to register and load all the locales in Node +if(!we[a]&&"undefined"!=typeof module&&module&&module.exports)try{b=se._abbr,require("./locale/"+a), +// because defineLocale currently also sets the global locale, we +// want to undo that for lazy loaded locales +Za(b)}catch(a){}return we[a]} +// This function will load locale and then set the global locale. If +// no arguments are passed in, it will simply return the current global +// locale key. +function Za(a,b){var c; +// moment.duration._locale = moment._locale = data; +return a&&(c=o(b)?ab(a):$a(a,b),c&&(se=c)),se._abbr}function $a(a,b){if(null!==b){var c=ve; +// treat as if there is no base config +// backwards compat for now: also set the locale +return b.abbr=a,null!=we[a]?(x("defineLocaleOverride","use moment.updateLocale(localeName, config) to change an existing locale. moment.defineLocale(localeName, config) should only be used for creating a new locale See http://momentjs.com/guides/#/warnings/define-locale/ for more info."),c=we[a]._config):null!=b.parentLocale&&(null!=we[b.parentLocale]?c=we[b.parentLocale]._config:x("parentLocaleUndefined","specified parentLocale is not defined yet. See http://momentjs.com/guides/#/warnings/parent-locale/")),we[a]=new B(A(c,b)),Za(a),we[a]} +// useful for testing +return delete we[a],null}function _a(a,b){if(null!=b){var c,d=ve; +// MERGE +null!=we[a]&&(d=we[a]._config),b=A(d,b),c=new B(b),c.parentLocale=we[a],we[a]=c, +// backwards compat for now: also set the locale +Za(a)}else +// pass null for config to unupdate, useful for tests +null!=we[a]&&(null!=we[a].parentLocale?we[a]=we[a].parentLocale:null!=we[a]&&delete we[a]);return we[a]} +// returns locale data +function ab(a){var b;if(a&&a._locale&&a._locale._abbr&&(a=a._locale._abbr),!a)return se;if(!c(a)){if( +//short-circuit everything else +b=Ya(a))return b;a=[a]}return Xa(a)}function bb(){return rd(we)}function cb(a){var b,c=a._a;return c&&l(a).overflow===-2&&(b=c[Zd]<0||c[Zd]>11?Zd:c[$d]<1||c[$d]>da(c[Yd],c[Zd])?$d:c[_d]<0||c[_d]>24||24===c[_d]&&(0!==c[ae]||0!==c[be]||0!==c[ce])?_d:c[ae]<0||c[ae]>59?ae:c[be]<0||c[be]>59?be:c[ce]<0||c[ce]>999?ce:-1,l(a)._overflowDayOfYear&&(b$d)&&(b=$d),l(a)._overflowWeeks&&b===-1&&(b=de),l(a)._overflowWeekday&&b===-1&&(b=ee),l(a).overflow=b),a} +// date from iso format +function db(a){var b,c,d,e,f,g,h=a._i,i=xe.exec(h)||ye.exec(h);if(i){for(l(a).iso=!0,b=0,c=Ae.length;boa(e)&&(l(a)._overflowDayOfYear=!0),c=sa(e,0,a._dayOfYear),a._a[Zd]=c.getUTCMonth(),a._a[$d]=c.getUTCDate()),b=0;b<3&&null==a._a[b];++b)a._a[b]=f[b]=d[b]; +// Zero out whatever was not defaulted, including time +for(;b<7;b++)a._a[b]=f[b]=null==a._a[b]?2===b?1:0:a._a[b]; +// Check for 24:00:00.000 +24===a._a[_d]&&0===a._a[ae]&&0===a._a[be]&&0===a._a[ce]&&(a._nextDay=!0,a._a[_d]=0),a._d=(a._useUTC?sa:ra).apply(null,f), +// Apply timezone offset from input. The actual utcOffset can be changed +// with parseZone. +null!=a._tzm&&a._d.setUTCMinutes(a._d.getUTCMinutes()-a._tzm),a._nextDay&&(a._a[_d]=24)}}function ib(a){var b,c,d,e,f,g,h,i;b=a._w,null!=b.GG||null!=b.W||null!=b.E?(f=1,g=4, +// TODO: We need to take the current isoWeekYear, but that depends on +// how we interpret now (local, utc, fixed offset). So create +// a now version of current config (take local/utc/offset flags, and +// create now). +c=fb(b.GG,a._a[Yd],va(rb(),1,4).year),d=fb(b.W,1),e=fb(b.E,1),(e<1||e>7)&&(i=!0)):(f=a._locale._week.dow,g=a._locale._week.doy,c=fb(b.gg,a._a[Yd],va(rb(),f,g).year),d=fb(b.w,1),null!=b.d?( +// weekday -- low day numbers are considered next week +e=b.d,(e<0||e>6)&&(i=!0)):null!=b.e?( +// local weekday -- counting starts from begining of week +e=b.e+f,(b.e<0||b.e>6)&&(i=!0)): +// default to begining of week +e=f),d<1||d>wa(c,f,g)?l(a)._overflowWeeks=!0:null!=i?l(a)._overflowWeekday=!0:(h=ua(c,d,e,f,g),a._a[Yd]=h.year,a._dayOfYear=h.dayOfYear)} +// date from string and format string +function jb(b){ +// TODO: Move this to another part of the creation flow to prevent circular deps +if(b._f===a.ISO_8601)return void db(b);b._a=[],l(b).empty=!0; +// This array is used to make a Date, either with `new Date` or `Date.UTC` +var c,d,e,f,g,h=""+b._i,i=h.length,j=0;for(e=X(b._f,b._locale).match(Bd)||[],c=0;c0&&l(b).unusedInput.push(g),h=h.slice(h.indexOf(d)+d.length),j+=d.length), +// don't parse if it's not a known token +Ed[f]?(d?l(b).empty=!1:l(b).unusedTokens.push(f),ca(f,d,b)):b._strict&&!d&&l(b).unusedTokens.push(f); +// add remaining unparsed input length to the string +l(b).charsLeftOver=i-j,h.length>0&&l(b).unusedInput.push(h), +// clear _12h flag if hour is <= 12 +b._a[_d]<=12&&l(b).bigHour===!0&&b._a[_d]>0&&(l(b).bigHour=void 0),l(b).parsedDateParts=b._a.slice(0),l(b).meridiem=b._meridiem, +// handle meridiem +b._a[_d]=kb(b._locale,b._a[_d],b._meridiem),hb(b),cb(b)}function kb(a,b,c){var d; +// Fallback +return null==c?b:null!=a.meridiemHour?a.meridiemHour(b,c):null!=a.isPM?(d=a.isPM(c),d&&b<12&&(b+=12),d||12!==b||(b=0),b):b} +// date from string and array of format strings +function lb(a){var b,c,d,e,f;if(0===a._f.length)return l(a).invalidFormat=!0,void(a._d=new Date(NaN));for(e=0;e +// 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset +// +0200, so we adjust the time as needed, to be valid. +// +// Keeping the time actually adds/subtracts (one hour) +// from the actual represented time. That is why we call updateOffset +// a second time. In case it wants us to change the offset again +// _changeInProgress == true case, then we have to adjust, because +// there is no such time in the given timezone. +function Cb(b,c){var d,e=this._offset||0;return this.isValid()?null!=b?("string"==typeof b?b=zb(Td,b):Math.abs(b)<16&&(b=60*b),!this._isUTC&&c&&(d=Bb(this)),this._offset=b,this._isUTC=!0,null!=d&&this.add(d,"m"),e!==b&&(!c||this._changeInProgress?Sb(this,Nb(b-e,"m"),1,!1):this._changeInProgress||(this._changeInProgress=!0,a.updateOffset(this,!0),this._changeInProgress=null)),this):this._isUTC?e:Bb(this):null!=b?this:NaN}function Db(a,b){return null!=a?("string"!=typeof a&&(a=-a),this.utcOffset(a,b),this):-this.utcOffset()}function Eb(a){return this.utcOffset(0,a)}function Fb(a){return this._isUTC&&(this.utcOffset(0,a),this._isUTC=!1,a&&this.subtract(Bb(this),"m")),this}function Gb(){if(this._tzm)this.utcOffset(this._tzm);else if("string"==typeof this._i){var a=zb(Sd,this._i);0===a?this.utcOffset(0,!0):this.utcOffset(zb(Sd,this._i))}return this}function Hb(a){return!!this.isValid()&&(a=a?rb(a).utcOffset():0,(this.utcOffset()-a)%60===0)}function Ib(){return this.utcOffset()>this.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()}function Jb(){if(!o(this._isDSTShifted))return this._isDSTShifted;var a={};if(p(a,this),a=ob(a),a._a){var b=a._isUTC?j(a._a):rb(a._a);this._isDSTShifted=this.isValid()&&u(a._a,b.toArray())>0}else this._isDSTShifted=!1;return this._isDSTShifted}function Kb(){return!!this.isValid()&&!this._isUTC}function Lb(){return!!this.isValid()&&this._isUTC}function Mb(){return!!this.isValid()&&(this._isUTC&&0===this._offset)}function Nb(a,b){var c,d,e,f=a, +// matching against regexp is expensive, do it on demand +g=null;// checks for null or undefined +return wb(a)?f={ms:a._milliseconds,d:a._days,M:a._months}:"number"==typeof a?(f={},b?f[b]=a:f.milliseconds=a):(g=He.exec(a))?(c="-"===g[1]?-1:1,f={y:0,d:t(g[$d])*c,h:t(g[_d])*c,m:t(g[ae])*c,s:t(g[be])*c,ms:t(xb(1e3*g[ce]))*c}):(g=Ie.exec(a))?(c="-"===g[1]?-1:1,f={y:Ob(g[2],c),M:Ob(g[3],c),w:Ob(g[4],c),d:Ob(g[5],c),h:Ob(g[6],c),m:Ob(g[7],c),s:Ob(g[8],c)}):null==f?f={}:"object"==typeof f&&("from"in f||"to"in f)&&(e=Qb(rb(f.from),rb(f.to)),f={},f.ms=e.milliseconds,f.M=e.months),d=new vb(f),wb(a)&&h(a,"_locale")&&(d._locale=a._locale),d}function Ob(a,b){ +// We'd normally use ~~inp for this, but unfortunately it also +// converts floats to ints. +// inp may be undefined, so careful calling replace on it. +var c=a&&parseFloat(a.replace(",",".")); +// apply sign while we're at it +return(isNaN(c)?0:c)*b}function Pb(a,b){var c={milliseconds:0,months:0};return c.months=b.month()-a.month()+12*(b.year()-a.year()),a.clone().add(c.months,"M").isAfter(b)&&--c.months,c.milliseconds=+b-+a.clone().add(c.months,"M"),c}function Qb(a,b){var c;return a.isValid()&&b.isValid()?(b=Ab(b,a),a.isBefore(b)?c=Pb(a,b):(c=Pb(b,a),c.milliseconds=-c.milliseconds,c.months=-c.months),c):{milliseconds:0,months:0}} +// TODO: remove 'name' arg after deprecation is removed +function Rb(a,b){return function(c,d){var e,f; +//invert the arguments, but complain about it +return null===d||isNaN(+d)||(x(b,"moment()."+b+"(period, number) is deprecated. Please use moment()."+b+"(number, period). See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info."),f=c,c=d,d=f),c="string"==typeof c?+c:c,e=Nb(c,d),Sb(this,e,a),this}}function Sb(b,c,d,e){var f=c._milliseconds,g=xb(c._days),h=xb(c._months);b.isValid()&&(e=null==e||e,f&&b._d.setTime(b._d.valueOf()+f*d),g&&P(b,"Date",O(b,"Date")+g*d),h&&ia(b,O(b,"Month")+h*d),e&&a.updateOffset(b,g||h))}function Tb(a,b){var c=a.diff(b,"days",!0);return c<-6?"sameElse":c<-1?"lastWeek":c<0?"lastDay":c<1?"sameDay":c<2?"nextDay":c<7?"nextWeek":"sameElse"}function Ub(b,c){ +// We want to compare the start of today, vs this. +// Getting start-of-today depends on whether we're local/utc/offset or not. +var d=b||rb(),e=Ab(d,this).startOf("day"),f=a.calendarFormat(this,e)||"sameElse",g=c&&(y(c[f])?c[f].call(this,d):c[f]);return this.format(g||this.localeData().calendar(f,this,rb(d)))}function Vb(){return new q(this)}function Wb(a,b){var c=r(a)?a:rb(a);return!(!this.isValid()||!c.isValid())&&(b=J(o(b)?"millisecond":b),"millisecond"===b?this.valueOf()>c.valueOf():c.valueOf()f&&(b=f),Dc.call(this,a,b,c,d,e))}function Dc(a,b,c,d,e){var f=ua(a,b,c,d,e),g=sa(f.year,0,f.dayOfYear);return this.year(g.getUTCFullYear()),this.month(g.getUTCMonth()),this.date(g.getUTCDate()),this} +// MOMENTS +function Ec(a){return null==a?Math.ceil((this.month()+1)/3):this.month(3*(a-1)+this.month()%3)} +// HELPERS +// MOMENTS +function Fc(a){var b=Math.round((this.clone().startOf("day")-this.clone().startOf("year"))/864e5)+1;return null==a?b:this.add(a-b,"d")}function Gc(a,b){b[ce]=t(1e3*("0."+a))} +// MOMENTS +function Hc(){return this._isUTC?"UTC":""}function Ic(){return this._isUTC?"Coordinated Universal Time":""}function Jc(a){return rb(1e3*a)}function Kc(){return rb.apply(null,arguments).parseZone()}function Lc(a){return a}function Mc(a,b,c,d){var e=ab(),f=j().set(d,b);return e[c](f,a)}function Nc(a,b,c){if("number"==typeof a&&(b=a,a=void 0),a=a||"",null!=b)return Mc(a,b,c,"month");var d,e=[];for(d=0;d<12;d++)e[d]=Mc(a,d,c,"month");return e} +// () +// (5) +// (fmt, 5) +// (fmt) +// (true) +// (true, 5) +// (true, fmt, 5) +// (true, fmt) +function Oc(a,b,c,d){"boolean"==typeof a?("number"==typeof b&&(c=b,b=void 0),b=b||""):(b=a,c=b,a=!1,"number"==typeof b&&(c=b,b=void 0),b=b||"");var e=ab(),f=a?e._week.dow:0;if(null!=c)return Mc(b,(c+f)%7,d,"day");var g,h=[];for(g=0;g<7;g++)h[g]=Mc(b,(g+f)%7,d,"day");return h}function Pc(a,b){return Nc(a,b,"months")}function Qc(a,b){return Nc(a,b,"monthsShort")}function Rc(a,b,c){return Oc(a,b,c,"weekdays")}function Sc(a,b,c){return Oc(a,b,c,"weekdaysShort")}function Tc(a,b,c){return Oc(a,b,c,"weekdaysMin")}function Uc(){var a=this._data;return this._milliseconds=Ue(this._milliseconds),this._days=Ue(this._days),this._months=Ue(this._months),a.milliseconds=Ue(a.milliseconds),a.seconds=Ue(a.seconds),a.minutes=Ue(a.minutes),a.hours=Ue(a.hours),a.months=Ue(a.months),a.years=Ue(a.years),this}function Vc(a,b,c,d){var e=Nb(b,c);return a._milliseconds+=d*e._milliseconds,a._days+=d*e._days,a._months+=d*e._months,a._bubble()} +// supports only 2.0-style add(1, 's') or add(duration) +function Wc(a,b){return Vc(this,a,b,1)} +// supports only 2.0-style subtract(1, 's') or subtract(duration) +function Xc(a,b){return Vc(this,a,b,-1)}function Yc(a){return a<0?Math.floor(a):Math.ceil(a)}function Zc(){var a,b,c,d,e,f=this._milliseconds,g=this._days,h=this._months,i=this._data; +// if we have a mix of positive and negative values, bubble down first +// check: https://github.com/moment/moment/issues/2166 +// The following code bubbles up values, see the tests for +// examples of what that means. +// convert days to months +// 12 months -> 1 year +return f>=0&&g>=0&&h>=0||f<=0&&g<=0&&h<=0||(f+=864e5*Yc(_c(h)+g),g=0,h=0),i.milliseconds=f%1e3,a=s(f/1e3),i.seconds=a%60,b=s(a/60),i.minutes=b%60,c=s(b/60),i.hours=c%24,g+=s(c/24),e=s($c(g)),h+=e,g-=Yc(_c(e)),d=s(h/12),h%=12,i.days=g,i.months=h,i.years=d,this}function $c(a){ +// 400 years have 146097 days (taking into account leap year rules) +// 400 years have 12 months === 4800 +return 4800*a/146097}function _c(a){ +// the reverse of daysToMonths +return 146097*a/4800}function ad(a){var b,c,d=this._milliseconds;if(a=J(a),"month"===a||"year"===a)return b=this._days+d/864e5,c=this._months+$c(b),"month"===a?c:c/12;switch( +// handle milliseconds separately because of floating point math errors (issue #1867) +b=this._days+Math.round(_c(this._months)),a){case"week":return b/7+d/6048e5;case"day":return b+d/864e5;case"hour":return 24*b+d/36e5;case"minute":return 1440*b+d/6e4;case"second":return 86400*b+d/1e3; +// Math.floor prevents floating point math errors here +case"millisecond":return Math.floor(864e5*b)+d;default:throw new Error("Unknown unit "+a)}} +// TODO: Use this.as('ms')? +function bd(){return this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*t(this._months/12)}function cd(a){return function(){return this.as(a)}}function dd(a){return a=J(a),this[a+"s"]()}function ed(a){return function(){return this._data[a]}}function fd(){return s(this.days()/7)} +// helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize +function gd(a,b,c,d,e){return e.relativeTime(b||1,!!c,a,d)}function hd(a,b,c){var d=Nb(a).abs(),e=jf(d.as("s")),f=jf(d.as("m")),g=jf(d.as("h")),h=jf(d.as("d")),i=jf(d.as("M")),j=jf(d.as("y")),k=e0,k[4]=c,gd.apply(null,k)} +// This function allows you to set the rounding function for relative time strings +function id(a){return void 0===a?jf:"function"==typeof a&&(jf=a,!0)} +// This function allows you to set a threshold for relative time strings +function jd(a,b){return void 0!==kf[a]&&(void 0===b?kf[a]:(kf[a]=b,!0))}function kd(a){var b=this.localeData(),c=hd(this,!a,b);return a&&(c=b.pastFuture(+this,c)),b.postformat(c)}function ld(){ +// for ISO strings we do not use the normal bubbling rules: +// * milliseconds bubble up until they become hours +// * days do not bubble at all +// * months bubble up until they become years +// This is because there is no context-free conversion between hours and days +// (think of clock changes) +// and also not between days and months (28-31 days per month) +var a,b,c,d=lf(this._milliseconds)/1e3,e=lf(this._days),f=lf(this._months); +// 3600 seconds -> 60 minutes -> 1 hour +a=s(d/60),b=s(a/60),d%=60,a%=60, +// 12 months -> 1 year +c=s(f/12),f%=12; +// inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js +var g=c,h=f,i=e,j=b,k=a,l=d,m=this.asSeconds();return m?(m<0?"-":"")+"P"+(g?g+"Y":"")+(h?h+"M":"")+(i?i+"D":"")+(j||k||l?"T":"")+(j?j+"H":"")+(k?k+"M":"")+(l?l+"S":""):"P0D"}var md,nd;nd=Array.prototype.some?Array.prototype.some:function(a){for(var b=Object(this),c=b.length>>>0,d=0;d68?1900:2e3)}; +// MOMENTS +var ke=N("FullYear",!0); +// FORMATTING +T("w",["ww",2],"wo","week"),T("W",["WW",2],"Wo","isoWeek"), +// ALIASES +I("week","w"),I("isoWeek","W"), +// PRIORITIES +L("week",5),L("isoWeek",5), +// PARSING +Y("w",Kd),Y("ww",Kd,Gd),Y("W",Kd),Y("WW",Kd,Gd),ba(["w","ww","W","WW"],function(a,b,c,d){b[d.substr(0,1)]=t(a)});var le={dow:0,// Sunday is the first day of the week. +doy:6}; +// FORMATTING +T("d",0,"do","day"),T("dd",0,0,function(a){return this.localeData().weekdaysMin(this,a)}),T("ddd",0,0,function(a){return this.localeData().weekdaysShort(this,a)}),T("dddd",0,0,function(a){return this.localeData().weekdays(this,a)}),T("e",0,0,"weekday"),T("E",0,0,"isoWeekday"), +// ALIASES +I("day","d"),I("weekday","e"),I("isoWeekday","E"), +// PRIORITY +L("day",11),L("weekday",11),L("isoWeekday",11), +// PARSING +Y("d",Kd),Y("e",Kd),Y("E",Kd),Y("dd",function(a,b){return b.weekdaysMinRegex(a)}),Y("ddd",function(a,b){return b.weekdaysShortRegex(a)}),Y("dddd",function(a,b){return b.weekdaysRegex(a)}),ba(["dd","ddd","dddd"],function(a,b,c,d){var e=c._locale.weekdaysParse(a,d,c._strict); +// if we didn't get a weekday name, mark the date as invalid +null!=e?b.d=e:l(c).invalidWeekday=a}),ba(["d","e","E"],function(a,b,c,d){b[d]=t(a)}); +// LOCALES +var me="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),ne="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),oe="Su_Mo_Tu_We_Th_Fr_Sa".split("_"),pe=Vd,qe=Vd,re=Vd;T("H",["HH",2],0,"hour"),T("h",["hh",2],0,Qa),T("k",["kk",2],0,Ra),T("hmm",0,0,function(){return""+Qa.apply(this)+S(this.minutes(),2)}),T("hmmss",0,0,function(){return""+Qa.apply(this)+S(this.minutes(),2)+S(this.seconds(),2)}),T("Hmm",0,0,function(){return""+this.hours()+S(this.minutes(),2)}),T("Hmmss",0,0,function(){return""+this.hours()+S(this.minutes(),2)+S(this.seconds(),2)}),Sa("a",!0),Sa("A",!1), +// ALIASES +I("hour","h"), +// PRIORITY +L("hour",13),Y("a",Ta),Y("A",Ta),Y("H",Kd),Y("h",Kd),Y("HH",Kd,Gd),Y("hh",Kd,Gd),Y("hmm",Ld),Y("hmmss",Md),Y("Hmm",Ld),Y("Hmmss",Md),aa(["H","HH"],_d),aa(["a","A"],function(a,b,c){c._isPm=c._locale.isPM(a),c._meridiem=a}),aa(["h","hh"],function(a,b,c){b[_d]=t(a),l(c).bigHour=!0}),aa("hmm",function(a,b,c){var d=a.length-2;b[_d]=t(a.substr(0,d)),b[ae]=t(a.substr(d)),l(c).bigHour=!0}),aa("hmmss",function(a,b,c){var d=a.length-4,e=a.length-2;b[_d]=t(a.substr(0,d)),b[ae]=t(a.substr(d,2)),b[be]=t(a.substr(e)),l(c).bigHour=!0}),aa("Hmm",function(a,b,c){var d=a.length-2;b[_d]=t(a.substr(0,d)),b[ae]=t(a.substr(d))}),aa("Hmmss",function(a,b,c){var d=a.length-4,e=a.length-2;b[_d]=t(a.substr(0,d)),b[ae]=t(a.substr(d,2)),b[be]=t(a.substr(e))});var se,te=/[ap]\.?m?\.?/i,ue=N("Hours",!0),ve={calendar:td,longDateFormat:ud,invalidDate:vd,ordinal:wd,ordinalParse:xd,relativeTime:yd,months:ge,monthsShort:he,week:le,weekdays:me,weekdaysMin:oe,weekdaysShort:ne,meridiemParse:te},we={},xe=/^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?/,ye=/^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?/,ze=/Z|[+-]\d\d(?::?\d\d)?/,Ae=[["YYYYYY-MM-DD",/[+-]\d{6}-\d\d-\d\d/],["YYYY-MM-DD",/\d{4}-\d\d-\d\d/],["GGGG-[W]WW-E",/\d{4}-W\d\d-\d/],["GGGG-[W]WW",/\d{4}-W\d\d/,!1],["YYYY-DDD",/\d{4}-\d{3}/],["YYYY-MM",/\d{4}-\d\d/,!1],["YYYYYYMMDD",/[+-]\d{10}/],["YYYYMMDD",/\d{8}/], +// YYYYMM is NOT allowed by the standard +["GGGG[W]WWE",/\d{4}W\d{3}/],["GGGG[W]WW",/\d{4}W\d{2}/,!1],["YYYYDDD",/\d{7}/]],Be=[["HH:mm:ss.SSSS",/\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss,SSSS",/\d\d:\d\d:\d\d,\d+/],["HH:mm:ss",/\d\d:\d\d:\d\d/],["HH:mm",/\d\d:\d\d/],["HHmmss.SSSS",/\d\d\d\d\d\d\.\d+/],["HHmmss,SSSS",/\d\d\d\d\d\d,\d+/],["HHmmss",/\d\d\d\d\d\d/],["HHmm",/\d\d\d\d/],["HH",/\d\d/]],Ce=/^\/?Date\((\-?\d+)/i;a.createFromInputFallback=w("value provided is not in a recognized ISO format. moment construction falls back to js Date(), which is not reliable across all browsers and versions. Non ISO date formats are discouraged and will be removed in an upcoming major release. Please refer to http://momentjs.com/guides/#/warnings/js-date/ for more info.",function(a){a._d=new Date(a._i+(a._useUTC?" UTC":""))}), +// constant that refers to the ISO standard +a.ISO_8601=function(){};var De=w("moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/",function(){var a=rb.apply(null,arguments);return this.isValid()&&a.isValid()?athis?this:a:n()}),Fe=function(){return Date.now?Date.now():+new Date};yb("Z",":"),yb("ZZ",""), +// PARSING +Y("Z",Td),Y("ZZ",Td),aa(["Z","ZZ"],function(a,b,c){c._useUTC=!0,c._tzm=zb(Td,a)}); +// HELPERS +// timezone chunker +// '+10:00' > ['10', '00'] +// '-1530' > ['-15', '30'] +var Ge=/([\+\-]|\d\d)/gi; +// HOOKS +// This function will be called whenever a moment is mutated. +// It is intended to keep the offset in sync with the timezone. +a.updateOffset=function(){}; +// ASP.NET json date format regex +var He=/^(\-)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)(\.\d*)?)?$/,Ie=/^(-)?P(?:(-?[0-9,.]*)Y)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)W)?(?:(-?[0-9,.]*)D)?(?:T(?:(-?[0-9,.]*)H)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)S)?)?$/;Nb.fn=vb.prototype;var Je=Rb(1,"add"),Ke=Rb(-1,"subtract");a.defaultFormat="YYYY-MM-DDTHH:mm:ssZ",a.defaultFormatUtc="YYYY-MM-DDTHH:mm:ss[Z]";var Le=w("moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.",function(a){return void 0===a?this.localeData():this.locale(a)}); +// FORMATTING +T(0,["gg",2],0,function(){return this.weekYear()%100}),T(0,["GG",2],0,function(){return this.isoWeekYear()%100}),xc("gggg","weekYear"),xc("ggggg","weekYear"),xc("GGGG","isoWeekYear"),xc("GGGGG","isoWeekYear"), +// ALIASES +I("weekYear","gg"),I("isoWeekYear","GG"), +// PRIORITY +L("weekYear",1),L("isoWeekYear",1), +// PARSING +Y("G",Rd),Y("g",Rd),Y("GG",Kd,Gd),Y("gg",Kd,Gd),Y("GGGG",Od,Id),Y("gggg",Od,Id),Y("GGGGG",Pd,Jd),Y("ggggg",Pd,Jd),ba(["gggg","ggggg","GGGG","GGGGG"],function(a,b,c,d){b[d.substr(0,2)]=t(a)}),ba(["gg","GG"],function(b,c,d,e){c[e]=a.parseTwoDigitYear(b)}), +// FORMATTING +T("Q",0,"Qo","quarter"), +// ALIASES +I("quarter","Q"), +// PRIORITY +L("quarter",7), +// PARSING +Y("Q",Fd),aa("Q",function(a,b){b[Zd]=3*(t(a)-1)}), +// FORMATTING +T("D",["DD",2],"Do","date"), +// ALIASES +I("date","D"), +// PRIOROITY +L("date",9), +// PARSING +Y("D",Kd),Y("DD",Kd,Gd),Y("Do",function(a,b){return a?b._ordinalParse:b._ordinalParseLenient}),aa(["D","DD"],$d),aa("Do",function(a,b){b[$d]=t(a.match(Kd)[0],10)}); +// MOMENTS +var Me=N("Date",!0); +// FORMATTING +T("DDD",["DDDD",3],"DDDo","dayOfYear"), +// ALIASES +I("dayOfYear","DDD"), +// PRIORITY +L("dayOfYear",4), +// PARSING +Y("DDD",Nd),Y("DDDD",Hd),aa(["DDD","DDDD"],function(a,b,c){c._dayOfYear=t(a)}), +// FORMATTING +T("m",["mm",2],0,"minute"), +// ALIASES +I("minute","m"), +// PRIORITY +L("minute",14), +// PARSING +Y("m",Kd),Y("mm",Kd,Gd),aa(["m","mm"],ae); +// MOMENTS +var Ne=N("Minutes",!1); +// FORMATTING +T("s",["ss",2],0,"second"), +// ALIASES +I("second","s"), +// PRIORITY +L("second",15), +// PARSING +Y("s",Kd),Y("ss",Kd,Gd),aa(["s","ss"],be); +// MOMENTS +var Oe=N("Seconds",!1); +// FORMATTING +T("S",0,0,function(){return~~(this.millisecond()/100)}),T(0,["SS",2],0,function(){return~~(this.millisecond()/10)}),T(0,["SSS",3],0,"millisecond"),T(0,["SSSS",4],0,function(){return 10*this.millisecond()}),T(0,["SSSSS",5],0,function(){return 100*this.millisecond()}),T(0,["SSSSSS",6],0,function(){return 1e3*this.millisecond()}),T(0,["SSSSSSS",7],0,function(){return 1e4*this.millisecond()}),T(0,["SSSSSSSS",8],0,function(){return 1e5*this.millisecond()}),T(0,["SSSSSSSSS",9],0,function(){return 1e6*this.millisecond()}), +// ALIASES +I("millisecond","ms"), +// PRIORITY +L("millisecond",16), +// PARSING +Y("S",Nd,Fd),Y("SS",Nd,Gd),Y("SSS",Nd,Hd);var Pe;for(Pe="SSSS";Pe.length<=9;Pe+="S")Y(Pe,Qd);for(Pe="S";Pe.length<=9;Pe+="S")aa(Pe,Gc); +// MOMENTS +var Qe=N("Milliseconds",!1); +// FORMATTING +T("z",0,0,"zoneAbbr"),T("zz",0,0,"zoneName");var Re=q.prototype;Re.add=Je,Re.calendar=Ub,Re.clone=Vb,Re.diff=ac,Re.endOf=mc,Re.format=ec,Re.from=fc,Re.fromNow=gc,Re.to=hc,Re.toNow=ic,Re.get=Q,Re.invalidAt=vc,Re.isAfter=Wb,Re.isBefore=Xb,Re.isBetween=Yb,Re.isSame=Zb,Re.isSameOrAfter=$b,Re.isSameOrBefore=_b,Re.isValid=tc,Re.lang=Le,Re.locale=jc,Re.localeData=kc,Re.max=Ee,Re.min=De,Re.parsingFlags=uc,Re.set=R,Re.startOf=lc,Re.subtract=Ke,Re.toArray=qc,Re.toObject=rc,Re.toDate=pc,Re.toISOString=dc,Re.toJSON=sc,Re.toString=cc,Re.unix=oc,Re.valueOf=nc,Re.creationData=wc, +// Year +Re.year=ke,Re.isLeapYear=qa, +// Week Year +Re.weekYear=yc,Re.isoWeekYear=zc, +// Quarter +Re.quarter=Re.quarters=Ec, +// Month +Re.month=ja,Re.daysInMonth=ka, +// Week +Re.week=Re.weeks=Aa,Re.isoWeek=Re.isoWeeks=Ba,Re.weeksInYear=Bc,Re.isoWeeksInYear=Ac, +// Day +Re.date=Me,Re.day=Re.days=Ja,Re.weekday=Ka,Re.isoWeekday=La,Re.dayOfYear=Fc, +// Hour +Re.hour=Re.hours=ue, +// Minute +Re.minute=Re.minutes=Ne, +// Second +Re.second=Re.seconds=Oe, +// Millisecond +Re.millisecond=Re.milliseconds=Qe, +// Offset +Re.utcOffset=Cb,Re.utc=Eb,Re.local=Fb,Re.parseZone=Gb,Re.hasAlignedHourOffset=Hb,Re.isDST=Ib,Re.isLocal=Kb,Re.isUtcOffset=Lb,Re.isUtc=Mb,Re.isUTC=Mb, +// Timezone +Re.zoneAbbr=Hc,Re.zoneName=Ic, +// Deprecations +Re.dates=w("dates accessor is deprecated. Use date instead.",Me),Re.months=w("months accessor is deprecated. Use month instead",ja),Re.years=w("years accessor is deprecated. Use year instead",ke),Re.zone=w("moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/",Db),Re.isDSTShifted=w("isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information",Jb);var Se=Re,Te=B.prototype;Te.calendar=C,Te.longDateFormat=D,Te.invalidDate=E,Te.ordinal=F,Te.preparse=Lc,Te.postformat=Lc,Te.relativeTime=G,Te.pastFuture=H,Te.set=z, +// Month +Te.months=ea,Te.monthsShort=fa,Te.monthsParse=ha,Te.monthsRegex=ma,Te.monthsShortRegex=la, +// Week +Te.week=xa,Te.firstDayOfYear=za,Te.firstDayOfWeek=ya, +// Day of Week +Te.weekdays=Ea,Te.weekdaysMin=Ga,Te.weekdaysShort=Fa,Te.weekdaysParse=Ia,Te.weekdaysRegex=Ma,Te.weekdaysShortRegex=Na,Te.weekdaysMinRegex=Oa, +// Hours +Te.isPM=Ua,Te.meridiem=Va,Za("en",{ordinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(a){var b=a%10,c=1===t(a%100/10)?"th":1===b?"st":2===b?"nd":3===b?"rd":"th";return a+c}}), +// Side effect imports +a.lang=w("moment.lang is deprecated. Use moment.locale instead.",Za),a.langData=w("moment.langData is deprecated. Use moment.localeData instead.",ab);var Ue=Math.abs,Ve=cd("ms"),We=cd("s"),Xe=cd("m"),Ye=cd("h"),Ze=cd("d"),$e=cd("w"),_e=cd("M"),af=cd("y"),bf=ed("milliseconds"),cf=ed("seconds"),df=ed("minutes"),ef=ed("hours"),ff=ed("days"),gf=ed("months"),hf=ed("years"),jf=Math.round,kf={s:45,// seconds to minute +m:45,// minutes to hour +h:22,// hours to day +d:26,// days to month +M:11},lf=Math.abs,mf=vb.prototype;mf.abs=Uc,mf.add=Wc,mf.subtract=Xc,mf.as=ad,mf.asMilliseconds=Ve,mf.asSeconds=We,mf.asMinutes=Xe,mf.asHours=Ye,mf.asDays=Ze,mf.asWeeks=$e,mf.asMonths=_e,mf.asYears=af,mf.valueOf=bd,mf._bubble=Zc,mf.get=dd,mf.milliseconds=bf,mf.seconds=cf,mf.minutes=df,mf.hours=ef,mf.days=ff,mf.weeks=fd,mf.months=gf,mf.years=hf,mf.humanize=kd,mf.toISOString=ld,mf.toString=ld,mf.toJSON=ld,mf.locale=jc,mf.localeData=kc, +// Deprecations +mf.toIsoString=w("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",ld),mf.lang=Le, +// Side effect imports +// FORMATTING +T("X",0,0,"unix"),T("x",0,0,"valueOf"), +// PARSING +Y("x",Rd),Y("X",Ud),aa("X",function(a,b,c){c._d=new Date(1e3*parseFloat(a,10))}),aa("x",function(a,b,c){c._d=new Date(t(a))}), +// Side effect imports +a.version="2.15.2",b(rb),a.fn=Se,a.min=tb,a.max=ub,a.now=Fe,a.utc=j,a.unix=Jc,a.months=Pc,a.isDate=f,a.locale=Za,a.invalid=n,a.duration=Nb,a.isMoment=r,a.weekdays=Rc,a.parseZone=Kc,a.localeData=ab,a.isDuration=wb,a.monthsShort=Qc,a.weekdaysMin=Tc,a.defineLocale=$a,a.updateLocale=_a,a.locales=bb,a.weekdaysShort=Sc,a.normalizeUnits=J,a.relativeTimeRounding=id,a.relativeTimeThreshold=jd,a.calendarFormat=Tb,a.prototype=Se;var nf=a;return nf}); \ No newline at end of file diff --git a/main.go b/main.go index 31f600f..19618e3 100644 --- a/main.go +++ b/main.go @@ -185,6 +185,7 @@ func runHTTPServer(address string) { adminRouter.HandleFunc("/candidate/{id}", candidate.Edit).Methods("PUT", "OPTIONS") adminRouter.HandleFunc("/candidate/{id}", candidate.Get).Methods("GET", "OPTIONS") adminRouter.HandleFunc("/candidate/report/{id}", report.Report).Methods("GET", "OPTIONS") + adminRouter.HandleFunc("/candidate/invite/{id}", candidate.ResendInvite).Methods("POST", "OPTIONS") adminRouter.HandleFunc("/candidates", candidate.Index).Methods("GET", "OPTIONS") n := negroni.Classic() diff --git a/quiz/quiz.go b/quiz/quiz.go index 4f626ab..9691ea3 100644 --- a/quiz/quiz.go +++ b/quiz/quiz.go @@ -152,6 +152,7 @@ type cand struct { Token string `json:"token"` Validity string `json:"validity"` Complete bool `json:"complete,string"` + Cancel bool `json:"cancel,string"` Quiz []quiz `json:"candidate.quiz"` Questions []qids `json:"candidate.question"` QuizStart time.Time `json:"quiz_start"` @@ -227,6 +228,7 @@ func candQuery(cid string) string { token validity complete + cancel quiz_start candidate.quiz { _uid_ @@ -270,7 +272,9 @@ func checkAndUpdate(uid string) (int, error) { quiz := cand.Quiz[0] if cand.Complete { return http.StatusUnauthorized, fmt.Errorf("You have already completed the quiz.") - + } + if cand.Cancel { + return http.StatusUnauthorized, fmt.Errorf("Your token isn't valid anymore. Please mail us at contact@dgraph.io.") } if quiz.Id == "" { return http.StatusUnauthorized, fmt.Errorf("Invalid token.") From a08ae25c894b7c3b7f801e57fbb837667d9558c2 Mon Sep 17 00:00:00 2001 From: Pawan Rawal Date: Tue, 8 Nov 2016 16:53:55 +0530 Subject: [PATCH 2/6] Modal kind of works --- .../app/components/invite/inviteController.js | 21 ++++++++----- .../invite/views/invite-dashboard.html | 31 +++++++++---------- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/admin/webUI/app/components/invite/inviteController.js b/admin/webUI/app/components/invite/inviteController.js index 1b21a26..98280bf 100644 --- a/admin/webUI/app/components/invite/inviteController.js +++ b/admin/webUI/app/components/invite/inviteController.js @@ -261,6 +261,8 @@ candidatesVm.expires = expires; candidatesVm.cancel = cancel; candidatesVm.resend = resend; + candidatesVm.showModal = showModal; + candidatesVm.candidate_email = ""; candidatesVm.quizID = $stateParams.quizID; @@ -303,16 +305,19 @@ console.log(err); }); + function showModal(candidateID, email) { + console.log(email) + candidatesVm.candidate_email = email; + dialog.showModal(); + dialog.querySelector('.submit').addEventListener('click', function() { + candidatesVm.cancel(candidateID); + dialog.close(); + }) + } + angular.element(document).ready(function() { var dialog = document.querySelector('dialog'); - var $delete = $('.delete-cand'); - if (!dialog.showModal) { - dialogPolyfill.registerDialog(dialog); - } - $delete.on('click', function() { - console.log("here") - dialog.showModal(); - }); + dialog.querySelector('.close').addEventListener('click', function() { dialog.close(); }); diff --git a/admin/webUI/app/components/invite/views/invite-dashboard.html b/admin/webUI/app/components/invite/views/invite-dashboard.html index 35ad8ef..40fd664 100644 --- a/admin/webUI/app/components/invite/views/invite-dashboard.html +++ b/admin/webUI/app/components/invite/views/invite-dashboard.html @@ -44,7 +44,7 @@
Candidate List for Quiz
- + @@ -90,14 +90,14 @@
Candidate List for Quiz
- + @@ -106,17 +106,16 @@
Candidate List for Quiz
+ +

Cancel

+
+

+ Are you sure that you wan't to cancel the invite sent to {{candidateVm.candidate_email}}? +

+
+
+ + +
+
- -

Are you sure you wan't to delete candidate information for?

- -
- - -
-
From 68850abf9062280cd981d09c9abe70c64b444fa6 Mon Sep 17 00:00:00 2001 From: Rahul-Sagore Date: Wed, 9 Nov 2016 02:06:21 +0530 Subject: [PATCH 3/6] Add custom material design modal --- admin/webUI/app/app.module.js | 18 ++++++++++++++--- .../app/components/invite/inviteController.js | 20 ++++++++++++++++++- .../invite/views/invite-dashboard.html | 13 ++++++++++-- admin/webUI/assets/css/_utility.css | 7 ++++++- admin/webUI/assets/css/custom.css | 12 +++++++++++ admin/webUI/index.html | 15 +++++++------- 6 files changed, 71 insertions(+), 14 deletions(-) diff --git a/admin/webUI/app/app.module.js b/admin/webUI/app/app.module.js index a286780..8ae8f36 100644 --- a/admin/webUI/app/app.module.js +++ b/admin/webUI/app/app.module.js @@ -190,6 +190,7 @@ angular.module('GruiApp').provider('RouteHelpers', ['APP_REQUIRES', function(app "$rootScope", "$state", "$stateParams", + "$sce", "$http", "$q", "MainService", @@ -208,7 +209,7 @@ angular.module('GruiApp').provider('RouteHelpers', ['APP_REQUIRES', function(app // CONTROLLERS, SERVICES FUNCTION DEFINITION // MAIN CONTROLLER - function MainController($scope, $rootScope, $state, $stateParams, $http, $q, MainService) { + function MainController($scope, $rootScope, $state, $stateParams, $sce, $http, $q, MainService) { //ViewModal binding using this, instead of $scope //Must be use with ControllerAs syntax in view mainVm = this; // $Scope aliase @@ -291,9 +292,19 @@ angular.module('GruiApp').provider('RouteHelpers', ['APP_REQUIRES', function(app if (!setting.template) { return } - mainVm.modal = { - template: setting.template + mainVm.modal = {}; + + // CHECK IF TEMPLATE IS STRING OR URL + mainVm.modal.isString = setting.isString ? true : false; + if (mainVm.modal.isString) { + setting.template = $sce.trustAsHtml(setting.template); } + + // SET TEMPLATE + mainVm.modal.template = setting.template; + mainVm.modal.class = setting.class || ""; + mainVm.modal.showYes = setting.showYes || false; + mainVm.showModal = true; } @@ -308,6 +319,7 @@ angular.module('GruiApp').provider('RouteHelpers', ['APP_REQUIRES', function(app mainVm.openModal({ // template: "./app/shared/_server_crash.html", template: modalContent, + isString: true, }); $rootScope.$broadcast("endQuiz", { message: modalContent, diff --git a/admin/webUI/app/components/invite/inviteController.js b/admin/webUI/app/components/invite/inviteController.js index 98280bf..e8fe5c5 100644 --- a/admin/webUI/app/components/invite/inviteController.js +++ b/admin/webUI/app/components/invite/inviteController.js @@ -254,7 +254,7 @@ } } - function candidatesController($rootScope, $stateParams, $state, inviteService, moment) { + function candidatesController($scope, $rootScope, $stateParams, $state, inviteService, moment) { candidatesVm = this; candidatesVm.sortType = 'score'; candidatesVm.sortReverse = true; @@ -262,6 +262,7 @@ candidatesVm.cancel = cancel; candidatesVm.resend = resend; candidatesVm.showModal = showModal; + candidatesVm.showCancelModal = showCancelModal; candidatesVm.candidate_email = ""; candidatesVm.quizID = $stateParams.quizID; @@ -315,6 +316,22 @@ }) } + function showCancelModal(candidateID, email) { + console.log(email) + candidatesVm.candidate_email = email; + // dialog.showModal(); + mainVm.openModal({ + template: $(".canel-invite-template").html(), + isString: true, + showYes: true, + class: "cancel-invite-modal" + }); + dialog.querySelector('.submit').addEventListener('click', function() { + candidatesVm.cancel(candidateID); + dialog.close(); + }) + } + angular.element(document).ready(function() { var dialog = document.querySelector('dialog'); @@ -437,6 +454,7 @@ angular.module('GruiApp').controller('candidateReportController', candidateReportDependency); var candidatesDependency = [ + "$scope", "$rootScope", "$stateParams", "$state", diff --git a/admin/webUI/app/components/invite/views/invite-dashboard.html b/admin/webUI/app/components/invite/views/invite-dashboard.html index 40fd664..885e57b 100644 --- a/admin/webUI/app/components/invite/views/invite-dashboard.html +++ b/admin/webUI/app/components/invite/views/invite-dashboard.html @@ -97,7 +97,8 @@
Candidate List for Quiz
@@ -115,7 +116,15 @@

Cancel

- +
+
+

Cancel

+
+

+ Are you sure that you wan't to cancel the invite sent to {{candidateVm.candidate_email}}? +

+
+
diff --git a/admin/webUI/assets/css/_utility.css b/admin/webUI/assets/css/_utility.css index f9b5dcc..39cd710 100644 --- a/admin/webUI/assets/css/_utility.css +++ b/admin/webUI/assets/css/_utility.css @@ -367,11 +367,16 @@ -ms-transform: translatex(-50%) translatey(-50%); -o-transform: translatex(-50%) translatey(-50%); transform: translate(-50%, -50%); + box-shadow: 0 9px 46px 8px rgba(0, 0, 0, .14), 0 11px 15px -7px rgba(0, 0, 0, .12), 0 24px 38px 3px rgba(0, 0, 0, .2); z-index: 101; } .modal-actions .mdl-button { - min-width: 120px; + margin-left: 10px; +} + +.invite-page .modal-overlay { + background: rgba(0, 0, 0, 0.0980392); } diff --git a/admin/webUI/assets/css/custom.css b/admin/webUI/assets/css/custom.css index 3b0e09d..197d833 100644 --- a/admin/webUI/assets/css/custom.css +++ b/admin/webUI/assets/css/custom.css @@ -530,6 +530,18 @@ body.home { background-position: -18px 10px; } +.cancel-invite-modal.modal-wrapper { + width: 300px +} + +.mdl-dialog__content { + padding: 20px 10px 0 10px; +} + +.mdl-dialog__title { + padding: 24px 10px 0; +} + /*CANDIDATE REPORT*/ diff --git a/admin/webUI/index.html b/admin/webUI/index.html index 45467a5..506c6fe 100644 --- a/admin/webUI/index.html +++ b/admin/webUI/index.html @@ -92,13 +92,14 @@
- @@ -97,8 +97,9 @@
Candidate List for Quiz
diff --git a/quiz/quiz.go b/quiz/quiz.go index 9691ea3..135ad56 100644 --- a/quiz/quiz.go +++ b/quiz/quiz.go @@ -152,7 +152,6 @@ type cand struct { Token string `json:"token"` Validity string `json:"validity"` Complete bool `json:"complete,string"` - Cancel bool `json:"cancel,string"` Quiz []quiz `json:"candidate.quiz"` Questions []qids `json:"candidate.question"` QuizStart time.Time `json:"quiz_start"` @@ -228,7 +227,6 @@ func candQuery(cid string) string { token validity complete - cancel quiz_start candidate.quiz { _uid_ @@ -273,9 +271,6 @@ func checkAndUpdate(uid string) (int, error) { if cand.Complete { return http.StatusUnauthorized, fmt.Errorf("You have already completed the quiz.") } - if cand.Cancel { - return http.StatusUnauthorized, fmt.Errorf("Your token isn't valid anymore. Please mail us at contact@dgraph.io.") - } if quiz.Id == "" { return http.StatusUnauthorized, fmt.Errorf("Invalid token.") From 3e3bb5568cc1eb1b98c1c0bd0a55f781600b319c Mon Sep 17 00:00:00 2001 From: Rahul-Sagore Date: Fri, 11 Nov 2016 02:50:26 +0530 Subject: [PATCH 5/6] Added modal code for delete/cancel invite and candidate --- admin/webUI/app/app.module.js | 10 +- .../app/components/candidate/views/quiz.html | 1 + .../app/components/invite/inviteController.js | 91 +++++++++++-------- .../invite/views/invite-dashboard.html | 59 +++++++----- admin/webUI/app/shared/_modal_template.html | 10 ++ admin/webUI/assets/css/_utility.css | 2 +- admin/webUI/assets/css/custom.css | 1 + admin/webUI/assets/lib/js/marked.min.js | 6 ++ admin/webUI/index.html | 10 +- 9 files changed, 122 insertions(+), 68 deletions(-) create mode 100644 admin/webUI/app/shared/_modal_template.html create mode 100644 admin/webUI/assets/lib/js/marked.min.js diff --git a/admin/webUI/app/app.module.js b/admin/webUI/app/app.module.js index 8ae8f36..62c69a5 100644 --- a/admin/webUI/app/app.module.js +++ b/admin/webUI/app/app.module.js @@ -119,7 +119,8 @@ angular.module('GruiApp').constant('APP_REQUIRES', { 'angular-select': ['assets/lib/js/angular-select.min.js'], 'codeMirror': ['assets/lib/js/codemirror.js'], 'javascript': ['assets/lib/js/javascript.js'], - 'marked': ['https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.2/marked.min.js'], + 'marked': ['assets/lib/js/marked.min.js'], + // 'marked': ['https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.2/marked.min.js'], 'highlight': ['assets/lib/js/highlight.pack.js'], 'moment': ['assets/lib/js/moment.min.js'], 'angular-moment': ['assets/lib/js/angular-moment.min.js'] @@ -191,6 +192,7 @@ angular.module('GruiApp').provider('RouteHelpers', ['APP_REQUIRES', function(app "$state", "$stateParams", "$sce", + "$parse", "$http", "$q", "MainService", @@ -209,7 +211,7 @@ angular.module('GruiApp').provider('RouteHelpers', ['APP_REQUIRES', function(app // CONTROLLERS, SERVICES FUNCTION DEFINITION // MAIN CONTROLLER - function MainController($scope, $rootScope, $state, $stateParams, $sce, $http, $q, MainService) { + function MainController($scope, $rootScope, $state, $stateParams, $sce, $parse, $http, $q, MainService) { //ViewModal binding using this, instead of $scope //Must be use with ControllerAs syntax in view mainVm = this; // $Scope aliase @@ -297,12 +299,14 @@ angular.module('GruiApp').provider('RouteHelpers', ['APP_REQUIRES', function(app // CHECK IF TEMPLATE IS STRING OR URL mainVm.modal.isString = setting.isString ? true : false; if (mainVm.modal.isString) { - setting.template = $sce.trustAsHtml(setting.template); + // setting.template = $parse($sce.trustAsHtml(setting.template))($scope); + $(".modal-wrapper").html($parse($sce.trustAsHtml(setting.template))($scope)); } // SET TEMPLATE mainVm.modal.template = setting.template; mainVm.modal.class = setting.class || ""; + mainVm.modal.hideClose = setting.hideClose || false; mainVm.modal.showYes = setting.showYes || false; mainVm.showModal = true; diff --git a/admin/webUI/app/components/candidate/views/quiz.html b/admin/webUI/app/components/candidate/views/quiz.html index 178a640..f98d256 100644 --- a/admin/webUI/app/components/candidate/views/quiz.html +++ b/admin/webUI/app/components/candidate/views/quiz.html @@ -162,4 +162,5 @@
Dgraph quiz ended

+
diff --git a/admin/webUI/app/components/invite/inviteController.js b/admin/webUI/app/components/invite/inviteController.js index 0c2a7ff..a6ce80f 100644 --- a/admin/webUI/app/components/invite/inviteController.js +++ b/admin/webUI/app/components/invite/inviteController.js @@ -254,18 +254,20 @@ } } - function candidatesController($scope, $rootScope, $stateParams, $state, inviteService, moment) { + function candidatesController($scope, $rootScope, $stateParams, $state, $timeout, $templateCache, inviteService, moment) { candidatesVm = this; candidatesVm.sortType = 'score'; candidatesVm.sortReverse = true; + candidatesVm.expires = expires; + candidatesVm.showCancelModal = showCancelModal; + candidatesVm.initiateCancel = initiateCancel; + candidatesVm.showDeleteModal = showDeleteModal; + candidatesVm.initiateDelete = initiateDelete; + candidatesVm.deleteCandFromArray = deleteFromArray; candidatesVm.cancel = cancel; candidatesVm.resend = resend; candidatesVm.delete = deleteCand; - candidatesVm.showModal = showModal; - candidatesVm.showCancelModal = showCancelModal; - candidatesVm.candidate_email = ""; - candidatesVm.deleteCandFromArray = deleteFromArray; candidatesVm.quizID = $stateParams.quizID; @@ -295,8 +297,8 @@ candidatesVm.quizCandidates.splice(i, 1) } // TODO - - Maybe store invite in a format that frontend directly - // understands. + //- Maybe store invite in a format that frontend directly + // understands. if (cand.complete == "false") { cand.invite_sent = new Date(Date.parse(cand.invite_sent)) || ''; continue; @@ -313,40 +315,45 @@ console.log(err); }); - function showModal(candidateID, email) { - - console.log(email) - candidatesVm.candidate_email = email; - dialog.showModal(); - dialog.querySelector('.submit').addEventListener('click', function() { - candidatesVm.cancel(candidateID); - dialog.close(); - }) + function showCancelModal(candidate) { + // Timeout to let dirty checking done first then modal content get + // updated variable text + candidatesVm.currentCancel = {}; + candidatesVm.currentCancel = candidate; + $timeout(function() { + mainVm.openModal({ + template: "cancel-modal-template", + showYes: true, + hideClose: true, + class: "cancel-invite-modal", + }); + }, 10); } - function showCancelModal(candidateID, email) { - console.log(email) - candidatesVm.candidate_email = email; - // dialog.showModal(); - mainVm.openModal({ - template: $(".canel-invite-template").html(), - isString: true, - showYes: true, - class: "cancel-invite-modal" - }); - dialog.querySelector('.submit').addEventListener('click', function() { - candidatesVm.cancel(candidateID); - dialog.close(); - }) + function initiateCancel() { + if (candidatesVm.currentCancel) { + candidatesVm.cancel(candidatesVm.currentCancel); + } } - angular.element(document).ready(function() { - var dialog = document.querySelector('dialog'); + function showDeleteModal(candidateID) { + candidatesVm.currentDelete = ""; + candidatesVm.currentDelete = candidateID; + $timeout(function() { + mainVm.openModal({ + template: "delete-candidate-template", + showYes: true, + hideClose: true, + class: "delete-candidate-modal", + }); + }, 10); + } - dialog.querySelector('.close').addEventListener('click', function() { - dialog.close(); - }); - }); + function initiateDelete() { + if (candidatesVm.currentDelete) { + candidatesVm.delete(candidatesVm.currentDelete); + } + } function expires(validity) { var numDays = moment(validity).diff(moment(), 'days') @@ -387,6 +394,9 @@ $state.transitionTo("invite.dashboard", { quizID: candidatesVm.quizID, }) + + candidatesVm.currentCancel = {}; + mainVm.hideModal(); }) } @@ -407,6 +417,13 @@ $state.transitionTo("invite.dashboard", { quizID: candidatesVm.quizID, }) + + candidatesVm.currentDelete = ""; + mainVm.hideModal(); + }, function(err) { + console.log(error) + candidatesVm.currentDelete = ""; + mainVm.hideModal(); }) } @@ -499,6 +516,8 @@ "$rootScope", "$stateParams", "$state", + "$timeout", + "$templateCache", "inviteService", "moment", candidatesController diff --git a/admin/webUI/app/components/invite/views/invite-dashboard.html b/admin/webUI/app/components/invite/views/invite-dashboard.html index c185f15..5964846 100644 --- a/admin/webUI/app/components/invite/views/invite-dashboard.html +++ b/admin/webUI/app/components/invite/views/invite-dashboard.html @@ -51,7 +51,8 @@
Candidate List for Quiz
@@ -97,9 +98,7 @@
Candidate List for Quiz
@@ -108,24 +107,38 @@
Candidate List for Quiz
- -

Cancel

-
-

- Are you sure that you wan't to cancel the invite sent to {{candidateVm.candidate_email}}? -

-
-
- - -
-
-
-

Cancel

-
-

- Are you sure that you wan't to cancel the invite sent to {{candidateVm.candidate_email}}? -

+ + + + + +
diff --git a/admin/webUI/app/shared/_modal_template.html b/admin/webUI/app/shared/_modal_template.html new file mode 100644 index 0000000..8886737 --- /dev/null +++ b/admin/webUI/app/shared/_modal_template.html @@ -0,0 +1,10 @@ + +
+ +
diff --git a/admin/webUI/assets/css/_utility.css b/admin/webUI/assets/css/_utility.css index 39cd710..9985680 100644 --- a/admin/webUI/assets/css/_utility.css +++ b/admin/webUI/assets/css/_utility.css @@ -357,7 +357,7 @@ } .modal-wrapper { - position: absolute; + position: fixed; padding: 15px; top: 50%; left: 50%; diff --git a/admin/webUI/assets/css/custom.css b/admin/webUI/assets/css/custom.css index 197d833..eb575ca 100644 --- a/admin/webUI/assets/css/custom.css +++ b/admin/webUI/assets/css/custom.css @@ -540,6 +540,7 @@ body.home { .mdl-dialog__title { padding: 24px 10px 0; + font-size: 2rem; } diff --git a/admin/webUI/assets/lib/js/marked.min.js b/admin/webUI/assets/lib/js/marked.min.js new file mode 100644 index 0000000..45adb9e --- /dev/null +++ b/admin/webUI/assets/lib/js/marked.min.js @@ -0,0 +1,6 @@ +/** + * marked - a markdown parser + * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed) + * https://github.com/chjj/marked + */ +(function(){var block={newline:/^\n+/,code:/^( {4}[^\n]+\n*)+/,fences:noop,hr:/^( *[-*_]){3,} *(?:\n+|$)/,heading:/^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,nptable:noop,lheading:/^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,blockquote:/^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,list:/^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:/^ *(?:comment|closed|closing) *(?:\n{2,}|\s*$)/,def:/^ *\[([^\]]+)\]: *]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,table:noop,paragraph:/^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,text:/^[^\n]+/};block.bullet=/(?:[*+-]|\d+\.)/;block.item=/^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;block.item=replace(block.item,"gm")(/bull/g,block.bullet)();block.list=replace(block.list)(/bull/g,block.bullet)("hr","\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))")("def","\\n+(?="+block.def.source+")")();block.blockquote=replace(block.blockquote)("def",block.def)();block._tag="(?!(?:"+"a|em|strong|small|s|cite|q|dfn|abbr|data|time|code"+"|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo"+"|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b";block.html=replace(block.html)("comment",//)("closed",/<(tag)[\s\S]+?<\/\1>/)("closing",/])*?>/)(/tag/g,block._tag)();block.paragraph=replace(block.paragraph)("hr",block.hr)("heading",block.heading)("lheading",block.lheading)("blockquote",block.blockquote)("tag","<"+block._tag)("def",block.def)();block.normal=merge({},block);block.gfm=merge({},block.normal,{fences:/^ *(`{3,}|~{3,}) *(\S+)? *\n([\s\S]+?)\s*\1 *(?:\n+|$)/,paragraph:/^/});block.gfm.paragraph=replace(block.paragraph)("(?!","(?!"+block.gfm.fences.source.replace("\\1","\\2")+"|"+block.list.source.replace("\\1","\\3")+"|")();block.tables=merge({},block.gfm,{nptable:/^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,table:/^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/});function Lexer(options){this.tokens=[];this.tokens.links={};this.options=options||marked.defaults;this.rules=block.normal;if(this.options.gfm){if(this.options.tables){this.rules=block.tables}else{this.rules=block.gfm}}}Lexer.rules=block;Lexer.lex=function(src,options){var lexer=new Lexer(options);return lexer.lex(src)};Lexer.prototype.lex=function(src){src=src.replace(/\r\n|\r/g,"\n").replace(/\t/g," ").replace(/\u00a0/g," ").replace(/\u2424/g,"\n");return this.token(src,true)};Lexer.prototype.token=function(src,top,bq){var src=src.replace(/^ +$/gm,""),next,loose,cap,bull,b,item,space,i,l;while(src){if(cap=this.rules.newline.exec(src)){src=src.substring(cap[0].length);if(cap[0].length>1){this.tokens.push({type:"space"})}}if(cap=this.rules.code.exec(src)){src=src.substring(cap[0].length);cap=cap[0].replace(/^ {4}/gm,"");this.tokens.push({type:"code",text:!this.options.pedantic?cap.replace(/\n+$/,""):cap});continue}if(cap=this.rules.fences.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"code",lang:cap[2],text:cap[3]});continue}if(cap=this.rules.heading.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"heading",depth:cap[1].length,text:cap[2]});continue}if(top&&(cap=this.rules.nptable.exec(src))){src=src.substring(cap[0].length);item={type:"table",header:cap[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:cap[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:cap[3].replace(/\n$/,"").split("\n")};for(i=0;i ?/gm,"");this.token(cap,top,true);this.tokens.push({type:"blockquote_end"});continue}if(cap=this.rules.list.exec(src)){src=src.substring(cap[0].length);bull=cap[2];this.tokens.push({type:"list_start",ordered:bull.length>1});cap=cap[0].match(this.rules.item);next=false;l=cap.length;i=0;for(;i1&&b.length>1)){src=cap.slice(i+1).join("\n")+src;i=l-1}}loose=next||/\n\n(?!\s*$)/.test(item);if(i!==l-1){next=item.charAt(item.length-1)==="\n";if(!loose)loose=next}this.tokens.push({type:loose?"loose_item_start":"list_item_start"});this.token(item,false,bq);this.tokens.push({type:"list_item_end"})}this.tokens.push({type:"list_end"});continue}if(cap=this.rules.html.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:this.options.sanitize?"paragraph":"html",pre:cap[1]==="pre"||cap[1]==="script"||cap[1]==="style",text:cap[0]});continue}if(!bq&&top&&(cap=this.rules.def.exec(src))){src=src.substring(cap[0].length);this.tokens.links[cap[1].toLowerCase()]={href:cap[2],title:cap[3]};continue}if(top&&(cap=this.rules.table.exec(src))){src=src.substring(cap[0].length);item={type:"table",header:cap[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:cap[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:cap[3].replace(/(?: *\| *)?\n$/,"").split("\n")};for(i=0;i])/,autolink:/^<([^ >]+(@|:\/)[^ >]+)>/,url:noop,tag:/^|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,link:/^!?\[(inside)\]\(href\)/,reflink:/^!?\[(inside)\]\s*\[([^\]]*)\]/,nolink:/^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,strong:/^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,em:/^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,code:/^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,br:/^ {2,}\n(?!\s*$)/,del:noop,text:/^[\s\S]+?(?=[\\?(?:\s+['"]([\s\S]*?)['"])?\s*/;inline.link=replace(inline.link)("inside",inline._inside)("href",inline._href)();inline.reflink=replace(inline.reflink)("inside",inline._inside)();inline.normal=merge({},inline);inline.pedantic=merge({},inline.normal,{strong:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,em:/^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/});inline.gfm=merge({},inline.normal,{escape:replace(inline.escape)("])","~|])")(),url:/^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,del:/^~~(?=\S)([\s\S]*?\S)~~/,text:replace(inline.text)("]|","~]|")("|","|https?://|")()});inline.breaks=merge({},inline.gfm,{br:replace(inline.br)("{2,}","*")(),text:replace(inline.gfm.text)("{2,}","*")()});function InlineLexer(links,options){this.options=options||marked.defaults;this.links=links;this.rules=inline.normal;this.renderer=this.options.renderer||new Renderer;this.renderer.options=this.options;if(!this.links){throw new Error("Tokens array requires a `links` property.")}if(this.options.gfm){if(this.options.breaks){this.rules=inline.breaks}else{this.rules=inline.gfm}}else if(this.options.pedantic){this.rules=inline.pedantic}}InlineLexer.rules=inline;InlineLexer.output=function(src,links,options){var inline=new InlineLexer(links,options);return inline.output(src)};InlineLexer.prototype.output=function(src){var out="",link,text,href,cap;while(src){if(cap=this.rules.escape.exec(src)){src=src.substring(cap[0].length);out+=cap[1];continue}if(cap=this.rules.autolink.exec(src)){src=src.substring(cap[0].length);if(cap[2]==="@"){text=cap[1].charAt(6)===":"?this.mangle(cap[1].substring(7)):this.mangle(cap[1]);href=this.mangle("mailto:")+text}else{text=escape(cap[1]);href=text}out+=this.renderer.link(href,null,text);continue}if(!this.inLink&&(cap=this.rules.url.exec(src))){src=src.substring(cap[0].length);text=escape(cap[1]);href=text;out+=this.renderer.link(href,null,text);continue}if(cap=this.rules.tag.exec(src)){if(!this.inLink&&/^/i.test(cap[0])){this.inLink=false}src=src.substring(cap[0].length);out+=this.options.sanitize?escape(cap[0]):cap[0];continue}if(cap=this.rules.link.exec(src)){src=src.substring(cap[0].length);this.inLink=true;out+=this.outputLink(cap,{href:cap[2],title:cap[3]});this.inLink=false;continue}if((cap=this.rules.reflink.exec(src))||(cap=this.rules.nolink.exec(src))){src=src.substring(cap[0].length);link=(cap[2]||cap[1]).replace(/\s+/g," ");link=this.links[link.toLowerCase()];if(!link||!link.href){out+=cap[0].charAt(0);src=cap[0].substring(1)+src;continue}this.inLink=true;out+=this.outputLink(cap,link);this.inLink=false;continue}if(cap=this.rules.strong.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.strong(this.output(cap[2]||cap[1]));continue}if(cap=this.rules.em.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.em(this.output(cap[2]||cap[1]));continue}if(cap=this.rules.code.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.codespan(escape(cap[2],true));continue}if(cap=this.rules.br.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.br();continue}if(cap=this.rules.del.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.del(this.output(cap[1]));continue}if(cap=this.rules.text.exec(src)){src=src.substring(cap[0].length);out+=escape(this.smartypants(cap[0]));continue}if(src){throw new Error("Infinite loop on byte: "+src.charCodeAt(0))}}return out};InlineLexer.prototype.outputLink=function(cap,link){var href=escape(link.href),title=link.title?escape(link.title):null;return cap[0].charAt(0)!=="!"?this.renderer.link(href,title,this.output(cap[1])):this.renderer.image(href,title,escape(cap[1]))};InlineLexer.prototype.smartypants=function(text){if(!this.options.smartypants)return text;return text.replace(/--/g,"—").replace(/(^|[-\u2014/(\[{"\s])'/g,"$1‘").replace(/'/g,"’").replace(/(^|[-\u2014/(\[{\u2018\s])"/g,"$1“").replace(/"/g,"”").replace(/\.{3}/g,"…")};InlineLexer.prototype.mangle=function(text){var out="",l=text.length,i=0,ch;for(;i.5){ch="x"+ch.toString(16)}out+="&#"+ch+";"}return out};function Renderer(options){this.options=options||{}}Renderer.prototype.code=function(code,lang,escaped){if(this.options.highlight){var out=this.options.highlight(code,lang);if(out!=null&&out!==code){escaped=true;code=out}}if(!lang){return"
"+(escaped?code:escape(code,true))+"\n
"}return'
'+(escaped?code:escape(code,true))+"\n
\n"};Renderer.prototype.blockquote=function(quote){return"
\n"+quote+"
\n"};Renderer.prototype.html=function(html){return html};Renderer.prototype.heading=function(text,level,raw){return"'+text+"\n"};Renderer.prototype.hr=function(){return this.options.xhtml?"
\n":"
\n"};Renderer.prototype.list=function(body,ordered){var type=ordered?"ol":"ul";return"<"+type+">\n"+body+"\n"};Renderer.prototype.listitem=function(text){return"
  • "+text+"
  • \n"};Renderer.prototype.paragraph=function(text){return"

    "+text+"

    \n"};Renderer.prototype.table=function(header,body){return"
    Validity + + Expires (days) + arrow_drop_up + arrow_drop_down + + Actions
    {{candidate.email}} {{candidate.invite_sent | date : 'MMM dd, yyyy'}}{{candidate.validity}}{{candidateVm.expires(candidate.validity)}} - EDIT + EDIT  |  + RESEND  |  + CANCEL
    {{candidate.name}} {{candidate.email}} {{candidate.score | number: 2}}
    {{candidate.email}} {{candidate.invite_sent | date : 'MMM dd, yyyy'}} {{candidateVm.expires(candidate.validity)}} EDIT  |  RESEND  |  - CANCEL + CANCEL
    EDIT  |  RESEND  |  - CANCEL + CANCEL  |  + MODAL
    {{candidate.quiz_start | date : 'MMM dd, yyyy'}} VIEW REPORT  |  - DELETE + DELETE
    EDIT  |  RESEND  |  - CANCEL  |  - MODAL + CANCEL + +
    {{candidate.quiz_start | date : 'MMM dd, yyyy'}} VIEW REPORT  |  - DELETE + + DELETE
    EDIT  |  RESEND  |  - CANCEL - - + CANCEL
    \n"+"\n"+header+"\n"+"\n"+body+"\n"+"
    \n"};Renderer.prototype.tablerow=function(content){return"\n"+content+"\n"};Renderer.prototype.tablecell=function(content,flags){var type=flags.header?"th":"td";var tag=flags.align?"<"+type+' style="text-align:'+flags.align+'">':"<"+type+">";return tag+content+"\n"};Renderer.prototype.strong=function(text){return""+text+""};Renderer.prototype.em=function(text){return""+text+""};Renderer.prototype.codespan=function(text){return""+text+""};Renderer.prototype.br=function(){return this.options.xhtml?"
    ":"
    "};Renderer.prototype.del=function(text){return""+text+""};Renderer.prototype.link=function(href,title,text){if(this.options.sanitize){try{var prot=decodeURIComponent(unescape(href)).replace(/[^\w:]/g,"").toLowerCase()}catch(e){return""}if(prot.indexOf("javascript:")===0){return""}}var out='
    ";return out};Renderer.prototype.image=function(href,title,text){var out=''+text+'":">";return out};function Parser(options){this.tokens=[];this.token=null;this.options=options||marked.defaults;this.options.renderer=this.options.renderer||new Renderer;this.renderer=this.options.renderer;this.renderer.options=this.options}Parser.parse=function(src,options,renderer){var parser=new Parser(options,renderer);return parser.parse(src)};Parser.prototype.parse=function(src){this.inline=new InlineLexer(src.links,this.options,this.renderer);this.tokens=src.reverse();var out="";while(this.next()){out+=this.tok()}return out};Parser.prototype.next=function(){return this.token=this.tokens.pop()};Parser.prototype.peek=function(){return this.tokens[this.tokens.length-1]||0};Parser.prototype.parseText=function(){var body=this.token.text;while(this.peek().type==="text"){body+="\n"+this.next().text}return this.inline.output(body)};Parser.prototype.tok=function(){switch(this.token.type){case"space":{return""}case"hr":{return this.renderer.hr()}case"heading":{return this.renderer.heading(this.inline.output(this.token.text),this.token.depth,this.token.text)}case"code":{return this.renderer.code(this.token.text,this.token.lang,this.token.escaped)}case"table":{var header="",body="",i,row,cell,flags,j;cell="";for(i=0;i/g,">").replace(/"/g,""").replace(/'/g,"'")}function unescape(html){return html.replace(/&([#\w]+);/g,function(_,n){n=n.toLowerCase();if(n==="colon")return":";if(n.charAt(0)==="#"){return n.charAt(1)==="x"?String.fromCharCode(parseInt(n.substring(2),16)):String.fromCharCode(+n.substring(1))}return""})}function replace(regex,opt){regex=regex.source;opt=opt||"";return function self(name,val){if(!name)return new RegExp(regex,opt);val=val.source||val;val=val.replace(/(^|[^\[])\^/g,"$1");regex=regex.replace(name,val);return self}}function noop(){}noop.exec=noop;function merge(obj){var i=1,target,key;for(;iAn error occured:

    "+escape(e.message+"",true)+"
    "}throw e}}marked.options=marked.setOptions=function(opt){merge(marked.defaults,opt);return marked};marked.defaults={gfm:true,tables:true,breaks:false,pedantic:false,sanitize:false,smartLists:false,silent:false,highlight:null,langPrefix:"lang-",smartypants:false,headerPrefix:"",renderer:new Renderer,xhtml:false};marked.Parser=Parser;marked.parser=Parser.parse;marked.Renderer=Renderer;marked.Lexer=Lexer;marked.lexer=Lexer.lex;marked.InlineLexer=InlineLexer;marked.inlineLexer=InlineLexer.output;marked.parse=marked;if(typeof exports==="object"){module.exports=marked}else if(typeof define==="function"&&define.amd){define(function(){return marked})}else{this.marked=marked}}).call(function(){return this||(typeof window!=="undefined"?window:global)}()); \ No newline at end of file diff --git a/admin/webUI/index.html b/admin/webUI/index.html index 506c6fe..a789334 100644 --- a/admin/webUI/index.html +++ b/admin/webUI/index.html @@ -9,8 +9,8 @@ Gru - - + + @@ -91,7 +91,7 @@
    - + - + From f54c7213782c7d91a1338346a4bb5d8fa9b645fd Mon Sep 17 00:00:00 2001 From: Rahul-Sagore Date: Sat, 12 Nov 2016 13:23:54 +0530 Subject: [PATCH 6/6] Add name of the deleted candidate inside modal content --- .../app/components/invite/inviteController.js | 6 +-- .../invite/views/invite-dashboard.html | 52 +++++++++---------- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/admin/webUI/app/components/invite/inviteController.js b/admin/webUI/app/components/invite/inviteController.js index a6ce80f..5f0e799 100644 --- a/admin/webUI/app/components/invite/inviteController.js +++ b/admin/webUI/app/components/invite/inviteController.js @@ -336,9 +336,9 @@ } } - function showDeleteModal(candidateID) { - candidatesVm.currentDelete = ""; - candidatesVm.currentDelete = candidateID; + function showDeleteModal(candidate) { + candidatesVm.currentDeleteName = candidate.name; + candidatesVm.currentDelete = candidate._uid_; $timeout(function() { mainVm.openModal({ template: "delete-candidate-template", diff --git a/admin/webUI/app/components/invite/views/invite-dashboard.html b/admin/webUI/app/components/invite/views/invite-dashboard.html index 5964846..537d93d 100644 --- a/admin/webUI/app/components/invite/views/invite-dashboard.html +++ b/admin/webUI/app/components/invite/views/invite-dashboard.html @@ -1,10 +1,10 @@ -
    +
    Candidate List for Quiz
    - +
    @@ -27,23 +27,23 @@
    Candidate List for Quiz
    Name Email -
    + Score - arrow_drop_up - arrow_drop_down + arrow_drop_up + arrow_drop_down - + Quiz Start - arrow_drop_up - arrow_drop_down + arrow_drop_up + arrow_drop_down Actions - + {{candidate.name}} {{candidate.email}} @@ -51,8 +51,8 @@
    Candidate List for Quiz
    {{candidate.quiz_start | date : 'MMM dd, yyyy'}} VIEW REPORT  |  - - DELETE + + DELETE @@ -74,31 +74,31 @@
    Candidate List for Quiz
    Email - + Invited - arrow_drop_up - arrow_drop_down + arrow_drop_up + arrow_drop_down - + Expires (days) - arrow_drop_up - arrow_drop_down + arrow_drop_up + arrow_drop_down Actions - + {{candidate.email}} {{candidate.invite_sent | date : 'MMM dd, yyyy'}} - {{candidateVm.expires(candidate.validity)}} + {{candidatesVm.expires(candidate.validity)}} - EDIT  |  - RESEND  |  - CANCEL + EDIT  |  + RESEND  |  + CANCEL @@ -113,11 +113,11 @@
    Candidate List for Quiz
    Cancel Invite

    - Are you sure that you wan't to cancel the invite sent to {{candidateVm.currentCancel.email}}? + Are you sure that you wan't to cancel the invite sent to {{candidatesVm.currentCancel.email}}?

    - +
    @@ -129,11 +129,11 @@
    Cancel Invite
    Delete Candidate

    - Are you sure that you wan't to delete this candidate? + Are you sure that you wan't to delete {{candidatesVm.currentDeleteName}}?

    - +