var templates = {}; $(document).ready(function() { if ( $(window).width() < 1024 ) { $('#filters').addClass('hidden'); } document.body.className = localStorage.getItem('theme'); boot(); }); var AppModel = Backbone.Model.extend({ defaults: { 'selectedIndex': 0, 'starredFilter': false, 'allFilter': false, 'unreadFilter': true, 'feedFilter': undefined, 'searchFilter': undefined }, initialize: function() { this.bind('change:selectedIndex', this.scroll_to_selected); // this.bind('change:selectedIndex', this.scroll_to_selected) }, boot: function() { this.items.boot(); this.tags.boot(); this.feeds.fetch({set: true, remove: false}) window.setInterval(function() { App.update_read_status() }, 5000); }, filterToFeed: function(feed) { if (feed.get('selected')) { feed.set('selected', false); this.set('feedFilter', undefined); } else { App.tags.models.forEach ( function (t) { t.set('selected', false); }); App.tag = null; App.feeds.models.forEach ( function (f) { f.set('selected', false); }); this.set('feedFilter', feed); feed.set('selected', true); } this.items.reboot(); }, filterToTag: function(tag) { App.tag = null; if (tag.get('selected')) { tag.set('selected', false); } else { App.tags.models.forEach ( function (t) { t.set('selected', false); }); App.feeds.models.forEach ( function (f) { f.set('selected', false); }); this.set('feedFilter', undefined); tag.set('selected', true); App.tag = tag.get('title'); } App.items.reboot(); }, filterToStarred: function() { this.set('starredFilter', true); this.set('allFilter', false); this.set('unreadFilter', false); this.items.reboot(); }, filterToAll: function() { this.set('searchFilter', undefined); this.set('starredFilter', false); this.set('allFilter', true); this.set('unreadFilter', false); this.items.reboot(); }, filterToUnread: function() { this.set('starredFilter', false); this.set('allFilter', false); this.set('unreadFilter', true); this.items.reboot(); }, filterToSearch: function() { this.set('searchFilter', $('#search').val()); this.set('starredFilter', false); this.set('allFilter', true); this.set('unreadFilter', false); this.items.reboot(); }, update_read_status: function() { var screen_top = $(window).scrollTop(); var screen_bottom = $(window).scrollTop() + $(window).height(); // // mark all visible items as read $.each($('.item'), function(i,v) { var item_top = $(v).offset().top; // console.log("i ", i, "item_top ", item_top, "screen_top ", screen_top, "screen_bottom ", screen_bottom); if( (item_top < screen_top)) { App.items.at(i).markRead(); // console.log('marking as read: ', i); } }); // window.setTimeout(App.update_read_status, 5000); }, scroll_to_selected: function() { var item = $('.item').eq(this.get('selectedIndex')); if(item.offset()) { var item_top = item.offset().top; $('.item').removeClass('selected'); item.addClass('selected'); $(window).scrollTop(item_top); } App.items.at(this.get('selectedIndex')).markRead(); if(App.items.models.length>1) { if(this.get('selected')>=App.items.models.length-1) { App.items.boot(); } } }, next: function() { if(this.get('selectedIndex') < this.items.models.length-1) { this.set('selectedIndex', this.get('selectedIndex')+1); } if(this.get('selectedIndex') == this.items.models.length-1) { App.items.boot(); } }, previous: function() { if(this.get('selectedIndex') > 0) { this.set('selectedIndex', this.get('selectedIndex')-1); } }, star: function() { if(this.get('selectedIndex') >= 0) { App.items.at(this.get('selectedIndex')).toggleStar(); } }, full: function() { if(this.get('selectedIndex') >= 0) { App.items.at(this.get('selectedIndex')).full(); } } }); var App = new AppModel(); var ControlsView = Backbone.View.extend({ className: 'controls', events: { 'click .starred_filter': 'filterToStarred', 'click .all_filter': 'filterToAll', 'click .unread_filter': 'filterToUnread', 'click .new_feed': 'newFeed', 'click .search_go': 'filterToSearch', 'click .light_theme': 'lightTheme', 'click .dark_theme': 'darkTheme', 'click .black_theme': 'blackTheme', }, initialize: function() { _.bindAll(this, 'render'); this.model.bind('change', this.render); }, filterToStarred: function() { App.filterToStarred(); }, filterToAll: function() { App.filterToAll(); }, filterToUnread: function() { App.filterToUnread(); }, filterToSearch: function() { App.filterToSearch(); }, newFeed: function() { var feed_url = prompt('New url to subscribe to'); var feed = new Feed({'url': feed_url}); App.feeds.add(feed); feed.save(); }, render: function() { var h = $.tmpl(templates.controls_template, { 'app': this.model.toJSON() }); $(this.el).html(h); return this; }, lightTheme: function() { document.body.className = "light"; localStorage.setItem("theme", "light"); }, darkTheme: function() { document.body.className = "dark"; localStorage.setItem("theme", "dark"); }, blackTheme: function() { document.body.className = "black"; localStorage.setItem("theme", "black"); }, }); var Item = Backbone.Model.extend({ idAttribute: "_id", url: '/item/', initialize: function() { var p_url = this.get('url'); p_url = p_url.replace('https://', ''); p_url = p_url.replace('http://', ''); this.set('p_url', p_url); this.bind('change', this.maybeSave); }, maybeSave: function() { if(this.hasChanged()) { this.save(); } }, markRead: function() { // recover if not tag if(this.get('read')) { return; } // var t = this.get('feed').tag; // var tag = App.tags.find(function(x){ return x.get('name') == t }); this.set('read', true); // if(tag) { // tag.set('unread', tag.get('unread')-1); // } }, toggleStar: function() { this.set({'starred': !(this.get('starred'))} ); }, star: function() { this.set({'starred': true}); }, unstar: function() { this.set({'starred': false}); }, full: function() { this.set({'full': !(this.get('full'))} ); // this should just use this.fetch() but // it kept GETing from /item instead of /item/id // so just hacking this in for now if(this.get('full_content') == "") { $.getJSON('/item/' + this.get('_id'), function(data) { var i = App.items.get(data['_id']) i.set('full_content', data['full_content']); }); } } }); var ItemCollection = Backbone.Collection.extend({ model: Item, initialize: function() { _.bindAll(this, 'boot', 'reboot'); }, boot: function() { if(App.loading) { return; } if(App.noMore) { return; } App.loading = true; url = '/stream/'; url=url+'?foo=bar' if(App.get('searchFilter')) { url = url + '&q=' + App.get('searchFilter'); } if(App.get('feedFilter')) { url = url + '&feed_url=' + App.get('feedFilter').get('url'); } if(App.get('starredFilter')) { url = url + '&starred=1'; } if(App.tag != undefined) { url = url + '&tag=' + App.tag; } if(App.items.last()) { url = url + '&max_id=' + App.items.last().get('_id'); } if(App.get('allFilter') || App.get('starredFilter')) { url = url + '&read_filter=all'; } console.log('fetching from ', url); var t = this; $.getJSON(url, function(data) { var items = []; $.each(data, function(i,v) { var item = new Item(v); t.add(item); items.push(item); if(t.models.length==1){ App.set('selectedIndex', 0); } }); // console.log("items ", items) if(items.length == 0) { // console.log("no more items"); App.noMore = true; // App.loading = true; } else { App.loading = false; } // we wait and add them all at once for performance on mobile App.itemListView.addAll(items); }); }, reboot: function() { App.noMore = false; App.loading = false; this.reset(); this.boot(); }, }); App.items = new ItemCollection(); var ItemView = Backbone.View.extend({ tagName: "div", className: "item", template: templates.item_template, events: { "click .star": "star", "click .unstar": "unstar", "click .full": "full", }, initialize: function() { _.bindAll(this, 'render', 'star'); this.model.bind('change', this.render); }, star: function() { this.model.star(); this.render(); }, unstar: function() { this.model.unstar(); this.render(); }, full: function() { this.model.full(); this.render(); }, render: function() { var h = $.tmpl(templates.item_template, { 'item': this.model.toJSON() }); $(this.el).html(h); return this; }, }); var ItemListView = Backbone.View.extend( { initialize: function() { _.bindAll(this, 'addOne', 'addAll', 'change', 'render', 'reset'); // App.items.bind('add', this.addOne); App.items.bind('reset', this.reset); }, addOne: function(item) { var view = new ItemView({'model': item}); this.$el.append(view.render().el); }, addAll: function(items) { // Posts.each(this.addOne); for(i in items) { item = items[i]; var view = new ItemView({'model': item}); this.$el.append(view.render().el); }; }, change: function() { }, render: function() { }, reset: function() { this.$el.children().remove(); } }); var Tag = Backbone.Model.extend({ }); var TagCollection = Backbone.Collection.extend({ model: Tag, initialize: function() { _.bindAll(this, 'boot'); }, boot: function() { var t = this; $.getJSON('/tag/', function(data) { $.each(data, function(i,v) { var tag = new Tag(v); t.add(tag); }); }); } }); App.tags = new TagCollection(); var TagView = Backbone.View.extend({ tagName: "li", className: "tag", events: { "click": "filterTo", }, initialize: function() { _.bindAll(this, 'render', 'filterTo'); this.model.bind('change', this.render); }, render: function() { var h = $.tmpl(templates.tag_template, { 'tag': this.model.toJSON() }); $(this.el).html(h); return this; }, filterTo: function() { App.filterToTag(this.model); } }); var TagListView = Backbone.View.extend( { initialize: function() { _.bindAll(this, 'addOne', 'addAll', 'change', 'render'); App.tags.bind('add', this.addOne); App.tags.bind('refresh', this.addAll); App.tags.bind('change', this.render); }, addOne: function(tag) { var view = new TagView({'model': tag}); this.$el.append(view.render().el); }, addAll: function() { App.tags.each(this.addOne); }, change: function() { }, render: function() { }, }); App.tag = undefined; App.page = 0; App.read_filter = 'unread'; var Feed = Backbone.Model.extend({ idAttribute: "_id", }); var FeedCollection = Backbone.Collection.extend({ model: Feed, url: '/feed/', initialize: function() { /// _.bindAll(this, 'boot'); //console.log('initialized'); }, }); App.feeds = new FeedCollection(); var FeedView = Backbone.View.extend({ tagName: "li", className: "feed", events: { "click .txt": "filterTo", "click .delete": "del", "click .edit": "edit", }, initialize: function() { _.bindAll(this, 'render', 'filterTo', "del"); this.model.bind('change', this.render); }, render: function() { var h = $.tmpl(templates.feed_template, { 'feed': this.model.toJSON() }); $(this.el).html(h); return this; }, filterTo: function() { // console.log('filtering to feed ', this.model); App.filterToFeed(this.model); }, del: function() { if( window.confirm("Unsubscribe from " + this.model.get("url") + "?" ) ) { this.model.destroy(); this.$el.remove(); } }, edit: function() { var cat = window.prompt("Category for this feed?", this.model.get("category")); if (cat != null) { this.model.set("category", cat); this.model.save(); } }, }); var FeedListView = Backbone.View.extend( { initialize: function() { _.bindAll(this, 'addOne', 'addAll', 'change', 'render'); App.feeds.bind('add', this.addOne); App.feeds.bind('refresh', this.addAll); App.feeds.bind('change', this.render); }, addOne: function(feed) { // console.log('adding a feed...', feed); var view = new FeedView({'model': feed}); this.$el.append(view.render().el); }, addAll: function() { // console.log('feed add all...'); App.feeds.each(this.addOne); }, change: function() { // console.log('feeds changed add all...'); }, render: function() { }, }); // var page = 0; // var read_filter = 'unread'; var selected_item = 0; function boot() { templates['item_template'] = $('#item_template').html(); templates['tag_template'] = $('#tag_template').html(); templates['feed_template'] = $('#feed_template').html(); templates['controls_template'] = $('#controls_template').html(); App.itemListView = new ItemListView(); App.itemListView.setElement($('#items')); App.tagListView = new TagListView(); App.tagListView.setElement($('#tags')); App.feedListView = new FeedListView(); App.feedListView.setElement($('#feeds')); App.controlsView = new ControlsView({model: App}); App.controlsView.setElement($('#controls')); App.controlsView.render(); infini_scroll(); $('#unread_filter').on('click', function() { App.read_filter = 'unread'; App.items.reboot(); }); $('#all_filter').on('click', function() { App.read_filter = 'all'; App.items.reboot(); }); // $('.logo').on('click', function() { // App.set('feedFilter', undefined); // App.items.reboot(); // }); // keyboard shortcuts $('body').keydown(function(event) { if(document.activeElement.id == "search") { return; } if (event.which == 74) { event.preventDefault(); App.next(); } if (event.which == 75) { event.preventDefault(); App.previous(); } if (event.which == 83) { event.preventDefault(); App.star(); } }); App.boot(); } // // this is legacy code function infini_scroll() { if(App.loading) { } else { var dh = $('#items').height() - $(window).height(); var st = $(window).scrollTop(); if ( (dh-st) < 100 ){ App.items.boot(); } } window.setTimeout(infini_scroll, 1000); } var ItemSelector = { selected_index: 0, }