tao-test/app/taoQtiItem/views/js/qtiCreator/helper/gridUnits.js

200 lines
5.9 KiB
JavaScript

/**
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; under version 2
* of the License (non-upgradable).
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright (c) 2015 (original work) Open Assessment Technologies SA ;
*/
define(['lodash'], function(_){
"use strict";
/**
* Argument cols format:
* [{elt:elementRef, units:6, min:4}]
*
* Return format:
* {last:6, middle:4, distributed:[{elt:elementRef, units:5}]}
*
* @param {array} cols
* @param {int} min
* @param {int} max
* @returns {object}
*/
function distributeUnits(cols, min, max){
max = max || 12;
var totalUnits = 0, size = 0, _cols = {}, ret = {}, minimized = [], decimals = [];
for(var i in cols){
_cols[i] = _.clone(cols[i]);
totalUnits += cols[i].units;
size++;
}
var avg = totalUnits / size;
_cols[size + 1] = {
'elt' : 'middle',
'units' : avg,
'min' : min
};
if(totalUnits + Math.round(avg) > max){
var refactoredTotalUnits = 0;
//need to squeeze the new col between existing ones:
//refactored
for(var i in _cols){
var col = _cols[i];
var refactoredUnits = col.units * max / (max + avg);//calculate the average, basis for the new inserted element's units
decimals[i] = Math.round((refactoredUnits % 1) * 100);//get its decimals for later usage
col.refactoredUnits = Math.round(refactoredUnits);
if(col.min && col.refactoredUnits < col.min){//a col cannot be smaller than its min units
col.refactoredUnits = col.min;
minimized[i] = true;//marked it as not changeable
}
refactoredTotalUnits += col.refactoredUnits;
}
if(refactoredTotalUnits > max){
//try ceil new units values:
for(var i; i < size + 1; i++){
var col = _cols[i];
if(col.decimal > 50 && col.refactoredUnits - 1 > col.min){
col.refactoredUnits--;
refactoredTotalUnits--;
}
if(refactoredTotalUnits === max){
break;//target achieved
}
}
}
var middleUnitValue = _cols[size + 1].refactoredUnits;
var lastUnitValue = (refactoredTotalUnits > max) ? max : middleUnitValue;
delete _cols[size + 1];
ret = {
last : lastUnitValue, //new col takes the remaining space
middle : middleUnitValue,
cols : _cols,
refactoredTotalUnits : refactoredTotalUnits
};
}else{
//there is "room" for the new element to fill the whole row:
var last = max - totalUnits;
ret = {
last : last,
middle : last,
cols : {}//no need to resize cols
};
}
return ret;
}
/**
* Rebistributs the cols proportionally to fill out the "max" width
*
* @param {array} cols
* @param {integer} max
* @returns {object}
*/
function redistributeUnits(cols, max){
max = max || 12;//default to max
var totalUnits = 0,
_cols = [],
totalRefactoredUnits = 0,
negative = [],
positive = [],
ret = [];
_.each(cols, function(col){
_cols.push(col);
totalUnits += col.units;
});
if(totalUnits > max){
throw 'the total number of units exceed the maximum of ' + max;
}
_.each(_cols, function(col){
var refactoredUnits = col.units * max / totalUnits;
var rounded = Math.round(refactoredUnits);
totalRefactoredUnits += rounded;
col.refactoredUnits = rounded;
if(rounded > refactoredUnits){
positive.push(col);
}else{
negative.push(col);
}
});
positive = _.sortBy(positive, 'refactoredUnits');
negative = _.sortBy(negative, 'refactoredUnits');
if(totalRefactoredUnits > max){
//too much !
//@todo : start with the hightest refactored
_.eachRight(positive, function(col){
col.refactoredUnits --;
totalRefactoredUnits--;
if(totalRefactoredUnits === max){
return false;
}
});
}else if(totalRefactoredUnits < max){
//@todo : start with the lowest refactored
_.each(negative, function(col){
col.refactoredUnits ++;
totalRefactoredUnits++;
if(totalRefactoredUnits === max){
return false;
}
});
}
_.each(negative, function(col){
ret.push(col);
});
_.each(positive, function(col){
ret.push(col);
});
return _cols;
}
return {
distribute : function(cols, min, max){
return distributeUnits(cols, min, max);
},
redistribute : function(cols, max){
return redistributeUnits(cols, max);
}
};
});