This commit is contained in:
Oleg Mokhov
2015-06-20 12:26:08 +03:00
committed by mokhov
parent a716969f4e
commit f3546ef3a5
85 changed files with 16682 additions and 1 deletions

View File

@@ -0,0 +1,320 @@
modules.define(
'chitalka',
[
'y-block',
'jquery',
'inherit',
'y-extend',
'chitalka-ui',
'storage'
],
function (
provide,
YBlock,
$,
inherit,
extend,
ChitalkaUI,
Storage
) {
var doc = $(document);
var reportUnimplemented = function (method) {
throw new Error('UNIMPLEMENTED METHOD: ' + method);
};
/**
* Расширение объекта Math для вычисления медианы массива
*
* @param {Array} array
* @returns {Number} медиана
*/
Math.median = function (array) {
if (!array) {
return;
}
var entries = array.length;
var median;
if (entries % 2 === 0) {
median = (array[entries / 2] + array[entries / 2 - 1]) / 2;
} else {
median = array[(entries - 1) / 2];
}
return median;
};
/**
* Выбирает из массива массив медиан в заданном количестве
*
* @param {Array} array
* @param {Number} q количество
*
* @return {Array}
*/
var limitArrayByMedians = function (array, q) {
var result = [];
if (!Array.isArray(array)) {
return result;
}
if (array.length <= q) {
return array;
}
var median = Math.median(array);
var index = array.indexOf(median);
var start = Math.round(index - q / 2);
return array.splice(start, q);
};
/**
* Хэлпер для сортировки массивов чисел
*
* @param {Number} a
* @param {Number} b
* @returns {Number} 1 - a >=b, else -1
*/
var numSort = function (a, b) {
a = parseInt(a, 10);
b = parseInt(b, 10);
return a >= b ? 1 : -1;
};
var Chitalka = inherit(YBlock, {
__constructor: function () {
this.__base.apply(this, arguments);
var params = extend({
keyboard: false,
touch: false,
controls: false,
fontSize: [9, 21],
// Длина свайпа в пикселах
swipeLength: 20
}, this._getOptions());
this._defaultFontSize = 15;
this._settings = new Storage('settings');
// Если читалка не доступна, то кидаем событие и больше
// ничего не делаем
if (!this._isAvailable()) {
this.emit('unavailable');
return;
}
if (params.keyboard) {
this._initKeyboardEvents();
}
if (params.touch) {
this._initTouchEvents();
}
this._fontSizeLimits = params.fontSize;
this._setUpSpeed();
this._initUI();
},
/**
* Выставить скорость чтения книги
*/
_setUpSpeed: function () {
this._speed = Math.median(this._settings.get('speeds')) || 500;
},
_isAvailable: function () {
return false;
},
/**
* Активирует реакцию читалки на события с клавиатуры
*/
_initKeyboardEvents: function () {
this._bindTo(doc, 'keydown', this._onKeyDown);
},
/**
* Активирует реакцию читалки на события блока «Controls»
*/
_initUI: function () {
this._ui = ChitalkaUI.find(doc).init(this);
//var controls = Controls.find(this.getDomNode());
},
/**
* Активация обработки тач-событий (в частности события swipe)
* в функции выполняется навешивание соответствующих событий
*/
_initTouchEvents: function () {
},
_onKeyDown: function (e) {
switch (e.keyCode) {
// Fn + Right
case 35:
this.lastPage();
break;
// Fn + Left
case 36:
this.firstPage();
break;
// Left
case 37:
this.previousPage();
e.preventDefault();
break;
// Right
case 39:
this.nextPage();
e.preventDefault();
break;
// +
case 61:
case 187:
this.zoomIn();
if (e.metaKey) {
e.preventDefault();
}
break;
// -
case 173:
case 189:
this.zoomOut();
if (e.metaKey) {
e.preventDefault();
}
break;
// reset
case 48:
if (e.metaKey) {
this.zoomReset();
}
break;
}
},
/**
* События перемещения по книге
*/
firstPage: function () {
reportUnimplemented('firstPage');
},
previousPage: function () {
reportUnimplemented('previousPage');
},
nextPage: function () {
reportUnimplemented('nextPage');
},
lastPage: function () {
reportUnimplemented('lastPage');
},
/**
* Функция сохранения скорости в аккумулируемый объект
*
* @param {Number} speed
*/
_storeSpeed: function (speed) {
this._speedAccumulator = this._speedAccumulator || [];
this._speedAccumulator.push(speed);
this._speedAccumulator = this._speedAccumulator.sort(numSort);
},
/**
* Функция проверки скорости и её корректировки
* общий принцип работы:
* есть два массива
* this._speedAccumulator аккумулирует чтение текущей книги
* speeds, который хранится в сторадже settings хранит 10 меток скорости для пользователя
* метки это медианы, которые всегда вычисляются из аккумулятора
* как только пользователь прочитывает 10 и более страниц, мы начинаем считать медиану и
* править speeds и класть туда новую скорость, вычисленную из аккумулятора
* При этом глобальная скорость чтения значительно изменится только если пользователь прочитает
* 15 страниц значительно быстрее/медленнее чем раньше.
* Во всех остальных случаях медиана поменяется совсем незначительно
*/
_checkSpeed: function () {
var speedEntries = this._speedAccumulator.length;
if (speedEntries > 10) {
this._speedAccumulator = this._speedAccumulator.sort(numSort);
var median = Math.median(this._speedAccumulator);
// Отсекаем совсем неадекватные скорости
if (median < 100000 && median > 10) {
this._speedAccumulator = this._speedAccumulator.sort(numSort);
if (!this._settings.get('speeds')) {
this._settings.save({
speeds: this._speedAccumulator
});
} else {
var speeds = limitArrayByMedians(this._settings.get('speeds'), 10);
if (speeds.length < 10) {
speeds.push(median);
} else {
if (median <= speeds[5]) {
speeds.pop();
speeds.unshift(median);
} else {
speeds.shift();
speeds.push(median);
}
}
speeds = speeds.sort(numSort);
this._settings.save({
speeds: speeds
});
}
this._speed = Math.median(this._settings.get('speeds'));
}
}
},
/**
* Вернуть текущую скорость чтения
* @returns {Number}
*/
getSpeed: function () {
return this._speed;
},
/**
* События зума книги
*/
zoomIn: function () {
reportUnimplemented('zoomIn');
},
zoomOut: function () {
reportUnimplemented('zoomOut');
},
zoomReset: function () {
reportUnimplemented('zoomReset');
}
});
provide(Chitalka);
});