Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"object-shorthand": [2, "consistent"],
"no-unused-vars": [1, {"vars": "local", "args": "none"}],
"quote-props": [1, "consistent-as-needed"],
"eqeqeq": 2,
"eqeqeq": [2, "smart"],
"brace-style": 2,
"curly": 2,
"quotes": [2, "single", { "avoidEscape": true }],
Expand Down
Empty file modified client/app/config/common.js
100644 → 100755
Empty file.
Empty file modified client/app/config/jiff.js
100644 → 100755
Empty file.
14 changes: 7 additions & 7 deletions client/app/controllers/analystController.js
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -202,13 +202,13 @@ define(['filesaver', 'pki'], function (filesaver, pki) {


return {
checkStatus,
changeStatus,
generateUrls,
getExistingParticipants,
generateTable,
generateSession,
getParameterByName,
checkStatus: checkStatus,
changeStatus: changeStatus,
generateUrls: generateUrls,
getExistingParticipants: getExistingParticipants,
generateTable: generateTable,
generateSession: generateSession,
getParameterByName: getParameterByName,
START: 'START',
PAUSE: 'PAUSE',
STOP: 'STOP'
Expand Down
28 changes: 21 additions & 7 deletions client/app/controllers/clientController.js
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* global alertify, $ */
define(['jquery', 'controllers/tableController', 'controllers/jiffController', 'alertify', 'alertify_defaults', 'table_template'],
function ($, tableController, jiffController, alertify, _, table_template) {
define(['jquery', 'controllers/tableController', 'controllers/jiffController', 'controllers/usabilityController', 'alertify', 'alertify_defaults', 'table_template'],
function ($, tableController, jiffController, usabilityController, alertify, _, table_template) {
var client = (function () {
/**
* Displays the given submission as the last submission in
Expand Down Expand Up @@ -94,7 +94,7 @@ define(['jquery', 'controllers/tableController', 'controllers/jiffController', '
dataType: 'text'
}).then(function (response) {
JSON.parse(response); // verify response is json (error responses are string messages)

var $parent = $('#session, #participation-code').parent();
$parent.removeClass('has-error').addClass('has-success has-feedback');
$parent.find('.success-icon').removeClass('hidden').addClass('show');
Expand All @@ -104,6 +104,7 @@ define(['jquery', 'controllers/tableController', 'controllers/jiffController', '
callback && callback(true);
}).catch(function (err) {
var errorMsg = SERVER_ERR;
usabilityController.addValidationError("SESSION_INFO_ERROR");
if (err && err.hasOwnProperty('responseText') && err.responseText !== undefined) {
errorMsg = err.responseText;
}
Expand All @@ -127,28 +128,32 @@ define(['jquery', 'controllers/tableController', 'controllers/jiffController', '
var $session = $('#session');
if (!validateSessionInput($session, false)) {
errors.push(SESSION_KEY_ERROR);
usabilityController.addValidationError("SESSION_KEY_ERROR");
}

var $participationCode = $('#participation-code');
if (!validateSessionInput($participationCode, false)) {
errors.push(PARTICIPATION_CODE_ERROR);
usabilityController.addValidationError("PARTICIPATION_CODE_ERROR");
}

// Validate the remaining components after session and
// and participation code are validated with the server.
var validateRemainingComponents = function (result) {
if (!result) {
errors.push(SESSION_PARTICIPATION_CODE_SERVER_ERROR);
usabilityController.addValidationError("SESSION_PARTICIPATION_CODE_SERVER_ERROR");
}

// Verify confirmation check box was checked
var verifyChecked = $('#verify').is(':checked');
if (!verifyChecked) {
errors.push(UNCHECKED_ERR);
usabilityController.addValidationError("UNCHECKED_ERR");
}

// Verify additional questions
if (table_template.survey != null) {
if (table_template.survey !== null) {
var questionsValid = true;
var questions = $('#questions form');
for (var q = 0; q < questions.length; q++) {
Expand Down Expand Up @@ -194,6 +199,7 @@ define(['jquery', 'controllers/tableController', 'controllers/jiffController', '
}
if (errors.indexOf(errorMsg) === -1) {
errors.push(errorMsg);
usabilityController.addValidationError("CELL_ERROR");
}
};
tableController.registerErrorHandler(errorHandler);
Expand Down Expand Up @@ -274,6 +280,12 @@ define(['jquery', 'controllers/tableController', 'controllers/jiffController', '
data_submission[tables_data[i].name] = tables_data[i].data;
}

if (document.getElementById('choose-file').files.length > 0) {
usabilityController.dataPrefilled();
}

data_submission['usability'] = usabilityController.analytics;

// Secret share / mask the data.
jiffController.client.submit(session, participationCode, data_submission, function (err, response) {
if (err == null || err === 200) {
Expand All @@ -286,8 +298,10 @@ define(['jquery', 'controllers/tableController', 'controllers/jiffController', '
} else if (err === 0 || err === 500) {
// check for status 0 or status 500 (Server not reachable.)
error(SERVER_ERR);
usabilityController.addValidationError("SERVER_ERR");
} else {
error(GENERIC_SUBMISSION_ERR);
usabilityController.addValidationError("GENERIC_SUBMISSION_ERR");
}

la.stop();
Expand Down Expand Up @@ -351,9 +365,9 @@ define(['jquery', 'controllers/tableController', 'controllers/jiffController', '
}

return {
validate,
constructAndSend,
validateSessionInput,
validate: validate,
constructAndSend: constructAndSend,
validateSessionInput: validateSessionInput,
};
})();

Expand Down
22 changes: 18 additions & 4 deletions client/app/controllers/jiffController.js
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,15 @@ define(['mpc', 'pki', 'BigNumber', 'jiff', 'jiff_bignumber', 'jiff_restAPI', 'ta
};
baseOptions = Object.assign(baseOptions, options);
baseOptions.hooks = Object.assign({}, baseOptions.hooks, cryptoHooks);
var bigNumberOptions = { Zp: '36893488147419103183' }; // 2^65-49
var bigNumberOptions = { Zp: '618970019642690137449562111' }; // 2^89-1

var restOptions = {
flushInterval: 0,
pollInterval: 0,
maxBatchSize: 1000
};

var instance = jiff.make_jiff('http://localhost:8080', session, baseOptions);
var instance = jiff.make_jiff(window.location.protocol + '//' + window.location.hostname, session, baseOptions);
instance.apply_extension(jiff_bignumber, bigNumberOptions);
instance.apply_extension(jiff_restAPI, restOptions);

Expand All @@ -92,13 +92,23 @@ define(['mpc', 'pki', 'BigNumber', 'jiff', 'jiff_bignumber', 'jiff_restAPI', 'ta
// List values according to consistent ordering
for (var i = 0; i < ordering.tables.length; i++) {
var t = ordering.tables[i];
values.push(dataSubmission[t.table][t.row][t.col]);
values.push(Math.round(dataSubmission[t.table][t.row][t.col]));
}
for (var j = 0; j < ordering.questions.length; j++) {
var q = ordering.questions[j];
values.push(dataSubmission['questions'][q.question][q.option]);
}

for (var k = 0; k < ordering.usability.length; k++) {
const m = ordering.usability[k].metric;
const f = ordering.usability[k].field;
if (f !== null) {
values.push(dataSubmission.usability[m][f]);
} else {
values.push(dataSubmission.usability[m]);
}
}

// Handle jiff errors returned from server
var options = {
onError: function (errorString) {
Expand All @@ -116,9 +126,13 @@ define(['mpc', 'pki', 'BigNumber', 'jiff', 'jiff_bignumber', 'jiff_restAPI', 'ta
jiff.restReceive = function () {
jiff.disconnect(false, false);
callback.apply(null, arguments);
}
};
for (var i = 0; i < values.length; i++) {
jiff.share(values[i], null, [1, 's1'], [jiff.id]);
// Share the square of the input for standard deviation: only for tables, but not for questions
if (i < ordering.tables.length) {
jiff.share(new BigNumber(values[i]).pow(2), null, [1, 's1'], [jiff.id]);
}
}
jiff.restFlush();
});
Expand Down
56 changes: 31 additions & 25 deletions client/app/controllers/tableController.js
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -708,8 +708,9 @@ define(['jquery', 'Handsontable', 'table_template', 'filesaver', 'alertify', 'qt

function updateTableWidth(maxWidth) {

$('#instructions').css('width', maxWidth);
$('#instructions').css('max-width', maxWidth);
//$('#instructions').css('width', '1153px');
$('#instructions').css('max-width', '1153px');

var documentWidth = $(window).width();
var containerWidth = parseFloat($('.container').first().width());
var offset = (containerWidth - maxWidth) / 2;
Expand Down Expand Up @@ -918,7 +919,7 @@ define(['jquery', 'Handsontable', 'table_template', 'filesaver', 'alertify', 'qt
return {sums, NaNs}
}

function saveTables(tables, session) {
function saveTables(tables, session, title) {

var tables_csv = [];

Expand All @@ -934,8 +935,7 @@ define(['jquery', 'Handsontable', 'table_template', 'filesaver', 'alertify', 'qt
}

tables_csv = tables_csv.join('\n\n\n');
filesaver.saveAs(new Blob([tables_csv], {type: 'text/plain;charset=utf-8'}), 'Aggregate_Data_' + session + '.csv');

filesaver.saveAs(new Blob([tables_csv], {type: 'text/plain;charset=utf-8'}), 'Aggregate_' + title + '_' + session + '.csv');
}

function getHeaderWidth(table) {
Expand Down Expand Up @@ -977,18 +977,18 @@ define(['jquery', 'Handsontable', 'table_template', 'filesaver', 'alertify', 'qt

function updateWidth(tables) {

var maxWidth = $('#instructions').width;

var maxWidth = $('#instructions').width();
for (var i = 0; i < tables.length; i++) {

var t = tables[i];

var w = getWidth(t) + getHeaderWidth(t);

t.updateSettings({
width: w,
width: w
});


if (w > maxWidth) {
maxWidth = w;
}
Expand All @@ -1010,6 +1010,11 @@ define(['jquery', 'Handsontable', 'table_template', 'filesaver', 'alertify', 'qt
return colWidths;
}

function saveUsability(usability, session) {
var json = JSON.stringify(usability);
filesaver.saveAs(new Blob([json], {type: 'application/json'}), 'Usability_' + session + '.json');
}

function saveQuestions(questions, session) {
if (questions == null) {
return;
Expand Down Expand Up @@ -1037,22 +1042,23 @@ define(['jquery', 'Handsontable', 'table_template', 'filesaver', 'alertify', 'qt
}

return {
makeTables,
registerValidator,
registerErrorHandler,
removeValidator,
removeValidators,
removeErrorHandler,
constructDataTables,
fillData,
saveTables,
saveQuestions,
displayReadTable,
resetTableWidth,
updateTableWidth,
getWidth,
updateWidth,
checkTotals,
createTableElems
makeTables: makeTables,
registerValidator: registerValidator,
registerErrorHandler: registerErrorHandler,
removeValidator: removeValidator,
removeValidators: removeValidators,
removeErrorHandler: removeErrorHandler,
constructDataTables: constructDataTables,
fillData: fillData,
saveTables: saveTables,
saveQuestions: saveQuestions,
saveUsability: saveUsability,
displayReadTable: displayReadTable,
resetTableWidth: resetTableWidth,
updateTableWidth: updateTableWidth,
getWidth: getWidth,
updateWidth: updateWidth,
checkTotals: checkTotals,
createTableElems: createTableElems
}
});
96 changes: 96 additions & 0 deletions client/app/controllers/usabilityController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
define(['table_template'], function (table_template) {

let analytics = {};
let timers = {};

function initialize() {
for (var metric of table_template.usability) {
if (typeof(metric) === 'string') {
analytics[metric] = 0;
} else if (typeof(metric) === 'object') {
var key = Object.keys(metric)[0];
var fields = metric[key];
analytics[key] = {};

for (var f of fields) {
analytics[key][f] = 0;
}
}
}

for (let k of Object.keys(analytics.time_spent)) {

if (k === 'page') {
timers[k] = new Date();
} else {
timers[k] = null;
}

$('#' + k).on("mouseenter", function() {
startTimer(k);
});

$('#' + k).on("mouseleave", function() {
endTimer(k);
});
}
window.addEventListener('blur', endTimer);
window.addEventListener('beforeunload', endTimer);
}

function stopAllTimers() {
for (let key in timers) {
if (timers[key] != null) {
endTimer(key);
}
}
}

function startTimer(key) {
timers[key] = new Date();
};

function endTimer(key) {
if (timers[key] == null) {
return;
}

if (typeof(key) !== 'string') {
key = 'page';
}
const endDate = new Date();
const spentTime = endDate.getTime() - timers[key].getTime();
analytics.time_spent[key] += spentTime;
};

function saveBrowser() {
// check Edge
var ua=navigator.userAgent,tem,M=ua.match(/(opera|chrome|safari|edge|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || [];
var browser = M[0].toLowerCase();

for (let key in analytics.browser) {
if (browser.includes(key)) {
analytics.browser[key] += 1;
return;
}
}
analytics.browser.other += 1;
}

function addValidationError(err) {
analytics.validation_errors[err] += 1;
}

function dataPrefilled() {
analytics.data_prefilled = 1;
}

return {
addValidationError: addValidationError,
analytics: analytics,
dataPrefilled: dataPrefilled,
initialize: initialize,
saveBrowser: saveBrowser,
stopAllTimers: stopAllTimers
};
});
Loading