From 3768393a07efe64098983c10dc134b0da83b6539 Mon Sep 17 00:00:00 2001 From: Stephan Vock Date: Thu, 13 Mar 2014 22:23:40 +0100 Subject: [PATCH 1/5] lets try to detect changes in the schedule #first attempt --- config.json | 1 + css/main.css | 11 ++++- index.html | 1 + js/plugin_factory.js | 2 + js/plugins/change-notify.js | 93 +++++++++++++++++++++++++++++++++++++ js/plugins/current-day.js | 2 - js/plugins/local-storage.js | 1 - 7 files changed, 107 insertions(+), 4 deletions(-) create mode 100644 js/plugins/change-notify.js diff --git a/config.json b/config.json index 6f096a2..1cdcd62 100644 --- a/config.json +++ b/config.json @@ -6,6 +6,7 @@ "url": "data/schedule.json" }, "plugins": [ + "change-notify", "current-day", "refresh", "star", diff --git a/css/main.css b/css/main.css index aea5f2d..b3a4001 100644 --- a/css/main.css +++ b/css/main.css @@ -114,4 +114,13 @@ h3 { .talk.starred .star-button { background-color: #ff69b4; -} \ No newline at end of file +} + +.change-notify { + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 50px; + background-color: greenyellow; +} diff --git a/index.html b/index.html index 7c02b34..0268852 100644 --- a/index.html +++ b/index.html @@ -29,6 +29,7 @@

+ diff --git a/js/plugin_factory.js b/js/plugin_factory.js index f8f5dbe..ac9d94d 100644 --- a/js/plugin_factory.js +++ b/js/plugin_factory.js @@ -13,6 +13,8 @@ PluginFactory.prototype.getPlugin = function(plugin_name) { return new Refresh(this.emitter, this.view_helper); case 'local-storage': return new LocalStorage(this.emitter); + case 'change-notify': + return new ChangeNotify(this.emitter, this.view_helper); default: throw new Error('Plugin does not exist with name: ' + plugin_name); } diff --git a/js/plugins/change-notify.js b/js/plugins/change-notify.js new file mode 100644 index 0000000..7832bd8 --- /dev/null +++ b/js/plugins/change-notify.js @@ -0,0 +1,93 @@ +function ChangeNotify(emitter, view_helper) { + this.emitter = emitter; + this.view_helper = view_helper; +} + +ChangeNotify.prototype.registerPlugin = function() { + var self = this; + // set up some sort of layer + var element = document.createElement('div'); + element.setAttribute('class', 'change-notify'); + document.getElementsByTagName('body')[0].appendChild(element); + + var current = null; + this.emitter.bind('schedule-data-ready', function(conference_data) { + if (null === current || conference_data === current) { + current = conference_data; + return; // fetching data from local storage or no local storage + } + + // compare talks -> Note: this might get really tricky + var currentData = JSON.parse(current), + newData = JSON.parse(conference_data); + + diff(currentData, newData, ["talk", "talks", "slot", "day", "schedule"]); + + // decide on output format + element.innerHTML = "different"; + current = conference_data; + }); +}; + +var propertyLength = 0, + propertyDiff = 1; + +function objectKeys(obj) { + if (typeof Object.keys === 'function') { + return Object.keys(obj); + } + + var keys = []; + for (var key in obj) keys.push(key); + return keys; +} + +function diff(a, b, types) { + types = JSON.parse(JSON.stringify(types)) + try { + var type = types.pop(), + ka = objectKeys(a), + kb = objectKeys(b), + key, i; + } catch (e) {//happens when one is a string literal and the other isn't + return; // this should never happen :) + } + + // having the same number of owned properties (keys incorporates + // hasOwnProperty) + if (ka.length != kb.length) + return notify(a, b, type, propertyLength); + //the same set of keys (although not necessarily the same order), + ka.sort(); + kb.sort(); + + //equivalent values for every corresponding key, and + //~~~possibly expensive deep test + for (i = ka.length - 1; i >= 0; i--) { + key = ka[i]; + if (typeof a[key] === 'object') { + diff(a[key], b[key], types); + } else if (a[key] != b[key]) { + notify(a, b, type, propertyDiff); + } + } +} + + +// somehow +function notify(a, b, type, typeDiff) { + if ('talks' === type) { + if (propertyLength === typeDiff) { + console.log("new talk added @todo figure out which one") + } else { + console.log("ignore, some sort of structure change") + } + } else if ('talk' === type) { + if (propertyDiff === typeDiff) { + console.log("existing talk was adjusted @todo figure out which one and check if maybe two where switched") + } else { + console.log("check what was done, maybe properties where added for empty talk") + } + } + console.log(a, b, type, typeDiff) +} diff --git a/js/plugins/current-day.js b/js/plugins/current-day.js index c222649..12364f8 100644 --- a/js/plugins/current-day.js +++ b/js/plugins/current-day.js @@ -21,5 +21,3 @@ CurrentDay.prototype.registerPlugin = function() { } }); }; - -MicroEvent.mixin(CurrentDay); diff --git a/js/plugins/local-storage.js b/js/plugins/local-storage.js index 47cb84d..103bbf7 100644 --- a/js/plugins/local-storage.js +++ b/js/plugins/local-storage.js @@ -10,7 +10,6 @@ LocalStorage.prototype.registerPlugin = function() { } this.emitter.bind('schedule-data-ready', function(conference_data) { - var schedule = localStorage.getItem('schedule'); localStorage.setItem('schedule', conference_data); }); } From 730827b04b5fcf78310ddcb4818c57fe54dde237 Mon Sep 17 00:00:00 2001 From: Stephan Vock Date: Fri, 14 Mar 2014 01:29:20 +0100 Subject: [PATCH 2/5] now this already works somehow. - design stuff missing - seems not to work with refresh --- css/main.css | 10 +- data/schedule.json | 2 +- js/plugins/change-notify.js | 204 ++++++++++++++++++++++++++---------- 3 files changed, 156 insertions(+), 60 deletions(-) diff --git a/css/main.css b/css/main.css index b3a4001..ce97ab2 100644 --- a/css/main.css +++ b/css/main.css @@ -121,6 +121,14 @@ h3 { bottom: 0; left: 0; width: 100%; - height: 50px; + height: auto; background-color: greenyellow; } + +.change-notify-entry { + width: 100%; + display: block; + border: #000000 solid 1px; + background-color: red; + padding: 5px; +} diff --git a/data/schedule.json b/data/schedule.json index 1794a11..35e5bcd 100644 --- a/data/schedule.json +++ b/data/schedule.json @@ -3,7 +3,7 @@ { "time": { "start": "09:30", - "end": "10:30" + "end": "10:31" }, "talks": [ { diff --git a/js/plugins/change-notify.js b/js/plugins/change-notify.js index 7832bd8..31542cd 100644 --- a/js/plugins/change-notify.js +++ b/js/plugins/change-notify.js @@ -1,14 +1,12 @@ function ChangeNotify(emitter, view_helper) { this.emitter = emitter; this.view_helper = view_helper; + + this.view = new NotifyView(this.view_helper); } ChangeNotify.prototype.registerPlugin = function() { var self = this; - // set up some sort of layer - var element = document.createElement('div'); - element.setAttribute('class', 'change-notify'); - document.getElementsByTagName('body')[0].appendChild(element); var current = null; this.emitter.bind('schedule-data-ready', function(conference_data) { @@ -18,76 +16,166 @@ ChangeNotify.prototype.registerPlugin = function() { } // compare talks -> Note: this might get really tricky - var currentData = JSON.parse(current), - newData = JSON.parse(conference_data); + var newTalks = self.prepareSchedule(JSON.parse(conference_data)), + currentTalks = self.prepareSchedule(JSON.parse(current)), + oldDiffs = [], + newDiffs = [], + i, + talk; + + for (i in newTalks) { + if (typeof currentTalks[i] === "undefined") { + newDiffs.push(newTalks[i]); + } else { + delete newTalks[i]; + delete currentTalks[i]; + } + } + + for (i in currentTalks) { + oldDiffs.push(currentTalks[i]); + } - diff(currentData, newData, ["talk", "talks", "slot", "day", "schedule"]); + while (newDiffs.length > 0) { + oldDiffs = self.calcDiff(newDiffs.pop(), oldDiffs); + } + + while (oldDiffs.length > 0) { + if (talk = oldDiffs.pop()) { + self.view.removedTalk(talk); + } + } // decide on output format - element.innerHTML = "different"; current = conference_data; }); }; -var propertyLength = 0, - propertyDiff = 1; +ChangeNotify.prototype.prepareSchedule = function(rawData) { + var talks = [], + day, + i, + j, + slot, + talk, + time; + for (day in rawData) { + for (i in rawData[day]) { + slot = rawData[day][i]; + time = slot.time; + for (j in slot.talks) { + talk = slot.talks[j]; + talk.day = day; + talk.time = time; -function objectKeys(obj) { - if (typeof Object.keys === 'function') { - return Object.keys(obj); + talks[JSON.stringify(talk)] = talk; + } + } } - var keys = []; - for (var key in obj) keys.push(key); - return keys; -} + return talks; +}; -function diff(a, b, types) { - types = JSON.parse(JSON.stringify(types)) - try { - var type = types.pop(), - ka = objectKeys(a), - kb = objectKeys(b), - key, i; - } catch (e) {//happens when one is a string literal and the other isn't - return; // this should never happen :) +ChangeNotify.prototype.calcDiff = function(talk, talks) { + if (0 === talks.length) { + this.view.newTalk(talk); + return []; } - // having the same number of owned properties (keys incorporates - // hasOwnProperty) - if (ka.length != kb.length) - return notify(a, b, type, propertyLength); - //the same set of keys (although not necessarily the same order), - ka.sort(); - kb.sort(); - - //equivalent values for every corresponding key, and - //~~~possibly expensive deep test - for (i = ka.length - 1; i >= 0; i--) { - key = ka[i]; - if (typeof a[key] === 'object') { - diff(a[key], b[key], types); - } else if (a[key] != b[key]) { - notify(a, b, type, propertyDiff); - } - } -} + var i, + compare; + for (i in talks) { + compare = talks[i]; + if (compare.speaker === talk.speaker + && compare.topic === talk.topic) { + + if (compare.description !== talk.description) { + this.view.descriptionTalk(talk); + } + if (compare.day === talk.day + && compare.time.start === talk.time.start + && compare.time.end === talk.time.end + && compare.location !== talk.location) { + this.view.locationMovedTalk(talk); + } else if ((compare.day !== talk.day + || compare.time.start !== talk.time.start + || compare.time.end !== talk.time.end) + && compare.location === talk.location) { + this.view.timeMovedTalk(talk); + } else if (compare.day !== talk.day + || compare.time.start !== talk.time.start + || compare.time.end !== talk.time.end + || compare.location !== talk.location) { + this.view.movedTalk(talk); + } -// somehow -function notify(a, b, type, typeDiff) { - if ('talks' === type) { - if (propertyLength === typeDiff) { - console.log("new talk added @todo figure out which one") - } else { - console.log("ignore, some sort of structure change") + delete talks[i]; + return talks; } - } else if ('talk' === type) { - if (propertyDiff === typeDiff) { - console.log("existing talk was adjusted @todo figure out which one and check if maybe two where switched") - } else { - console.log("check what was done, maybe properties where added for empty talk") + + if (compare.day === talk.day + && compare.time.start === talk.time.start + && compare.time.end === talk.time.end + && compare.location === talk.location) { + if (compare.speaker === talk.speaker + && compare.topic !== talk.topic) { + delete talks[i]; + this.view.topicTalk(talk) + return talks; + } else if (compare.speaker !== talk.speaker + && compare.topic === talk.topic) { + delete talks[i]; + this.view.speakerTalk(talk) + return talks; + } } } - console.log(a, b, type, typeDiff) + + self.view.newTalk(talk); + return talks; +}; + +function NotifyView(view_helper) { + this.view_helper = view_helper; + + this.element = document.createElement('div'); + this.element.setAttribute('class', 'change-notify'); + document.getElementsByTagName('body')[0].appendChild(this.element); } + +NotifyView.prototype.newTalk = function(talk) { + this.addChange("New talk added to the schedule: " + talk.topic + " by " + talk.speaker + " at " + talk.day + " " + talk.time.start + " - " + talk.time.end); +}; + +NotifyView.prototype.removedTalk = function(talk) { + this.addChange("Talk removed from schedule: " + talk.topic + " by " + talk.speaker + " at " + talk.day + " " + talk.time.start + " - " + talk.time.end); +}; + +NotifyView.prototype.locationMovedTalk = function(talk) { + this.addChange("New location for talk: " + talk.topic + " by " + talk.speaker + " will now be in " + talk.location); +}; + +NotifyView.prototype.timeMovedTalk = function(talk) { + this.addChange("New slot for talk: " + talk.topic + " by " + talk.speaker + " will now be at " + talk.day + " " + talk.time.start + " - " + talk.time.end); +}; + +NotifyView.prototype.movedTalk = function(talk) { + this.addChange("New slot for talk: " + talk.topic + " by " + talk.speaker + " will now be at " + talk.day + " " + talk.time.start + " - " + talk.time.end + " in " + talk.location); +}; + +NotifyView.prototype.descriptionTalk = function(talk) { + this.addChange("The Talk: " + talk.topic + " by " + talk.speaker + " got an updated description!") +}; + +NotifyView.prototype.topicTalk = function(talk) { + this.addChange("Topic update for talk by " + talk.speaker + " at " + talk.day + " " + talk.time.start + " - " + talk.time.end) +}; + +NotifyView.prototype.speakerTalk = function(talk) { + this.addChange("Speaker update for talk " + talk.topic + " at " + talk.day + " " + talk.time.start + " - " + talk.time.end) +}; + +NotifyView.prototype.addChange = function(change) { + this.element.innerHTML = this.element.innerHTML + '
' + change + "
"; +}; From 9e87b834ba2ff5ca96e010c6af78716ea9783323 Mon Sep 17 00:00:00 2001 From: Stephan Vock Date: Sat, 22 Mar 2014 22:11:43 +0100 Subject: [PATCH 3/5] notifications are now fixed at the bottom added close button for each notification --- css/main.css | 9 +++++++-- js/plugins/change-notify.js | 21 +++++++++++++++++++-- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/css/main.css b/css/main.css index ce97ab2..a9253ca 100644 --- a/css/main.css +++ b/css/main.css @@ -117,12 +117,11 @@ h3 { } .change-notify { - position: absolute; + position: fixed; bottom: 0; left: 0; width: 100%; height: auto; - background-color: greenyellow; } .change-notify-entry { @@ -131,4 +130,10 @@ h3 { border: #000000 solid 1px; background-color: red; padding: 5px; + font-size: 1.5em; +} + +.change-notify-close { + float: right; + margin-right: 10px; } diff --git a/js/plugins/change-notify.js b/js/plugins/change-notify.js index 31542cd..db813b8 100644 --- a/js/plugins/change-notify.js +++ b/js/plugins/change-notify.js @@ -46,7 +46,6 @@ ChangeNotify.prototype.registerPlugin = function() { } } - // decide on output format current = conference_data; }); }; @@ -139,6 +138,7 @@ ChangeNotify.prototype.calcDiff = function(talk, talks) { function NotifyView(view_helper) { this.view_helper = view_helper; + this.changeCounter = 0; this.element = document.createElement('div'); this.element.setAttribute('class', 'change-notify'); document.getElementsByTagName('body')[0].appendChild(this.element); @@ -177,5 +177,22 @@ NotifyView.prototype.speakerTalk = function(talk) { }; NotifyView.prototype.addChange = function(change) { - this.element.innerHTML = this.element.innerHTML + '
' + change + "
"; + var div = document.createElement('div'), + a = document.createElement('a'); + + div.setAttribute('class', 'change-notify-entry'); + div.innerText = change; + a.setAttribute('class', 'change-notify-close'); + a.id = "change" + (this.changeCounter++); + a.innerText = 'X'; + a.href = "#"; + div.appendChild(a); + this.element.appendChild(div); + + //this.element.innerHTML = this.element.innerHTML + '
' + change + 'X
'; + var self = this; + div.addEventListener('click', function(event) { + self.element.removeChild(div); + event.preventDefault ? event.preventDefault() : event.returnValue = false; + }, false); }; From ce8bb40ae300757cb41d241bcd0bc5b50b90c2ca Mon Sep 17 00:00:00 2001 From: Stephan Vock Date: Sat, 22 Mar 2014 22:13:42 +0100 Subject: [PATCH 4/5] fixed scheudle :) --- data/schedule.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/schedule.json b/data/schedule.json index 35e5bcd..1794a11 100644 --- a/data/schedule.json +++ b/data/schedule.json @@ -3,7 +3,7 @@ { "time": { "start": "09:30", - "end": "10:31" + "end": "10:30" }, "talks": [ { From 3f15a56a73da6a07d724dfaf871f864f41dbd507 Mon Sep 17 00:00:00 2001 From: Stephan Vock Date: Sat, 22 Mar 2014 22:16:53 +0100 Subject: [PATCH 5/5] reverted some changes to other plugins --- js/plugins/current-day.js | 2 ++ js/plugins/local-storage.js | 1 + 2 files changed, 3 insertions(+) diff --git a/js/plugins/current-day.js b/js/plugins/current-day.js index 12364f8..c222649 100644 --- a/js/plugins/current-day.js +++ b/js/plugins/current-day.js @@ -21,3 +21,5 @@ CurrentDay.prototype.registerPlugin = function() { } }); }; + +MicroEvent.mixin(CurrentDay); diff --git a/js/plugins/local-storage.js b/js/plugins/local-storage.js index 103bbf7..47cb84d 100644 --- a/js/plugins/local-storage.js +++ b/js/plugins/local-storage.js @@ -10,6 +10,7 @@ LocalStorage.prototype.registerPlugin = function() { } this.emitter.bind('schedule-data-ready', function(conference_data) { + var schedule = localStorage.getItem('schedule'); localStorage.setItem('schedule', conference_data); }); }