diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..196b097
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+*.sw?
+.sass-cache
+build/
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..88f0ff7
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,14 @@
+build :
+ mkdir -p build/css
+ cp src/www/*.* build
+ cp -r src/www/js build
+# cp -r resources/* build/.
+ sass src/www/css/nursery-schedule.scss build/css/nursery-schedule.css
+ sass src/www/css/schedule-maker.scss build/css/schedule-maker.css
+
+clean :
+ -rm -r build
+
+local-deploy: build
+ cp -r build ~/temp/server
+ ssh jdb-server 'rm -r ~/public_html/nursery-schedule; mv temp/build ~/public_html/nursery-schedule'
diff --git a/index.html b/index.html
deleted file mode 100644
index 346e7ae..0000000
--- a/index.html
+++ /dev/null
@@ -1,177 +0,0 @@
-
-
-
-
-
-
-
-
-
First Sunday, Oct. 6th
-
-
- Toddlers
- - Sara Bernard
- - Priscilla Reid
- - Becca Torres
-
-
- Infants
- - Latonya Kirton
- - Susan Vacca
- - Brandie Kristoff
-
-
-
-
- Evening Service
- - Susan Miller
- - TBD
-
-
-
-
-
-
Second Sunday, Oct. 13th
-
-
- Toddlers
- - Sara Bernard
- - Priscilla Reid
- - Rebecca Dombroski
-
-
- Infants
- - Latonya Kirton
- - Susan Vacca
- - Mila Hill
-
-
-
-
- Evening Service
- - Zoe Torres
- - Hannah Torres
-
-
-
-
-
-
Third Sunday, Oct. 20th
-
-
- Toddlers
- - Sara Bernard
- - Priscilla Reid
- - Della Borrego
-
-
- Infants
- - Latonya Kirton
- - Susan Vacca
- - Deborah McDonald
-
-
-
-
- Evening Service
- - TBD
- - Alayna Robert
-
-
-
-
-
-
Fourth Sunday, Oct. 27th
-
-
- Toddlers
- - Sara Bernard
- - Priscilla Reid
- - TBD
-
-
- Infants
- - Latonya Kirton
- - Susan Vacca
- - Crystal Johnson
-
-
-
-
- Evening Service
- - Deidra Dawson
-
-
- Shekinah Dawson
-
-
-
-
-
-
Fifth Sunday
-
-
- Toddlers
- - Sara Bernard
- - Priscilla Reid
- - Julie Froese
-
-
- Infants
- - Latonya Kirton
- - Susan Vacca
- - TBD
-
-
-
-
- Evening Service
- - TBD
-
-
- TBD
-
-
-
-
-
-
-
-
First Wednesday, Oct. 2nd
-
- - Courtney or Bryan Bootka
- - Gabby Galvez
-
-
-
-
-
Second Wednesday, Oct. 9th
-
- - Reeta or Lionel Aguilar
- - Stephanie Langley
-
-
-
-
-
Third Wednesday, Oct. 16th
-
- - Christina Grooms
- - Lanell Hanson
-
-
-
-
-
Fourth Wednesday, Oct. 23rd
-
- - Cassie Hernandez
- - Regena Dumas
-
-
-
-
-
Fifth Wednesday, Oct. 30th
-
-
-
-
-
-
diff --git a/nursery-schedule.scss b/src/www/css/nursery-schedule.scss
similarity index 57%
rename from nursery-schedule.scss
rename to src/www/css/nursery-schedule.scss
index d6c5093..f5674bf 100644
--- a/nursery-schedule.scss
+++ b/src/www/css/nursery-schedule.scss
@@ -3,6 +3,10 @@
* @author Jonathan Bernard
*/
+// Fonts
+@import url(http://fonts.googleapis.com/css?family=Abel|Lato|Josefin+Sans:400,600|Titillium+Web:400,300,600|Open+Sans|Raleway:400,600,500|Nunito:300,400|Oxygen:400,700);
+
+
/// Global Rules
* {
-moz-box-sizing: border-box;
@@ -11,18 +15,34 @@
margin: 0;
padding: 0; }
+/* HTML5 elements */
+article,aside,details,figcaption,figure,
+footer,header,hgroup,menu,nav,section {
+ display:block; }
+
html { font-size: 90%; }
+body {
+ font-family: "Abel";
+ line-height: 1.1em; }
+
+h5 {
+ font-size: small;
+ font-weight: normal;
+ text-decoration: underline; }
+
+body.alt {
+ font-family: "Nunito";
+ font-weight: 300;
+
+ h3 { font-weight: 400; }
+ h5 { font-weight: 300; } }
+
/*html {
background-color: $bgColor;
color: $fgColor;
font-size: 150%; }*/
-/* HTML5 elements */
-article,aside,details,figcaption,figure,
-footer,header,hgroup,menu,nav,section {
- display:block; }
-
.sundays, .wednesdays { }
.first, .second, .third, .fourth, .fifth {
@@ -31,16 +51,15 @@ footer,header,hgroup,menu,nav,section {
vertical-align: top;
width: 20em; }
-.date {
- float: right;
- margin-right: 5rem; }
+.date { }
ul { list-style: none; }
-.am ul {
+.toddlers, .infants {
display: inline-block;
+ vertical-align: top;
width: 9rem; }
-div.am, div.pm {
+div.am, div.pm, .wednesdays ul {
margin-top: 0.5rem; }
diff --git a/src/www/css/schedule-maker.scss b/src/www/css/schedule-maker.scss
new file mode 100644
index 0000000..186f854
--- /dev/null
+++ b/src/www/css/schedule-maker.scss
@@ -0,0 +1,108 @@
+/**
+ * Nursery Schedule Maker
+ * @author Jonathan Bernard
+ */
+
+/// Global Rules
+* {
+ -moz-box-sizing: border-box;
+ -webkit-box-sizing: border-box;
+ box-sizing: border-box;
+ margin: 0;
+ padding: 0; }
+
+/* HTML5 elements */
+article,aside,details,figcaption,figure,
+footer,header,hgroup,menu,nav,section {
+ display:block; }
+
+body {
+ line-height: normal;
+ margin: 2rem; }
+
+.header { position: relative; }
+
+.load-dialog {
+ background: rgba(0, 0, 0, 0.5);
+ bottom: 0;
+ display: none;
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ z-index: 10;
+
+ div {
+ text-align: center;
+ margin-top: 4rem;
+
+ span {
+ background: whitesmoke;
+ border-radius: 3px;
+ padding: 1em;
+
+ #fileLoad { width: 30rem; } } } }
+
+.tools {
+
+ position: absolute;
+ top: 0;
+ right: 0;
+
+ input[type="date"] {
+ border: solid thin gray;
+ border-radius: 3px; }
+
+ ul {
+ list-style: none;
+
+ li {
+ padding-right: 0.5rem;
+ display: inline-block; } }
+
+ .publish { text-decoration: line-through; } }
+
+.sundays { border-right: solid thin lightgray; }
+.wednesdays { padding-left: 2rem; }
+
+.sundays, .wednesdays {
+ display: inline-block;
+ line-height: 1.1rem;
+ margin-top: 2rem;
+ vertical-align: top;
+ width: 49%;
+
+ .teacher-needed {
+ color: #A00;
+ font-style: italic; }
+
+ li {
+ position: relative;
+
+ input.name {
+ display: none;
+ width: 8rem; }
+
+ .clone, .remove {
+ cursor: pointer;
+ display: none;
+ padding: 0 0.5em;
+ position: absolute; }
+
+ &:hover {
+ .clone, .remove { display: inline-block; } }
+
+ &.editing {
+ input.name { display: inline-block; }
+ span.name { display: none; } }
+
+ &.editing:hover {
+ .clone, .remove { display: none; } } } }
+
+.sundays {
+ .remove { left: 7.5rem; }
+ .clone { left: 6.5rem; } }
+
+.wednesdays {
+ .remove { left: 11.5rem; }
+ .clone { left: 10.5rem; } }
diff --git a/src/www/index.html b/src/www/index.html
new file mode 100644
index 0000000..b6392e4
--- /dev/null
+++ b/src/www/index.html
@@ -0,0 +1,197 @@
+
+
+
+
+
+
+
+
+
First Sunday, Oct. 6th
+
+
+
Toddlers
+
+ - Sara Bernard
+ - Priscilla Reid
+ - Becca Torres
+
+
+
+
Infants
+
+ - Latonya Kirton
+ - Susan Vacca
+ - Brandie Kristoff
+
+
+
+
+
+
+
+
Second Sunday, Oct. 13th
+
+
+
Toddlers
+
+ - Sara Bernard
+ - Priscilla Reid
+ - Rebecca Dombroski
+
+
+
+
Infants
+
+ - Latonya Kirton
+ - Susan Vacca
+ - Mila Hill
+
+
+
+
+
Evening Service
+
+ - Zoe Torres
+ - Hannah Torres
+
+
+
+
+
+
Third Sunday, Oct. 20th
+
+
+
Toddlers
+
+ - Sara Bernard
+ - Priscilla Reid
+ - Della Borrego
+
+
+
+
Infants
+
+ - Latonya Kirton
+ - Susan Vacca
+ - Deborah McDonald
+
+
+
+
+
+
+
+
Fourth Sunday, Oct. 27th
+
+
+
Toddlers
+
+ - Sara Bernard
+ - Priscilla Reid
+ - TBD
+
+
+
+
Infants
+
+ - Latonya Kirton
+ - Susan Vacca
+ - Crystal Johnson
+
+
+
+
+
Evening Service
+
+ - Deidra Dawson
+ - Shekinah Dawson
+
+
+
+
+
+
Fifth Sunday
+
+
+
Toddlers
+
+ - Sara Bernard
+ - Priscilla Reid
+ - Julie Froese
+
+
+
+
Infants
+
+ - Latonya Kirton
+ - Susan Vacca
+ - TBD
+
+
+
+
+
+
+
+
+
+
First Wednesday, Oct. 2nd
+
+ - Courtney or Bryan Bootka
+ - Gabby Galvez
+
+
+
+
+
Second Wednesday, Oct. 9th
+
+ - Reeta or Lionel Aguilar
+ - Stephanie Langley
+
+
+
+
+
Third Wednesday, Oct. 16th
+
+ - Christina Grooms
+ - Lanell Hanson
+
+
+
+
+
Fourth Wednesday, Oct. 23rd
+
+ - Cassie Hernandez
+ - Regena Dumas
+
+
+
+
+
Fifth Wednesday, Oct. 30th
+
+
+
+
+
+
diff --git a/src/www/js/schedule-maker.js b/src/www/js/schedule-maker.js
new file mode 100644
index 0000000..fd70015
--- /dev/null
+++ b/src/www/js/schedule-maker.js
@@ -0,0 +1,254 @@
+(function() {
+ var root = this;
+
+ var SM = root.ScheduleMaker = {};
+
+ SM.minSunAmTeachers = 3;
+ SM.minSunPmTeachers = 2;
+ SM.minWedTeachers = 2;
+
+ SM.views = [];
+
+ SM.ServiceView = function(element) {
+
+ // #### Set properties
+ this.el = element;
+ this.$el = $(element);
+ var thisView = this;
+
+ this.$el.attr('viewId', SM.views.length)
+ SM.views.push(thisView);
+
+ // #### Set methods
+ this.findTeacherMinimum = function($ulEl) {
+ if ($ulEl.parents('.am').length > 0) {
+ return SM.minSunAmTeachers; }
+ else if ($ulEl.parents('.pm').length > 0) {
+ return SM.minSunPmTeachers; }
+ else return SM.minWedTeachers; };
+
+ this.volunteersAdded = function(event) {
+ // event.target should refer to the ul receiving the item.
+ var $ulEl = $(event.target);
+
+ if ($ulEl.find('li.teacher-needed').length > 0) {
+ $ulEl.find('li.teacher-needed').first().remove();
+ $ulEl.sortable("refresh"); } };
+
+ this.updatePlaceholders = function(event) {
+ // event.target should refer to the ul receiving the item.
+ var $ulEl = $(event.target);
+
+ while ($ulEl.find('li').length <
+ this.findTeacherMinimum($ulEl)) {
+ var $li = $(document.createElement('li'));
+ $li.addClass('teacher-needed');
+ $li.text('teacher needed');
+ $li.on('dblclick', this.editPlaceholder);
+ $ulEl.append($li[0]);
+ $ulEl.sortable("refresh"); } };
+
+ this.deleteName = function (event) {
+ // event.target is the ul > li > span element containing the 'X'
+ var ulEl = $(event.target).closest('ul')[0];
+ $(event.target).closest('li').remove();
+ this.updatePlaceholders({target: ulEl})};
+
+ this.copyName = function (event) {
+ // event.target is the ul > li > span element containing the 'C'
+ var $liEl = $(event.target).closest('li');
+ var $ulEl = $liEl.closest('ul');
+ $ulEl.append($liEl.clone(true));
+ this.volunteersAdded({target: $ulEl[0]}); };
+
+ this.editName = function(event) {
+ // event.target is the li > span.name element that was clicked.
+ var $spanEl = $(event.target);
+ var $liEl = $spanEl.parent();
+ $liEl.find('input.name').val($spanEl.text());
+ $liEl.addClass('editing');
+ $liEl.find('input.name').focus(); };
+
+ this.saveName = function(event) {
+ // event.target is the li > input.name element that was blurred.
+ var $inputEl = $(event.target);
+ var $liEl = $inputEl.parent();
+ $liEl.find('span.name').text($inputEl.val());
+ $liEl.removeClass('editing'); };
+
+ this.editPlaceholder = function(event) {
+ var liEl = this.newName(event);
+ this.editName({target: $(liEl).find('span.name')[0]}); };
+
+ this.newName = function(event) {
+ var $ulEl = $(event.target).closest('ul');
+ var $liEl = $(document.createElement('li'));
+ $liEl.append('' +
+ 'CX');
+ $liEl.find('span.name').on('dblclick', this.editName);
+ $liEl.find('input.name').on('blur', this.saveName);
+ $liEl.find('.remove').on('click', this.deleteName);
+ $liEl.find('.clone').on('click', this.copyName);
+
+ $ulEl.append($liEl[0]);
+
+ this.volunteersAdded({target: $ulEl[0]});
+ $ulEl.sortable("refresh");
+ return $liEl[0]; };
+
+ var funs = ['newName', 'saveName', 'editName', 'deleteName',
+ 'copyName', 'editPlaceholder', 'volunteersAdded',
+ 'updatePlaceholders'];
+ funs.forEach(function(funName) {
+ thisView[funName] = thisView[funName].bind(thisView); });
+
+ // #### Initialize the existing view objects.
+ var $volunteerLists = this.$el.find('ul');
+ $volunteerLists.sortable({
+ connectWith: 'ul',
+ cancel: 'li.teacher-needed' });
+
+ // updatePlaceholders adds place-holders if there are not enough
+ // teachers. We call this once during initialization to pad out the
+ // lists to the minimums
+ $volunteerLists.each(function(idx) {
+ thisView.updatePlaceholders({target: this}); });
+
+ // #### Event handlers
+
+ // Handlers to refresh the missing teacher spots when someone is
+ // drag-and-dropped.
+ $volunteerLists.on("sortreceive", this.volunteersAdded);
+ $volunteerLists.on("sortremove", this.updatePlaceholders);
+
+ // Handler to remove names when the 'X' is clicked.
+ this.$el.find('.remove').on('click', this.deleteName);
+
+ // Handler to edit names when they are double-clicked.
+ this.$el.find('span.name').on('dblclick', this.editName);
+
+ // Handler to save the editing changes back to the li
+ this.$el.find('input.name').on('blur', this.saveName);
+ };
+
+ SM.saveSchedule = function() {
+
+ // Create the JSON object to serialize to the file.
+ var data = {};
+
+ // Save the date.
+ data.date = $('input[type=date]').val();
+
+ // Gather the sunday data
+ data.sundays = {};
+ $('.sundays > div').each(function() {
+ var divEl = this;
+ var $divEl = $(this);
+
+ data.sundays[divEl.className] = {};
+
+ // Save each of the service data.
+ $divEl.find('ul').each(function() {
+ var ulEl = this;
+ var $ulEl = $(this);
+
+ var roomName = 'pm';
+ if ($ulEl.parents('.toddlers').length > 0) roomName = 'toddlers';
+ else if ($ulEl.parents('.infants').length > 0) roomName = 'infants';
+
+ data.sundays[divEl.className][roomName] =
+ $ulEl.find('span.name').map(function() {
+ return $(this).text(); }).get();
+ });
+ });
+
+ // Gather Wednesday data
+ data.wednesdays = {};
+ $('.wednesdays > div').each(function() {
+ var divEl = this;
+ var $divEl = $(this);
+
+ // Save the service data.
+ data.wednesdays[divEl.className] = $divEl.find('span.name').map(
+ function() { return $(this).text(); }).get(); });
+
+ var jsonData = JSON.stringify(data);
+ var jsonBlob = new Blob([jsonData], {type: 'text/plain'});
+
+ // Save the file to disk by presenting it as a download to the user.
+ var linkEl = document.createElement('a');
+ var $linkEl = $(linkEl);
+ linkEl.download = "nursery-schedule-" + $('input[type=date]').val();
+ linkEl.innerHTML = "Download Schedule Data"
+
+ if (window.webkitURL != null) {
+ linkEl.href = window.webkitURL.createObjectURL(jsonBlob); }
+ else {
+ linkEl.href = window.URL.createObjectURL(jsonBlob);
+ $(linkEl).on("click", function (e) { $(e.target).remove(); });
+ $(linkEl).css('display', 'none');
+ $('body').append(linkEl); }
+ linkEl.click(); };
+
+ SM.hideLoadDialog = function(e) {
+ if (e.target == $('#fileLoad')[0]) return;
+ $('.load-dialog').fadeOut(); };
+
+ SM.showLoadDialog = function() { $('.load-dialog').fadeIn(); };
+
+ SM.loadSchedule = function() {
+ // Remove exsting data.
+ $('.sundays ul li, .wednesdays ul li').remove()
+
+ var fileName = $('#fileLoad')[0].files[0];
+ var fileReader = new FileReader();
+
+ fileReader.onload = function(e) {
+ var fileText = e.target.result;
+ var data = JSON.parse(fileText);
+
+ // Restore the date.
+ $('input[type=date]').val(data.date);
+
+ // Restore Sunday services
+ for(var day in data.sundays) {
+ for(var roomName in data.sundays[day]) {
+ var $divEl = $('.sundays .' + day);
+ var $ulEl = $divEl.find('.' + roomName + ' ul');
+ var view = SM.views[parseInt($divEl.attr('viewId'))];
+ data.sundays[day][roomName].forEach(function(personName) {
+ var liEl = view.newName({target: $ulEl[0]});
+ $(liEl).find('span.name').text(personName); });
+ view.updatePlaceholders({target: $ulEl[0]}); } }
+
+ // Restore Wednesday services
+ for(var day in data.wednesdays) {
+ var $divEl = $('.wednesdays .' + day);
+ var $ulEl = $divEl.find('ul');
+ var view = SM.views[parseInt($divEl.attr('viewId'))];
+ data.wednesdays[day].forEach(function(personName) {
+ var liEl = view.newName({target: $ulEl[0]});
+ $(liEl).find('span.name').text(personName); });
+ view.updatePlaceholders({target: $ulEl[0]}); } }
+
+ fileReader.readAsText(fileName, "UTF-8");
+ };
+
+ SM.publicShedule = function() {
+ // TODO
+ };
+
+ SM.init = function() {
+ // Create our ServiceViews
+ $('.sundays > div, .wednesdays > div').each(function(idx, elem) {
+ var view = new SM.ServiceView(elem); });
+
+ // Wire up our toolbar
+ $('.save').on('click', SM.saveSchedule);
+ $('.load').on('click', SM.showLoadDialog);
+ $('.publish').on('click', SM.publishSchedule);
+ $('.load-dialog').on('click', SM.hideLoadDialog);
+ $('.load-dialog a').on('click', SM.loadSchedule);
+ };
+
+}).call(this);
diff --git a/src/www/schedule-maker.html b/src/www/schedule-maker.html
new file mode 100644
index 0000000..e8f3d7b
--- /dev/null
+++ b/src/www/schedule-maker.html
@@ -0,0 +1,182 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+