About Presenteract
Presenteract is a project to facilitate interactive presentations, where the audience can see and interact with slides from their phone/device/laptop.
-Audience
+Audience
Connect to the currently "open" deck, for this presentaiton. Often there is a QR code or a URL provided to make this simpler.
Wait for the Presenter to change slides for you.
Polls should be very simple, just choose an option and submit.
-Presenters
-To present, you must login, via Facebook or via Google. Once logged in, you'll have an option for "My Presentations" and the ability to add new ones.
-New Deck/Presenations will be created without any slides. You must add at least one slide to be able to use it.
-Only "Open" Presenations are available to audience members. You can edit Presenations while open, and audience members should get your changes automatically synced.
-Only the "owner" / "creator" of a Presenation can control/run it.
-Help / Contact
+{{> onDeviceNote}}
+
+Presenters
+ For now, you use a browser to Present, not the app... :(
+
To present, you must login, via Facebook or via Google (link on the right side of the header). Once logged in, you'll have an option for "My Presentations" and the ability to add new ones.
+New Decks/Presenations will be created without any slides. You must add at least one slide to be able to use it.
+
+ Open Presenations are available to audience members. If it's not Open, it's not available.
+ Closed Presenations can easily be opened, as long as they contain slides. Just click on the the word "Closed" to toggle it to "Open".
+
+ Visible Presentations will show up on the homepage while open.
+ Invisible Presentations will not, but can still be accessed via URL/QRcode.
+
+You can edit Presenations & Slides while open, and audience members should get your changes automatically synced.
+Only the "owner" / "creator" of a Presenation can control/run it. Right now, that's only one person, you... we may open this up to allow you to share ownership with others... Let us know if this is important to you...
+
+Help / Contact
Bug Reports and Feature Requests are available. If there is a significant need, we will improve this to a knowledge base.
-Developers, the code is available on GitHub
+Developers, the code is available on GitHub. Pull Requests are appriciated.
+
Built With
-
Wow. At every step of the way I've been impressed by MeteorJS. The framework is exception in the functionality it provides users in the application. It is also very easy to work in and includes tons of tools for developers.
+
Wow. At every step of the way I've been impressed by MeteorJS. The framework is exceptional, every time I work with it, I'm more impressed. It is also very easy to develop in and includes amazing tools right out of the box. I can't recommend it enough.
-
-
PhoneGap is an excellent project, wrapping web applications into mobile device "apps".
+
+
Apache Cordova / PhoneGap is an excellent project, wrapping web applications into mobile device "apps". A browser as an App, with a JavaScript API to native device functionality.
-
This Excellent and Prolific CSS framework makes createing attractive, standardized, responsive, and very functional web applications easy.
+
This Excellent and Prolific CSS framework makes creating attractive, standardized, responsive, and very functional web applications easy.
-
Who doesn't use jQuery? In fact, we don't use it a ton, because MeteorJS does most of the lifting, but we still use jQuery to work with the DOM a bit.
+
Who doesn't use jQuery? In fact, we don't use it a ton, because MeteorJS does most of the heavy lifting (and much of the light work too), but we still use jQuery to work with the DOM a bit.
@@ -48,4 +60,21 @@
For the admin interface, we have a "Click to Edit" or "Edit in Place" interface provided by X-Editable. It rocks!
+
+Device Information
+Ignore the following information... I doubt you'll ever need it.
+
+ - deviceBase
+ - {{getSession 'deviceBase'}}
+ - cordovaLoaded
+ - {{getSession 'cordovaLoaded'}}
+ - cordovaStatus
+ - {{getSession 'cordovaStatus'}}
+ - DecksLoaded
+ - {{getSession 'DecksLoaded'}}
+ - SlidesLoaded
+ - {{getSession 'SlidesLoaded'}} (only loaded when deck selected)
+ - PollsLoaded
+ - {{getSession 'PollsLoaded'}} (only loaded when slide selected)
+
diff --git a/client/views/deckView.js b/client/views/deckView.js
index 6880052..e434f27 100644
--- a/client/views/deckView.js
+++ b/client/views/deckView.js
@@ -27,7 +27,7 @@ Template.deckView.helpers({
return Slides.find({deckId: Session.get('deckId')}).count();
},
'slides': function() {
- return Slides.find({deckId: Session.get('deckId')}, { sort: { order: 1 } }).fetch();
+ return Slides.forDeck(Session.get('deckId'));
},
'slide': function() {
var deck = Decks.findOne(Session.get('deckId'));
@@ -37,61 +37,28 @@ Template.deckView.helpers({
return Slides.findOne(deck.slideId);
},
'currentSlideInt': function() {
- var deck = Decks.findOne(Session.get('deckId'));
- if (! (_.isString(deck.slideId) && deck.slideId.length)) {
- return 1;
- }
- var slides = Slides.find(
- {deckId: Session.get('deckId')},
- { sort: { order: 1 }, fields: { _id: 1 }}
- ).fetch();
- for (var i = 0; i < slides.length; i++) {
- if (slides[i]._id == deck.slideId) {
- return i + 1;
- }
- }
- return 1;
+ return Decks.slideIndex(Session.get('deckId'));
}
});
+
+
// implemented as directly callable methods on the template
// useful for self-referencing
Template.deckView.prevSlideId = function() {
- var deck = Decks.findOne(Session.get('deckId'));
- if (! (_.isObject(deck) && _.has(deck, 'slideId') && _.isString(deck.slideId) && deck.slideId.length)) {
+ var currentIndex = Decks.slideIndex(Session.get('deckId'));
+ if (currentIndex < 2) {
return '';
}
- var slides = Slides.find(
- {deckId: Session.get('deckId')},
- { sort: { order: 1 }, fields: { _id: 1 }}
- ).fetch();
- for (var i = 0; i < slides.length; i++) {
- if (slides[i]._id == deck.slideId) {
- if (i < 1) {
- return '';
- }
- return slides[(i - 1)]._id;
- }
- }
- return '';
+ var slides = Slides.forDeck(Session.get('deckId'));
+ return slides[(currentIndex - 2)]._id;
};
Template.deckView.nextSlideId = function() {
- var deck = Decks.findOne(Session.get('deckId'));
- if (! (_.isObject(deck) && _.has(deck, 'slideId') && _.isString(deck.slideId) && deck.slideId.length)) {
+ var currentIndex = Decks.slideIndex(Session.get('deckId'));
+ var slides = Slides.forDeck(Session.get('deckId'));
+ if (currentIndex >= slides.length) {
return '';
}
- var slides = Slides.find(
- {deckId: Session.get('deckId')},
- { sort: { order: 1 }, fields: { _id: 1 }}
- ).fetch();
- for (var i = 0; i < slides.length; i++) {
- if (slides[i]._id == deck.slideId) {
- if ((i + 1) == slides.length) {
- return '';
- }
- return slides[(i + 1)]._id;
- }
- }
- return '';
+ return slides[currentIndex]._id;
};
Template.deckView.isOwner = function() {
var deck = Decks.findOne(Session.get('deckId'));
@@ -99,6 +66,7 @@ Template.deckView.isOwner = function() {
};
// stand alone callable version of setSlide event
// can be triggered via keyboard nav
+// only works if .setSlideNext is visible & has data('id')
Template.deckView.setSlideNext = function() {
if (!$(".setSlideNext").is(":visible")) {
return false;
@@ -111,6 +79,7 @@ Template.deckView.setSlideNext = function() {
}
// stand alone callable version of setSlide event
// can be triggered via keyboard nav
+// only works if .setSlidePrev is visible & has data('id')
Template.deckView.setSlidePrev = function() {
if (!$(".setSlidePrev").is(":visible")) {
return false;
diff --git a/client/views/home.html b/client/views/home.html
index 3eaac8c..aaef5de 100644
--- a/client/views/home.html
+++ b/client/views/home.html
@@ -23,9 +23,56 @@