+
+
+ What's The Point?
+
+
+
+
+
+
+
+
+
+
+
diff --git a/point.yml b/point.yml
new file mode 100644
index 0000000..716528c
--- /dev/null
+++ b/point.yml
@@ -0,0 +1,52 @@
+#
+# What's The Point presentation configuration file
+#
+
+data:
+ file: "../slides.yml"
+ type:
+ #html
+ markdown
+ #pdf
+
+dimension:
+ width: 1100
+ height: 700
+
+theme:
+ #default
+ clean
+ #aperture
+
+control:
+ #local
+ remote:
+ webcastorUrl: "https://webcastor.herokuapp.com:443"
+ channelId: "fc503470-051e-11e4-8b02-cbfbda9da717"
+
+binding:
+ - keyboard
+ - touch
+ - speech
+
+plugins:
+ - autoscale
+ #- prettify
+ #- chartjs
+ #- doge
+
+
+#
+# Plug-ins and others parameters
+#
+
+speechSettings:
+ lang: "fr-FR"
+ keywords:
+ NEXT_SLIDE:
+ - "suivant"
+ PREVIOUS_SLIDE:
+ - "précédent"
+
+prettifySettings:
+ lang: javascript
diff --git a/point/base.css b/point/base.css
new file mode 100644
index 0000000..fcdc2a6
--- /dev/null
+++ b/point/base.css
@@ -0,0 +1,114 @@
+/*
+ * This file is part of "What's The Point"
+ * Copyright (C) 2014 Pacien TRAN-GIRARD
+ *
+ * "What's The Point" is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * "What's The Point" 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+@import url("libs/normalizecss/normalize.css");
+
+html {
+ width: 100%;
+ height: 100%;
+}
+
+body {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ background: black;
+}
+
+noscript {
+ position: absolute;
+ width: 20em;
+ height: 5em;
+ margin: auto;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ text-align: center;
+ color: white;
+ background: black;
+}
+
+/* loading animation */
+/* http://codepen.io/lixquid/pen/ybjmr */
+
+#loadingclock {
+ position: absolute;
+ margin: auto;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ width: 48px;
+ height: 48px;
+ border: 2px solid #ccc;
+ border-radius: 100%;
+}
+
+#loadingclock:before {
+ display: block;
+ position: absolute;
+ left: 23px;
+ top: 2px;
+ width: 2px;
+ height: 22px;
+ background-color: #ccc;
+ animation: spin 3s linear infinite;
+ -webkit-animation: spin 3s linear infinite;
+ content: " ";
+ transform-origin: 1px 22px;
+ -webkit-transform-origin: 1px 22px;
+}
+
+#loadingclock:after {
+ display: block;
+ position: absolute;
+ left: 23px;
+ top: 3px;
+ width: 2px;
+ height: 21px;
+ background-color: #ccc;
+ animation: spin 18s linear infinite;
+ -webkit-animation: spin 18s linear infinite;
+ content: "";
+ transform-origin: 1px 21px;
+ -webkit-transform-origin: 1px 21px;
+}
+
+@-moz-keyframes spin {
+ to {
+ transform: rotate(360deg);
+ }
+}
+
+@-webkit-keyframes spin {
+ to {
+ -webkit-transform: rotate(360deg);
+ }
+}
+
+@-o-keyframes spin {
+ to {
+ transform: rotate(360deg);
+ }
+}
+
+@keyframes spin {
+ to {
+ transform: rotate(360deg);
+ }
+}
diff --git a/point/binding/keyboard.js b/point/binding/keyboard.js
new file mode 100644
index 0000000..14eabc2
--- /dev/null
+++ b/point/binding/keyboard.js
@@ -0,0 +1,70 @@
+/*
+ * This file is part of "What's The Point"
+ * Copyright (C) 2014 Pacien TRAN-GIRARD
+ *
+ * "What's The Point" is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * "What's The Point" 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+define(["control/control"], function (control) {
+
+ var keyboard = {
+
+ KEYCODE: {
+ BACKSPACE: 8,
+ ENTER: 13,
+ SPACE: 32,
+ END: 35,
+ HOME: 36,
+ LEFT: 37,
+ UP: 38,
+ RIGHT: 39,
+ DOWN: 40,
+ },
+
+ init: function (settings) {
+ this.bindEvent();
+ },
+
+ translate: function (keyCode) {
+ var gotoEvent;
+ switch (keyCode) {
+ case this.KEYCODE.LEFT:
+ case this.KEYCODE.BACKSPACE:
+ return control.dispatchEvent(control.EVENT.GOTO, control.GOTO.PREVIOUS_SLIDE);
+
+ case this.KEYCODE.RIGHT:
+ case this.KEYCODE.ENTER:
+ case this.KEYCODE.SPACE:
+ return control.dispatchEvent(control.EVENT.GOTO, control.GOTO.NEXT_SLIDE);
+
+ case this.KEYCODE.HOME:
+ return control.dispatchEvent(control.EVENT.GOTO, control.GOTO.FIRST_SLIDE);
+
+ case this.KEYCODE.END:
+ return control.dispatchEvent(control.EVENT.GOTO, control.GOTO.LAST_SLIDE);
+ }
+
+ },
+
+ bindEvent: function () {
+ document.addEventListener("keydown", function (keydownEvent) {
+ // TODO: ignore if focus in form
+ keyboard.translate(keydownEvent.keyCode);
+ });
+ },
+ };
+
+ return keyboard;
+
+});
diff --git a/point/binding/network.js b/point/binding/network.js
new file mode 100644
index 0000000..11cf58a
--- /dev/null
+++ b/point/binding/network.js
@@ -0,0 +1,40 @@
+/*
+ * This file is part of "What's The Point"
+ * Copyright (C) 2014 Pacien TRAN-GIRARD
+ *
+ * "What's The Point" is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * "What's The Point" 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+define(["control/control", "libs/webcastor/webcastor"], function (control, webcastor) {
+
+ var network = {
+
+ init: function (settings) {
+ webcastor.init(settings, function (socket) {
+ network.bindEvents();
+ });
+ },
+
+ /* network -> local */
+ bindEvents: function () {
+ webcastor.on("message", function (message) {
+ var event = JSON.parse(message);
+ control.dispatchEvent(event.event, event.eventDetail, false);
+ });
+ },
+ };
+
+ return network;
+
+});
diff --git a/point/binding/speech.js b/point/binding/speech.js
new file mode 100644
index 0000000..41f5914
--- /dev/null
+++ b/point/binding/speech.js
@@ -0,0 +1,89 @@
+/*
+ * This file is part of "What's The Point"
+ * Copyright (C) 2014 Pacien TRAN-GIRARD
+ *
+ * "What's The Point" is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * "What's The Point" 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+define(["control/control"], function (control) {
+
+ var speech = {
+
+ init: function (settings) {
+ if ("speechRecognition" in window || "webkitSpeechRecognition" in window) {
+ var recognition = new webkitSpeechRecognition();
+
+ recognition.continuous = true;
+ recognition.interimResults = true;
+ recognition.lang = settings.speechSettings.lang;
+
+ recognition.onresult = this.onResult;
+
+ recognition.onend = function () {
+ recognition.start();
+ };
+
+ recognition.start();
+ }
+
+ this.sleepDelay = 1500;
+ this.wakeupTime = 0;
+
+ this.command = {
+ NEXT_SLIDE: settings.speechSettings.keywords.NEXT_SLIDE,
+ PREVIOUS_SLIDE: settings.speechSettings.keywords.PREVIOUS_SLIDE,
+ };
+ },
+
+ onResult: function (speechEvent) {
+ var result = event.results[event.resultIndex];
+
+ if (result.isFinal) {
+ return;
+ }
+
+ var sentence = result[0].transcript.split(" ");
+ var command = sentence[sentence.length - 1];
+ speech.processCommand(command);
+ },
+
+ processCommand: function (speechCommand) {
+ if (Date.now() < speech.wakeupTime) {
+ return;
+ }
+
+ var command = speech.translateCommand(speechCommand);
+
+ if (command === undefined) {
+ return;
+ }
+
+ speech.wakeupTime = Date.now() + speech.sleepDelay;
+ control.dispatchEvent(control.EVENT.GOTO, control.GOTO[command]);
+ },
+
+ translateCommand: function (speechCommand) {
+ for (var command in speech.command) {
+ for (var index in speech.command[command]) {
+ if (speechCommand.indexOf(speech.command[command][index]) > -1) {
+ return command;
+ }
+ }
+ }
+ },
+ };
+
+ return speech;
+
+});
diff --git a/point/binding/touch.js b/point/binding/touch.js
new file mode 100644
index 0000000..a09d5fd
--- /dev/null
+++ b/point/binding/touch.js
@@ -0,0 +1,93 @@
+/*
+ * This file is part of "What's The Point"
+ * Copyright (C) 2014 Pacien TRAN-GIRARD
+ *
+ * "What's The Point" is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * "What's The Point" 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+define(["libs/hammerjs/hammer.min", "control/control"], function (hammer, control) {
+
+ var touch = {
+
+ ACTION: {
+ SWIPE: "swipe",
+ DOUBLETAP: "doubletap",
+ TOUCHMOVE: "touchmove",
+ DRAG: "drag",
+ },
+
+ DIRECTION: {
+ DOWN: "down",
+ LEFT: "left",
+ UP: "up",
+ RIGHT: "right",
+ },
+
+ init: function (settings) {
+ this.touchZone = document.body;
+
+ this.hammerElement = hammer(this.touchZone);
+
+ this.hammerElement.options.drag = true;
+ this.hammerElement.options.dragBlockHorizontal = true;
+ this.hammerElement.options.dragBlockVertical = true;
+ this.hammerElement.options.dragLockMinDistance = 20;
+
+ this.disableSelect();
+ this.bindEvent();
+ },
+
+ disableSelect: function () {
+ this.touchZone.style.WebkitTouchCallout = "none";
+ this.touchZone.style.WebkitUserSelect = "none";
+ this.touchZone.style.KhtmlUserSelect = "none";
+ this.touchZone.style.MozUserSelect = "none";
+ this.touchZone.style.msUserSelect = "none";
+ this.touchZone.style.userSelect = "none";
+ },
+
+ translateSwipe: function (swipeDirection) {
+ switch (swipeDirection) {
+ case this.DIRECTION.LEFT:
+ return control.dispatchEvent(control.EVENT.GOTO, control.GOTO.NEXT_SLIDE);
+
+ case this.DIRECTION.RIGHT:
+ return control.dispatchEvent(control.EVENT.GOTO, control.GOTO.PREVIOUS_SLIDE);
+
+ case this.DIRECTION.UP:
+ return control.dispatchEvent(control.EVENT.SHOW, control.SHOW.NOTES);
+
+ case this.DIRECTION.DOWN:
+ return control.dispatchEvent(control.EVENT.SHOW, control.SHOW.SLIDES);
+ }
+ },
+
+ handleDoubletap: function () {
+ control.dispatchEvent(control.EVENT.TOGGLE, control.TOGGLE.FULLSCREEN);
+ },
+
+ bindEvent: function () {
+ this.hammerElement.on(this.ACTION.SWIPE, function (swipeEvent) {
+ touch.translateSwipe(swipeEvent.gesture.direction);
+ });
+
+ this.hammerElement.on(this.ACTION.DOUBLETAP, function (doubletapEvent) {
+ touch.handleDoubletap();
+ });
+ },
+ };
+
+ return touch;
+
+});
diff --git a/point/control/control.js b/point/control/control.js
new file mode 100644
index 0000000..4ec21da
--- /dev/null
+++ b/point/control/control.js
@@ -0,0 +1,83 @@
+/*
+ * This file is part of "What's The Point"
+ * Copyright (C) 2014 Pacien TRAN-GIRARD
+ *
+ * "What's The Point" is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * "What's The Point" 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+define(function () {
+
+ var control = {
+
+ MODE: {
+ MASTER: "master",
+ SLAVE: "slave",
+ FREE: "free",
+ },
+
+ EVENT: {
+ GOTO: "goTo",
+ SLIDE: "slide",
+ SHOW: "show",
+ TOGGLE: "toggle",
+ TRIGGER: "trigger",
+ },
+
+ SLIDE: {
+
+ },
+
+ GOTO: {
+ PREVIOUS_SLIDE: "previousSlide",
+ NEXT_SLIDE: "nextSlide",
+ FIRST_SLIDE: "firstSlide",
+ LAST_SLIDE: "lastSlide",
+ },
+
+ SHOW: {
+ SLIDES: "slides",
+ NOTES: "notes",
+ },
+
+ TOGGLE: {
+ FULLSCREEN: "fullscreen",
+ },
+
+ TRIGGER: {
+
+ },
+
+ init: function () {
+ return;
+ },
+
+ dispatchEvent: function (eventType, eventDetail, forward) {
+ return document.dispatchEvent(new CustomEvent(eventType, {
+ "detail": {
+ "detail": eventDetail,
+ "forward": forward !== undefined ? forward : true,
+ },
+ }));
+ },
+
+ bindEvent: function (eventType, eventListener) {
+ document.addEventListener(eventType, function (event) {
+ eventListener(event.detail);
+ });
+ },
+ };
+
+ return control;
+
+});
diff --git a/point/control/fullscreen.js b/point/control/fullscreen.js
new file mode 100644
index 0000000..6e53bc4
--- /dev/null
+++ b/point/control/fullscreen.js
@@ -0,0 +1,68 @@
+/*
+ * This file is part of "What's The Point"
+ * Copyright (C) 2014 Pacien TRAN-GIRARD
+ *
+ * "What's The Point" is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * "What's The Point" 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+define(["control/control"], function (control) {
+
+ var fullscreen = {
+
+ init: function () {
+ this.bindEvent();
+ },
+
+ toggleFullscreen: function () {
+ // from
+ // https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Using_full_screen_mode#Toggling_fullscreenController_mode
+ if (!document.fullscreenControllerElement && // alternative
+ // standard method
+ !document.mozFullScreenElement && !document.webkitFullscreenElement && !document.msFullscreenElement) {// current
+ // working
+ // methods
+ if (document.documentElement.requestFullscreen) {
+ document.documentElement.requestFullscreen();
+ } else if (document.documentElement.msRequestFullscreen) {
+ document.documentElement.msRequestFullscreen();
+ } else if (document.documentElement.mozRequestFullScreen) {
+ document.documentElement.mozRequestFullScreen();
+ } else if (document.documentElement.webkitRequestFullscreen) {
+ document.documentElement.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
+ }
+ } else {
+ if (document.exitFullscreen) {
+ document.exitFullscreen();
+ } else if (document.msExitFullscreen) {
+ document.msExitFullscreen();
+ } else if (document.mozCancelFullScreen) {
+ document.mozCancelFullScreen();
+ } else if (document.webkitExitFullscreen) {
+ document.webkitExitFullscreen();
+ }
+ }
+ },
+
+ bindEvent: function () {
+ control.bindEvent(control.EVENT.TOGGLE, function (toggleEvent) {
+ if (toggleEvent.detail === control.TOGGLE.FULLSCREEN) {
+ fullscreen.toggleFullscreen();
+ }
+ });
+ },
+ };
+
+ return fullscreen;
+
+});
diff --git a/point/control/layout.js b/point/control/layout.js
new file mode 100644
index 0000000..84a55ff
--- /dev/null
+++ b/point/control/layout.js
@@ -0,0 +1,61 @@
+/*
+ * This file is part of "What's The Point"
+ * Copyright (C) 2014 Pacien TRAN-GIRARD
+ *
+ * "What's The Point" is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * "What's The Point" 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+define(["control/control"], function (control) {
+
+ var layout = {
+
+ init: function () {
+ this.screen = document.getElementsByTagName("p-screen")[0];
+ this.bindEvent();
+ },
+
+ CLASS: {
+ SLIDES: "slides",
+ NODES: "notes",
+ },
+
+ reset: function () {
+ for (var className in this.CLASS) {
+ this.screen.classList.remove(this.CLASS[className]);
+ }
+ },
+
+ show: function (element) {
+ this.reset();
+ switch (element) {
+ case control.SHOW.SLIDES:
+ this.screen.classList.add("slides");
+ break;
+
+ case control.SHOW.NOTES:
+ this.screen.classList.add("notes");
+ break;
+ }
+ },
+
+ bindEvent: function () {
+ control.bindEvent(control.EVENT.SHOW, function (showEvent) {
+ layout.show(showEvent.detail);
+ });
+ },
+ };
+
+ return layout;
+
+});
diff --git a/point/control/network.js b/point/control/network.js
new file mode 100644
index 0000000..e782257
--- /dev/null
+++ b/point/control/network.js
@@ -0,0 +1,58 @@
+/*
+ * This file is part of "What's The Point"
+ * Copyright (C) 2014 Pacien TRAN-GIRARD
+ *
+ * "What's The Point" is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * "What's The Point" 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+define([ "control/control", "libs/webcastor/webcastor", "control/slide" ], function (control, webcastor, slide) {
+
+ var network = {
+
+ init: function (settings) {
+ webcastor.init(settings, function () {
+ network.bindEvents();
+ });
+ },
+
+ send: function (event, eventDetail) {
+ var message = JSON.stringify({
+ "event": event,
+ "eventDetail": eventDetail,
+ });
+ webcastor.send(message);
+ },
+
+ bindEvent: function (event) {
+ control.bindEvent(event, function (eventDetail) {
+ if (!eventDetail.forward) {
+ return false;
+ }
+ network.send(event, eventDetail.detail);
+ });
+ },
+
+ /* local -> network */
+ bindEvents: function () {
+ var events = [ control.EVENT.SLIDE, control.EVENT.TRIGGER ];
+ for (var i = 0; i < events.length; i++) {
+ this.bindEvent(events[i]);
+ }
+ },
+
+ };
+
+ return network;
+
+});
diff --git a/point/control/slide.js b/point/control/slide.js
new file mode 100644
index 0000000..c539a60
--- /dev/null
+++ b/point/control/slide.js
@@ -0,0 +1,86 @@
+/*
+ * This file is part of "What's The Point"
+ * Copyright (C) 2014 Pacien TRAN-GIRARD
+ *
+ * "What's The Point" is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * "What's The Point" 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+define(["control/control"], function (control) {
+
+ var slide = {
+
+ init: function () {
+ this.slideCount = document.getElementsByTagName("p-slide").length;
+ this.start();
+ this.bindEvent();
+ },
+
+ start: function () {
+ var slideIndex = location.hash.substr(1);
+ location.hash = 0;
+ location.hash = 1;
+ this.setCurrentSlide(slideIndex);
+ },
+
+ setCurrentSlide: function (slideIndex) {
+ if (isNaN(slideIndex) || slideIndex < 1 || slideIndex > this.slideCount) {
+ return false;
+ }
+ location.hash = slideIndex;
+ return true;
+ },
+
+ getCurrentSlideIndex: function () {
+ var hash = location.hash.substring(1);
+ return isNaN(hash) || hash < 1 || hash > this.slideCount ? 0 : Number(hash);
+ },
+
+ shift: function (delta) {
+ return this.getCurrentSlideIndex() + delta;
+ },
+
+ getIndex: function (target) {
+ switch (target) {
+ case control.GOTO.PREVIOUS_SLIDE:
+ return this.shift(-1);
+
+ case control.GOTO.NEXT_SLIDE:
+ return this.shift(+1);
+
+ case control.GOTO.FIRST_SLIDE:
+ return 1;
+
+ case control.GOTO.LAST_SLIDE:
+ return this.slideCount;
+ }
+ },
+
+ translate: function (target) {
+ control.dispatchEvent(control.EVENT.SLIDE, this.getIndex(target));
+ },
+
+ bindEvent: function () {
+ control.bindEvent(control.EVENT.GOTO, function (gotoEvent) {
+ slide.translate(gotoEvent.detail);
+ });
+
+ control.bindEvent(control.EVENT.SLIDE, function (slideEvent) {
+ slide.setCurrentSlide(slideEvent.detail);
+ });
+ },
+ };
+
+ return slide;
+
+});
diff --git a/point/data/html.js b/point/data/html.js
new file mode 100644
index 0000000..66448cc
--- /dev/null
+++ b/point/data/html.js
@@ -0,0 +1,86 @@
+/*
+ * This file is part of "What's The Point"
+ * Copyright (C) 2014 Pacien TRAN-GIRARD
+ *
+ * "What's The Point" is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * "What's The Point" 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+define(function () {
+
+ var xml = {
+
+ init: function () {
+ return;
+ },
+
+ getProp: function (object, dom, property, method) {
+ var elements = dom.getElementsByTagName(property);
+ if (elements.length > 0) {
+ object[property] = method(elements[0]);
+ }
+ return object;
+ },
+
+ getInnerText: function (object, dom, property) {
+ return this.getProp(object, dom, property, function (element) {
+ return element.textContent;
+ });
+ },
+
+ getInnerHtml: function (object, dom, property) {
+ return this.getProp(object, dom, property, function (element) {
+ if (window.XMLSerializer !== undefined) {
+ return (new window.XMLSerializer()).serializeToString(element);
+ } else if (element.xml !== undefined) {
+ return element.xml;
+ }
+ return element.innerHTML;
+ });
+ },
+
+ parseSlide: function (domSlide) {
+ var slide = {};
+
+ ["type", "title", "subtitle"].forEach(function (tag) {
+ xml.getInnerText(slide, domSlide, tag);
+ });
+
+ ["content", "notes"].forEach(function (tag) {
+ xml.getInnerHtml(slide, domSlide, tag);
+ });
+
+ return slide;
+ },
+
+ parseSlides: function (domSlides) {
+ var slides = [];
+
+ for (var i = 0; i < domSlides.length; i++) {
+ slides.push(this.parseSlide(domSlides[i]));
+ }
+
+ return slides;
+ },
+
+ parse: function (rawData, callback) {
+ var dom = new DOMParser().parseFromString(rawData, "text/xml");
+ var domSlides = dom.getElementsByTagName("slide");
+
+ callback(this.parseSlides(domSlides));
+ },
+ };
+
+ return xml;
+
+});
diff --git a/point/data/markdown.js b/point/data/markdown.js
new file mode 100644
index 0000000..38a564d
--- /dev/null
+++ b/point/data/markdown.js
@@ -0,0 +1,61 @@
+/*
+ * This file is part of "What's The Point"
+ * Copyright (C) 2014 Pacien TRAN-GIRARD
+ *
+ * "What's The Point" is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * "What's The Point" 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+requirejs.config({
+ shim: {
+ "markdownjs": {
+ exports: "markdown",
+ },
+ },
+ paths: {
+ "markdownjs": "libs/markdownjs/markdown.min",
+ },
+});
+
+define(["js-yaml", "markdownjs"], function (jsyaml, markdownjs) {
+
+ var markdown = {
+
+ init: function () {
+ return;
+ },
+
+ renderSlide: function (slide) {
+ if (slide.content !== undefined) {
+ slide.content = markdownjs.toHTML(slide.content);
+ }
+ if (slide.notes !== undefined) {
+ slide.notes = markdownjs.toHTML(slide.notes);
+ }
+ return slide;
+ },
+
+ parse: function (rawData, callback) {
+ var slides = [];
+
+ jsyaml.safeLoadAll(rawData, function (slide) {
+ slides.push(markdown.renderSlide(slide));
+ });
+
+ callback(slides);
+ },
+ };
+
+ return markdown;
+
+});
diff --git a/point/data/pdf.js b/point/data/pdf.js
new file mode 100644
index 0000000..f789bdf
--- /dev/null
+++ b/point/data/pdf.js
@@ -0,0 +1,130 @@
+/*
+ * This file is part of "What's The Point"
+ * Copyright (C) 2014 Pacien TRAN-GIRARD
+ *
+ * "What's The Point" is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * "What's The Point" 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+requirejs.config({
+ shim: {
+ "pdfjs": {
+ exports: "PDFJS",
+ },
+ },
+ paths: {
+ "pdfjs": "libs/pdfjs/pdf",
+ },
+});
+
+define(["pdfjs"], function (pdfjs) {
+
+ var pdf = {
+
+ init: function (settings) {
+ this.fileUrl = settings.data.file;
+ this.width = settings.dimension.width;
+ this.height = settings.dimension.height;
+
+ this.slides = [];
+
+ pdfjs.disableRange = true;
+ pdfjs.workerSrc = "point/libs/pdfjs/pdf.worker.js";
+ },
+
+ makeCanvas: function () {
+ var canvas = document.createElement("canvas");
+ canvas.width = pdf.width;
+ canvas.height = pdf.height;
+ return canvas;
+ },
+
+ clearOutline: function (context, slideWidth, slideHeight, offsetX, offsetY) {
+ context.clearRect(0, 0, offsetX, pdf.height);
+ context.clearRect(offsetX + slideWidth, 0, offsetX, pdf.height);
+ context.clearRect(0, 0, pdf.width, offsetY);
+ context.clearRect(0, offsetY + slideHeight, pdf.width, offsetY);
+ return context;
+ },
+
+ renderSlide: function (pdfDocument, slideIndex, callback) {
+ pdfDocument.getPage(slideIndex).then(function (pdfPage) {
+
+ var viewport = pdfPage.getViewport(1);
+ var slideWidth = viewport.width / 2;
+ var slideHeight = viewport.height;
+
+ var widthRatio = pdf.width / slideWidth;
+ var heightRatio = pdf.height / slideHeight;
+ var scale = Math.min(widthRatio, heightRatio);
+ slideWidth *= scale;
+ slideHeight *= scale;
+
+ var offsetX = (pdf.width - slideWidth) / 2;
+ var offsetY = (pdf.height - slideHeight) / 2;
+
+ var contentViewport = new pdfjs.PageViewport(pdfPage.view, scale, 0, offsetX, offsetY);
+ var notesViewport = new pdfjs.PageViewport(pdfPage.view, scale, 0, -slideWidth + offsetX, offsetY);
+
+ var contentCanvas = pdf.makeCanvas();
+ var contentContext = contentCanvas.getContext("2d");
+
+ var notesCanvas = pdf.makeCanvas();
+ var notesContext = notesCanvas.getContext("2d");
+
+ var contentRenderContext = {
+ canvasContext: contentContext,
+ viewport: contentViewport,
+ };
+
+ var notesRenderContext = {
+ canvasContext: notesContext,
+ viewport: notesViewport,
+ };
+
+ pdfPage.render(contentRenderContext).then(function () {
+ pdf.clearOutline(contentContext, slideWidth, slideHeight, offsetX, offsetY);
+
+ pdfPage.render(notesRenderContext).then(function () {
+ pdf.clearOutline(notesContext, slideWidth, slideHeight, offsetX, offsetY);
+
+ pdf.registerSlide(contentCanvas, notesCanvas, pdfDocument, slideIndex, callback);
+
+ });
+ });
+ });
+ },
+
+ registerSlide: function (contentCanvas, notesCanvas, pdfDocument, slideIndex, callback) {
+ pdf.slides[slideIndex - 1] = {
+ content: contentCanvas,
+ notes: notesCanvas,
+ };
+
+ if (slideIndex < pdfDocument.pdfInfo.numPages) {
+ pdf.renderSlide(pdfDocument, slideIndex + 1, callback);
+ } else {
+ callback(pdf.slides);
+ }
+ },
+
+ parse: function (rawData, callback) {
+ pdfjs.getDocument(require.toUrl(this.fileUrl)).then(function (pdfDocument) {
+ pdf.renderSlide(pdfDocument, 1, callback);
+ });
+ },
+ };
+
+ return pdf;
+
+});
diff --git a/point/data/renderSlide.js b/point/data/renderSlide.js
new file mode 100644
index 0000000..e149f41
--- /dev/null
+++ b/point/data/renderSlide.js
@@ -0,0 +1,127 @@
+/*
+ * This file is part of "What's The Point"
+ * Copyright (C) 2014 Pacien TRAN-GIRARD
+ *
+ * "What's The Point" is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * "What's The Point" 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+define(function () {
+
+ var renderSlide = {
+
+ init: function () {
+ this.lastTitle = undefined;
+ },
+
+ appendNode: function (parent, tag, content, appendMethod) {
+ var node = document.createElement(tag);
+ appendMethod(node, content);
+ parent.appendChild(node);
+ return parent;
+ },
+
+ appendHtmlNode: function (parent, tag, htmlContent) {
+ return this.appendNode(parent, tag, htmlContent, function (parent, htmlContent) {
+ parent.innerHTML = htmlContent;
+ });
+ },
+
+ appendObjectNode: function (parent, tag, node) {
+ return this.appendNode(parent, tag, node, function (parent, node) {
+ parent.appendChild(node);
+ });
+ },
+
+ appendTextNode: function (parent, tag, text) {
+ return this.appendObjectNode(parent, tag, document.createTextNode(text));
+ },
+
+ appendContentNode: function (parent, tag, content) {
+ if (typeof (content) === "string") {
+ this.appendHtmlNode(parent, tag, content);
+ } else {
+ this.appendObjectNode(parent, tag, content);
+ }
+ },
+
+ renderTitle: function (slideData) {
+ var title = slideData.title;
+ var subtitle = slideData.subtitle;
+
+ if (title !== undefined) {
+ this.lastTitle = title;
+ } else {
+ if (subtitle !== undefined) {
+ title = this.lastTitle;
+ } else {
+ this.lastTitle = undefined;
+ }
+ }
+
+ var titleNode;
+ if (title !== undefined || subtitle !== undefined) {
+ titleNode = document.createElement("s-title");
+ } else {
+ titleNode = document.createDocumentFragment("s-title");
+ }
+
+ if (title !== undefined) {
+ this.appendTextNode(titleNode, "h1", title);
+ }
+
+ if (subtitle !== undefined) {
+ this.appendTextNode(titleNode, "h2", subtitle);
+ }
+
+ return titleNode;
+ },
+
+ renderBody: function (slideData) {
+ var bodyNode = document.createDocumentFragment();
+ //var bodyNode = document.createElement("s-body");
+
+ if (slideData.content !== undefined) {
+ this.appendContentNode(bodyNode, "s-content", slideData.content);
+ }
+
+ var notes = slideData.notes === undefined ? "" : slideData.notes;
+ this.appendContentNode(bodyNode, "s-notes", notes);
+
+ return bodyNode;
+ },
+
+ renderSlide: function (slideData, index) {
+ var slide = document.createElement("p-slide");
+ slide.setAttribute("id", index + 1);
+ slide.appendChild(this.renderTitle(slideData));
+ slide.appendChild(this.renderBody(slideData));
+ return slide;
+ },
+
+ renderSlides: function (slidesData) {
+ var slides = document.createDocumentFragment();
+ for (var i = 0; i < slidesData.length; i++) {
+ slides.appendChild(this.renderSlide(slidesData[i], i));
+ }
+ return slides;
+ },
+
+ render: function (slidesData, callback) {
+ callback(this.renderSlides(slidesData));
+ },
+ };
+
+ return renderSlide;
+
+});
diff --git a/point/libs/hammerjs/hammer.min.js b/point/libs/hammerjs/hammer.min.js
new file mode 100644
index 0000000..d7b2e9a
--- /dev/null
+++ b/point/libs/hammerjs/hammer.min.js
@@ -0,0 +1,313 @@
+/*! Hammer.JS - v1.1.3 - 2014-05-20
+ * http://eightmedia.github.io/hammer.js
+ *
+ * Copyright (c) 2014 Jorik Tangelder ;
+ * Licensed under the MIT license */
+
+
+!function (a, b) {
+ "use strict";
+ function c() {
+ d.READY || (s.determineEventTypes(), r.each(d.gestures, function (a) {
+ u.register(a)
+ }), s.onTouch(d.DOCUMENT, n, u.detect), s.onTouch(d.DOCUMENT, o, u.detect), d.READY = !0)
+ }
+
+ var d = function v(a, b) {
+ return new v.Instance(a, b || {})
+ };
+ d.VERSION = "1.1.3", d.defaults = {behavior: {userSelect: "none", touchAction: "pan-y", touchCallout: "none", contentZooming: "none", userDrag: "none", tapHighlightColor: "rgba(0,0,0,0)"}}, d.DOCUMENT = document, d.HAS_POINTEREVENTS = navigator.pointerEnabled || navigator.msPointerEnabled, d.HAS_TOUCHEVENTS = "ontouchstart"in a, d.IS_MOBILE = /mobile|tablet|ip(ad|hone|od)|android|silk/i.test(navigator.userAgent), d.NO_MOUSEEVENTS = d.HAS_TOUCHEVENTS && d.IS_MOBILE || d.HAS_POINTEREVENTS, d.CALCULATE_INTERVAL = 25;
+ var e = {}, f = d.DIRECTION_DOWN = "down", g = d.DIRECTION_LEFT = "left", h = d.DIRECTION_UP = "up", i = d.DIRECTION_RIGHT = "right", j = d.POINTER_MOUSE = "mouse", k = d.POINTER_TOUCH = "touch", l = d.POINTER_PEN = "pen", m = d.EVENT_START = "start", n = d.EVENT_MOVE = "move", o = d.EVENT_END = "end", p = d.EVENT_RELEASE = "release", q = d.EVENT_TOUCH = "touch";
+ d.READY = !1, d.plugins = d.plugins || {}, d.gestures = d.gestures || {};
+ var r = d.utils = {extend: function (a, c, d) {
+ for (var e in c)!c.hasOwnProperty(e) || a[e] !== b && d || (a[e] = c[e]);
+ return a
+ }, on: function (a, b, c) {
+ a.addEventListener(b, c, !1)
+ }, off: function (a, b, c) {
+ a.removeEventListener(b, c, !1)
+ }, each: function (a, c, d) {
+ var e, f;
+ if ("forEach"in a)a.forEach(c, d); else if (a.length !== b) {
+ for (e = 0, f = a.length; f > e; e++)if (c.call(d, a[e], e, a) === !1)return
+ } else for (e in a)if (a.hasOwnProperty(e) && c.call(d, a[e], e, a) === !1)return
+ }, inStr: function (a, b) {
+ return a.indexOf(b) > -1
+ }, inArray: function (a, b) {
+ if (a.indexOf) {
+ var c = a.indexOf(b);
+ return-1 === c ? !1 : c
+ }
+ for (var d = 0, e = a.length; e > d; d++)if (a[d] === b)return d;
+ return!1
+ }, toArray: function (a) {
+ return Array.prototype.slice.call(a, 0)
+ }, hasParent: function (a, b) {
+ for (; a;) {
+ if (a == b)return!0;
+ a = a.parentNode
+ }
+ return!1
+ }, getCenter: function (a) {
+ var b = [], c = [], d = [], e = [], f = Math.min, g = Math.max;
+ return 1 === a.length ? {pageX: a[0].pageX, pageY: a[0].pageY, clientX: a[0].clientX, clientY: a[0].clientY} : (r.each(a, function (a) {
+ b.push(a.pageX), c.push(a.pageY), d.push(a.clientX), e.push(a.clientY)
+ }), {pageX: (f.apply(Math, b) + g.apply(Math, b)) / 2, pageY: (f.apply(Math, c) + g.apply(Math, c)) / 2, clientX: (f.apply(Math, d) + g.apply(Math, d)) / 2, clientY: (f.apply(Math, e) + g.apply(Math, e)) / 2})
+ }, getVelocity: function (a, b, c) {
+ return{x: Math.abs(b / a) || 0, y: Math.abs(c / a) || 0}
+ }, getAngle: function (a, b) {
+ var c = b.clientX - a.clientX, d = b.clientY - a.clientY;
+ return 180 * Math.atan2(d, c) / Math.PI
+ }, getDirection: function (a, b) {
+ var c = Math.abs(a.clientX - b.clientX), d = Math.abs(a.clientY - b.clientY);
+ return c >= d ? a.clientX - b.clientX > 0 ? g : i : a.clientY - b.clientY > 0 ? h : f
+ }, getDistance: function (a, b) {
+ var c = b.clientX - a.clientX, d = b.clientY - a.clientY;
+ return Math.sqrt(c * c + d * d)
+ }, getScale: function (a, b) {
+ return a.length >= 2 && b.length >= 2 ? this.getDistance(b[0], b[1]) / this.getDistance(a[0], a[1]) : 1
+ }, getRotation: function (a, b) {
+ return a.length >= 2 && b.length >= 2 ? this.getAngle(b[1], b[0]) - this.getAngle(a[1], a[0]) : 0
+ }, isVertical: function (a) {
+ return a == h || a == f
+ }, setPrefixedCss: function (a, b, c, d) {
+ var e = ["", "Webkit", "Moz", "O", "ms"];
+ b = r.toCamelCase(b);
+ for (var f = 0; f < e.length; f++) {
+ var g = b;
+ if (e[f] && (g = e[f] + g.slice(0, 1).toUpperCase() + g.slice(1)), g in a.style) {
+ a.style[g] = (null == d || d) && c || "";
+ break
+ }
+ }
+ }, toggleBehavior: function (a, b, c) {
+ if (b && a && a.style) {
+ r.each(b, function (b, d) {
+ r.setPrefixedCss(a, d, b, c)
+ });
+ var d = c && function () {
+ return!1
+ };
+ "none" == b.userSelect && (a.onselectstart = d), "none" == b.userDrag && (a.ondragstart = d)
+ }
+ }, toCamelCase: function (a) {
+ return a.replace(/[_-]([a-z])/g, function (a) {
+ return a[1].toUpperCase()
+ })
+ }}, s = d.event = {preventMouseEvents: !1, started: !1, shouldDetect: !1, on: function (a, b, c, d) {
+ var e = b.split(" ");
+ r.each(e, function (b) {
+ r.on(a, b, c), d && d(b)
+ })
+ }, off: function (a, b, c, d) {
+ var e = b.split(" ");
+ r.each(e, function (b) {
+ r.off(a, b, c), d && d(b)
+ })
+ }, onTouch: function (a, b, c) {
+ var f = this, g = function (e) {
+ var g, h = e.type.toLowerCase(), i = d.HAS_POINTEREVENTS, j = r.inStr(h, "mouse");
+ j && f.preventMouseEvents || (j && b == m && 0 === e.button ? (f.preventMouseEvents = !1, f.shouldDetect = !0) : i && b == m ? f.shouldDetect = 1 === e.buttons || t.matchType(k, e) : j || b != m || (f.preventMouseEvents = !0, f.shouldDetect = !0), i && b != o && t.updatePointer(b, e), f.shouldDetect && (g = f.doDetect.call(f, e, b, a, c)), g == o && (f.preventMouseEvents = !1, f.shouldDetect = !1, t.reset()), i && b == o && t.updatePointer(b, e))
+ };
+ return this.on(a, e[b], g), g
+ }, doDetect: function (a, b, c, d) {
+ var e = this.getTouchList(a, b), f = e.length, g = b, h = e.trigger, i = f;
+ b == m ? h = q : b == o && (h = p, i = e.length - (a.changedTouches ? a.changedTouches.length : 1)), i > 0 && this.started && (g = n), this.started = !0;
+ var j = this.collectEventData(c, g, e, a);
+ return b != o && d.call(u, j), h && (j.changedLength = i, j.eventType = h, d.call(u, j), j.eventType = g, delete j.changedLength), g == o && (d.call(u, j), this.started = !1), g
+ }, determineEventTypes: function () {
+ var b;
+ return b = d.HAS_POINTEREVENTS ? a.PointerEvent ? ["pointerdown", "pointermove", "pointerup pointercancel lostpointercapture"] : ["MSPointerDown", "MSPointerMove", "MSPointerUp MSPointerCancel MSLostPointerCapture"] : d.NO_MOUSEEVENTS ? ["touchstart", "touchmove", "touchend touchcancel"] : ["touchstart mousedown", "touchmove mousemove", "touchend touchcancel mouseup"], e[m] = b[0], e[n] = b[1], e[o] = b[2], e
+ }, getTouchList: function (a, b) {
+ if (d.HAS_POINTEREVENTS)return t.getTouchList();
+ if (a.touches) {
+ if (b == n)return a.touches;
+ var c = [], e = [].concat(r.toArray(a.touches), r.toArray(a.changedTouches)), f = [];
+ return r.each(e, function (a) {
+ r.inArray(c, a.identifier) === !1 && f.push(a), c.push(a.identifier)
+ }), f
+ }
+ return a.identifier = 1, [a]
+ }, collectEventData: function (a, b, c, d) {
+ var e = k;
+ return r.inStr(d.type, "mouse") || t.matchType(j, d) ? e = j : t.matchType(l, d) && (e = l), {center: r.getCenter(c), timeStamp: Date.now(), target: d.target, touches: c, eventType: b, pointerType: e, srcEvent: d, preventDefault: function () {
+ var a = this.srcEvent;
+ a.preventManipulation && a.preventManipulation(), a.preventDefault && a.preventDefault()
+ }, stopPropagation: function () {
+ this.srcEvent.stopPropagation()
+ }, stopDetect: function () {
+ return u.stopDetect()
+ }}
+ }}, t = d.PointerEvent = {pointers: {}, getTouchList: function () {
+ var a = [];
+ return r.each(this.pointers, function (b) {
+ a.push(b)
+ }), a
+ }, updatePointer: function (a, b) {
+ a == o || a != o && 1 !== b.buttons ? delete this.pointers[b.pointerId] : (b.identifier = b.pointerId, this.pointers[b.pointerId] = b)
+ }, matchType: function (a, b) {
+ if (!b.pointerType)return!1;
+ var c = b.pointerType, d = {};
+ return d[j] = c === (b.MSPOINTER_TYPE_MOUSE || j), d[k] = c === (b.MSPOINTER_TYPE_TOUCH || k), d[l] = c === (b.MSPOINTER_TYPE_PEN || l), d[a]
+ }, reset: function () {
+ this.pointers = {}
+ }}, u = d.detection = {gestures: [], current: null, previous: null, stopped: !1, startDetect: function (a, b) {
+ this.current || (this.stopped = !1, this.current = {inst: a, startEvent: r.extend({}, b), lastEvent: !1, lastCalcEvent: !1, futureCalcEvent: !1, lastCalcData: {}, name: ""}, this.detect(b))
+ }, detect: function (a) {
+ if (this.current && !this.stopped) {
+ a = this.extendEventData(a);
+ var b = this.current.inst, c = b.options;
+ return r.each(this.gestures, function (d) {
+ !this.stopped && b.enabled && c[d.name] && d.handler.call(d, a, b)
+ }, this), this.current && (this.current.lastEvent = a), a.eventType == o && this.stopDetect(), a
+ }
+ }, stopDetect: function () {
+ this.previous = r.extend({}, this.current), this.current = null, this.stopped = !0
+ }, getCalculatedData: function (a, b, c, e, f) {
+ var g = this.current, h = !1, i = g.lastCalcEvent, j = g.lastCalcData;
+ i && a.timeStamp - i.timeStamp > d.CALCULATE_INTERVAL && (b = i.center, c = a.timeStamp - i.timeStamp, e = a.center.clientX - i.center.clientX, f = a.center.clientY - i.center.clientY, h = !0), (a.eventType == q || a.eventType == p) && (g.futureCalcEvent = a), (!g.lastCalcEvent || h) && (j.velocity = r.getVelocity(c, e, f), j.angle = r.getAngle(b, a.center), j.direction = r.getDirection(b, a.center), g.lastCalcEvent = g.futureCalcEvent || a, g.futureCalcEvent = a), a.velocityX = j.velocity.x, a.velocityY = j.velocity.y, a.interimAngle = j.angle, a.interimDirection = j.direction
+ }, extendEventData: function (a) {
+ var b = this.current, c = b.startEvent, d = b.lastEvent || c;
+ (a.eventType == q || a.eventType == p) && (c.touches = [], r.each(a.touches, function (a) {
+ c.touches.push({clientX: a.clientX, clientY: a.clientY})
+ }));
+ var e = a.timeStamp - c.timeStamp, f = a.center.clientX - c.center.clientX, g = a.center.clientY - c.center.clientY;
+ return this.getCalculatedData(a, d.center, e, f, g), r.extend(a, {startEvent: c, deltaTime: e, deltaX: f, deltaY: g, distance: r.getDistance(c.center, a.center), angle: r.getAngle(c.center, a.center), direction: r.getDirection(c.center, a.center), scale: r.getScale(c.touches, a.touches), rotation: r.getRotation(c.touches, a.touches)}), a
+ }, register: function (a) {
+ var c = a.defaults || {};
+ return c[a.name] === b && (c[a.name] = !0), r.extend(d.defaults, c, !0), a.index = a.index || 1e3, this.gestures.push(a), this.gestures.sort(function (a, b) {
+ return a.index < b.index ? -1 : a.index > b.index ? 1 : 0
+ }), this.gestures
+ }};
+ d.Instance = function (a, b) {
+ var e = this;
+ c(), this.element = a, this.enabled = !0, r.each(b, function (a, c) {
+ delete b[c], b[r.toCamelCase(c)] = a
+ }), this.options = r.extend(r.extend({}, d.defaults), b || {}), this.options.behavior && r.toggleBehavior(this.element, this.options.behavior, !0), this.eventStartHandler = s.onTouch(a, m, function (a) {
+ e.enabled && a.eventType == m ? u.startDetect(e, a) : a.eventType == q && u.detect(a)
+ }), this.eventHandlers = []
+ }, d.Instance.prototype = {on: function (a, b) {
+ var c = this;
+ return s.on(c.element, a, b, function (a) {
+ c.eventHandlers.push({gesture: a, handler: b})
+ }), c
+ }, off: function (a, b) {
+ var c = this;
+ return s.off(c.element, a, b, function (a) {
+ var d = r.inArray({gesture: a, handler: b});
+ d !== !1 && c.eventHandlers.splice(d, 1)
+ }), c
+ }, trigger: function (a, b) {
+ b || (b = {});
+ var c = d.DOCUMENT.createEvent("Event");
+ c.initEvent(a, !0, !0), c.gesture = b;
+ var e = this.element;
+ return r.hasParent(b.target, e) && (e = b.target), e.dispatchEvent(c), this
+ }, enable: function (a) {
+ return this.enabled = a, this
+ }, dispose: function () {
+ var a, b;
+ for (r.toggleBehavior(this.element, this.options.behavior, !1), a = -1; b = this.eventHandlers[++a];)r.off(this.element, b.gesture, b.handler);
+ return this.eventHandlers = [], s.off(this.element, e[m], this.eventStartHandler), null
+ }}, function (a) {
+ function b(b, d) {
+ var e = u.current;
+ if (!(d.options.dragMaxTouches > 0 && b.touches.length > d.options.dragMaxTouches))switch (b.eventType) {
+ case m:
+ c = !1;
+ break;
+ case n:
+ if (b.distance < d.options.dragMinDistance && e.name != a)return;
+ var j = e.startEvent.center;
+ if (e.name != a && (e.name = a, d.options.dragDistanceCorrection && b.distance > 0)) {
+ var k = Math.abs(d.options.dragMinDistance / b.distance);
+ j.pageX += b.deltaX * k, j.pageY += b.deltaY * k, j.clientX += b.deltaX * k, j.clientY += b.deltaY * k, b = u.extendEventData(b)
+ }
+ (e.lastEvent.dragLockToAxis || d.options.dragLockToAxis && d.options.dragLockMinDistance <= b.distance) && (b.dragLockToAxis = !0);
+ var l = e.lastEvent.direction;
+ b.dragLockToAxis && l !== b.direction && (b.direction = r.isVertical(l) ? b.deltaY < 0 ? h : f : b.deltaX < 0 ? g : i), c || (d.trigger(a + "start", b), c = !0), d.trigger(a, b), d.trigger(a + b.direction, b);
+ var q = r.isVertical(b.direction);
+ (d.options.dragBlockVertical && q || d.options.dragBlockHorizontal && !q) && b.preventDefault();
+ break;
+ case p:
+ c && b.changedLength <= d.options.dragMaxTouches && (d.trigger(a + "end", b), c = !1);
+ break;
+ case o:
+ c = !1
+ }
+ }
+
+ var c = !1;
+ d.gestures.Drag = {name: a, index: 50, handler: b, defaults: {dragMinDistance: 10, dragDistanceCorrection: !0, dragMaxTouches: 1, dragBlockHorizontal: !1, dragBlockVertical: !1, dragLockToAxis: !1, dragLockMinDistance: 25}}
+ }("drag"), d.gestures.Gesture = {name: "gesture", index: 1337, handler: function (a, b) {
+ b.trigger(this.name, a)
+ }}, function (a) {
+ function b(b, d) {
+ var e = d.options, f = u.current;
+ switch (b.eventType) {
+ case m:
+ clearTimeout(c), f.name = a, c = setTimeout(function () {
+ f && f.name == a && d.trigger(a, b)
+ }, e.holdTimeout);
+ break;
+ case n:
+ b.distance > e.holdThreshold && clearTimeout(c);
+ break;
+ case p:
+ clearTimeout(c)
+ }
+ }
+
+ var c;
+ d.gestures.Hold = {name: a, index: 10, defaults: {holdTimeout: 500, holdThreshold: 2}, handler: b}
+ }("hold"), d.gestures.Release = {name: "release", index: 1 / 0, handler: function (a, b) {
+ a.eventType == p && b.trigger(this.name, a)
+ }}, d.gestures.Swipe = {name: "swipe", index: 40, defaults: {swipeMinTouches: 1, swipeMaxTouches: 1, swipeVelocityX: .6, swipeVelocityY: .6}, handler: function (a, b) {
+ if (a.eventType == p) {
+ var c = a.touches.length, d = b.options;
+ if (c < d.swipeMinTouches || c > d.swipeMaxTouches)return;
+ (a.velocityX > d.swipeVelocityX || a.velocityY > d.swipeVelocityY) && (b.trigger(this.name, a), b.trigger(this.name + a.direction, a))
+ }
+ }}, function (a) {
+ function b(b, d) {
+ var e, f, g = d.options, h = u.current, i = u.previous;
+ switch (b.eventType) {
+ case m:
+ c = !1;
+ break;
+ case n:
+ c = c || b.distance > g.tapMaxDistance;
+ break;
+ case o:
+ !r.inStr(b.srcEvent.type, "cancel") && b.deltaTime < g.tapMaxTime && !c && (e = i && i.lastEvent && b.timeStamp - i.lastEvent.timeStamp, f = !1, i && i.name == a && e && e < g.doubleTapInterval && b.distance < g.doubleTapDistance && (d.trigger("doubletap", b), f = !0), (!f || g.tapAlways) && (h.name = a, d.trigger(h.name, b)))
+ }
+ }
+
+ var c = !1;
+ d.gestures.Tap = {name: a, index: 100, handler: b, defaults: {tapMaxTime: 250, tapMaxDistance: 10, tapAlways: !0, doubleTapDistance: 20, doubleTapInterval: 300}}
+ }("tap"), d.gestures.Touch = {name: "touch", index: -1 / 0, defaults: {preventDefault: !1, preventMouse: !1}, handler: function (a, b) {
+ return b.options.preventMouse && a.pointerType == j ? void a.stopDetect() : (b.options.preventDefault && a.preventDefault(), void(a.eventType == q && b.trigger("touch", a)))
+ }}, function (a) {
+ function b(b, d) {
+ switch (b.eventType) {
+ case m:
+ c = !1;
+ break;
+ case n:
+ if (b.touches.length < 2)return;
+ var e = Math.abs(1 - b.scale), f = Math.abs(b.rotation);
+ if (e < d.options.transformMinScale && f < d.options.transformMinRotation)return;
+ u.current.name = a, c || (d.trigger(a + "start", b), c = !0), d.trigger(a, b), f > d.options.transformMinRotation && d.trigger("rotate", b), e > d.options.transformMinScale && (d.trigger("pinch", b), d.trigger("pinch" + (b.scale < 1 ? "in" : "out"), b));
+ break;
+ case p:
+ c && b.changedLength < 2 && (d.trigger(a + "end", b), c = !1)
+ }
+ }
+
+ var c = !1;
+ d.gestures.Transform = {name: a, index: 45, defaults: {transformMinScale: .01, transformMinRotation: 1}, handler: b}
+ }("transform"), "function" == typeof define && define.amd ? define(function () {
+ return d
+ }) : "undefined" != typeof module && module.exports ? module.exports = d : a.Hammer = d
+}(window);
+//# sourceMappingURL=hammer.min.map
diff --git a/point/libs/hammerjs/hammer.min.map b/point/libs/hammerjs/hammer.min.map
new file mode 100644
index 0000000..61db733
--- /dev/null
+++ b/point/libs/hammerjs/hammer.min.map
@@ -0,0 +1 @@
+{"version": 3, "file": "hammer.min.js", "sources": ["hammer.js"], "names": ["window", "undefined", "setup", "Hammer", "READY", "Event", "determineEventTypes", "Utils", "each", "gestures", "gesture", "Detection", "register", "onTouch", "DOCUMENT", "EVENT_MOVE", "detect", "EVENT_END", "element", "options", "Instance", "VERSION", "defaults", "behavior", "userSelect", "touchAction", "touchCallout", "contentZooming", "userDrag", "tapHighlightColor", "document", "HAS_POINTEREVENTS", "navigator", "pointerEnabled", "msPointerEnabled", "HAS_TOUCHEVENTS", "IS_MOBILE", "test", "userAgent", "NO_MOUSEEVENTS", "CALCULATE_INTERVAL", "EVENT_TYPES", "DIRECTION_DOWN", "DIRECTION_LEFT", "DIRECTION_UP", "DIRECTION_RIGHT", "POINTER_MOUSE", "POINTER_TOUCH", "POINTER_PEN", "EVENT_START", "EVENT_RELEASE", "EVENT_TOUCH", "plugins", "utils", "extend", "dest", "src", "merge", "key", "hasOwnProperty", "on", "type", "handler", "addEventListener", "off", "removeEventListener", "obj", "iterator", "context", "i", "len", "forEach", "length", "call", "inStr", "find", "indexOf", "inArray", "index", "toArray", "Array", "prototype", "slice", "hasParent", "node", "parent", "parentNode", "getCenter", "touches", "pageX", "pageY", "clientX", "clientY", "min", "Math", "max", "touch", "push", "apply", "getVelocity", "deltaTime", "deltaX", "deltaY", "x", "abs", "y", "getAngle", "touch1", "touch2", "atan2", "PI", "getDirection", "getDistance", "sqrt", "getScale", "start", "end", "this", "getRotation", "isVertical", "direction", "setPrefixedCss", "prop", "value", "toggle", "prefixes", "toCamelCase", "p", "toUpperCase", "style", "toggleBehavior", "props", "falseFn", "onselectstart", "ondragstart", "str", "replace", "s", "event", "preventMouseEvents", "started", "shouldDetect", "hook", "types", "split", "eventType", "self", "onTouchHandler", "ev", "triggerType", "srcType", "toLowerCase", "isPointer", "isMouse", "button", "buttons", "PointerEvent", "matchType", "updatePointer", "doDetect", "reset", "touchList", "getTouchList", "touchListLength", "triggerChange", "trigger", "changedLength", "changedTouches", "evData", "collectEventData", "identifiers", "concat", "identifier", "pointerType", "center", "timeStamp", "Date", "now", "target", "srcEvent", "preventDefault", "preventManipulation", "stopPropagation", "stopDetect", "pointers", "touchlist", "pointer", "pointerEvent", "pointerId", "pt", "MSPOINTER_TYPE_MOUSE", "MSPOINTER_TYPE_TOUCH", "MSPOINTER_TYPE_PEN", "detection", "current", "previous", "stopped", "startDetect", "inst", "eventData", "startEvent", "lastEvent", "lastCalcEvent", "futureCalcEvent", "lastCalcData", "name", "extendEventData", "instOptions", "enabled", "getCalculatedData", "cur", "recalc", "calcEv", "calcData", "velocity", "angle", "velocityX", "velocityY", "interimAngle", "interimDirection", "startEv", "lastEv", "distance", "scale", "rotation", "sort", "a", "b", "eventStartHandler", "eventHandlers", "splice", "createEvent", "initEvent", "dispatchEvent", "enable", "state", "dispose", "eh", "dragGesture", "dragMaxTouches", "triggered", "dragMinDistance", "startCenter", "dragDistanceCorrection", "factor", "dragLockToAxis", "dragLockMinDistance", "lastDirection", "dragBlockVertical", "dragBlockHorizontal", "Drag", "Gesture", "holdGesture", "clearTimeout", "timer", "setTimeout", "holdTimeout", "holdThreshold", "Hold", "Release", "Infinity", "Swipe", "swipeMinTouches", "swipeMaxTouches", "swipeVelocityX", "swipeVelocityY", "tapGesture", "sincePrev", "didDoubleTap", "prev", "hasMoved", "tapMaxDistance", "tapMaxTime", "doubleTapInterval", "doubleTapDistance", "tapAlways", "Tap", "Touch", "preventMouse", "transformGesture", "scaleThreshold", "rotationThreshold", "transformMinScale", "transformMinRotation", "Transform", "define", "amd", "module", "exports"], "mappings": ";;;;;;;CAMA,SAAUA,EAAQC,GAChB,YA2OF,SAASC,KACFC,EAAOC,QAKVC,EAAMC,sBAGNC,EAAMC,KAAKL,EAAOM,SAAU,SAASC,GACjCC,EAAUC,SAASF,KAIvBL,EAAMQ,QAAQV,EAAOW,SAAUC,EAAYJ,EAAUK,QACrDX,EAAMQ,QAAQV,EAAOW,SAAUG,EAAWN,EAAUK,QAGpDb,EAAOC,OAAQ,GAxOnB,GAAID,GAAS,QAASA,GAAOe,EAASC,GAClC,MAAO,IAAIhB,GAAOiB,SAASF,EAASC,OAUxChB,GAAOkB,QAAU,QAgBjBlB,EAAOmB,UAOHC,UAQIC,WAAY,OASZC,YAAa,QAUbC,aAAc,OAQdC,eAAgB,OAShBC,SAAU,OAaVC,kBAAmB,kBAU3B1B,EAAOW,SAAWgB,SAOlB3B,EAAO4B,kBAAoBC,UAAUC,gBAAkBD,UAAUE,iBAOjE/B,EAAOgC,gBAAmB,gBAAkBnC,GAO5CG,EAAOiC,UAAY,6CAA6CC,KAAKL,UAAUM,WAO/EnC,EAAOoC,eAAkBpC,EAAOgC,iBAAmBhC,EAAOiC,WAAcjC,EAAO4B,kBAQ/E5B,EAAOqC,mBAAqB,EAU5B,IAAIC,MASAC,EAAiBvC,EAAOuC,eAAiB,OACzCC,EAAiBxC,EAAOwC,eAAiB,OACzCC,EAAezC,EAAOyC,aAAe,KACrCC,EAAkB1C,EAAO0C,gBAAkB,QAS3CC,EAAgB3C,EAAO2C,cAAgB,QACvCC,EAAgB5C,EAAO4C,cAAgB,QACvCC,EAAc7C,EAAO6C,YAAc,MASnCC,EAAc9C,EAAO8C,YAAc,QACnClC,EAAaZ,EAAOY,WAAa,OACjCE,EAAYd,EAAOc,UAAY,MAC/BiC,EAAgB/C,EAAO+C,cAAgB,UACvCC,EAAchD,EAAOgD,YAAc,OASvChD,GAAOC,OAAQ,EAOfD,EAAOiD,QAAUjD,EAAOiD,YAQxBjD,EAAOM,SAAWN,EAAOM,YAkCzB,IAAIF,GAAQJ,EAAOkD,OAUfC,OAAQ,SAAgBC,EAAMC,EAAKC,GAC/B,IAAI,GAAIC,KAAOF,IACPA,EAAIG,eAAeD,IAASH,EAAKG,KAASzD,GAAawD,IAG3DF,EAAKG,GAAOF,EAAIE,GAEpB,OAAOH,IAUXK,GAAI,SAAY1C,EAAS2C,EAAMC,GAC3B5C,EAAQ6C,iBAAiBF,EAAMC,GAAS,IAU5CE,IAAK,SAAa9C,EAAS2C,EAAMC,GAC7B5C,EAAQ+C,oBAAoBJ,EAAMC,GAAS,IAa/CtD,KAAM,SAAc0D,EAAKC,EAAUC,GAC/B,GAAIC,GAAGC,CAGP,IAAG,WAAaJ,GACZA,EAAIK,QAAQJ,EAAUC,OAEnB,IAAGF,EAAIM,SAAWvE,GACrB,IAAIoE,EAAI,EAAGC,EAAMJ,EAAIM,OAAYF,EAAJD,EAASA,IAClC,GAAGF,EAASM,KAAKL,EAASF,EAAIG,GAAIA,EAAGH,MAAS,EAC1C,WAKR,KAAIG,IAAKH,GACL,GAAGA,EAAIP,eAAeU,IAClBF,EAASM,KAAKL,EAASF,EAAIG,GAAIA,EAAGH,MAAS,EAC3C,QAahBQ,MAAO,SAAelB,EAAKmB,GACvB,MAAOnB,GAAIoB,QAAQD,GAAQ,IAU/BE,QAAS,SAAiBrB,EAAKmB,GAC3B,GAAGnB,EAAIoB,QAAS,CACZ,GAAIE,GAAQtB,EAAIoB,QAAQD,EACxB,OAAkB,KAAVG,GAAgB,EAAQA,EAEhC,IAAI,GAAIT,GAAI,EAAGC,EAAMd,EAAIgB,OAAYF,EAAJD,EAASA,IACtC,GAAGb,EAAIa,KAAOM,EACV,MAAON,EAGf,QAAO,GAUfU,QAAS,SAAiBb,GACtB,MAAOc,OAAMC,UAAUC,MAAMT,KAAKP,EAAK,IAU3CiB,UAAW,SAAmBC,EAAMC,GAChC,KAAMD,GAAM,CACR,GAAGA,GAAQC,EACP,OAAO,CAEXD,GAAOA,EAAKE,WAEhB,OAAO,GASXC,UAAW,SAAmBC,GAC1B,GAAIC,MACA