fixes, implement undo and tooltips and aligntools

This commit is contained in:
Reaby committed 2020-02-05 00:23:34 +02:00
1 parent fced76c2ef
commit 904e8c3904
6 files changed
+532 -369

No files matched your search

Binary file not shown.

Before

Width:  |  Height:  |  Size: 194 KiB

After

Width:  |  Height:  |  Size: 194 KiB

@@ -1 +1 @@
{"version":"2.7.0","objects":[{"type":"i-text","version":"2.7.0","left":505.15,"top":73,"width":268.71,"height":63.28,"fill":"#fff","stroke":"","shadow":{"color":"rgba(0,0,0,0.6)","blur":5,"offsetX":2,"offsetY":2,"affectStroke":false},"text":"Features","fontSize":56,"fontWeight":900,"fontFamily":"Arial","id":"header","styles":{}},{"type":"i-text","version":"2.7.0","left":227,"top":194.61,"width":825.13,"height":413.67,"fill":"#fff","stroke":"","shadow":{"color":"rgba(0,0,0,0.6)","blur":5,"offsetX":2,"offsetY":2,"affectStroke":false},"text":"Easy-to-use editor for slides supports\nadding text and images to slides.\n\n\n\nFinnish and English language support, \nautomatically set from browser language.\n\nSupports web content as slides with scaling\nis useful for timetables, tournament brackets...","fontSize":32,"fontWeight":900,"fontFamily":"Arial","textAlign":"center","id":"normal","styles":{}},{"type":"image","version":"2.7.0","left":200,"top":291.07,"width":1310,"height":141,"scaleX":0.68,"scaleY":0.68,"crossOrigin":"","src":"/images/default/toolbar.png","filters":[]}]}
{"version":"3.6.1","objects":[{"type":"i-text","version":"3.6.1","left":505.15,"top":73,"width":268.71,"height":63.28,"fill":"#fff","stroke":"","shadow":{"color":"rgba(0,0,0,0.6)","blur":5,"offsetX":2,"offsetY":2,"affectStroke":false,"nonScaling":false},"text":"Features","fontSize":56,"fontWeight":900,"fontFamily":"Arial","id":"header","styles":{}},{"type":"i-text","version":"3.6.1","left":227,"top":194.61,"width":825.13,"height":413.67,"fill":"#fff","stroke":"","shadow":{"color":"rgba(0,0,0,0.6)","blur":5,"offsetX":2,"offsetY":2,"affectStroke":false,"nonScaling":false},"text":"Easy-to-use editor for slides supports\nadding text and images to slides.\n\n\n\nFinnish and English language support, \nautomatically set from browser language.\n\nSupports web content as slides with scaling\nis useful for timetables, tournament brackets...","fontSize":32,"fontWeight":900,"fontFamily":"Arial","textAlign":"center","id":"normal","styles":{}},{"type":"image","version":"3.6.1","left":200,"top":291.07,"width":1310,"height":141,"scaleX":0.68,"scaleY":0.68,"crossOrigin":"","src":"/images/default/toolbar.png","filters":[]}]}
+27 -2
View File
@@ -82,7 +82,12 @@
"sendToFront": "Send to front",
"moveForward": "Move forward",
"moveBackward": "Move backward",
"sendToBack": "Send to back"
"sendToBack": "Send to back",
"centerHorizontal": "Center Horizontal",
"centerVertical": "Center Vertical",
"copy": "Copy element",
"paste": "Paste element",
"remove": "Remove element"
},
"addLink": {
"name": "Name",
@@ -90,6 +95,26 @@
"zoom": "Zoom page by",
"duration": "Display duration (seconds), leave blank for default",
"displayTime": "Display time"
},
"tooltip": {
"header": "Insert header",
"paragraph": "Insert text",
"image": "Insert an image",
"bringToFront": "Arrage element topmost",
"bringForward": "Brings element forward",
"sendBackward": "Send element backward",
"sendToBack": "Send element back",
"alignLeft": "Align left",
"alignCenter": "Align center",
"alignRight": "Align right",
"alignUp": "Align top",
"alignDown": "Align bottom",
"alignJustify": "Justify Align",
"fontPlus": "Increase font size",
"fontMinus": "Decrease font size",
"centerHorizontal":"Center Horizontal",
"centerVertical":"Center Vertical",
"undo": "Undo last action"
}
},
"index": {
@@ -98,4 +123,4 @@
"lite": "Lite",
"splitter": "or"
}
}
}
+21 -1
View File
@@ -90,6 +90,26 @@
"zoom": "Suurennus",
"duration": "Pituus (sekunneissa), tyhjä on oletusarvo",
"displayTime": "Näytä aika"
},
"tooltip": {
"header": "Lisää otsikko",
"paragraph": "Lisää teksti",
"image": "Lisää kuva",
"bringToFront": "Tuo edustalle",
"bringForward": "Tuo eteenpäin",
"sendBackward": "Vie taaksepäin",
"sendToBack": "Vie taustalle",
"alignLeft": "Tasaa vasemmalle",
"alignCenter": "Keskitä",
"alignRight": "Tasaa oikealle",
"alignUp": "Tasaa yläosat",
"alignDown": "Tasaa alaosat",
"alignJustify": "Tasaa",
"fontPlus": "Lisää kirjaisimen kokoa",
"fontMinus": "Vähennä kirjaisimen kokoa",
"centerHorizontal": "Keskitä vaakasuunnassa",
"centerVertical": "Keskitä pystysuunnassa",
"undo": "Kumoa"
}
},
"index": {
@@ -98,4 +118,4 @@
"lite": "Kevyt",
"splitter": "tai"
}
}
}
+117 -7
View File
@@ -5,6 +5,9 @@ var grid = 1280 / 32;
var _clipboard = null;
var slideName = "untitled";
var undoData = [];
var undoActive = false;
bundleData = {
background: "",
@@ -19,7 +22,7 @@ $(function () {
canvas.includeDefaultValues = false;
canvas.preserveObjectStacking = true;
canvas.antialias = true;
canvas.on('object:moving', function (options) {
if (Math.round(options.target.left / grid * 4) % 4 === 0) {
options.target.set({
@@ -32,6 +35,19 @@ $(function () {
}
});
canvas.on("object:added", function() {
if (undoActive) {
saveState();
}
});
canvas.on("object:modified", function() {
if (undoActive) {
saveState();
}
});
$('html').keyup(function (e) {
if (e.keyCode === 46) {
var obj = canvas.getActiveObject();
@@ -63,7 +79,7 @@ $(function () {
hoverable: true,
position: 'bottom center',
delay: {
show: 200,
show: 50,
hide: 800
}
});
@@ -141,6 +157,36 @@ $("#contextmenu .item").click(function () {
$("#contextmenu").hide(100);
});
function saveState() {
if (undoData.length >= 10) {
undoData.shift();
}
undoData.push(canvas.toJSON(['id', 'fontSize']));
}
function undo() {
let json = {};
if (undoData.length > 1) {
undoData.pop();
json = undoData[undoData.length-1];
}
if (undoData.length == 1) {
json = undoData[undoData.length-1];
}
undoActive = false;
canvas.loadFromJSON(json, function () {
canvas.requestRenderAll();
undoActive = true;
}, function (obj, elem) {
if (elem.type == "line") {
elem.selectable = false
}
});
}
/**
* Displays the local time for bottom of screen
* hh:mm
@@ -347,14 +393,14 @@ function drawGrid() {
strokeDashArray: [w, w],
opacity: 0.5,
selectable: false,
zIndex: 0
zIndex: -1
}));
canvas.add(new fabric.Line([0, i * grid, 1280, i * grid], {
stroke: '#ccc',
strokeDashArray: [w, w],
opacity: 0.5,
selectable: false,
zIndex: 0
zIndex: -1
}))
}
canvas.renderAll();
@@ -377,10 +423,12 @@ function checkTimeDisplay() {
}
function nextSlide(data) {
undoActive = false;
canvas.loadFromJSON(data.json, function () {
drawGrid();
canvas.renderAll();
canvas.requestRenderAll();
undoActive = true;
saveState();
}, function (obj, object) {
if (object.type === "i-text") {
@@ -415,7 +463,7 @@ function nextSlide(data) {
object.lockUniScaling = true;
object.hasRotatingPoint = false;
}
object.preserveObjectStacking = true;
object.lockUniScaling = true;
});
@@ -754,6 +802,68 @@ function setCenter(direction) {
}
}
function alignObject(direction) {
let objects = canvas.getActiveObjects();
let active = canvas.getActiveObject();
let first = true;
for (var obj of objects) {
if (first) {
first = false;
active = obj;
}
switch(direction) {
case "top":
if (obj.top < active.top) active = obj;
break;
case "bottom":
if ((obj.top + obj.height) > (active.top + active.height)) active = obj;
break;
case "left": {
if (obj.left < active.left) active = obj;
break;
}
case "right": {
if ((obj.left + obj.width) > (active.left + active.width)) active = obj;
break;
}
}
}
for (var obj of objects) {
if (direction == "top") {
obj.set(
{
top: parseFloat(active.top)
});
}
if (direction == "bottom") {
obj.set(
{
top: parseFloat(active.top + active.height - obj.height)
});
}
if (direction == "left") {
obj.set(
{
left: parseFloat(active.left)
});
}
if (direction == "right") {
obj.set(
{
left: parseFloat(active.left + active.width - obj.width)
});
}
obj.setCoords();
}
canvas.discardActiveObject(null);
canvas.requestRenderAll();
}
function fontSize(direction) {
for (var obj of canvas.getActiveObjects()) {
var sizes = [20, 28, 32, 36, 40, 44, 48, 50, 54, 58, 64, 72, 96];
+366 -358
View File
@@ -1,414 +1,422 @@
{% extends 'layout/edit.twig' %}
{% block header %}
<script src="https://ajax.googleapis.com/ajax/libs/webfont/1.6.26/webfont.js"></script>
<script src="/socket.io/socket.io.js"></script>
<script>
var bundle = "{{ bundle }}";
var file = "{{ file }}";
{% if displayId != null %}
var displayId = {{ displayId }};
{% else %}
var displayId = 0;
{% endif %}
</script>
<style>
label {
color: white;
}
<script src="https://ajax.googleapis.com/ajax/libs/webfont/1.6.26/webfont.js"></script>
<script src="/socket.io/socket.io.js"></script>
<script>
var bundle = "{{ bundle }}";
var file = "{{ file }}";
var displayId = {{ displayId }};
</script>
<style>
label {
color: white;
}
canvas {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-moz-font-smoothing: antialiased;
font-smoothing: antialiased;
text-rendering: geometricPrecision;
font-smooth: always;
}
</style>
canvas {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-moz-font-smoothing: antialiased;
font-smoothing: antialiased;
text-rendering: geometricPrecision;
font-smooth: always;
}
</style>
{% endblock %}
{% block body %}
<div class="ui primary pointing menu" style="margin: 0;">
<div class="item">
<div class="ui input">
<label for="duration"></label>
<input type="number" id="duration" placeholder="{{ t("navs.duration") }}" min="5"/>
</div>
<div class="ui primary pointing menu" style="margin: 0;">
<div class="item">
<div class="ui input">
<label for="duration"></label>
<input type="number" id="duration" placeholder="{{ t("navs.duration") }}" min="5" />
</div>
</div>
<div class="item">
<div id="override" class="ui checkbox">
<input id="lbl2" type="checkbox" />
<label for="lbl2">{{ t("navs.override") }} </label>
</div>
<div class="item">
<div id="override" class="ui checkbox">
<input id="lbl2" type="checkbox"/>
<label for="lbl2">{{ t("navs.override") }} </label>
</div>
<div id="displaytime" class="ui toggle checkbox">
<input id="lbl" type="checkbox"/>
<label for="lbl">{{ t("navs.time") }}</label>
</div>
<div id="displaytime" class="ui toggle checkbox">
<input id="lbl" type="checkbox" />
<label for="lbl">{{ t("navs.time") }}</label>
</div>
<div id="transitions" class="ui dropdown item">
<div class="ui small breadcrumb">
<span class="section">{{ t("navs.transition") }}</span>
<i class="right chevron icon divider"></i>
<span id="currentTransition" class="section"></span>
</div>
<i class="dropdown icon"></i>
</div>
<div id="transitions" class="ui dropdown item">
<div class="ui small breadcrumb">
<span class="section">{{ t("navs.transition") }}</span>
<i class="right chevron icon divider"></i>
<span id="currentTransition" class="section"></span>
</div>
<i class="dropdown icon"></i>
</div>
<div class="item">
<div class="ui labeled input">
<label class="ui right pointing label" for="slide_name">{{ t("navs.slideName") }}</label>
<input class="ui input" name="slideName" type="text" id="slideName" value="untitled" />
</div>
</div>
<div class="right menu">
<div class="item">
<div class="ui labeled input">
<label class="ui right pointing label" for="slide_name">{{ t("navs.slideName") }}</label>
<input class="ui input" name="slideName" type="text" id="slideName" value="untitled"/>
</div>
</div>
<div class="right menu">
<div class="item">
<div class="ui green buttons">
<div onclick="save()" class="ui button">{{ t("actions.save") }}</div>
<div class="ui floating dropdown icon button" id="dropdownSave">
<i class="dropdown icon"></i>
<div class="menu">
<div onclick="saveTemplate()" class="item"><i
class="save icon"></i> {{ t("actions.savetemplate") }}</div>
</div>
<div class="ui green buttons">
<div onclick="save()" class="ui button">{{ t("actions.save") }}</div>
<div class="ui floating dropdown icon button" id="dropdownSave">
<i class="dropdown icon"></i>
<div class="menu">
<div onclick="saveTemplate()" class="item"><i class="save icon"></i>
{{ t("actions.savetemplate") }}</div>
</div>
</div>
</div>
{% if displayId != null %}
<div class="ui red basic buttons">
<div onclick="cueSlide({{ displayId }})" class="ui button">{{ t("actions.announce") }}</div>
<div class="ui floating dropdown icon button" id="dropdownAnnounce">
<i class="dropdown icon"></i>
<div class="menu">
<div onclick="cueSlide(null)" class="item"><i
class="exclamation icon"></i> {{ t("actions.announceAll") }}</div>
</div>
</div>
{% if displayId != null %}
<div class="ui red basic buttons">
<div onclick="cueSlide({{ displayId }})" class="ui button">{{ t("actions.announce") }}</div>
<div class="ui floating dropdown icon button" id="dropdownAnnounce">
<i class="dropdown icon"></i>
<div class="menu">
<div onclick="cueSlide(null)" class="item"><i class="exclamation icon"></i>
{{ t("actions.announceAll") }}</div>
</div>
{% else %}
<a href="#" onclick="cueSlide(null)" class="ui red button">{{ t("actions.announceAll") }}</a>
{% endif %}
</div>
<div class="item">
<a href="#" onclick="window.close()" class="ui button">{{ t("actions.cancel") }}</a>
</div>
</div>
</div>
<div class="ui menu" style="margin: 0;">
<div class="item">
<div class="ui inverted buttons">
<a href="#" onclick="addHeader('header')" class="ui basic icon button"><i
class="ui heading icon"></i></a>
<a href="#" onclick="addText('paragraph text')" class="ui basic icon button"><i
class="ui paragraph icon"></i></a>
<a href="#" onclick="openImageBrowser()" class="ui basic icon button"><i
class="ui image icon"></i></a>
</div>
</div>
<div class="item">
<div class="ui inverted buttons">
<a class="ui basic icon button"
onclick="setZindex('bringToFront');">
<i class="ui level up icon"></i>
</a>
<a class="ui basic icon button"
onclick="setZindex('bringForward');">
<i class="ui arrow up icon"></i>
</a>
<a class="ui basic icon button"
onclick="setZindex('sendBackwards>');">
<i class="ui arrow down icon"></i>
</a>
<a class="ui basic icon button"
onclick="setZindex('sendToBack');">
<i class="ui level down icon"></i>
</a>
</div>
</div>
<div class="item">
<div class="ui inverted buttons">
<a href="#" onclick="setAlign('left')" class="ui basic icon button"><i
class="ui align left icon"></i></a>
<a href="#" onclick="setAlign('center')" class="ui basic icon button"><i
class="ui align center icon"></i></a>
<a href="#" onclick="setAlign('right')" class="ui basic icon button"><i
class="ui align right icon"></i></a>
<a href="#" onclick="setAlign('justify')" class="ui basic icon button"><i
class="ui align justify icon"></i></a>
</div>
</div>
<div class="item">
<div onclick="fontSize(1);" class="ui basic icon button">
<i class="icons">
<i class="plus icon"></i>
<i class="corner font icon"></i>
</i>
</div>
<div onclick="fontSize(-1);" class="ui basic icon button">
<i class="icons">
<i class="minus icon"></i>
<i class="corner font icon"></i>
</i>
</div>
</div>
<div class="item">
<div id="colorPicker" class="ui basic button">{{ t("admin.editSlide.changeColor") }} </div>
<div class="ui popup" style="display: none; min-width: 500px;">
<div onclick="changeColor(this);" class="ui white basic icon button"></div>
<div onclick="changeColor(this);" class="ui grey icon button"></div>
<div onclick="changeColor(this);" style="background:black;" class="ui black icon button"></div>
<div onclick="changeColor(this);" class="ui red icon icon button"></div>
<div onclick="changeColor(this);" class="ui orange icon button"></div>
<div onclick="changeColor(this);" class="ui yellow icon button"></div>
<div onclick="changeColor(this);" class="ui olive icon button"></div>
<div onclick="changeColor(this);" class="ui green icon button"></div>
<div onclick="changeColor(this);" class="ui teal icon button"></div>
<div onclick="changeColor(this);" class="ui blue icon button"></div>
<div onclick="changeColor(this);" class="ui violet icon button"></div>
<div onclick="changeColor(this);" class="ui purple icon button"></div>
<div onclick="changeColor(this);" class="ui pink icon button"></div>
<div onclick="changeColor(this);" class="ui brown icon button"></div>
</div>
</div>
<div class="item">
<div class="ui basic icon button" onclick="setCenter('h')"><i class="arrows alternate horizontal icon"></i>
</div>
<div class="ui basic icon button" onclick="setCenter('v')"><i class="arrows alternate vertical icon"></i>
</div>
</div>
<div class="right menu">
<div class="item">
<div class="ui inverted buttons"><a href="#" onclick="copyObject()" class="ui basic icon button"><i
class="ui copy icon"></i></a>
<a href="#" onclick="pasteObject()" class="ui basic icon button"><i
class="ui paste icon"></i></a>
<a href="#" onclick="removeSelectedObjects()" class="ui basic icon button"><i
class="ui remove icon"></i></a>
</div>
</div>
{% else %}
<a href="#" onclick="cueSlide(null)" class="ui red button">{{ t("actions.announceAll") }}</a>
{% endif %}
</div>
<div class="item">
<a href="#" onclick="window.close()" class="ui button">{{ t("actions.cancel") }}</a>
</div>
</div>
</div>
<div class="ui menu" style="margin: 0;">
<div class="item">
<div class="ui inverted buttons">
<a href="#" onclick="addHeader('header')" class="ui basic icon button" data-content="{{ t("admin.tooltip.header")}}"><i class="ui heading icon"></i></a>
<a href="#" onclick="addText('paragraph text')" class="ui basic icon button" data-content="{{t("admin.tooltip.paragraph")}}"><i class="ui paragraph icon"></i></a>
<a href="#" onclick="openImageBrowser()" class="ui basic icon button" data-content="{{t("admin.tooltip.image")}}"><i class="ui image icon"></i></a>
</div>
</div>
<div class="item">
<div class="ui inverted buttons">
<a class="ui basic icon button" onclick="setZindex('bringToFront');" data-content="{{t("admin.tooltip.bringToFront")}}">
<i class="ui level up icon"></i>
</a>
<a class="ui basic icon button" onclick="setZindex('bringForward');" data-content="{{t("admin.tooltip.bringForward")}}">
<i class="ui arrow up icon"></i>
</a>
<a class="ui basic icon button" onclick="setZindex('sendBackwards>');" data-content="{{t("admin.tooltip.sendBackward")}}">
<i class="ui arrow down icon"></i>
</a>
<a class="ui basic icon button" onclick="setZindex('sendToBack');" data-content="{{t("admin.tooltip.sendToBack")}}">
<i class="ui level down icon"></i>
</a>
</div>
</div>
<div style="margin:0; padding:0;">
<div id="matchsize">
<canvas id="edit" width="1280" height="720" style="position: fixed; z-index:10;"></canvas>
<div id="bg">
<img id="bgimg" class="fsimage" src=""/>
</div>
<video muted loop autoplay id="bgvid2" poster="">
</video>
<div id="time2" class="noselect delay animated">00:00</div>
<div class="item">
<div class="ui inverted buttons">
<a href="#" onclick="setAlign('left')" class="ui basic icon button" data-content="{{t("admin.tooltip.alignLeft")}}"><i class="ui align left icon"></i></a>
<a href="#" onclick="setAlign('center')" class="ui basic icon button" data-content="{{t("admin.tooltip.alignCenter")}}"><i
class="ui align center icon"></i></a>
<a href="#" onclick="setAlign('right')" class="ui basic icon button" data-content="{{t("admin.tooltip.alignRight")}}"><i class="ui align right icon"></i></a>
<a href="#" onclick="setAlign('justify')" class="ui basic icon button" data-content="{{t("admin.tooltip.alignJustify")}}"><i
class="ui align justify icon"></i></a>
</div>
</div>
<div class="item">
<div onclick="fontSize(1);" class="ui basic icon button" data-content="{{t("admin.tooltip.fontPlus")}}">
<i class="icons">
<i class="plus icon"></i>
<i class="corner font icon"></i>
</i>
</div>
<div onclick="fontSize(-1);" class="ui basic icon button" data-content="{{t("admin.tooltip.fontMinus")}}">
<i class="icons">
<i class="minus icon"></i>
<i class="corner font icon"></i>
</i>
</div>
</div>
<div class="item">
<div id="colorPicker" class="ui basic button">{{ t("admin.editSlide.changeColor") }} </div>
<div id="contextmenu" class="ui small vertical menu" style="display: none; position: absolute; z-index: 1000;">
<a class="item" data-action="copy">
{{ t("actions.copy") }}
</a>
<a class="item" data-action="paste">
{{ t("actions.paste") }}
</a>
<div class="ui dropdown item">
<i class="dropdown icon"></i>
{{ t("admin.editSlide.order") }}
<div class="menu">
<div class="item" data-action="bringToFront">{{ t("admin.editSlide.sendToFront") }}</div>
<div class="item" data-action="bringForward">{{ t("admin.editSlide.moveForward") }}</div>
<div class="item" data-action="sendBackwards">{{ t("admin.editSlide.moveBackward") }}</div>
<div class="item" data-action="sendToBack">{{ t("admin.editSlide.sendToBack") }}</div>
<div class="ui popup" style="display: none; min-width: 500px;">
<div onclick="changeColor(this);" class="ui white basic icon button"></div>
<div onclick="changeColor(this);" class="ui grey icon button"></div>
<div onclick="changeColor(this);" style="background:black;" class="ui black icon button"></div>
<div onclick="changeColor(this);" class="ui red icon icon button"></div>
<div onclick="changeColor(this);" class="ui orange icon button"></div>
<div onclick="changeColor(this);" class="ui yellow icon button"></div>
<div onclick="changeColor(this);" class="ui olive icon button"></div>
<div onclick="changeColor(this);" class="ui green icon button"></div>
<div onclick="changeColor(this);" class="ui teal icon button"></div>
<div onclick="changeColor(this);" class="ui blue icon button"></div>
<div onclick="changeColor(this);" class="ui violet icon button"></div>
<div onclick="changeColor(this);" class="ui purple icon button"></div>
<div onclick="changeColor(this);" class="ui pink icon button"></div>
<div onclick="changeColor(this);" class="ui brown icon button"></div>
</div>
</div>
<div class="item">
<div class="ui basic icon button" onclick="setCenter('h')" data-content="{{t("admin.tooltip.centerHorizontal")}}"><i class="arrows alternate horizontal icon"></i></div>
<div class="ui basic icon button" onclick="setCenter('v')" data-content="{{t("admin.tooltip.centerVertical")}}"><i class="arrows alternate vertical icon"></i></div>
<div class="ui basic icon button" onclick="alignObject('left')" data-content="{{t("admin.tooltip.alignLeft")}}"><i class="arrow alternate circle left outline icon"></i></div>
<div class="ui basic icon button" onclick="alignObject('right')" data-content="{{t("admin.tooltip.alignRight")}}"><i class="arrow alternate circle right outline icon"></i></div>
<div class="ui basic icon button" onclick="alignObject('top')" data-content="{{t("admin.tooltip.alignUp")}}"><i class="arrow alternate circle up outline icon"></i></div>
<div class="ui basic icon button" onclick="alignObject('bottom')" data-content="{{t("admin.tooltip.alignDown")}}"><i class="arrow alternate circle down outline icon"></i></div>
</div>
<div class="right menu">
<div class="item">
<div class="ui inverted buttons">
<a href="#" onclick="undo()" class="ui basic icon button" data-content="{{ t("admin.tooltip.undo") }}"><i
class="ui undo icon"></i> {{ t("admin.tooltip.undo") }}</a>
<a href="#" onclick="copyObject()" class="ui basic icon button" data-content="{{t("admin.tooltip.copy")}}"><i
class="ui copy icon"></i></a>
<a href="#" onclick="pasteObject()" class="ui basic icon button"><i class="ui paste icon" data-content="{{t("admin.tooltip.paste")}}"></i></a>
<a href="#" onclick="removeSelectedObjects()" class="ui basic icon button" data-content="{{t("admin.tooltip.remove")}}"><i
class="ui remove icon"></i></a>
</div>
</div>
<a class="item" data-action="delete">
{{ t("actions.delete") }}
</a>
</div>
</div>
<div id="imageLayer" class="ui modal">
<div class="header">{{ t("admin.editSlide.insertImage") }}</div>
<div id="dropzone" class="scrolling content">
<div class="ui info message">{{ t("admin.editSlide.dropToUpload") }}</div>
<div id="imageList" class="ui three stackable cards">
</div>
<div style="margin:0; padding:0;">
<div id="matchsize">
<canvas id="edit" width="1280" height="720" style="position: fixed; z-index:10;"></canvas>
<div id="bg">
<img id="bgimg" class="fsimage" src="" />
</div>
<div class="actions">
<div class="ui cancel button">{{ t("actions.cancel") }}</div>
<video muted loop autoplay id="bgvid2" poster="">
</video>
<div id="time2" class="noselect delay animated">00:00</div>
</div>
</div>
<div id="contextmenu" class="ui small vertical menu" style="display: none; position: absolute; z-index: 1000;">
<a class="item" data-action="copy">
{{ t("actions.copy") }}
</a>
<a class="item" data-action="paste">
{{ t("actions.paste") }}
</a>
<div class="ui dropdown item">
<i class="dropdown icon"></i>
{{ t("admin.editSlide.order") }}
<div class="menu">
<div class="item" data-action="bringToFront">{{ t("admin.editSlide.sendToFront") }}</div>
<div class="item" data-action="bringForward">{{ t("admin.editSlide.moveForward") }}</div>
<div class="item" data-action="sendBackwards">{{ t("admin.editSlide.moveBackward") }}</div>
<div class="item" data-action="sendToBack">{{ t("admin.editSlide.sendToBack") }}</div>
</div>
</div>
<a class="item" data-action="delete">
{{ t("actions.delete") }}
</a>
</div>
<canvas id="tempCanvas" width="1280" height="720" style="display: none"></canvas>
<div id="imageLayer" class="ui modal">
<div class="header">{{ t("admin.editSlide.insertImage") }}</div>
<div id="dropzone" class="scrolling content">
<div class="ui info message">{{ t("admin.editSlide.dropToUpload") }}</div>
<div id="imageList" class="ui three stackable cards">
<script>
var socket = io.connect("{{ config.serverUrl }}:{{ config.serverListenPort }}/admin-" + displayId);
</script>
<script>
var images = {};
</div>
</div>
<div class="actions">
<div class="ui cancel button">{{ t("actions.cancel") }}</div>
</div>
</div>
$(function () {
var opts = {
dragClass: "active",
on: {
load: function (e, file) {
// check file type
var imageType = /image.(jpeg|png)/;
if (!file.type.match(imageType)) {
// alert("File \"" + file.name + "\" is not a valid image file, only jpeg and png are supported");
return false;
}
<canvas id="tempCanvas" width="1280" height="720" style="display: none"></canvas>
// check file size
if (parseInt(file.size / 1024) > 2050) {
alert("File \"" + file.name + "\" is too big. Max allowed size is 2 MB.");
return false;
}
createBox(e, file);
},
}
};
FileReaderJS.setupDrop(document.getElementById('dropzone'), opts);
FileReaderJS.setupClipboard(document.body, opts);
<script>
var socket = io.connect("{{ config.serverUrl }}:{{ config.serverListenPort }}/admin-" + displayId);
</script>
<script>
var images = {};
$('.ui.button').popup({
delay: {
show: 1000,
hide: 0
},
position: "bottom left"
});
$(function () {
var opts = {
dragClass: "active",
on: {
load: function (e, file) {
// check file type
var imageType = /image.(jpeg|png)/;
if (!file.type.match(imageType)) {
// alert("File \"" + file.name + "\" is not a valid image file, only jpeg and png are supported");
return false;
}
// check file size
if (parseInt(file.size / 1024) > 2050) {
alert("File \"" + file.name + "\" is too big. Max allowed size is 2 MB.");
return false;
}
createBox(e, file);
},
}
};
FileReaderJS.setupDrop(document.getElementById('dropzone'), opts);
FileReaderJS.setupClipboard(document.body, opts);
});
function createBox(e, file) {
var uid = uuidv4();
var imgName = file.name;
function createBox(e, file) {
var uid = uuidv4();
var imgName = file.name;
var src = e.target.result;
var tempCanvas = new fabric.StaticCanvas("tempCanvas", {width: 1280, height: 720});
tempCanvas.backgroundColor = null;
tempCanvas.backgroundImage = null;
var src = e.target.result;
var tempCanvas = new fabric.StaticCanvas("tempCanvas", {
width: 1280,
height: 720
});
tempCanvas.backgroundColor = null;
tempCanvas.backgroundImage = null;
fabric.Image.fromURL(src, function (bgImage) {
fabric.Image.fromURL(src, function (bgImage) {
var canvasAspect = tempCanvas.width / tempCanvas.height;
var imgAspect = bgImage.width / bgImage.height;
var left, top, scaleFactor;
var canvasAspect = tempCanvas.width / tempCanvas.height;
var imgAspect = bgImage.width / bgImage.height;
var left, top, scaleFactor;
if (canvasAspect >= imgAspect) {
scaleFactor = tempCanvas.width / bgImage.width;
left = 0;
top = -((bgImage.height * scaleFactor) - tempCanvas.height) / 2;
} else {
scaleFactor = tempCanvas.height / bgImage.height;
top = 0;
left = -((bgImage.width * scaleFactor) - tempCanvas.width) / 2;
}
if (canvasAspect >= imgAspect) {
scaleFactor = tempCanvas.width / bgImage.width;
left = 0;
top = -((bgImage.height * scaleFactor) - tempCanvas.height) / 2;
} else {
scaleFactor = tempCanvas.height / bgImage.height;
top = 0;
left = -((bgImage.width * scaleFactor) - tempCanvas.width) / 2;
}
bgImage.set({
top: top,
left: left,
originX: 'left',
originY: 'top',
scaleX: scaleFactor,
scaleY: scaleFactor
});
bgImage.lockUniScaling = true;
tempCanvas.add(bgImage);
tempCanvas.renderAll();
images[uid] = {data: src, crop: tempCanvas.toDataURL(), name: imgName, type: file.type};
var template = ` <div class="ui card" id="${uid}">
<div class="image">
<img class="" src="${src}" alt="image">
</div>
<div class="content">
<div class="center aligned header">${imgName}</div>
</div>
<div class="extra content">
<div class="ui tiny basic button" onclick="upload('${uid}', 'original');">{{ t("actions.upload") }}</div>
<div class="ui tiny basic button" onclick="upload('${uid}', 'scale');">{{ t("actions.uploadScale") }}</div>
<div class="ui tiny basic button" onclick="upload('${uid}', 'createSlide');">{{ t("actions.createNewSlide") }}</div>
<div class="ui tiny basic button" onclick="cancelUpload('${uid}');">{{ t("actions.cancel") }}</div>
</div>
</div>`;
$("#imageList").append(template);
bgImage.set({
top: top,
left: left,
originX: 'left',
originY: 'top',
scaleX: scaleFactor,
scaleY: scaleFactor
});
}
bgImage.lockUniScaling = true;
tempCanvas.add(bgImage);
tempCanvas.renderAll();
images[uid] = {
data: src,
crop: tempCanvas.toDataURL(),
name: imgName,
type: file.type
};
var template = `
<div class="ui card" id="${uid}">
<div class="image">
<img class="" src="${src}" alt="image">
</div>
<div class="content">
<div class="center aligned header">${imgName}</div>
</div>
<div class="extra content">
<div class="ui tiny basic button" onclick="upload('${uid}', 'original');">{{ t("actions.upload") }}</div>
<div class="ui tiny basic button" onclick="upload('${uid}', 'scale');">{{ t("actions.uploadScale") }}</div>
<div class="ui tiny basic button" onclick="upload('${uid}', 'createSlide');">{{ t("actions.createNewSlide") }}</div>
<div class="ui tiny basic button" onclick="cancelUpload('${uid}');">{{ t("actions.cancel") }}</div>
</div>
</div>`;
$("#imageList").append(template);
});
}
function upload(uid, type) {
function upload(uid, type) {
if (images[uid] !== null) {
var busyTemplate = `<div class="card">
<div class="ui active dimmer">
<div class="ui text loader">Uploading</div>
</div>
</div>`;
if (images[uid] !== null) {
var busyTemplate = `
<div class="card">
<div class="ui active dimmer">
<div class="ui text loader">Uploading</div>
</div>
</div>`;
let filename = images[uid].name.replace(/\.[^/.]+$/, "");
switch (type) {
case "original":
$("#" + uid).html(busyTemplate);
socket.emit("edit.uploadImage", {
bundleName: bundle,
name: filename,
imageData: images[uid].data,
type: images[uid].type,
});
delete (images[uid]);
break;
case "scale":
$("#" + uid).html(busyTemplate);
socket.emit("edit.uploadImage", {
bundleName: bundle,
name: filename + "_crop",
imageData: images[uid].crop,
type: "image/png",
});
delete (images[uid]);
break;
case "createSlide":
saveAsFullScreenImage(filename, images[uid].data);
$("#" + uid).remove();
delete (images[uid]);
break;
}
let filename = images[uid].name.replace(/\.[^/.]+$/, "");
switch (type) {
case "original":
$("#" + uid).html(busyTemplate);
socket.emit("edit.uploadImage", {
bundleName: bundle,
name: filename,
imageData: images[uid].data,
type: images[uid].type,
});
delete(images[uid]);
break;
case "scale":
$("#" + uid).html(busyTemplate);
socket.emit("edit.uploadImage", {
bundleName: bundle,
name: filename + "_crop",
imageData: images[uid].crop,
type: "image/png",
});
delete(images[uid]);
break;
case "createSlide":
saveAsFullScreenImage(filename, images[uid].data);
$("#" + uid).remove();
delete(images[uid]);
break;
}
}
}
function addImagesFromUploadQueue() {
function addImagesFromUploadQueue() {
for (var i in images) {
var uid = i;
var image = images[i];
var template = ` <div class="ui card" id="${uid}">
<div class="image">
<img class="" src="${image.data}" alt="image">
</div>
<div class="content">
<div class="center aligned header">${image.name}</div>
</div>
<div class="extra content">
<div class="ui tiny basic button" onclick="upload('${uid}', 'original');">{{ t("actions.upload") }}</div>
<div class="ui tiny basic button" onclick="upload('${uid}', 'scale');">{{ t("actions.uploadScale") }}</div>
<div class="ui tiny basic button" onclick="upload('${uid}', 'createSlide');">{{ t("actions.createNewSlide") }}</div>
<div class="ui tiny basic button" onclick="cancelUpload('${uid}');">{{ t("actions.cancel") }}</div>
</div>
</div>`;
$("#imageList").append(template);
}
for (var i in images) {
var uid = i;
var image = images[i];
var template = `
<div class="ui card" id="${uid}">
<div class="image">
<img class="" src="${image.data}" alt="image">
</div>
<div class="content">
<div class="center aligned header">${image.name}</div>
</div>
<div class="extra content">
<div class="ui tiny basic button" onclick="upload('${uid}', 'original');">{{ t("actions.upload") }}</div>
<div class="ui tiny basic button" onclick="upload('${uid}', 'scale');">{{ t("actions.uploadScale") }}</div>
<div class="ui tiny basic button" onclick="upload('${uid}', 'createSlide');">{{ t("actions.createNewSlide") }}</div>
<div class="ui tiny basic button" onclick="cancelUpload('${uid}');">{{ t("actions.cancel") }}</div>
</div>
</div>`;
$("#imageList").append(template);
}
}
function cancelUpload(uid) {
delete images[uid];
$("#" + uid).remove();
}
</script>
<script src="/js/edit.js"></script>
{% endblock %}
function cancelUpload(uid) {
delete images[uid];
$("#" + uid).remove();
}
</script>
<script src="/js/edit.js"></script>
{% endblock %}