Skip to content

Commit

Permalink
implemented editng for decks and slides
Browse files Browse the repository at this point in the history
  • Loading branch information
zeroasterisk committed Apr 24, 2013
1 parent ddff581 commit d4a7700
Show file tree
Hide file tree
Showing 16 changed files with 430 additions and 12 deletions.
2 changes: 1 addition & 1 deletion .meteor/packages
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ accounts-meetup
bootstrap
router
chartjs
bootstrap-wysiwyg
tour
d3
accounts-ui-bootstrap-dropdown
moment
validation
x-editable-bootstrap
bootstrap-growl
13 changes: 13 additions & 0 deletions DeveloperNotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ MeteorJS will work with the files in any organizational method... but it helps t
$ touch server/publish.js
$ touch client/subscribe.js
$ touch client/app.js
$ touch client/index.html
$ touch client/index.js
$ touch client/lib/router.js
$ touch client/views/home.html
$ touch client/views/home.js
Expand All @@ -98,4 +100,15 @@ MeteorJS will work with the files in any organizational method... but it helps t
$ touch client/views/_poll.js


Start Developing
----------------

client/index.html

Setup the basic page layout, content to be supplied by other templates, coordinated via the router.

Note the seperate templates for header and footer aren't needed, but are nice to segment code.

Note the special `{{loginButtons}}` code? That's our Automatic login functionality for Accounts.


45 changes: 45 additions & 0 deletions client/lib/notify.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
(function() {


// Notifications based on $.bootstrapGrowl()
// mrt add bootstrap-growl
//

Notify = {
options: {
ele: 'body', // which element to append to
type: 'info', // (null, 'info', 'error', 'success')
offset: {from: 'top', amount: 20}, // 'top', or 'bottom'
align: 'right', // ('left', 'right', or 'center')
width: 250, // (integer, or 'auto')
delay: 4000,
allow_dismiss: true,
stackup_spacing: 10 // spacing between consecutively stacked growls.
},
optionize: function(options) {
if (_.isObject(options)) {
return _.extend(this.options, options);
}
return this.options;
},
alert: function(message, options) {
$.bootstrapGrowl(message, _.extend(this.optionize(options), {type: 'alert'}));
},
info: function(message, options) {
$.bootstrapGrowl(message, _.extend(this.optionize(options), {type: 'info'}));
},
error: function(message, options) {
$.bootstrapGrowl(message, _.extend(this.optionize(options), {type: 'error'}));
},
success: function(message, options) {
$.bootstrapGrowl(message, _.extend(this.optionize(options), {type: 'success'}));
},
// clear all existing notificiations
clear: function() {
$('.bootstrap-growl').remove();
}
}


}());

13 changes: 7 additions & 6 deletions client/lib/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
// no slide provided, default to first
var firstSlide = Slides.find({deckId: deckId}, {sort: { order: 1 } }).fetch()[0];
if (!_.isObject(firstSlide)) {
throw new Meteor.Error(500, 'Deck has no slides');
Notify.alert('Deck has no slides');
return 'decks';
}
slideId = firstSlide._id;
Expand All @@ -24,7 +24,7 @@
}
var deck = Decks.findOne({ _id: deckId});
if (! (_.isObject(deck) && deck.owner == Meteor.userId())) {
throw new Meteor.Error(500, 'Access denied, you are not the owner');
Notify.alert('Access denied, you are not the owner');
return 'decks';
}
Session.set('deckId', deckId);
Expand All @@ -37,7 +37,7 @@
}
var deck = Decks.findOne({ _id: deckId});
if (! (_.isObject(deck) && deck.owner == Meteor.userId())) {
throw new Meteor.Error(500, 'Access denied, you are not the owner');
Notify.alert('Access denied, you are not the owner');
return 'decks';
}
Meteor.call('deckOpen', deckId);
Expand All @@ -51,7 +51,7 @@
}
var deck = Decks.findOne({ _id: deckId});
if (! (_.isObject(deck) && deck.owner == Meteor.userId())) {
throw new Meteor.Error(500, 'Access denied, you are not the owner');
Notify.alert('Access denied, you are not the owner');
return 'decks';
}
Meteor.call('deckClose', deckId);
Expand Down Expand Up @@ -105,7 +105,7 @@

});

Meteor.Router.filter('requireDecks', {only: ['decks', 'deck']});
Meteor.Router.filter('requireDecks', {only: ['decks', 'deck', 'deckEdit']});

Meteor.startup(function() {
Meteor.autorun(function() {
Expand Down Expand Up @@ -133,7 +133,8 @@
trackEvent(e.event, e.properties);
});
} else {
console.log('------ Loading… --------');
Notify.clear();
console.log('------ Loaded --------');
}
});
});
Expand Down
6 changes: 6 additions & 0 deletions client/views/_slideThumb.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<template name="_slideThumb">

{{_id}}
{{title}}

</template>
60 changes: 60 additions & 0 deletions client/views/deckEdit.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<template name="deckEdit">
<ul class="breadcrumb">
<li><a href="/"><i class="icon-home"></i> Home</a> <span class="divider">/</span></li>
<li><a href="/decksMine"><i class="icon-user"></i> My Decks</a> <span class="divider">/</span></li>
<li class="active"><i class="icon-book"></i> Deck</li>
</ul>
<h1>{{deck.title}}</h1>
<p>Editing Deck {{getSession 'deckId'}}</p>

<h4>Slides ({{slidesCount}})</h4>
<ul class="thumbnails">
{{#each slides}}
<li class="thumbnail span4 slide-thumb" style="overflow: hidden;">
<strong href="#" class="slide-eip" data-pk="{{_id}}"
data-type="text" data-inputclass="input-medium"
data-name="title" data-mode="inline" title="Title"
>{{title}}</strong>
<div class="pull-right hide edit-icons">
<a href="#" class="deleteSlide" data-toggle="tooltip" title="delete slide"><i class="icon-remove"></i></a>
<a href="/deckEditSlide/{{deckId}}/{{_id}}" data-toggle="tooltip" title="edit slide content"><i class="icon-edit"></i></a>
<a href="#" class="moveSlideUp" data-toggle="tooltip" title="move up"><i class="icon-arrow-up"></i></a>
<a href="#" class="moveSlideDown" data-toggle="tooltip" title="move up"><i class="icon-arrow-down"></i></a>
</div>
<br>
<span href="#" class="slide-eip muted" data-pk="{{_id}}"
data-type="textarea" data-inputclass="input-medium"
data-name="short" data-mode="inline" title="Short"
>{{short}}</span>
</li>
{{/each}}
</ul>

<p>
<a href="#" class="newSlide btn btn-success"><i class="icon-plus icon-white"></i> Add Slide</a>
</p>

{{#if getSession 'confirmSlideDeletion'}}
{{> confirmSlideDeletion}}
{{/if}}

</template>


<template name="confirmSlideDeletion">
<div class="modal fade confirmSlideDeletion">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h3>Delete Slide</h3>
</div>
<div class="modal-body">
<strong>{{slide.title}}</strong><br>
<p class="muted">{{slide.short}}</p>
</div>
<div class="modal-footer">
<a href="#" class="btn cancel">Cancel</a>
<a href="#" class="btn btn-primary">Delete Slide</a>
</div>
</div>
</template>

94 changes: 94 additions & 0 deletions client/views/deckEdit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
Template.deckEdit.events({
'click .newSlide': function(event) {
Meteor.call('newSlide', Session.get('deckId'));
return false;
},
'click .moveSlideUp': function(event) {
Slides.moveSlide(this._id, 'up');
return false;
},
'click .moveSlideDown': function(event) {
Slides.moveSlide(this._id, 'down');
return false;
},
'click .deleteSlide': function(event) {
Session.set('slideId', this._id);
Session.set('confirmSlideDeletion', true);
return false;
},
});
Template.deckEdit.helpers({
deck: function() {
return Decks.findOne({ _id: Session.get('deckId') });
},
slides: function() {
return Slides.find({ deckId: Session.get('deckId') }, { sort: { order: 1 } });
},
slidesCount: function() {
return Slides.find({ deckId: Session.get('deckId') }).count();
}
});
Template.deckEdit.rendered = function() {
// setup hover-edit-icons
$(document).on('mouseenter.editIcon', '.slide-thumb', function(event) {
$(this).find('.edit-icons').show('fast');
});
$(document).on('mouseleave.editIcon', '.slide-thumb', function(event) {
$(this).find('.edit-icons').hide('fast');
});
// setup which changes as slides re-render/change
Deps.autorun(function() {
var slideCount = Slides.find({ deckId: Session.get('deckId') }).count();
if (slideCount === 0) {
return false;
}
// setup in-place
$('.slide-eip').editable({
url: function(params) {
var d = new $.Deferred;
var slide = {};
slide[params.name] = params.value;
console.log('editable', params, slide, _.isObject(slide));
var updated = Slides.update({ _id: params.pk }, { $set: slide });
console.log('editable-done', updated);
return d.resolve();
}
});
});
};




// ------------------------------------
// confirmSlideDeletion Modal
// ------------------------------------

Template.confirmSlideDeletion.rendered = function() {
var slideId = Session.get('slideId');
if (! (_.isString(slideId) && slideId.length)) {
Session.set('confirmSlideDeletion', false);
Template.confirmSlideDeletion.closer();
}
window.location.hash = 'confirmSlideDeletion';
$('.confirmSlideDeletion').modal('show');
$('.confirmSlideDeletion').on('hidden', function() {
window.location.hash = '';
Session.set('confirmSlideDeletion', false);
});
};
Template.confirmSlideDeletion.closer = function() {
$('.confirmSlideDeletion').modal('hide');
$('.modal-backdrop').hide('fast');
};
Template.confirmSlideDeletion.events({
'click .cancel': function(event) {
Template.confirmSlideDeletion.closer();
event.preventDefault();
return false;
}
});
Template.confirmSlideDeletion.slide = function() {
return Slides.findOne(Session.get('slideId'));
};

48 changes: 48 additions & 0 deletions client/views/deckEditSlide.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<template name="deckEditSlide">
{{#with slide}}
<ul class="breadcrumb">
<li><a href="/"><i class="icon-home"></i> Home</a> <span class="divider">/</span></li>
<li><a href="/decksMine"><i class="icon-user"></i> My Decks</a> <span class="divider">/</span></li>
<li><a href="/deckEdit/{{deckId}}"><i class="icon-book"></i> Deck</a> <span class="divider">/</span></li>
<li class="active"><i class="icon-list-alt"></i> Edit Slide</li>
</ul>
<h1>Edit Slide</h1>

<form id="form-slide-edit" action="?" class="form-horizontal">

<div class="control-group">
<label class="control-label">Title</label>
<div class="controls">
<input name="title" value="{{title}}">
</div>
</div>
<div class="control-group">
<label class="control-label">Short Description</label>
<div class="controls">
<textarea name="short" rows="2" maxlength="512" >{{short}}</textarea>
</div>
</div>
<div class="control-group">
<label class="control-label">
Slide Content<br>
<a href="#" class="editSlideContent"><i class="icon-edit"></i> edit</a>
</label>
<div class="controls">


<!--textarea name="body" rows="10" maxlength="2048" class="wysiwyg">{{body}}</textarea-->
<textarea id="editor" name="body" rows="10">{{body}}</textarea>
</div>
</div>

<div class="form-actions">
<button class="btn btn-primary" type="submit">Save</button>
&nbsp;
<a href="/deckEdit/{{deckId}}">Cancel</a>
</div>
</form>

{{/with}}


</template>
35 changes: 35 additions & 0 deletions client/views/deckEditSlide.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
Template.deckEditSlide.rendered = function() {
/*
$('#editor').editable({
url : function(params) {
$('#body').val(params.value);
}
});
$(document).on('click', '.editSlideContent', function() {
$('#editor').editable('toggle');
});
*/

};
Template.deckEditSlide.events({
'submit form': function(event) {
event.stopPropagation();
Slides.update(Session.get('slideId'), { $set: {
title: $('input[name="title"]').val(),
short: $('textarea[name="short"]').val(),
body: $('textarea[name="body"]').val(),
}}, null, function(err) {
if (_.isString(err) && err.length) {
Notify.alert('Unable to save, ' + err);
return false;
}
Notify.success('Saved');
return true;
});
return false;
}
});
Template.deckEditSlide.slide = function() {
return Slides.findOne(Session.get('slideId'));
}
Loading

0 comments on commit d4a7700

Please sign in to comment.