diff options
-rw-r--r-- | static/ui.js | 4 | ||||
-rw-r--r-- | web/rice-box.go | 12 |
2 files changed, 6 insertions, 10 deletions
diff --git a/static/ui.js b/static/ui.js index 9742314..cc7ad8d 100644 --- a/static/ui.js +++ b/static/ui.js @@ -632,10 +632,6 @@ function boot() { event.preventDefault(); App.star(); } - if (event.which == 70) { - event.preventDefault(); - App.full(); - } }); App.boot(); diff --git a/web/rice-box.go b/web/rice-box.go index 62070ab..49857d6 100644 --- a/web/rice-box.go +++ b/web/rice-box.go @@ -55,18 +55,18 @@ func init() { } fileb := &embedded.EmbeddedFile{ Filename: "style.css", - FileModTime: time.Unix(1538242745, 0), + FileModTime: time.Unix(1538242901, 0), Content: string("html {\n font-size: 18px;\n}\nbody {\n font-size: 1.0000rem;\n line-height: 1.500rem;\n min-width: 45rem;\n}\nh1 {\n font-size: 3.1875rem;\n line-height: 3.7500rem;\n margin-top: 1.25rem;\n margin-bottom: 2.5rem;\n}\nh2 {\n font-size: 1.7500rem;\n line-height: 2.5000rem;\n margin-top: 2.5rem;\n margin-bottom: 1.25rem;\n}\nh3 {\n font-size: 1.3125rem;\n line-height: 2.5000rem;\n margin-top: 1.25rem;\n margin-bottom: 0rem;\n}\np, ul {\n margin-top: 0rem;\n margin-bottom: 1.25rem;\n}\n\n#filters h4 {\n margin-bottom: 0;\n}\n\nblockquote {\n padding: 1rem 1rem 0 1rem;\n}\n\nbody {\n font-family: Palatino, Georgia;\n}\n\nh1, h2, h3, h4, h5, #controls {\n font-family: 'Helvetica Neue';\n font-weight: 'bold';\n}\n\n#controls, .control {\n font-variant: small-caps;\n text-transform: lowercase;\n}\n\n\n#controls ul {\n margin-top: 1em;\n padding: 0;\n}\n\n#controls li {\n width: 100%;\n list-style: none;\n margin-left: 0;\n text-align: center;\n margin-top: 10px;\n background-color: whitesmoke;\n}\n\nh2 {\n margin: 0;\n padding: 0;\n}\n\na, a:hover, a:active {\n text-decoration: none;\n color: blue;\n}\n\nimg {\n max-width: 100%;\n height: auto;\n}\n\np {\n margin-top: 1em;\n}\n\np.dateline {\n margin-top: 0;\n font-weight: normal;\n font-size: .75em;\n color: #ccc;\n}\n\np.dateline a {\n color: #ccc;\n}\n\n.item {\n padding: 1rem;\n margin-top: 5rem;\n}\n\nh3 {\n padding: 0;\n margin: 0;\n}\n\n#items {\n margin: 2rem auto;\n max-width: 35rem;\n overflow: hidden;\n}\n\n\n#filters {\n position: fixed;\n top: 0;\n left: 0;\n padding: 3rem 1rem 0 1rem;\n width: 10rem;\n cursor: pointer;\n color: #777;\n height: 100%;\n overflow-y: auto;\n background-color: #ccc;\n transition-property: left;\n transition-duration: .4s;\n}\n\n#filters.hidden {\n left: -13rem;\n}\n\n#tags, #feeds {\n font-family: 'Helvetica Neue';\n list-style: none;\n margin: 0;\n padding: 0;\n}\n\n#tags li, #feeds li {\n font-size: .75em;\n padding-bottom: .25em;\n}\n\npre {\n display: none;\n}\n\n.read {\n}\n\n.selected {\n}\n\n.newFilter {\n color: black;\n}\n\n\n.all .newFilter {\n color: #777;\n}\n\n.logo {\n margin: 0;\n padding: 1rem;\n position: fixed;\n top: 0;\n left: 0;\n color: white;\n line-height: 1em;\n z-index: 1;\n cursor: pointer;\n width: 10rem;\n font-size: 2rem;\n}\n\n.hasunread {\n color: blue;\n}\n\n.active, .all .everythingFilter {\n color: black;\n}\n\n.full {\n cursor: pointer;\n}\n\n.star {\n color: black;\n cursor: pointer;\n}\n\n.unstar {\n color: blue;\n cursor: pointer;\n}\n\n#loading {\n width: 100%;\n font-size: 24px;\n background-color: #ccc;\n}\n\nbutton {\n font-family: 'Helvetica Neue';\n font-size: 16px;\n padding: 3px 10px;\n background: whitesmoke;\n color: blue;\n font-weight: bold;\n border: none;\n width: 100%;\n}\n\n\n@media only screen and (max-device-width: 768px) {\n html {\n width: 100%;\n font-size: 22px;\n }\n\n body {\n min-width: 0;\n width: 100%;\n max-width: 100%;\n /* overflow: hidden; */\n }\n\n .logo {\n width: 100%;\n }\n\n #filters li, #filters h4 {\n font-size: 1.5rem;\n }\n\n /* #filters h4, #filters h1 { */\n /* display: none; */\n /* } */\n\n /* #controls { */\n /* width: 100%; */\n /* font-size: 1.5rem; */\n /* } */\n\n /* #controls ul { */\n /* padding: 0; */\n /* margin: 0; */\n /* text-align: center; */\n /* } */\n\n /* #controls li { */\n /* display: inline; */\n /* } */\n\n /* #filters { */\n /* width: 100%; */\n /* height: 50px; */\n /* position: fixed; */\n /* top: 0; */\n /* left: 0; */\n /* background: #ccc; */\n /* } */\n\n\n #items { */\n margin: 0 auto;\n max-width: 100%;\n }\n}\n\n@media only screen and (max-device-width: 400px) {\n html {\n font-size: 16px;\n }\n\n body {\n min-width: 0;\n width: 100%;\n }\n}\n\nbody.dark {\n color: #fff;\n background-color: #24292e;\n}\n\nbody.black {\n color: #fff;\n background-color: black;\n}\n\nbody.dark a, body.black a {\n color: rgb(90, 200, 250);\n}\n\nbody.dark button, body.dark #controls li a {\n color: black;\n}\n\n\nbody.black button, body.black #controls li a {\n color: black;\n}\n\n.themes button {\n width: 30%;\n}\n"), } filec := &embedded.EmbeddedFile{ Filename: "ui.html", - FileModTime: time.Unix(1538242667, 0), + FileModTime: time.Unix(1538242901, 0), Content: string("<!DOCTYPE html>\n<html>\n <head>\n <title>neko rss mode</title>\n <link rel=\"stylesheet\" href=\"/static/style.css\" />\n <script src=\"/static/jquery-3.3.1.min.js\"></script>\n <script src=\"/static/jquery.tmpl.min.js\"></script>\n <script src=\"/static/underscore-1.8.3.min.js\"></script>\n <script src=\"/static/backbone-1.3.3.min.js\"></script>\n <script>\n PUBLIC_VERSION = false;\n </script>\n <script src=\"/static/ui.js\"></script>\n <meta name=\"viewport\" content=\"width=device-width,height=device-height, initial-scale=1, maximum-scale=1\" />\n <base target=\"_blank\">\n </head>\n <body>\n <h1 class=\"logo\" onclick=\"$('#filters').toggleClass('hidden');\">🐱</h1>\n\n <div id=\"filters\">\n\n <div id=\"controls\"></div>\n <h4 onclick=\"$('#tags').toggle();\">Tags</h4> \n <ul id=\"tags\" style=\"display: none;\">\n </ul>\n \n <h4 onclick=\"$('#feeds').toggle();\">Feeds</h4> \n <ul id=\"feeds\" style=\"display: none;\">\n </ul>\n\n <h4 onclick=\"$('#export').toggle();\">Export</h4>\n <ul id=\"export\" style=\"display: none;\">\n <li><a href=\"/export/opml\">opml</a></li>\n <li><a href=\"/export/text\">text</a></li>\n <li><a href=\"/export/json\">json</a></li>\n </ul>\n </div>\n \n </div>\n\n <div id=\"c\">\n <div id=\"items\">\n </div> \n </div>\n \n <script id=\"item_template\" type=\"text/jqtmp\">\n <h2><a class=\"i\" id=\"i_${item_id}\" href=\"${item.url}\">${item.title }</a> \n <span class={{if item.starred}}\"unstar\"{{else}}\"star\"{{/if}}>★</span>\n </h2>\n <p class=\"dateline\" style=\"clear: both;\">\n <a href=\"${item.feed_url}\">${item.feed_title}</a> | <a href=\"${item.url}\">${item.p_url}</a>\n | ${item.feed_category} |\n <span class=\"full\">{{if item.full}}hide{{else}}scrape{{/if}} full text</span>\n \n </p>\n {{if item.header_image}}\n <div class=\"img\"><img src=\"${item.header_image}\" /></div>\n {{/if}}\n <div class=\"description\">\n {{if item.full}}\n {{html item.full_content}}\n {{else}}\n {{html item.description}}\n {{/if}}\n </div>\n </script>\n\n <script id=\"tag_template\" type=\"text/jqtmp\">\n {{if tag.selected}}<b>{{/if}}\n ${tag.title}\n {{if tag.selected}}</b>{{/if}}\n </script>\n\n <script id=\"feed_template\" type=\"text/jqtmp\">\n {{if feed.selected}}<b>{{/if}}\n <span class=\"txt\">\n {{if feed.title}}\n ${feed.title}\n {{else}}\n ${feed.url}\n {{/if}}\n\n </span>\n <span class=\"edit\">[e]</span>\n <span class=\"delete\">[x]</span>\n {{if feed.selected}}</b>{{/if}}\n </script>\n\n <script id=\"controls_template\" type=\"text/jqtmp\">\n <ul>\n <li class=\"unread_filter\">\n <a {{if app.unreadFilter}}style=\"font-weight: bold;\"{{/if}} \n >unread</a>\n </li>\n <li class=\"all_filter\">\n <a \n {{if app.allFilter}}style=\"font-weight: bold;\"{{/if}} \n >all</a> \n </li>\n <li class=\"starred_filter\">\n <a {{if app.starredFilter}}style=\"font-weight: bold;\"{{/if}}\n >★ starred</a>\n </li>\n <li>\n <button class=\"new_feed\"> + new </button>\n </li>\n <li>\n <input id=\"search\" type=\"search\" /><button class=\"search_go\">search</button>\n </li>\n\t <li class=\"themes\">\n <button class=\"light_theme\">light</button>\n <button class=\"dark_theme\">dark</button>\n <button class=\"black_theme\">black</button>\n\t\t</li>\n\t </ul>\n </script> \n \n</body>\n</html> \n"), } filed := &embedded.EmbeddedFile{ Filename: "ui.js", - FileModTime: time.Unix(1538242832, 0), - Content: string("var templates = {};\n\n$(document).ready(function() {\n if ( $(window).width() < 1024 ) {\n $('#filters').addClass('hidden');\n }\n document.body.className = localStorage.getItem('theme');\n boot();\n});\n\nvar AppModel = Backbone.Model.extend({\n defaults: {\n 'selectedIndex': 0,\n 'starredFilter': false,\n 'allFilter': false,\n 'unreadFilter': true,\n 'feedFilter': undefined,\n 'searchFilter': undefined\n },\n\n initialize: function() {\n this.bind('change:selectedIndex', this.scroll_to_selected);\n// this.bind('change:selectedIndex', this.scroll_to_selected)\n },\n\n boot: function() {\n this.items.boot();\n this.tags.boot();\n this.feeds.fetch({set: true, remove: false})\n window.setInterval(function() { App.update_read_status() }, 5000);\n },\n\n filterToFeed: function(feed) {\n if (feed.get('selected')) {\n feed.set('selected', false);\n this.set('feedFilter', undefined);\n }\n else {\n App.tags.models.forEach ( function (t) {\n t.set('selected', false);\n });\n App.tag = null;\n App.feeds.models.forEach ( function (f) {\n f.set('selected', false);\n });\n\n this.set('feedFilter', feed);\n feed.set('selected', true);\n }\n this.items.reboot();\n },\n\n filterToTag: function(tag) {\n App.tag = null;\n if (tag.get('selected')) {\n tag.set('selected', false);\n }\n else {\n App.tags.models.forEach ( function (t) {\n t.set('selected', false);\n });\n App.feeds.models.forEach ( function (f) {\n f.set('selected', false);\n });\n this.set('feedFilter', undefined);\n tag.set('selected', true);\n App.tag = tag.get('title');\n }\n App.items.reboot();\n },\n\n filterToStarred: function() {\n this.set('starredFilter', true);\n this.set('allFilter', false);\n this.set('unreadFilter', false);\n this.items.reboot();\n },\n\n filterToAll: function() {\n this.set('searchFilter', undefined);\n this.set('starredFilter', false);\n this.set('allFilter', true);\n this.set('unreadFilter', false);\n this.items.reboot();\n },\n\n filterToUnread: function() {\n this.set('starredFilter', false);\n this.set('allFilter', false);\n this.set('unreadFilter', true);\n this.items.reboot();\n },\n\n filterToSearch: function() {\n this.set('searchFilter', $('#search').val());\n this.set('starredFilter', false);\n this.set('allFilter', true);\n this.set('unreadFilter', false);\n this.items.reboot();\n },\n\n update_read_status: function() {\n var screen_top = $(window).scrollTop();\n var screen_bottom = $(window).scrollTop() + $(window).height();\n\n // // mark all visible items as read\n $.each($('.item'), function(i,v) {\n var item_top = $(v).offset().top;\n // console.log(\"i \", i, \"item_top \", item_top, \"screen_top \", screen_top, \"screen_bottom \", screen_bottom);\n\n if( (item_top < screen_top)) {\n App.items.at(i).markRead();\n // console.log('marking as read: ', i);\n }\n });\n// window.setTimeout(App.update_read_status, 5000);\n },\n\n scroll_to_selected: function() {\n var item = $('.item').eq(this.get('selectedIndex'));\n if(item.offset()) {\n var item_top = item.offset().top;\n $('.item').removeClass('selected');\n item.addClass('selected');\n $(window).scrollTop(item_top);\n }\n App.items.at(this.get('selectedIndex')).markRead();\n if(App.items.models.length>1) {\n if(this.get('selected')>=App.items.models.length-1) {\n App.items.boot();\n }\n }\n },\n\n next: function() {\n if(this.get('selectedIndex') < this.items.models.length-1) {\n this.set('selectedIndex', this.get('selectedIndex')+1);\n }\n if(this.get('selectedIndex') == this.items.models.length-1) {\n App.items.boot();\n }\n },\n\n previous: function() {\n if(this.get('selectedIndex') > 0) {\n this.set('selectedIndex', this.get('selectedIndex')-1);\n }\n },\n\n star: function() {\n if(this.get('selectedIndex') >= 0) {\n App.items.at(this.get('selectedIndex')).toggleStar();\n }\n },\n\n full: function() {\n if(this.get('selectedIndex') >= 0) {\n App.items.at(this.get('selectedIndex')).full();\n }\n }\n\n});\nvar App = new AppModel();\n\nvar ControlsView = Backbone.View.extend({\n className: 'controls',\n\n events: {\n 'click .starred_filter': 'filterToStarred',\n 'click .all_filter': 'filterToAll',\n 'click .unread_filter': 'filterToUnread',\n 'click .new_feed': 'newFeed',\n 'click .search_go': 'filterToSearch',\n 'click .light_theme': 'lightTheme',\n 'click .dark_theme': 'darkTheme',\n 'click .black_theme': 'blackTheme',\n },\n\n initialize: function() {\n _.bindAll(this, 'render');\n this.model.bind('change', this.render);\n },\n\n filterToStarred: function() {\n App.filterToStarred();\n },\n\n filterToAll: function() {\n App.filterToAll();\n },\n\n filterToUnread: function() {\n App.filterToUnread();\n },\n\n filterToSearch: function() {\n App.filterToSearch();\n },\n\n newFeed: function() {\n var feed_url = prompt('New url to subscribe to');\n var feed = new Feed({'url': feed_url});\n App.feeds.add(feed);\n feed.save();\n },\n\n render: function() {\n var h = $.tmpl(templates.controls_template, { 'app': this.model.toJSON() });\n $(this.el).html(h);\n return this;\n },\n\n lightTheme: function() {\n document.body.className = \"light\";\n localStorage.setItem(\"theme\", \"light\");\n },\n\n darkTheme: function() {\n document.body.className = \"dark\";\n localStorage.setItem(\"theme\", \"dark\");\n },\n\n blackTheme: function() {\n document.body.className = \"black\";\n localStorage.setItem(\"theme\", \"black\");\n },\n \n});\n\n\n\nvar Item = Backbone.Model.extend({\n idAttribute: \"_id\",\n url: '/item/',\n\n initialize: function() {\n var p_url = this.get('url');\n p_url = p_url.replace('https://', '');\n p_url = p_url.replace('http://', '');\n this.set('p_url', p_url);\n this.bind('change', this.maybeSave);\n },\n\n maybeSave: function() {\n if(this.hasChanged()) {\n this.save();\n }\n },\n\n markRead: function() {\n // recover if not tag\n if(this.get('read')) {\n return;\n }\n\n // var t = this.get('feed').tag;\n // var tag = App.tags.find(function(x){ return x.get('name') == t });\n this.set('read', true);\n // if(tag) {\n // tag.set('unread', tag.get('unread')-1);\n // }\n },\n\n toggleStar: function() {\n this.set({'starred': !(this.get('starred'))} );\n },\n\n star: function() {\n this.set({'starred': true});\n },\n\n unstar: function() {\n this.set({'starred': false});\n },\n\n full: function() {\n this.set({'full': !(this.get('full'))} );\n // this should just use this.fetch() but\n // it kept GETing from /item instead of /item/id\n // so just hacking this in for now\n\n if(this.get('full_content') == \"\") {\n $.getJSON('/item/' + this.get('_id'), function(data) {\n var i = App.items.get(data['_id'])\n i.set('full_content', data['full_content']);\n });\n }\n }\n\n});\n\n\nvar ItemCollection = Backbone.Collection.extend({\n model: Item,\n\n initialize: function() {\n _.bindAll(this, 'boot', 'reboot');\n },\n\n boot: function() {\n if(App.loading) {\n return;\n }\n if(App.noMore) {\n return;\n }\n\n App.loading = true;\n url = '/stream/';\n url=url+'?foo=bar'\n if(App.get('searchFilter')) {\n url = url + '&q=' + App.get('searchFilter');\n }\n if(App.get('feedFilter')) {\n url = url + '&feed_url=' + App.get('feedFilter').get('url');\n }\n if(App.get('starredFilter')) {\n url = url + '&starred=1';\n }\n if(App.tag != undefined) {\n url = url + '&tag=' + App.tag;\n }\n if(App.items.last()) {\n url = url + '&max_id=' + App.items.last().get('_id');\n }\n\n if(App.get('allFilter') || App.get('starredFilter')) {\n url = url + '&read_filter=all';\n }\n\n console.log('fetching from ', url);\n var t = this;\n $.getJSON(url, function(data) {\n var items = [];\n $.each(data, function(i,v) {\n var item = new Item(v);\n t.add(item);\n items.push(item);\n if(t.models.length==1){\n App.set('selectedIndex', 0);\n }\n });\n // console.log(\"items \", items)\n if(items.length == 0) {\n // console.log(\"no more items\");\n App.noMore = true;\n // App.loading = true;\n }\n else {\n App.loading = false;\n }\n // we wait and add them all at once for performance on mobile\n App.itemListView.addAll(items);\n\n });\n },\n\n reboot: function() {\n App.noMore = false;\n App.loading = false;\n this.reset();\n this.boot();\n },\n\n\n});\nApp.items = new ItemCollection();\n\n\nvar ItemView = Backbone.View.extend({\n tagName: \"div\",\n className: \"item\",\n template: templates.item_template,\n events: {\n \"click .star\": \"star\",\n \"click .unstar\": \"unstar\",\n \"click .full\": \"full\",\n },\n\n initialize: function() {\n _.bindAll(this, 'render', 'star');\n this.model.bind('change', this.render);\n },\n\n star: function() {\n this.model.star();\n this.render();\n },\n\n unstar: function() {\n this.model.unstar();\n this.render();\n },\n\n full: function() {\n this.model.full();\n this.render();\n },\n\n render: function() {\n var h = $.tmpl(templates.item_template, { 'item': this.model.toJSON() });\n $(this.el).html(h);\n return this;\n },\n});\n\nvar ItemListView = Backbone.View.extend( {\n initialize: function() {\n _.bindAll(this, 'addOne', 'addAll', 'change', 'render', 'reset');\n // App.items.bind('add', this.addOne);\n App.items.bind('reset', this.reset);\n },\n addOne: function(item) {\n var view = new ItemView({'model': item});\n this.$el.append(view.render().el);\n },\n addAll: function(items) {\n // Posts.each(this.addOne);\n for(i in items) {\n item = items[i];\n var view = new ItemView({'model': item});\n this.$el.append(view.render().el);\n };\n },\n change: function() {\n },\n render: function() {\n },\n reset: function() {\n this.$el.children().remove();\n }\n});\n\nvar Tag = Backbone.Model.extend({\n});\n\nvar TagCollection = Backbone.Collection.extend({\n model: Tag,\n initialize: function() {\n _.bindAll(this, 'boot');\n },\n\n boot: function() {\n var t = this;\n $.getJSON('/tag/', function(data) {\n $.each(data, function(i,v) {\n var tag = new Tag(v);\n t.add(tag);\n });\n });\n }\n});\nApp.tags = new TagCollection();\n\n\nvar TagView = Backbone.View.extend({\n tagName: \"li\",\t\n className: \"tag\",\n events: {\n \"click\": \"filterTo\",\n },\n initialize: function() {\n _.bindAll(this, 'render', 'filterTo');\n this.model.bind('change', this.render);\n },\n render: function() {\n var h = $.tmpl(templates.tag_template, { 'tag': this.model.toJSON() });\n $(this.el).html(h);\n return this;\n },\n filterTo: function() {\n App.filterToTag(this.model);\n }\n});\n\n\nvar TagListView = Backbone.View.extend( {\n\n initialize: function() {\n _.bindAll(this, 'addOne', 'addAll', 'change', 'render');\n App.tags.bind('add', this.addOne);\n App.tags.bind('refresh', this.addAll);\n App.tags.bind('change', this.render);\n },\n addOne: function(tag) {\n var view = new TagView({'model': tag});\n this.$el.append(view.render().el);\n },\n addAll: function() {\n App.tags.each(this.addOne);\n },\n change: function() {\n },\n render: function() {\n },\n});\n\nApp.tag = undefined;\nApp.page = 0;\nApp.read_filter = 'unread';\n\n\nvar Feed = Backbone.Model.extend({\n idAttribute: \"_id\",\n});\n\nvar FeedCollection = Backbone.Collection.extend({\n model: Feed,\n url: '/feed/',\n\n initialize: function() {\n /// _.bindAll(this, 'boot');\n //console.log('initialized');\n },\n});\nApp.feeds = new FeedCollection();\n\nvar FeedView = Backbone.View.extend({\n tagName: \"li\",\n className: \"feed\",\n events: {\n \"click .txt\": \"filterTo\",\n \"click .delete\": \"del\",\n \"click .edit\": \"edit\",\n },\n initialize: function() {\n _.bindAll(this, 'render', 'filterTo', \"del\");\n this.model.bind('change', this.render);\n },\n render: function() {\n var h = $.tmpl(templates.feed_template, { 'feed': this.model.toJSON() });\n $(this.el).html(h);\n return this;\n },\n filterTo: function() {\n // console.log('filtering to feed ', this.model);\n App.filterToFeed(this.model);\n },\n del: function() {\n if( window.confirm(\"Unsubscribe from \" + this.model.get(\"url\") + \"?\" ) ) {\n this.model.destroy();\n this.$el.remove();\n }\n },\n edit: function() {\n var cat = window.prompt(\"Category for this feed?\", this.model.get(\"category\"));\n if (cat != null) {\n this.model.set(\"category\", cat);\n this.model.save();\n }\n },\n});\n\n\nvar FeedListView = Backbone.View.extend( {\n initialize: function() {\n _.bindAll(this, 'addOne', 'addAll', 'change', 'render');\n App.feeds.bind('add', this.addOne);\n App.feeds.bind('refresh', this.addAll);\n App.feeds.bind('change', this.render);\n },\n addOne: function(feed) {\n // console.log('adding a feed...', feed);\n var view = new FeedView({'model': feed});\n this.$el.append(view.render().el);\n },\n addAll: function() {\n // console.log('feed add all...');\n App.feeds.each(this.addOne);\n },\n change: function() {\n // console.log('feeds changed add all...');\n },\n render: function() {\n },\n});\n\n\n// var page = 0;\n// var read_filter = 'unread';\n\nvar selected_item = 0;\n\nfunction boot() {\n templates['item_template'] = $('#item_template').html();\n templates['tag_template'] = $('#tag_template').html();\n templates['feed_template'] = $('#feed_template').html();\n templates['controls_template'] = $('#controls_template').html();\n\n App.itemListView = new ItemListView();\n App.itemListView.setElement($('#items'));\n App.tagListView = new TagListView();\n App.tagListView.setElement($('#tags'));\n App.feedListView = new FeedListView();\n App.feedListView.setElement($('#feeds'));\n App.controlsView = new ControlsView({model: App});\n App.controlsView.setElement($('#controls'));\n App.controlsView.render();\n\n infini_scroll();\n\n $('#unread_filter').on('click', function() {\n App.read_filter = 'unread';\n App.items.reboot();\n });\n\n $('#all_filter').on('click', function() {\n App.read_filter = 'all';\n App.items.reboot();\n });\n\n// $('.logo').on('click', function() {\n // App.set('feedFilter', undefined);\n // App.items.reboot();\n\n// });\n\n // keyboard shortcuts\n $('body').keydown(function(event) {\n if(document.activeElement.id == \"search\") {\n return;\n }\n if (event.which == 74) {\n event.preventDefault();\n App.next();\n }\n if (event.which == 75) {\n event.preventDefault();\n App.previous();\n }\n if (event.which == 83) {\n event.preventDefault();\n App.star();\n }\n if (event.which == 70) {\n event.preventDefault();\n App.full();\n }\n });\n\n App.boot();\n}\n\n\n// // this is legacy code\n\nfunction infini_scroll() {\n if(App.loading) {\n }\n else {\n var dh = $('#items').height() - $(window).height();\n var st = $(window).scrollTop();\n if ( (dh-st) < 100 ){\n App.items.boot();\n }\n }\n window.setTimeout(infini_scroll, 1000);\n}\n\nvar ItemSelector = {\n selected_index: 0,\n}\n"), + FileModTime: time.Unix(1538709815, 0), + Content: string("var templates = {};\n\n$(document).ready(function() {\n if ( $(window).width() < 1024 ) {\n $('#filters').addClass('hidden');\n }\n document.body.className = localStorage.getItem('theme');\n boot();\n});\n\nvar AppModel = Backbone.Model.extend({\n defaults: {\n 'selectedIndex': 0,\n 'starredFilter': false,\n 'allFilter': false,\n 'unreadFilter': true,\n 'feedFilter': undefined,\n 'searchFilter': undefined\n },\n\n initialize: function() {\n this.bind('change:selectedIndex', this.scroll_to_selected);\n// this.bind('change:selectedIndex', this.scroll_to_selected)\n },\n\n boot: function() {\n this.items.boot();\n this.tags.boot();\n this.feeds.fetch({set: true, remove: false})\n window.setInterval(function() { App.update_read_status() }, 5000);\n },\n\n filterToFeed: function(feed) {\n if (feed.get('selected')) {\n feed.set('selected', false);\n this.set('feedFilter', undefined);\n }\n else {\n App.tags.models.forEach ( function (t) {\n t.set('selected', false);\n });\n App.tag = null;\n App.feeds.models.forEach ( function (f) {\n f.set('selected', false);\n });\n\n this.set('feedFilter', feed);\n feed.set('selected', true);\n }\n this.items.reboot();\n },\n\n filterToTag: function(tag) {\n App.tag = null;\n if (tag.get('selected')) {\n tag.set('selected', false);\n }\n else {\n App.tags.models.forEach ( function (t) {\n t.set('selected', false);\n });\n App.feeds.models.forEach ( function (f) {\n f.set('selected', false);\n });\n this.set('feedFilter', undefined);\n tag.set('selected', true);\n App.tag = tag.get('title');\n }\n App.items.reboot();\n },\n\n filterToStarred: function() {\n this.set('starredFilter', true);\n this.set('allFilter', false);\n this.set('unreadFilter', false);\n this.items.reboot();\n },\n\n filterToAll: function() {\n this.set('searchFilter', undefined);\n this.set('starredFilter', false);\n this.set('allFilter', true);\n this.set('unreadFilter', false);\n this.items.reboot();\n },\n\n filterToUnread: function() {\n this.set('starredFilter', false);\n this.set('allFilter', false);\n this.set('unreadFilter', true);\n this.items.reboot();\n },\n\n filterToSearch: function() {\n this.set('searchFilter', $('#search').val());\n this.set('starredFilter', false);\n this.set('allFilter', true);\n this.set('unreadFilter', false);\n this.items.reboot();\n },\n\n update_read_status: function() {\n var screen_top = $(window).scrollTop();\n var screen_bottom = $(window).scrollTop() + $(window).height();\n\n // // mark all visible items as read\n $.each($('.item'), function(i,v) {\n var item_top = $(v).offset().top;\n // console.log(\"i \", i, \"item_top \", item_top, \"screen_top \", screen_top, \"screen_bottom \", screen_bottom);\n\n if( (item_top < screen_top)) {\n App.items.at(i).markRead();\n // console.log('marking as read: ', i);\n }\n });\n// window.setTimeout(App.update_read_status, 5000);\n },\n\n scroll_to_selected: function() {\n var item = $('.item').eq(this.get('selectedIndex'));\n if(item.offset()) {\n var item_top = item.offset().top;\n $('.item').removeClass('selected');\n item.addClass('selected');\n $(window).scrollTop(item_top);\n }\n App.items.at(this.get('selectedIndex')).markRead();\n if(App.items.models.length>1) {\n if(this.get('selected')>=App.items.models.length-1) {\n App.items.boot();\n }\n }\n },\n\n next: function() {\n if(this.get('selectedIndex') < this.items.models.length-1) {\n this.set('selectedIndex', this.get('selectedIndex')+1);\n }\n if(this.get('selectedIndex') == this.items.models.length-1) {\n App.items.boot();\n }\n },\n\n previous: function() {\n if(this.get('selectedIndex') > 0) {\n this.set('selectedIndex', this.get('selectedIndex')-1);\n }\n },\n\n star: function() {\n if(this.get('selectedIndex') >= 0) {\n App.items.at(this.get('selectedIndex')).toggleStar();\n }\n },\n\n full: function() {\n if(this.get('selectedIndex') >= 0) {\n App.items.at(this.get('selectedIndex')).full();\n }\n }\n\n});\nvar App = new AppModel();\n\nvar ControlsView = Backbone.View.extend({\n className: 'controls',\n\n events: {\n 'click .starred_filter': 'filterToStarred',\n 'click .all_filter': 'filterToAll',\n 'click .unread_filter': 'filterToUnread',\n 'click .new_feed': 'newFeed',\n 'click .search_go': 'filterToSearch',\n 'click .light_theme': 'lightTheme',\n 'click .dark_theme': 'darkTheme',\n 'click .black_theme': 'blackTheme',\n },\n\n initialize: function() {\n _.bindAll(this, 'render');\n this.model.bind('change', this.render);\n },\n\n filterToStarred: function() {\n App.filterToStarred();\n },\n\n filterToAll: function() {\n App.filterToAll();\n },\n\n filterToUnread: function() {\n App.filterToUnread();\n },\n\n filterToSearch: function() {\n App.filterToSearch();\n },\n\n newFeed: function() {\n var feed_url = prompt('New url to subscribe to');\n var feed = new Feed({'url': feed_url});\n App.feeds.add(feed);\n feed.save();\n },\n\n render: function() {\n var h = $.tmpl(templates.controls_template, { 'app': this.model.toJSON() });\n $(this.el).html(h);\n return this;\n },\n\n lightTheme: function() {\n document.body.className = \"light\";\n localStorage.setItem(\"theme\", \"light\");\n },\n\n darkTheme: function() {\n document.body.className = \"dark\";\n localStorage.setItem(\"theme\", \"dark\");\n },\n\n blackTheme: function() {\n document.body.className = \"black\";\n localStorage.setItem(\"theme\", \"black\");\n },\n \n});\n\n\n\nvar Item = Backbone.Model.extend({\n idAttribute: \"_id\",\n url: '/item/',\n\n initialize: function() {\n var p_url = this.get('url');\n p_url = p_url.replace('https://', '');\n p_url = p_url.replace('http://', '');\n this.set('p_url', p_url);\n this.bind('change', this.maybeSave);\n },\n\n maybeSave: function() {\n if(this.hasChanged()) {\n this.save();\n }\n },\n\n markRead: function() {\n // recover if not tag\n if(this.get('read')) {\n return;\n }\n\n // var t = this.get('feed').tag;\n // var tag = App.tags.find(function(x){ return x.get('name') == t });\n this.set('read', true);\n // if(tag) {\n // tag.set('unread', tag.get('unread')-1);\n // }\n },\n\n toggleStar: function() {\n this.set({'starred': !(this.get('starred'))} );\n },\n\n star: function() {\n this.set({'starred': true});\n },\n\n unstar: function() {\n this.set({'starred': false});\n },\n\n full: function() {\n this.set({'full': !(this.get('full'))} );\n // this should just use this.fetch() but\n // it kept GETing from /item instead of /item/id\n // so just hacking this in for now\n\n if(this.get('full_content') == \"\") {\n $.getJSON('/item/' + this.get('_id'), function(data) {\n var i = App.items.get(data['_id'])\n i.set('full_content', data['full_content']);\n });\n }\n }\n\n});\n\n\nvar ItemCollection = Backbone.Collection.extend({\n model: Item,\n\n initialize: function() {\n _.bindAll(this, 'boot', 'reboot');\n },\n\n boot: function() {\n if(App.loading) {\n return;\n }\n if(App.noMore) {\n return;\n }\n\n App.loading = true;\n url = '/stream/';\n url=url+'?foo=bar'\n if(App.get('searchFilter')) {\n url = url + '&q=' + App.get('searchFilter');\n }\n if(App.get('feedFilter')) {\n url = url + '&feed_url=' + App.get('feedFilter').get('url');\n }\n if(App.get('starredFilter')) {\n url = url + '&starred=1';\n }\n if(App.tag != undefined) {\n url = url + '&tag=' + App.tag;\n }\n if(App.items.last()) {\n url = url + '&max_id=' + App.items.last().get('_id');\n }\n\n if(App.get('allFilter') || App.get('starredFilter')) {\n url = url + '&read_filter=all';\n }\n\n console.log('fetching from ', url);\n var t = this;\n $.getJSON(url, function(data) {\n var items = [];\n $.each(data, function(i,v) {\n var item = new Item(v);\n t.add(item);\n items.push(item);\n if(t.models.length==1){\n App.set('selectedIndex', 0);\n }\n });\n // console.log(\"items \", items)\n if(items.length == 0) {\n // console.log(\"no more items\");\n App.noMore = true;\n // App.loading = true;\n }\n else {\n App.loading = false;\n }\n // we wait and add them all at once for performance on mobile\n App.itemListView.addAll(items);\n\n });\n },\n\n reboot: function() {\n App.noMore = false;\n App.loading = false;\n this.reset();\n this.boot();\n },\n\n\n});\nApp.items = new ItemCollection();\n\n\nvar ItemView = Backbone.View.extend({\n tagName: \"div\",\n className: \"item\",\n template: templates.item_template,\n events: {\n \"click .star\": \"star\",\n \"click .unstar\": \"unstar\",\n \"click .full\": \"full\",\n },\n\n initialize: function() {\n _.bindAll(this, 'render', 'star');\n this.model.bind('change', this.render);\n },\n\n star: function() {\n this.model.star();\n this.render();\n },\n\n unstar: function() {\n this.model.unstar();\n this.render();\n },\n\n full: function() {\n this.model.full();\n this.render();\n },\n\n render: function() {\n var h = $.tmpl(templates.item_template, { 'item': this.model.toJSON() });\n $(this.el).html(h);\n return this;\n },\n});\n\nvar ItemListView = Backbone.View.extend( {\n initialize: function() {\n _.bindAll(this, 'addOne', 'addAll', 'change', 'render', 'reset');\n // App.items.bind('add', this.addOne);\n App.items.bind('reset', this.reset);\n },\n addOne: function(item) {\n var view = new ItemView({'model': item});\n this.$el.append(view.render().el);\n },\n addAll: function(items) {\n // Posts.each(this.addOne);\n for(i in items) {\n item = items[i];\n var view = new ItemView({'model': item});\n this.$el.append(view.render().el);\n };\n },\n change: function() {\n },\n render: function() {\n },\n reset: function() {\n this.$el.children().remove();\n }\n});\n\nvar Tag = Backbone.Model.extend({\n});\n\nvar TagCollection = Backbone.Collection.extend({\n model: Tag,\n initialize: function() {\n _.bindAll(this, 'boot');\n },\n\n boot: function() {\n var t = this;\n $.getJSON('/tag/', function(data) {\n $.each(data, function(i,v) {\n var tag = new Tag(v);\n t.add(tag);\n });\n });\n }\n});\nApp.tags = new TagCollection();\n\n\nvar TagView = Backbone.View.extend({\n tagName: \"li\",\t\n className: \"tag\",\n events: {\n \"click\": \"filterTo\",\n },\n initialize: function() {\n _.bindAll(this, 'render', 'filterTo');\n this.model.bind('change', this.render);\n },\n render: function() {\n var h = $.tmpl(templates.tag_template, { 'tag': this.model.toJSON() });\n $(this.el).html(h);\n return this;\n },\n filterTo: function() {\n App.filterToTag(this.model);\n }\n});\n\n\nvar TagListView = Backbone.View.extend( {\n\n initialize: function() {\n _.bindAll(this, 'addOne', 'addAll', 'change', 'render');\n App.tags.bind('add', this.addOne);\n App.tags.bind('refresh', this.addAll);\n App.tags.bind('change', this.render);\n },\n addOne: function(tag) {\n var view = new TagView({'model': tag});\n this.$el.append(view.render().el);\n },\n addAll: function() {\n App.tags.each(this.addOne);\n },\n change: function() {\n },\n render: function() {\n },\n});\n\nApp.tag = undefined;\nApp.page = 0;\nApp.read_filter = 'unread';\n\n\nvar Feed = Backbone.Model.extend({\n idAttribute: \"_id\",\n});\n\nvar FeedCollection = Backbone.Collection.extend({\n model: Feed,\n url: '/feed/',\n\n initialize: function() {\n /// _.bindAll(this, 'boot');\n //console.log('initialized');\n },\n});\nApp.feeds = new FeedCollection();\n\nvar FeedView = Backbone.View.extend({\n tagName: \"li\",\n className: \"feed\",\n events: {\n \"click .txt\": \"filterTo\",\n \"click .delete\": \"del\",\n \"click .edit\": \"edit\",\n },\n initialize: function() {\n _.bindAll(this, 'render', 'filterTo', \"del\");\n this.model.bind('change', this.render);\n },\n render: function() {\n var h = $.tmpl(templates.feed_template, { 'feed': this.model.toJSON() });\n $(this.el).html(h);\n return this;\n },\n filterTo: function() {\n // console.log('filtering to feed ', this.model);\n App.filterToFeed(this.model);\n },\n del: function() {\n if( window.confirm(\"Unsubscribe from \" + this.model.get(\"url\") + \"?\" ) ) {\n this.model.destroy();\n this.$el.remove();\n }\n },\n edit: function() {\n var cat = window.prompt(\"Category for this feed?\", this.model.get(\"category\"));\n if (cat != null) {\n this.model.set(\"category\", cat);\n this.model.save();\n }\n },\n});\n\n\nvar FeedListView = Backbone.View.extend( {\n initialize: function() {\n _.bindAll(this, 'addOne', 'addAll', 'change', 'render');\n App.feeds.bind('add', this.addOne);\n App.feeds.bind('refresh', this.addAll);\n App.feeds.bind('change', this.render);\n },\n addOne: function(feed) {\n // console.log('adding a feed...', feed);\n var view = new FeedView({'model': feed});\n this.$el.append(view.render().el);\n },\n addAll: function() {\n // console.log('feed add all...');\n App.feeds.each(this.addOne);\n },\n change: function() {\n // console.log('feeds changed add all...');\n },\n render: function() {\n },\n});\n\n\n// var page = 0;\n// var read_filter = 'unread';\n\nvar selected_item = 0;\n\nfunction boot() {\n templates['item_template'] = $('#item_template').html();\n templates['tag_template'] = $('#tag_template').html();\n templates['feed_template'] = $('#feed_template').html();\n templates['controls_template'] = $('#controls_template').html();\n\n App.itemListView = new ItemListView();\n App.itemListView.setElement($('#items'));\n App.tagListView = new TagListView();\n App.tagListView.setElement($('#tags'));\n App.feedListView = new FeedListView();\n App.feedListView.setElement($('#feeds'));\n App.controlsView = new ControlsView({model: App});\n App.controlsView.setElement($('#controls'));\n App.controlsView.render();\n\n infini_scroll();\n\n $('#unread_filter').on('click', function() {\n App.read_filter = 'unread';\n App.items.reboot();\n });\n\n $('#all_filter').on('click', function() {\n App.read_filter = 'all';\n App.items.reboot();\n });\n\n// $('.logo').on('click', function() {\n // App.set('feedFilter', undefined);\n // App.items.reboot();\n\n// });\n\n // keyboard shortcuts\n $('body').keydown(function(event) {\n if(document.activeElement.id == \"search\") {\n return;\n }\n if (event.which == 74) {\n event.preventDefault();\n App.next();\n }\n if (event.which == 75) {\n event.preventDefault();\n App.previous();\n }\n if (event.which == 83) {\n event.preventDefault();\n App.star();\n }\n });\n\n App.boot();\n}\n\n\n// // this is legacy code\n\nfunction infini_scroll() {\n if(App.loading) {\n }\n else {\n var dh = $('#items').height() - $(window).height();\n var st = $(window).scrollTop();\n if ( (dh-st) < 100 ){\n App.items.boot();\n }\n }\n window.setTimeout(infini_scroll, 1000);\n}\n\nvar ItemSelector = {\n selected_index: 0,\n}\n"), } filee := &embedded.EmbeddedFile{ Filename: "underscore-1.8.3.min.js", @@ -82,7 +82,7 @@ func init() { // define dirs dir1 := &embedded.EmbeddedDir{ Filename: "", - DirModTime: time.Unix(1538242832, 0), + DirModTime: time.Unix(1538709815, 0), ChildFiles: []*embedded.EmbeddedFile{ file2, // ".DS_Store" file3, // "backbone-1.3.3.min.js" @@ -108,7 +108,7 @@ func init() { // register embeddedBox embedded.RegisterEmbeddedBox(`../static`, &embedded.EmbeddedBox{ Name: `../static`, - Time: time.Unix(1538242832, 0), + Time: time.Unix(1538709815, 0), Dirs: map[string]*embedded.EmbeddedDir{ "": dir1, }, |