blob: adbff2fe65d2c398c92dc5a08f6de92c571c67ce [file] [log] [blame]
/* Licensed under the Apache License, Version 2.0 (the "License") http://www.apache.org/licenses/LICENSE-2.0 */
const Role = require('./wb-role');
const WbTools = require('./wb-tools');
const WbZoom = require('./wb-zoom');
const APointer = require('./wb-tool-apointer');
const Player = require('./wb-player');
const TMath = require('./wb-tool-math');
const StaticTMath = require('./wb-tool-stat-math');
require('fabric'); // will produce `fabric` namespace
const BUMPER = 100
, extraProps = ['uid', 'fileId', 'fileType', 'count', 'slide', 'omType', '_src', 'formula'];
module.exports = class Wb {
constructor(wbo, tcid, _role) {
this.id = wbo.wbId;
this.title = wbo.name;
this.width = wbo.width;
this.height = wbo.height;
this.slide = 0;
const canvases = [], self = this;
let wbEl, tools, zoomBar
, role = null, scrollTimeout = null;
function _removeHandler(o) {
const __o = self._findObject(o);
if (!!__o) {
const cnvs = canvases[o.slide];
if (!!cnvs) {
if ('Video' === __o.omType) {
$('#wb-video-' + __o.uid).remove();
}
cnvs.remove(__o);
}
}
}
function _modifyHandler(_o) {
_removeHandler(_o);
_createHandler(_o);
}
function _createHandler(_o) {
switch (_o.fileType) {
case 'VIDEO':
case 'RECORDING':
//no-op
break;
case 'PRESENTATION':
{
const ccount = canvases.length;
for (let i = 0; i < _o.count; ++i) {
if (canvases.length < i + 1) {
addCanvas();
}
const canvas = canvases[i];
if (_o.deleted) {
ToolUtil.addDeletedItem(canvas, _o);
} else {
let scale = self.width / _o.width;
scale = scale < 1 ? 1 : scale;
canvas.setBackgroundImage(_o._src + '&slide=' + i, canvas.renderAll.bind(canvas)
, {scaleX: scale, scaleY: scale});
}
}
zoomBar.update(role, canvases.length);
if (ccount !== canvases.length) {
tools.reactivateBtn();
self._showCurrentSlide();
}
}
break;
default:
{
const canvas = canvases[_o.slide];
if (!!canvas) {
_o.selectable = canvas.selection;
_o.editable = ('text' === tools.getMode() || 'textbox' === tools.getMode());
canvas.add(_o);
}
}
break;
}
}
function _createObject(arr, handler) {
fabric.util.enlivenObjects(arr, function(objects) {
for (let i = 0; i < objects.length; ++i) {
const _o = objects[i];
_o.loaded = true;
handler(_o);
}
self.eachCanvas(function(canvas) {
canvas.requestRenderAll();
});
});
}
//events
function objCreatedHandler(o) {
if (role === Role.NONE && o.omType !== 'pointer') {
return;
}
let json;
switch(o.omType) {
case 'pointer':
json = o;
break;
default:
o.includeDefaultValues = false;
json = self._toOmJson(o);
break;
}
OmUtil.wbAction({action: 'createObj', data: {
wbId: self.id
, obj: json
}});
}
function objAddedHandler(e) {
const o = e.target;
if (o.loaded === true) {
return;
}
switch(o.omType) {
case 'textbox':
case 'i-text':
o.uid = uuidv4();
o.slide = this.slide;
objCreatedHandler(o);
break;
default:
o.selectable = this.selection;
break;
}
}
function objModifiedHandler(e) {
const o = e.target, items = [];
if (role === Role.NONE && o.omType !== 'pointer') {
return;
}
function modifiedAction(items) {
OmUtil.wbAction({action: 'modifyObj', data: {
wbId: self.id
, obj: items
}});
}
o.includeDefaultValues = false;
if ('activeSelection' === o.type) {
o.clone(function(_o) {
// ungrouping
_o.includeDefaultValues = false;
const _items = _o.destroy().getObjects();
for (let i = 0; i < _items.length; ++i) {
items.push(self._toOmJson(_items[i]));
}
modifiedAction(items);
}, extraProps);
} else {
items.push(self._toOmJson(o));
modifiedAction(items);
}
}
function objSelectedHandler(e) {
tools.updateCoordinates(e.target);
}
function selectionCleared(e) {
const o = e.target;
if (!o || '' !== o.text) {
return;
}
if ('textbox' === o.omType || 'i-text' === o.omType) {
OmUtil.wbAction({action: 'deleteObj', data: {
wbId: self.id
, obj: [{
uid: o.uid
, slide: o.slide
}]
}});
}
}
function pathCreatedHandler(o) {
o.path.uid = uuidv4();
o.path.slide = this.slide;
o.path.omType = 'freeDraw';
objCreatedHandler(o.path);
}
function scrollHandler() {
if (scrollTimeout !== null) {
clearTimeout(scrollTimeout);
}
scrollTimeout = setTimeout(function() {
const sc = wbEl.find('.scroll-container')
, canvases = sc.find('.canvas-container');
if (Math.round(sc.height() + sc[0].scrollTop) === sc[0].scrollHeight) {
if (self.slide !== canvases.length - 1) {
self._doSetSlide(canvases.length - 1);
}
return false;
}
canvases.each(function(idx) {
const h = $(this).height(), pos = $(this).position();
if (self.slide !== idx && pos.top > BUMPER - h && pos.top < BUMPER) {
self._doSetSlide(idx);
return false;
}
});
}, 100);
}
/*TODO interactive text change
var textEditedHandler = function (e) {
var obj = e.target;
OmUtil.log('Text Edit Exit', obj);
};
var textChangedHandler = function (e) {
var obj = e.target;
OmUtil.log('Text Changed', obj);
};*/
function setHandlers(canvas) {
// off everything first to prevent duplicates
canvas.off({
'wb:object:created': objCreatedHandler
, 'object:modified': objModifiedHandler
, 'object:added': objAddedHandler
, 'object:selected': objSelectedHandler
, 'path:created': pathCreatedHandler
//, 'text:editing:exited': textEditedHandler
//, 'text:changed': textChangedHandler
, 'before:selection:cleared': selectionCleared
});
canvas.on({
'wb:object:created': objCreatedHandler
, 'object:modified': objModifiedHandler
});
if (role !== Role.NONE) {
canvas.on({
'object:added': objAddedHandler
, 'object:selected': objSelectedHandler
, 'path:created': pathCreatedHandler
, 'before:selection:cleared': selectionCleared
//, 'text:editing:exited': textEditedHandler
//, 'text:changed': textChangedHandler
});
}
}
function addCanvas() {
const sl = canvases.length
, cid = 'can-' + self.id + '-slide-' + sl
, c = $('<canvas></canvas>').attr('id', cid);
wbEl.find('.canvases').append(c);
const canvas = new fabric.Canvas(c.attr('id'), {
preserveObjectStacking: true
});
canvas.wbId = self.id;
canvas.slide = sl;
canvases.push(canvas);
const cc = $('#' + cid).closest('.canvas-container');
if (role === Role.NONE) {
if (sl === self.slide) {
cc.show();
} else {
cc.hide();
}
}
__setSize(canvas);
setHandlers(canvas);
}
function __setSize(_cnv) {
_cnv.setWidth(zoomBar.getZoom() * self.width)
.setHeight(zoomBar.getZoom() * self.height)
.setZoom(zoomBar.getZoom());
}
function _setSize(skipSendWsMsg) {
zoomBar.setSize();
self.eachCanvas(function(canvas) {
__setSize(canvas);
});
if (!skipSendWsMsg) {
self._doSetSlide(self.slide);
}
}
function _videoStatus(json) {
const g = self._findObject(json);
if (!!g) {
g.videoStatus(json.status);
}
}
this._toOmJson = (o) => {
const r = o.toJSON(extraProps);
switch (o.omType) {
case 'Video':
delete r.objects;
break;
case TMath.TYPE:
delete r.objects;
break;
default:
//no-op
}
return r;
};
this._findObject = (o) => {
let _o = null;
const cnvs = canvases[o.slide];
if (!!cnvs) {
cnvs.forEachObject(function(__o) {
if (!!__o && o.uid === __o.uid) {
_o = __o;
return false;
}
});
}
return _o;
};
this.setRole = (_role) => {
if (role !== _role) {
role = _role;
const sc = wbEl.find('.scroll-container');
if (role === Role.NONE) {
sc.off('scroll', scrollHandler);
} else {
sc.on('scroll', scrollHandler);
}
self._showCurrentSlide();
this.eachCanvas(function(canvas) {
setHandlers(canvas);
canvas.forEachObject(function(__o) {
if (!!__o && __o.omType === 'Video') {
__o.setPlayable(role);
}
});
});
tools.setRole(role);
zoomBar.setRole(role);
zoomBar.update(role, canvases.length);
_setSize();
}
};
this.setSize = (wbo) => {
this.width = wbo.width;
this.height = wbo.height;
zoomBar.init(wbo);
_setSize();
};
this.doSetSize = _setSize;
this.resize = () => {
if (zoomBar.getMode() !== 'ZOOM') {
_setSize(true);
}
};
this._showCurrentSlide = () => {
wbEl.find('.scroll-container .canvas-container').each(function(idx) {
if (role === Role.PRESENTER) {
$(this).show();
const cclist = wbEl.find('.scroll-container .canvas-container');
if (cclist.length > self.slide) {
cclist[self.slide].scrollIntoView();
}
} else {
if (idx === self.slide) {
$(this).show();
} else {
$(this).hide();
}
}
});
};
this._doSetSlide = (_sld) => {
const sld = 1 * _sld;
if (sld < 0 || sld > canvases.length - 1) {
return;
}
self.slide = _sld;
OmUtil.wbAction({action: 'setSlide', data: {
wbId: self.id
, slide: _sld
}});
zoomBar.update(role, canvases.length);
};
this.setSlide = (_sl) => {
self.slide = _sl;
self._showCurrentSlide();
};
this.createObj = (obj) => {
const arr = [], del = [], _arr = Array.isArray(obj) ? obj : [obj];
for (let i = 0; i < _arr.length; ++i) {
const o = _arr[i];
if (!!o.deleted && 'PRESENTATION' !== o.fileType) {
del.push(o);
continue;
}
switch(o.omType) {
case 'pointer':
new APointer(this).create(canvases[o.slide], o);
break;
case 'Video':
Player.create(canvases[o.slide], o, self);
break;
case TMath.TYPE:
StaticTMath.create(o, canvases[o.slide]);
break;
default:
{
const __o = self._findObject(o);
if (!__o) {
arr.push(o);
}
}
break;
}
}
if (arr.length > 0) {
_createObject(arr, _createHandler);
}
for (let i = 0; i < del.length; ++i) {
const o = del[i];
ToolUtil.addDeletedItem(canvases[o.slide], o);
}
};
this.load = this.createObj;
this.modifyObj = (obj) => { //TODO need to be unified
const arr = [], _arr = Array.isArray(obj) ? obj : [obj];
for (let i = 0; i < _arr.length; ++i) {
const o = _arr[i];
switch(o.omType) {
case 'pointer':
_modifyHandler(new APointer(this).create(canvases[o.slide], o));
break;
case 'Video':
{
const g = self._findObject(o);
if (!!g) {
Player.modify(g, o);
}
}
break;
case TMath.TYPE:
{
_removeHandler(o);
StaticTMath.create(o, canvases[o.slide]);
}
break;
default:
arr.push(o);
break;
}
}
if (arr.length > 0) {
_createObject(arr, _modifyHandler);
}
};
this.removeObj = (arr) => {
for (let i = 0; i < arr.length; ++i) {
_removeHandler(arr[i]);
}
};
this.clearAll = () => {
for (let i = 1; i < canvases.length; ++i) {
const cc = $('#can-' + this.id + '-slide-' + i).closest('.canvas-container');
cc.remove();
canvases[i].dispose();
}
$('.room-block .wb-block .wb-video').remove();
canvases.splice(1);
canvases[0].clear();
zoomBar.update(role, canvases.length);
};
this.clearSlide = (_sl) => {
if (canvases.length > _sl) {
const canvas = canvases[_sl];
let arr = canvas.getObjects();
while (arr.length > 0) {
canvas.remove(arr[arr.length - 1]);
arr = canvas.getObjects();
}
$('.room-block .wb-block .wb-video.slide-' + _sl).remove();
canvas.requestRenderAll();
}
};
this.getCanvas = (_slide) => {
return canvases[typeof(_slide) === 'number' ? _slide : self.slide];
};
this.eachCanvas = (func) => {
for (let i = 0; i < canvases.length; ++i) {
func(canvases[i]);
}
};
this.videoStatus = _videoStatus;
this.getRole = () => {
return role;
};
this.getFormula = () => {
return tools.getMath();
};
this.getZoom = () => {
return zoomBar.getZoom();
};
this.destroy = () => {
tools.destroy();
};
wbEl = $('#' + tcid);
tools = new WbTools(wbEl, this);
zoomBar = new WbZoom(wbEl, this);
zoomBar.init(wbo);
addCanvas();
this.setRole(_role);
}
getId() {
return this.id;
}
};