Initial commit
This commit is contained in:
		
						commit
						3490d8aab7
					
				
							
								
								
									
										21
									
								
								LICENSE.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								LICENSE.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					The MIT License (MIT)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Copyright (c) 2015 Thomas FORGIONE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
				
			||||||
 | 
					of this software and associated documentation files (the "Software"), to deal
 | 
				
			||||||
 | 
					in the Software without restriction, including without limitation the rights
 | 
				
			||||||
 | 
					to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
				
			||||||
 | 
					copies of the Software, and to permit persons to whom the Software is
 | 
				
			||||||
 | 
					furnished to do so, subject to the following conditions:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The above copyright notice and this permission notice shall be included in
 | 
				
			||||||
 | 
					all copies or substantial portions of the Software.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
				
			||||||
 | 
					IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
				
			||||||
 | 
					FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
				
			||||||
 | 
					AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
				
			||||||
 | 
					LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
				
			||||||
 | 
					OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
				
			||||||
 | 
					THE SOFTWARE.
 | 
				
			||||||
							
								
								
									
										18
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					# slideshow.io
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## What is it
 | 
				
			||||||
 | 
					Client-server application to manage slides on different computers during a
 | 
				
			||||||
 | 
					presentation.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You can upload your pdf, and a link will be sent so you can share it with your
 | 
				
			||||||
 | 
					viewer. You will have a *speaker* interface, allowing you to switch between
 | 
				
			||||||
 | 
					slides and interact with them (underline elements, use a pointer...) and your
 | 
				
			||||||
 | 
					viewer will see what you are currently doing.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Install
 | 
				
			||||||
 | 
					A simple `npm install` will work.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## License
 | 
				
			||||||
 | 
					This software is under MIT license. Check
 | 
				
			||||||
 | 
					[LICENSE.md](https://github.com/tforgione/slideshow.io/blob/master/LICENSE.md) for
 | 
				
			||||||
 | 
					more information.
 | 
				
			||||||
							
								
								
									
										61
									
								
								lib/get.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								lib/get.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,61 @@
 | 
				
			|||||||
 | 
					var express = require('express');
 | 
				
			||||||
 | 
					var fs = require('fs');
 | 
				
			||||||
 | 
					var log = require('log.js')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = function(parent){
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    log.debug("Loading get :");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fs.readdirSync(__dirname + '/../routes').forEach(function(name){
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // index.js in controller, with function as pages (views.py for django)
 | 
				
			||||||
 | 
					        var obj = require('./../routes/' + name + '/index');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // urls.js, just like django urls.py
 | 
				
			||||||
 | 
					        var urls = require('./../routes/' + name + '/urls');
 | 
				
			||||||
 | 
					        name = obj.name || name;
 | 
				
			||||||
 | 
					        var app = express();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // allow specifying the view engine
 | 
				
			||||||
 | 
					        if (obj.engine) app.set('view engine', obj.engine);
 | 
				
			||||||
 | 
					        app.set('views', __dirname + '/../routes/' + name + '/views');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // generate routes based
 | 
				
			||||||
 | 
					        // on the exported methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        log.debug('   ' + name + ':');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (var key in urls) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            app.get(key, ((key) => function(req, res, next) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                var path = obj[urls[key]](req, res, function(view) {
 | 
				
			||||||
 | 
					                    res.render(
 | 
				
			||||||
 | 
					                        __dirname +
 | 
				
			||||||
 | 
					                        '/../routes/' +
 | 
				
			||||||
 | 
					                        name + '/views/' +
 | 
				
			||||||
 | 
					                        view,
 | 
				
			||||||
 | 
					                        res.locals,
 | 
				
			||||||
 | 
					                        function(err, out) {
 | 
				
			||||||
 | 
					                            if (err !== null) {
 | 
				
			||||||
 | 
					                                log.pugerror(err);
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            res.send(out);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                }, next);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            })(key));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            log.debug('      ' + key + ' -> ' + name + '.' + urls[key]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        log.debug();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // mount the app
 | 
				
			||||||
 | 
					        parent.use(app);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										145
									
								
								lib/log.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								lib/log.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,145 @@
 | 
				
			|||||||
 | 
					var express = require('express');
 | 
				
			||||||
 | 
					var http = require('http');
 | 
				
			||||||
 | 
					var yargs = require('yargs');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var argv = yargs.argv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var log = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var Color = {
 | 
				
			||||||
 | 
					    DEFAULT:0,
 | 
				
			||||||
 | 
					    BLACK:1,
 | 
				
			||||||
 | 
					    RED:2,
 | 
				
			||||||
 | 
					    GREEN:3,
 | 
				
			||||||
 | 
					    YELLOW:4,
 | 
				
			||||||
 | 
					    BLUE:5,
 | 
				
			||||||
 | 
					    MAGENTA:6,
 | 
				
			||||||
 | 
					    CYAN:7,
 | 
				
			||||||
 | 
					    ORANGE:8
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function getColorCode(c) {
 | 
				
			||||||
 | 
					    switch (c) {
 | 
				
			||||||
 | 
					        case Color.DEFAULT: return '\u001b[0m';
 | 
				
			||||||
 | 
					        case Color.BLACK:   return '\u001b[30m';
 | 
				
			||||||
 | 
					        case Color.RED:     return '\u001b[31m';
 | 
				
			||||||
 | 
					        case Color.GREEN:   return '\u001b[32m';
 | 
				
			||||||
 | 
					        case Color.YELLOW:  return '\u001b[33m';
 | 
				
			||||||
 | 
					        case Color.BLUE:    return '\u001b[34m';
 | 
				
			||||||
 | 
					        case Color.MAGENTA: return '\u001b[35m';
 | 
				
			||||||
 | 
					        case Color.CYAN:    return '\u001b[36m';
 | 
				
			||||||
 | 
					        case Color.ORANGE:  return '\u001b[38;5;202m';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var isDev = require('express')().get('env') === 'development';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var write;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if (argv.nolisten || argv.n) {
 | 
				
			||||||
 | 
					    write = function(elt, color) { }
 | 
				
			||||||
 | 
					} else if (isDev) {
 | 
				
			||||||
 | 
					    write = function(elt, color) {
 | 
				
			||||||
 | 
					        console.log(getColorCode(color) + elt + getColorCode(Color.DEFAULT));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					} else {
 | 
				
			||||||
 | 
					    write = function(elt, color) {
 | 
				
			||||||
 | 
					        console.log(elt);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					log.ready = function(msg) {
 | 
				
			||||||
 | 
					    write('[RDY] ' + new Date() + ' ' + msg, Color.GREEN);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					log.request = function(req, res, time) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (req.headers['x-forwarded-for'] !== undefined || isDev) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var isStatic = req.url.substr(0, 7) === '/static' || req.url === '/favicon.ico';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        write(
 | 
				
			||||||
 | 
					            '[REQ] ' + new Date() + ' ' +
 | 
				
			||||||
 | 
					                (req.headers['x-forwarded-for'] || req.connection.remoteAddress) +
 | 
				
			||||||
 | 
					                (time !== undefined ? (' in ' + ("      " + time).slice(-6) + ' ms') : '') +
 | 
				
			||||||
 | 
					                ' : ' + (isStatic && req.url !== '/favicon.ico' ? '/static' + req.url : req.url),
 | 
				
			||||||
 | 
					            isStatic ? Color.YELLOW : Color.CYAN
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					log.socket = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					log.socket.connection = function(socket, isTest) {
 | 
				
			||||||
 | 
					    write(
 | 
				
			||||||
 | 
					        '[SOK] ' + new Date() + ' ' +
 | 
				
			||||||
 | 
					        (socket.handshake.headers['x-forwarded-for'] || socket.handshake.address) + (isTest ? ' test' : '') + ' connection',
 | 
				
			||||||
 | 
					        Color.MAGENTA
 | 
				
			||||||
 | 
					     );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					log.socket.disconnect = function(socket, isTest) {
 | 
				
			||||||
 | 
					    write(
 | 
				
			||||||
 | 
					        '[SOK] ' + new Date() + ' ' +
 | 
				
			||||||
 | 
					            (socket.handshake.headers['x-forwarded-for'] || socket.handshake.address) + (isTest ? ' test' : '') + ' disconnect',
 | 
				
			||||||
 | 
					        Color.MAGENTA
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					log.dberror = function(error) {
 | 
				
			||||||
 | 
					    write(
 | 
				
			||||||
 | 
					        '[DBE] ' + new Date() + ' ' + error,
 | 
				
			||||||
 | 
					        Color.RED
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					log.prefetcherror = function(error) {
 | 
				
			||||||
 | 
					    write(
 | 
				
			||||||
 | 
					        '[PFE] ' + new Date() + ' ' + error,
 | 
				
			||||||
 | 
					        Color.RED
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					log.mailerror = function(error) {
 | 
				
			||||||
 | 
					    write(
 | 
				
			||||||
 | 
					        '[MLE] ' + new Date() + ' ' + error,
 | 
				
			||||||
 | 
					        Color.RED
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					log.debug = function(info, force) {
 | 
				
			||||||
 | 
					    if (isDev || force === true) {
 | 
				
			||||||
 | 
					        write(
 | 
				
			||||||
 | 
					            '[DBG] ' + (info !== undefined ? info : ''),
 | 
				
			||||||
 | 
					            Color.YELLOW
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					log.pugerror = function(error) {
 | 
				
			||||||
 | 
					    write(
 | 
				
			||||||
 | 
					        '[PER] ' + new Date() + ' ' + error,
 | 
				
			||||||
 | 
					        Color.RED
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					log.warning = function(message) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    write(
 | 
				
			||||||
 | 
					        '[WRN] ' + new Date() + ' ' + message,
 | 
				
			||||||
 | 
					        Color.ORANGE
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					log.faceerror = function(message) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    write(
 | 
				
			||||||
 | 
					        '[FER] ' + new Date() + ' ' + message,
 | 
				
			||||||
 | 
					        Color.RED
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = log;
 | 
				
			||||||
							
								
								
									
										34
									
								
								lib/socket.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								lib/socket.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,34 @@
 | 
				
			|||||||
 | 
					module.exports = function(io) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    io.on('connection', function(socket) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        socket.emit('welcome');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        socket.on('viewer', function(filename) {
 | 
				
			||||||
 | 
					            socket.join(filename);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        socket.on('speaker', function(filename, socketId) {
 | 
				
			||||||
 | 
					            socket.join(filename);
 | 
				
			||||||
 | 
					            socket.speakerId = socketId;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        socket.on('change-slide', function(filename, pageNumber) {
 | 
				
			||||||
 | 
					            socket.broadcast.to(filename).emit('update', pageNumber);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        socket.on('pointer', function(filename, id, x, y) {
 | 
				
			||||||
 | 
					            if (id === socket.speakerId) {
 | 
				
			||||||
 | 
					                socket.broadcast.to(filename).emit('pointer', 'speaker', x, y);
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                socket.broadcast.to(filename).emit('pointer', 'speaker', x, y);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        socket.on('viewer-laser', function(filename, enabled) {
 | 
				
			||||||
 | 
					            socket.broadcast.to(filename).emit('viewer-laser', enabled);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										16
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					    "name" : "slideshow.io",
 | 
				
			||||||
 | 
					    "version" : "0.1.0",
 | 
				
			||||||
 | 
					    "dependencies" : {
 | 
				
			||||||
 | 
					        "express" : "*",
 | 
				
			||||||
 | 
					        "pug" : "*",
 | 
				
			||||||
 | 
					        "socket.io" : "*",
 | 
				
			||||||
 | 
					        "node-uuid" : "*",
 | 
				
			||||||
 | 
					        "body-parser" : "*",
 | 
				
			||||||
 | 
					        "app-module-path":"*"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "repository" : {
 | 
				
			||||||
 | 
					        "type" : "git",
 | 
				
			||||||
 | 
					        "url" : "https://github.com/tforgione/slideshow.io"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										6
									
								
								routes/index/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								routes/index/index.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					module.exports.index = function(req, res, render, next) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    res.setHeader('Content-Type', 'text/html');
 | 
				
			||||||
 | 
					    render('index.pug', res.locals)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										3
									
								
								routes/index/urls.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								routes/index/urls.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					module.exports = {
 | 
				
			||||||
 | 
					    '/' : 'index'
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										5
									
								
								routes/index/views/index.pug
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								routes/index/views/index.pug
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					extends ../../../views/main.pug
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					block content
 | 
				
			||||||
 | 
					    p.
 | 
				
			||||||
 | 
					        Hello world !
 | 
				
			||||||
							
								
								
									
										25
									
								
								routes/speaker/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								routes/speaker/index.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					var fs = require('fs');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports.index = function(req, res, render, next) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fs.stat('static/uploaded/' + req.params.file + '.pdf', function(err) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (err === null) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            res.locals.file = req.params.file;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            res.setHeader('Content-Type', 'text/html');
 | 
				
			||||||
 | 
					            render('index.pug', res.locals);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // 404 : file does not exist
 | 
				
			||||||
 | 
					            var error = new Error('File does not exist');
 | 
				
			||||||
 | 
					            error.status = 404;
 | 
				
			||||||
 | 
					            next(error);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										3
									
								
								routes/speaker/urls.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								routes/speaker/urls.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					module.exports = {
 | 
				
			||||||
 | 
					    '/speaker/:file' : 'index'
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										51
									
								
								routes/speaker/views/index.pug
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								routes/speaker/views/index.pug
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,51 @@
 | 
				
			|||||||
 | 
					extends ../../../views/main.pug
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					block append css
 | 
				
			||||||
 | 
					    link(href="/static/css/style.css", rel="stylesheet")
 | 
				
			||||||
 | 
					    link(href="/static/css/speaker.css", rel="stylesheet")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					block content
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .row
 | 
				
			||||||
 | 
					        .col-md-8
 | 
				
			||||||
 | 
					            #canvases
 | 
				
			||||||
 | 
					                canvas#canvas-pdf(style={"border" : "1px solid #000000", position:'absolute'})
 | 
				
			||||||
 | 
					                canvas#canvas-paint.noselect(onmousedown="sio.onMouseDown(event);", onmousemove="sio.onMouseMove(event);", onmouseup="sio.onMouseUp(event);", onmouseout="sio.onMouseUp(event);", style={position:'absolute'})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            p
 | 
				
			||||||
 | 
					                .btn-group
 | 
				
			||||||
 | 
					                    button.btn.btn-default#first(onclick="sio.firstSlide();")
 | 
				
			||||||
 | 
					                        span.glyphicon.glyphicon-step-backward
 | 
				
			||||||
 | 
					                    button.btn.btn-default#previous(aria-hidden='true', onclick="sio.previousSlide();")
 | 
				
			||||||
 | 
					                        span.glyphicon.glyphicon-play.glyphicon-flip
 | 
				
			||||||
 | 
					                    input.btn.btn-default#counter(type='text', onclick="sio.clearCounter();", onblur="sio.update();", onkeydown="if (event.keyCode === 13) sio.changeSlideFromCounter(event);")
 | 
				
			||||||
 | 
					                    button.btn.btn-default#next(onclick="sio.nextSlide();")
 | 
				
			||||||
 | 
					                        span.glyphicon.glyphicon-play
 | 
				
			||||||
 | 
					                    button.btn.btn-default#last(onclick="sio.lastSlide();")
 | 
				
			||||||
 | 
					                        span.glyphicon.glyphicon-step-forward
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                span(style={'margin-left':'10px'})
 | 
				
			||||||
 | 
					                .btn-group
 | 
				
			||||||
 | 
					                    button.btn.btn-default#sync(onclick="sio.syncAudience();") Sync viewer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                span(style={'margin-left':'10px'})
 | 
				
			||||||
 | 
					                .btn-group
 | 
				
			||||||
 | 
					                    button.btn.btn-default#viewer-laser(onclick="sio.switchAudienceLaser();") Audience laser is disabled
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .col-md-4
 | 
				
			||||||
 | 
					            .btn-group
 | 
				
			||||||
 | 
					                button.btn.btn-default#start(onclick="sio.startPresentation();")
 | 
				
			||||||
 | 
					                    span.glyphicon.glyphicon-play
 | 
				
			||||||
 | 
					                button.btn.btn-default#stop(onclick="sio.stopPresentation();", disabled)
 | 
				
			||||||
 | 
					                    span.glyphicon.glyphicon-stop
 | 
				
			||||||
 | 
					            p Total time : 
 | 
				
			||||||
 | 
					                span#totalTime
 | 
				
			||||||
 | 
					            p Slide time : 
 | 
				
			||||||
 | 
					                span#slideTime
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					block js
 | 
				
			||||||
 | 
					    script filename = '#{file}';
 | 
				
			||||||
 | 
					    script(src="/static/js/pdf.js")
 | 
				
			||||||
 | 
					    script(src="/static/js/pdf.worker.js")
 | 
				
			||||||
 | 
					    script(src="/socket.io/socket.io.js")
 | 
				
			||||||
 | 
					    script(src="/static/js/speaker.js")
 | 
				
			||||||
							
								
								
									
										25
									
								
								routes/viewer/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								routes/viewer/index.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					var fs = require('fs');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports.index = function(req, res, render, next) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fs.stat('static/uploaded/' + req.params.file + '.pdf', function(err) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (err === null) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            res.locals.file = req.params.file;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            res.setHeader('Content-Type', 'text/html');
 | 
				
			||||||
 | 
					            render('index.pug', res.locals);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // 404 : file does not exist
 | 
				
			||||||
 | 
					            var error = new Error('File does not exist');
 | 
				
			||||||
 | 
					            error.status = 404;
 | 
				
			||||||
 | 
					            next(error);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										3
									
								
								routes/viewer/urls.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								routes/viewer/urls.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					module.exports = {
 | 
				
			||||||
 | 
					    '/viewer/:file' : 'index'
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										17
									
								
								routes/viewer/views/index.pug
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								routes/viewer/views/index.pug
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					extends ../../../views/base.pug
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					block css
 | 
				
			||||||
 | 
					    link(href="/static/css/style.css", rel="stylesheet")
 | 
				
			||||||
 | 
					    link(href="/static/css/viewer.css", rel="stylesheet")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					block base_content
 | 
				
			||||||
 | 
					    #canvases
 | 
				
			||||||
 | 
					        canvas#canvas-pdf.absoluteCenter(style={position:'absolute'})
 | 
				
			||||||
 | 
					        canvas#canvas-paint.absoluteCenter.noselect(onmousedown="sio.onMouseDown(event);", onmousemove="sio.onMouseMove(event);", onmouseup="sio.onMouseUp(event);", onmouseout="sio.onMouseUp(event);", style={position:'absolute'})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					block js
 | 
				
			||||||
 | 
					    script filename = '#{file}';
 | 
				
			||||||
 | 
					    script(src="/static/js/pdf.js")
 | 
				
			||||||
 | 
					    script(src="/static/js/pdf.worker.js")
 | 
				
			||||||
 | 
					    script(src="/socket.io/socket.io.js")
 | 
				
			||||||
 | 
					    script(src="/static/js/viewer.js")
 | 
				
			||||||
							
								
								
									
										72
									
								
								server.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								server.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,72 @@
 | 
				
			|||||||
 | 
					require('app-module-path').addPath('./lib');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var http = require('http');
 | 
				
			||||||
 | 
					var express = require('express');
 | 
				
			||||||
 | 
					var pug = require('pug');
 | 
				
			||||||
 | 
					var bp = require('body-parser');
 | 
				
			||||||
 | 
					var socket = require('socket.js');
 | 
				
			||||||
 | 
					var log = require('log.js');
 | 
				
			||||||
 | 
					var app = express();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Socket.io initialization
 | 
				
			||||||
 | 
					var http = require('http').Server(app);
 | 
				
			||||||
 | 
					var io = require('socket.io')(http);
 | 
				
			||||||
 | 
					require('./lib/socket.js')(io);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var isDev = app.get('env') === 'development';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					app.set('view engine', 'pug');
 | 
				
			||||||
 | 
					app.set('trust proxy', 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// parse application/x-www-form-urlencoded
 | 
				
			||||||
 | 
					app.use(bp.urlencoded({ extended: false }))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// parse application/json
 | 
				
			||||||
 | 
					app.use(bp.json())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Log request and time to answer
 | 
				
			||||||
 | 
					app.use(function(req, res, next) {
 | 
				
			||||||
 | 
					    let start = Date.now();
 | 
				
			||||||
 | 
					    res.on('finish', function() {
 | 
				
			||||||
 | 
					        log.request(req, res, Date.now() - start);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    res.locals.title = "slideshow.io";
 | 
				
			||||||
 | 
					    next();
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Load controllers
 | 
				
			||||||
 | 
					require('./lib/get')(app);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Static files
 | 
				
			||||||
 | 
					app.use('/static', express.static('static'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// When error raised
 | 
				
			||||||
 | 
					app.use(function(err, req, res, next) {
 | 
				
			||||||
 | 
					    if (err.status === 404) {
 | 
				
			||||||
 | 
					        res.setHeader('Content-Type', 'text/html');
 | 
				
			||||||
 | 
					        res.send('Error 404');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// When route not found, raise not found
 | 
				
			||||||
 | 
					app.use(function(req, res) {
 | 
				
			||||||
 | 
					    res.setHeader('Content-Type', 'text/html');
 | 
				
			||||||
 | 
					    res.send('Error 404');
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Set ports and ip address
 | 
				
			||||||
 | 
					var serverPort, serverIpAddress;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if ( isDev ) {
 | 
				
			||||||
 | 
					    serverPort = 4001;
 | 
				
			||||||
 | 
					    serverIpAddress = 'localhost';
 | 
				
			||||||
 | 
					} else {
 | 
				
			||||||
 | 
					    // Openhift conf
 | 
				
			||||||
 | 
					    serverPort = process.env.OPENSHIFT_NODEJS_PORT || 8080;
 | 
				
			||||||
 | 
					    serverIpAddress = process.env.OPENSHIFT_NODEJS_IP || '127.0.0.1';
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Start server
 | 
				
			||||||
 | 
					http.listen(serverPort, serverIpAddress, function() {
 | 
				
			||||||
 | 
					    log.debug("Now listening " + serverIpAddress + ":" + serverPort);
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
							
								
								
									
										34
									
								
								static/css/signin.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								static/css/signin.css
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,34 @@
 | 
				
			|||||||
 | 
					.form-signin {
 | 
				
			||||||
 | 
					  max-width: 330px;
 | 
				
			||||||
 | 
					  padding: 15px;
 | 
				
			||||||
 | 
					  margin: 0 auto;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.form-signin .form-signin-heading,
 | 
				
			||||||
 | 
					.form-signin .checkbox {
 | 
				
			||||||
 | 
					  margin-bottom: 10px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.form-signin .checkbox {
 | 
				
			||||||
 | 
					  font-weight: normal;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.form-signin .form-control {
 | 
				
			||||||
 | 
					  position: relative;
 | 
				
			||||||
 | 
					  height: auto;
 | 
				
			||||||
 | 
					  -webkit-box-sizing: border-box;
 | 
				
			||||||
 | 
					     -moz-box-sizing: border-box;
 | 
				
			||||||
 | 
					          box-sizing: border-box;
 | 
				
			||||||
 | 
					  padding: 10px;
 | 
				
			||||||
 | 
					  font-size: 16px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.form-signin .form-control:focus {
 | 
				
			||||||
 | 
					  z-index: 2;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.form-signin input[type="email"] {
 | 
				
			||||||
 | 
					  margin-bottom: -1px;
 | 
				
			||||||
 | 
					  border-bottom-right-radius: 0;
 | 
				
			||||||
 | 
					  border-bottom-left-radius: 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.form-signin input[type="password"] {
 | 
				
			||||||
 | 
					  margin-bottom: 10px;
 | 
				
			||||||
 | 
					  border-top-left-radius: 0;
 | 
				
			||||||
 | 
					  border-top-right-radius: 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										8
									
								
								static/css/speaker.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								static/css/speaker.css
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					.glyphicon-flip {
 | 
				
			||||||
 | 
					    -moz-transform: scaleX(-1);
 | 
				
			||||||
 | 
					    -o-transform: scaleX(-1);
 | 
				
			||||||
 | 
					    -webkit-transform: scaleX(-1);
 | 
				
			||||||
 | 
					    transform: scaleX(-1);
 | 
				
			||||||
 | 
					    filter: FlipH;
 | 
				
			||||||
 | 
					    -ms-filter: "FlipH";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										9
									
								
								static/css/style.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								static/css/style.css
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					.noselect {
 | 
				
			||||||
 | 
					    cursor: default;
 | 
				
			||||||
 | 
					    -webkit-touch-callout: none;
 | 
				
			||||||
 | 
					    -webkit-user-select: none;
 | 
				
			||||||
 | 
					    -khtml-user-select: none;
 | 
				
			||||||
 | 
					    -moz-user-select: none;
 | 
				
			||||||
 | 
					    -ms-user-select: none;
 | 
				
			||||||
 | 
					    user-select: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										10
									
								
								static/css/viewer.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								static/css/viewer.css
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					#canvas {
 | 
				
			||||||
 | 
					    margin:auto;
 | 
				
			||||||
 | 
					    position:absolute;
 | 
				
			||||||
 | 
					    top:0;
 | 
				
			||||||
 | 
					    bottom:0;
 | 
				
			||||||
 | 
					    left:0;
 | 
				
			||||||
 | 
					    right:0;
 | 
				
			||||||
 | 
					    max-height:100%;
 | 
				
			||||||
 | 
					    max-width:100%;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										10375
									
								
								static/js/pdf.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10375
									
								
								static/js/pdf.js
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										42034
									
								
								static/js/pdf.worker.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										42034
									
								
								static/js/pdf.worker.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										291
									
								
								static/js/speaker.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										291
									
								
								static/js/speaker.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,291 @@
 | 
				
			|||||||
 | 
					$(function() { sio = (function() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var sio = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var counter = $('#counter');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var canvasPdf = $('#canvas-pdf').get(0);
 | 
				
			||||||
 | 
					    var contextPdf = canvasPdf.getContext('2d');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var canvasPaint = $('#canvas-paint').get(0);
 | 
				
			||||||
 | 
					    var contextPaint = canvasPaint.getContext('2d');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var pdf;
 | 
				
			||||||
 | 
					    var currentPage = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var startTime = 0;
 | 
				
			||||||
 | 
					    var startSlide = 0;
 | 
				
			||||||
 | 
					    var refreshIntervalId = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var pointer = false;
 | 
				
			||||||
 | 
					    var shouldUpdatePointer = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var canvasPdfBounding;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var lasers = {};
 | 
				
			||||||
 | 
					    var drawAudienceLasers = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    PDFJS.getDocument('/static/uploaded/' + filename + '.pdf').then(function getPdf(_pdf) {
 | 
				
			||||||
 | 
					        pdf = _pdf;
 | 
				
			||||||
 | 
					        updateUI();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var socket = io();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    socket.on('welcome', function() {
 | 
				
			||||||
 | 
					        socket.emit('speaker', filename, socket.id);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    socket.on('pointer', canvasPointer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function filterInt(value) {
 | 
				
			||||||
 | 
					        if(/^(\-|\+)?([0-9]+|Infinity)$/.test(value))
 | 
				
			||||||
 | 
					            return Number(value);
 | 
				
			||||||
 | 
					        return NaN;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var updateUI = function() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        counter.val(currentPage + '/' + pdf.pdfInfo.numPages);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $('#previous,#first').prop('disabled', currentPage === 1);
 | 
				
			||||||
 | 
					        $('#next,#last').prop('disabled', currentPage === pdf.pdfInfo.numPages);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        pdf.getPage(currentPage).then(function(page) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            previousPage = currentPage;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var viewport = page.getViewport(2.0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            canvasPdf.width = viewport.width;
 | 
				
			||||||
 | 
					            canvasPdf.height = viewport.height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            canvasPaint.width = viewport.width;
 | 
				
			||||||
 | 
					            canvasPaint.height = viewport.height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $('#canvases').width(canvasPdf.width + 'px');
 | 
				
			||||||
 | 
					            $('#canvases').height(canvasPdf.height + 'px');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            canvasPdfBounding = canvasPdf.getBoundingClientRect();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var renderContext = {
 | 
				
			||||||
 | 
					                canvasContext: contextPdf,
 | 
				
			||||||
 | 
					                viewport: viewport
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            page.render(renderContext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function updateAudience() { socket.emit('change-slide', filename, currentPage); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function formatTime(ms) {
 | 
				
			||||||
 | 
					        var sec = padToTwo(Math.floor((ms / 1000) % 60));
 | 
				
			||||||
 | 
					        var min = padToTwo(Math.floor(((ms / 1000 - sec) % 3600) / 60));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return min + ':' + sec;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function updateTimers() {
 | 
				
			||||||
 | 
					        if (refreshIntervalId !== 0) {
 | 
				
			||||||
 | 
					            $('#totalTime').html(formatTime(Date.now() - startTime));
 | 
				
			||||||
 | 
					            $('#slideTime').html(formatTime(Date.now() - startSlide));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function padToTwo(number) {
 | 
				
			||||||
 | 
					        if (number<=99) { number = ("0"+number).slice(-2); }
 | 
				
			||||||
 | 
					        return number;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function resetTimeSlide() {
 | 
				
			||||||
 | 
					        startSlide = Date.now();
 | 
				
			||||||
 | 
					        updateTimers();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Check if number is valid, and updates
 | 
				
			||||||
 | 
					    // number undefined means sync all clients
 | 
				
			||||||
 | 
					    function changeSlide(number) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (isNaN(number) || number < 1 || number > pdf.pdfInfo.numPages) {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (currentPage === undefined || currentPage === number) {
 | 
				
			||||||
 | 
					            updateAudience();
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        currentPage = number;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        updateUI();
 | 
				
			||||||
 | 
					        updateAudience();
 | 
				
			||||||
 | 
					        resetTimeSlide();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function canvasPointer(id,x,y) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Clear canvas
 | 
				
			||||||
 | 
					        canvasPaint.width = canvasPaint.width;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (id != undefined) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (x != undefined && y != undefined) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                lasers[id] = {x:x, y:y};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                delete lasers[id];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (var laserIndex in lasers) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var laser = lasers[laserIndex];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (drawAudienceLasers === true || laserIndex === socket.id) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                contextPaint.fillStyle = laserIndex === socket.id ? 'red' : 'green';
 | 
				
			||||||
 | 
					                contextPaint.beginPath();
 | 
				
			||||||
 | 
					                contextPaint.arc(laser.x * canvasPdf.width, laser.y * canvasPdf.height, 10, 0, Math.PI*2, true);
 | 
				
			||||||
 | 
					                contextPaint.closePath();
 | 
				
			||||||
 | 
					                contextPaint.fill();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sio.onMouseDown = function(event) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var x = (event.x - canvasPdfBounding.left) / canvasPdf.width;
 | 
				
			||||||
 | 
					        var y = (event.y - canvasPdfBounding.top) / canvasPdf.height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        socket.emit('pointer', filename, socket.id, x, y);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        pointer = true;
 | 
				
			||||||
 | 
					        shouldUpdatePointer = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        canvasPointer(socket.id, x, y);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sio.onMouseMove = function(event) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (pointer) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var x = (event.x - canvasPdfBounding.left) / canvasPdf.width;
 | 
				
			||||||
 | 
					            var y = (event.y - canvasPdfBounding.top) / canvasPdf.height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (shouldUpdatePointer) {
 | 
				
			||||||
 | 
					                // Update
 | 
				
			||||||
 | 
					                socket.emit('pointer', filename, socket.id, x, y);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                shouldUpdatePointer = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                setTimeout(function() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    shouldUpdatePointer = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                }, 20);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            canvasPointer(socket.id, x, y);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sio.onMouseUp = function(event) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        socket.emit('pointer', filename, socket.id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        pointer = false;
 | 
				
			||||||
 | 
					        shouldUpdatePointer = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        canvasPointer(socket.id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sio.startPresentation = function() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        startTime = startSlide = Date.now();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        refreshIntervalId = setInterval(updateTimers, 1000);
 | 
				
			||||||
 | 
					        updateTimers();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $('#start').prop('disabled', true);
 | 
				
			||||||
 | 
					        $('#stop').prop('disabled', false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sio.stopPresentation = function() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        clearInterval(refreshIntervalId);
 | 
				
			||||||
 | 
					        refreshIntervalId = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $('#start').prop('disabled', false);
 | 
				
			||||||
 | 
					        $('#stop').prop('disabled', true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sio.changeSlideFromCounter = function() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var slideNumber = filterInt($('#counter').val());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        changeSlide(slideNumber);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // lose focus
 | 
				
			||||||
 | 
					        $(':focus').blur();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sio.switchAudienceLaser = function() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var laser = $('#viewer-laser');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (drawAudienceLasers === false) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Laser is disabled, will be enabled
 | 
				
			||||||
 | 
					            laser.text('Audience laser is enabled');
 | 
				
			||||||
 | 
					            laser.removeClass('btn-default').addClass('btn-primary');
 | 
				
			||||||
 | 
					            drawAudienceLasers = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            laser.text('Audience laser is disabled');
 | 
				
			||||||
 | 
					            laser.removeClass('btn-primary').addClass('btn-default');
 | 
				
			||||||
 | 
					            drawAudienceLasers = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        socket.emit('viewer-laser', filename, drawAudienceLasers);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sio.clearCounter   = function() { $('#counter').val('');             };
 | 
				
			||||||
 | 
					    sio.nextSlide      = function() { changeSlide(currentPage + 1);      };
 | 
				
			||||||
 | 
					    sio.previousSlide  = function() { changeSlide(currentPage - 1);      };
 | 
				
			||||||
 | 
					    sio.firstSlide     = function() { changeSlide(1);                    };
 | 
				
			||||||
 | 
					    sio.lastSlide      = function() { changeSlide(pdf.pdfInfo.numPages); };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sio.syncAudience   = updateAudience;
 | 
				
			||||||
 | 
					    sio.update         = updateUI;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $(window).resize(updateUI);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return sio;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					})(); });
 | 
				
			||||||
							
								
								
									
										175
									
								
								static/js/viewer.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										175
									
								
								static/js/viewer.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,175 @@
 | 
				
			|||||||
 | 
					$(function() { sio = (function() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var sio = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var canvasPdf = $('#canvas-pdf').get(0);
 | 
				
			||||||
 | 
					    var contextPdf = canvasPdf.getContext('2d');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var canvasPaint = $('#canvas-paint').get(0);
 | 
				
			||||||
 | 
					    var contextPaint = canvasPaint.getContext('2d');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var pdf;
 | 
				
			||||||
 | 
					    var pageNumber = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var pointer = false;
 | 
				
			||||||
 | 
					    var canvasPdfBounding;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var drawAudienceLaser = false;
 | 
				
			||||||
 | 
					    var lasers = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    PDFJS.getDocument('/static/uploaded/' + filename + '.pdf').then(function getPdfHelloWorld(_pdf) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        pdf = _pdf;
 | 
				
			||||||
 | 
					        update();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var socket = io();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    socket.on('welcome', function() {
 | 
				
			||||||
 | 
					        socket.emit('viewer', filename);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    socket.on('update', function(newPageNumber) {
 | 
				
			||||||
 | 
					        pageNumber = newPageNumber;
 | 
				
			||||||
 | 
					        update();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    socket.on('viewer-laser', function(enabled) {
 | 
				
			||||||
 | 
					        drawAudienceLaser = enabled;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    socket.on('pointer', canvasPointer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function update() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        pdf.getPage(pageNumber).then(function(page) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var scale;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // width / height
 | 
				
			||||||
 | 
					            var ratio = page.pageInfo.view[2] / page.pageInfo.view[3];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (window.innerWidth < window.innerHeight) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                canvasPdf.width = window.innerWidth;
 | 
				
			||||||
 | 
					                canvasPdf.height = canvasPdf.width / ratio;
 | 
				
			||||||
 | 
					                scale = canvasPdf.width / page.getViewport(1.0).width;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                canvasPdf.height = window.innerHeight;
 | 
				
			||||||
 | 
					                canvasPdf.width = ratio * canvasPdf.height;
 | 
				
			||||||
 | 
					                scale = canvasPdf.width / page.getViewport(1.0).width;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            canvasPaint.width = canvasPdf.width;
 | 
				
			||||||
 | 
					            canvasPaint.height = canvasPdf.height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $('#canvases').width(canvasPdf.width + 'px');
 | 
				
			||||||
 | 
					            $('#canvases').height(canvasPdf.height + 'px');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            canvasPdfBounding = canvasPdf.getBoundingClientRect();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var viewport = page.getViewport(scale);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var renderContext = {
 | 
				
			||||||
 | 
					                canvasContext: contextPdf,
 | 
				
			||||||
 | 
					                viewport: viewport
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            page.render(renderContext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function canvasPointer(id,x,y) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Clear canvas
 | 
				
			||||||
 | 
					        canvasPaint.width = canvasPaint.width;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (id != undefined) {
 | 
				
			||||||
 | 
					            if ( x != undefined && y != undefined) {
 | 
				
			||||||
 | 
					                lasers[id] = {x:x, y:y};
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                delete lasers[id];
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (var laserIndex in lasers) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var laser = lasers[laserIndex];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (drawAudienceLaser === true || laserIndex === 'speaker') {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                contextPaint.fillStyle = laserIndex === 'speaker' ? 'red' : 'green';
 | 
				
			||||||
 | 
					                contextPaint.beginPath();
 | 
				
			||||||
 | 
					                contextPaint.arc(laser.x * canvasPdf.width, laser.y * canvasPdf.height, 10, 0, Math.PI*2, true);
 | 
				
			||||||
 | 
					                contextPaint.closePath();
 | 
				
			||||||
 | 
					                contextPaint.fill();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $(window).resize(update);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sio.onMouseDown = function() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var x = (event.x - canvasPdfBounding.left) / canvasPdf.width;
 | 
				
			||||||
 | 
					        var y = (event.y - canvasPdfBounding.top) / canvasPdf.height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        socket.emit('pointer', filename, socket.id, x, y);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        pointer = true;
 | 
				
			||||||
 | 
					        shouldUpdatePointer = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        canvasPointer(socket.id, x, y);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sio.onMouseMove = function(event) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (pointer) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var x = (event.x - canvasPdfBounding.left) / canvasPdf.width;
 | 
				
			||||||
 | 
					            var y = (event.y - canvasPdfBounding.top) / canvasPdf.height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (shouldUpdatePointer) {
 | 
				
			||||||
 | 
					                // Update
 | 
				
			||||||
 | 
					                socket.emit('pointer', filename, socket.id, x, y);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                shouldUpdatePointer = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                setTimeout(function() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    shouldUpdatePointer = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                }, 20);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            canvasPointer(socket.id, x, y);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sio.onMouseUp = function(event) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        socket.emit('pointer', filename, socket.id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        pointer = false;
 | 
				
			||||||
 | 
					        shouldUpdatePointer = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        canvasPointer(socket.id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return sio;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					})(); });
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								static/uploaded/last_slides.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								static/uploaded/last_slides.pdf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								static/uploaded/main.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								static/uploaded/main.pdf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										14
									
								
								views/base.pug
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								views/base.pug
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					doctype
 | 
				
			||||||
 | 
					html( lang="en" )
 | 
				
			||||||
 | 
					    head
 | 
				
			||||||
 | 
					        title slideshow.io
 | 
				
			||||||
 | 
					        meta( charset='utf-8' )
 | 
				
			||||||
 | 
					        meta( http-equiv='X-UA-Compatible', content='IE=edge' )
 | 
				
			||||||
 | 
					        block css
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    body
 | 
				
			||||||
 | 
					        block base_content
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        script( src='http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js' )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        block js
 | 
				
			||||||
							
								
								
									
										28
									
								
								views/main.pug
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								views/main.pug
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					extends ./base.pug
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					block css
 | 
				
			||||||
 | 
					    meta( name='viewport', content='width=device-width, initial-scale=1.0' )
 | 
				
			||||||
 | 
					    meta( name='description', content='Baking Bootstrap Snippets with Jade' )
 | 
				
			||||||
 | 
					    //- Bootswatch Theme
 | 
				
			||||||
 | 
					    link(href="https://bootswatch.com/cerulean/bootstrap.min.css", rel="stylesheet")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					block base_content
 | 
				
			||||||
 | 
					    nav.navbar.navbar-default( role="navigation" )
 | 
				
			||||||
 | 
					        .container
 | 
				
			||||||
 | 
					            .navbar-header
 | 
				
			||||||
 | 
					                button.navbar-toggle.collapsed( type="button", data-toggle="collapse", data-target="#navbar-inverse", aria-expanded="false", aria-controls="navbar")
 | 
				
			||||||
 | 
					                    span.sr-only Toggle navigation
 | 
				
			||||||
 | 
					                    span.icon-bar
 | 
				
			||||||
 | 
					                    span.icon-bar
 | 
				
			||||||
 | 
					                    span.icon-bar
 | 
				
			||||||
 | 
					                a.navbar-brand(href="#") slideshow.io
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            #navbar-inverse.collapse.navbar-collapse
 | 
				
			||||||
 | 
					                ul.nav.navbar-nav
 | 
				
			||||||
 | 
					                    li: a( href="#about" ) About
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .container
 | 
				
			||||||
 | 
					        block content
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					block prepend js
 | 
				
			||||||
 | 
					    script( src='http://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js' )
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user