From 9d51e999ba95e4b58328e38c89ccd3c0ece88a8a Mon Sep 17 00:00:00 2001 From: Samuel Clay Date: Tue, 19 Oct 2010 20:57:25 -0400 Subject: [PATCH 01/13] First draft of brand new dual-mode classifiers. Both tumbs up and thumbs down in the same classifier. Hover behavior works, not much else, so far. --- media/css/reader.css | 98 ++++++++++----- media/js/inflector.js | 158 +++++++++++++++++++++++++ media/js/newsblur/reader_classifier.js | 136 +++++++++++---------- settings.py | 1 + 4 files changed, 302 insertions(+), 91 deletions(-) create mode 100644 media/js/inflector.js diff --git a/media/css/reader.css b/media/css/reader.css index eaecb01b5..f55437b69 100644 --- a/media/css/reader.css +++ b/media/css/reader.css @@ -1922,7 +1922,7 @@ a.NB-splash-link:hover { .NB-classifier .NB-classifier-tag label { } -.NB-classifier .NB-classifier-tag-count { +.NB-classifier .NB-classifier-count { font-size: 10px; font-weight: bold; margin: 0 6px 0 2px; @@ -2263,9 +2263,11 @@ background: transparent; display: block; margin: 2px 6px 6px 0; cursor: pointer; - padding: 0 9px 0 4px; + padding: 0 34px 0 26px; font-size: 12px; text-transform: uppercase; + background-color: #F5CD09; + position: relative; } .NB-classifiers .NB-classifier input[type=checkbox] { @@ -2283,43 +2285,81 @@ background: transparent; } .NB-classifiers .NB-classifier label b { - color: #303030; + color: #957D09; text-shadow: none; font-weight: normal; } -.NB-classifiers .NB-classifier.NB-classifier-tag { - background-color: #FFA200; -} -.NB-classifiers .NB-classifier.NB-classifier-tag label { - text-shadow: 1px 1px 0 #cF7200; -} - -.NB-classifiers .NB-classifier.NB-classifier-title { - background-color: #FF7940; -} -.NB-classifiers .NB-classifier.NB-classifier-title label { - text-shadow: 1px 1px 0 #cF4910; -} - -.NB-classifiers .NB-classifier.NB-classifier-author { - background-color: #60D6A7; -} -.NB-classifiers .NB-classifier.NB-classifier-author label { - text-shadow: 1px 1px 0 #30a677; -} - -.NB-classifiers .NB-classifier.NB-classifier-publisher { - background-color: #6a93d4; -} -.NB-classifiers .NB-classifier.NB-classifier-publisher label { - text-shadow: 1px 1px 0 #3A63A4; +.NB-classifiers .NB-classifier label span { + text-shadow: 1px 1px 0 #F4E576; } .NB-classifiers .NB-classifier.NB-classifier-facet-disabled { background-color: white; } +.NB-classifiers .NB-classifier input { + display: none; +} + +.NB-classifiers .NB-classifier .feed_favicon { + margin-top: -2px; +} + +.NB-classifiers .NB-classifier .NB-classifier-icon-like { + width: 16px; + height: 16px; + background: transparent url('../img/reader/thumbs-up.png') no-repeat 0 0; + position: absolute; + left: 6px; + top: 2px; +} + +.NB-classifiers .NB-classifier .NB-classifier-icon-dislike { + width: 26px; + height: 20px; + position: absolute; + top: 0; + right: 0; + background: transparent url('../img/reader/thumbs-down.png') no-repeat 6px -2px; +} + +.NB-classifiers .NB-classifier .NB-classifier-icon-dislike-inner { + margin: 4px 4px 0 0; + width: 18px; + height: 13px; + border-left: 1px solid #F5E529; +} + +.NB-classifiers .NB-classifier.NB-classifier-hover-like { + background-color: #54B54E; +} +.NB-classifiers .NB-classifier.NB-classifier-hover-like label b { + color: white; +} +.NB-classifiers .NB-classifier.NB-classifier-hover-like label span { + color: white; + text-shadow: 1px 1px 0 #254E18; +} +.NB-classifiers .NB-classifier.NB-classifier-hover-like .NB-classifier-icon-dislike { + opacity: .1; +} +.NB-classifiers .NB-classifier.NB-classifier-hover-dislike { + background-color: #C92123; +} +.NB-classifiers .NB-classifier.NB-classifier-hover-dislike label b { + color: white; +} +.NB-classifiers .NB-classifier.NB-classifier-hover-dislike label span { + color: white; + text-shadow: 1px 1px 0 #7F1012; +} +.NB-classifiers .NB-classifier.NB-classifier-hover-dislike .NB-classifier-icon-dislike { + opacity: 1; +} +.NB-classifiers .NB-classifier.NB-classifier-hover-dislike .NB-classifier-icon-like { + opacity: .1; +} /* =================== */ /* = Mouse Indicator = */ /* =================== */ diff --git a/media/js/inflector.js b/media/js/inflector.js new file mode 100644 index 000000000..721059e86 --- /dev/null +++ b/media/js/inflector.js @@ -0,0 +1,158 @@ +// Naive English transformations on words. +window.Inflector = { + + small : "(a|an|and|as|at|but|by|en|for|if|in|of|on|or|the|to|v[.]?|via|vs[.]?)", + punct : "([!\"#$%&'()*+,./:;<=>?@[\\\\\\]^_`{|}~-]*)", + + // Titleize function by John Resig after John Gruber. MIT Licensed. + titleize : function(s) { + s = s.replace(/[-.\/_]/g, ' ').replace(/\s+/gm, ' '); + var cap = this.capitalize; + var parts = [], split = /[:.;?!] |(?: |^)["Ò]/g, index = 0; + while (true) { + var m = split.exec(s); + parts.push( s.substring(index, m ? m.index : s.length) + .replace(/\b([A-Za-z][a-z.'Õ]*)\b/g, function(all){ + return (/[A-Za-z]\.[A-Za-z]/).test(all) ? all : cap(all); + }) + .replace(RegExp("\\b" + this.small + "\\b", "ig"), this.lowercase) + .replace(RegExp("^" + this.punct + this.small + "\\b", "ig"), function(all, punct, word) { + return punct + cap(word); + }) + .replace(RegExp("\\b" + this.small + this.punct + "$", "ig"), cap)); + index = split.lastIndex; + if ( m ) parts.push( m[0] ); + else break; + } + return parts.join("").replace(/ V(s?)\. /ig, " v$1. ") + .replace(/(['Õ])S\b/ig, "$1s") + .replace(/\b(AT&T|Q&A)\b/ig, function(all){ + return all.toUpperCase(); + }); + }, + + // Delegate to the ECMA5 String.prototype.trim function, if available. + trim : function(s) { + return s.trim ? s.trim() : s.replace(/^\s+|\s+$/g, ''); + }, + + // Trim leading and trailing non-whitespace characters, and add ellipses. + // Try to find natural breaks in the sentence, and avoid breaking HTML fragments. + trimExcerpt : function(s) { + s = s.replace(/^([^<>]{0,100}?[.,!]|[^<>\s]+)/g, ''); + s = s.replace(/(([.,!]\s?)[^<>]{0,100}?|[^<>\s]+)$/g, '$2'); + return '…' + s + '…'; + }, + + camelize : function(s) { + var parts = s.split('-'), len = parts.length; + if (len == 1) return parts[0]; + + var camelized = s.charAt(0) == '-' + ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1) + : parts[0]; + + for (var i = 1; i < len; i++) + camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1); + + return camelized; + }, + + lowercase : function(s) { + return s.toLowerCase(); + }, + + capitalize : function(s) { + return s.charAt(0).toUpperCase() + s.substring(1).toLowerCase(); + }, + + underscore : function(s) { + return s.replace(/::/g, '/').replace(/([A-Z]+)([A-Z][a-z])/g,'$1_$2').replace(/([a-z\d])([A-Z])/g,'$1_$2').replace(/-/g,'_').toLowerCase(); + }, + + spacify : function(s) { + return s.replace(/_/g, ' '); + }, + + dasherize : function(s) { + return s.replace(/_/g,'-'); + }, + + singularize : function(s) { + return s.replace(/s$/, ''); + }, + + // Only works for words that pluralize by adding an 's', end in a 'y', or + // that we've special-cased. Not comprehensive. + pluralize : function(s, count) { + if (count == 1) return s; + if (s == 'person') return 'people'; + if (s.match(/y$/i)) return s.replace(/y$/i, 'ies'); + return s + 's'; + }, + + classify : function(s) { + return this.camelize(this.capitalize(this.dasherize(this.singularize(s)))); + }, + + possessivize : function(s) { + var endsInS = s.charAt(s.length - 1) == 's'; + return s + (endsInS ? "'" : "'s"); + }, + + truncate : function(s, length, truncation) { + length = length || 30; + truncation = _.isUndefined(truncation) ? '...' : truncation; + return s.length > length ? s.slice(0, length - truncation.length) + truncation : s; + }, + + // Convert a string (usually a title), to something appropriate for use in a URL. + // Apostrophes and quotes are removed, non-word-chars become spaces, whitespace + // is trimmed, lowercased, and spaces become dashes. + sluggify : function(s) { + return $.trim(s.replace(/['"]+/g, '').replace(/\W+/g, ' ')).toLowerCase().replace(/\s+/g, '-'); + }, + + commify : function(list, options) { + var words = []; + _.each(list, function(word, i) { + if (options.quote) word = '"' + word + '"'; + words.push(word); + var end = i == list.length - 1 ? '' : + (i == list.length - 2) && options.conjunction ? ', ' + options.conjunction + ' ' : + ', '; + words.push(end); + }); + return words.join(''); + }, + + // Convert bytes into KB or MB + bytesToMB : function(bytes) { + var byteSize = Math.round(bytes / 1024 * 100) * 0.01; + var suffix = 'KB'; + if (byteSize > 1000) { + byteSize = Math.round(byteSize * 0.001 * 100) * 0.01; + suffix = 'MB'; + } + var sizeParts = byteSize.toString().split('.'); + byteSize = sizeParts[0] + (sizeParts.length > 1 ? '.' + sizeParts[1].substr(0,1) : ''); + return byteSize + ' ' + suffix; + }, + + // Normalize an entered-by-hand url, trimming and adding the protocol, if missing. + normalizeUrl : function(s) { + s = Inflector.trim(s); + if (!s) return null; + return (/^https?:\/\//).test(s) ? s : 'http://' + s; + }, + + // From Prototype.js. Strip out HTML tags. + stripTags : function(s) { + return s.replace(/<\w+(\s+("[^"]*"|'[^']*'|[^>])+)?>|<\/\w+>/gi, ''); + }, + + escapeRegExp : function(s) { + return s.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1'); + } + +}; \ No newline at end of file diff --git a/media/js/newsblur/reader_classifier.js b/media/js/newsblur/reader_classifier.js index 3fac7ae1a..6fd98459e 100644 --- a/media/js/newsblur/reader_classifier.js +++ b/media/js/newsblur/reader_classifier.js @@ -64,7 +64,7 @@ NEWSBLUR.ReaderClassifierStory = function(story_id, feed_id, options) { this.runner_story(); }; -var classifier = { +var classifier_prototype = { runner_trainer: function() { this.user_classifiers = {}; @@ -512,21 +512,8 @@ var classifier = { && this.user_classifiers.authors[author] == this.score) { input_attrs['checked'] = 'checked'; } - - var $author = $.make('span', { className: 'NB-classifier-container NB-classifier-author-container' }, [ - $.make('span', { className: 'NB-classifier NB-classifier-author' }, [ - $.make('input', input_attrs), - $.make('label', { 'for': 'classifier_author_'+a }, [ - $.make('b', 'Author: '), - $.make('span', author) - ]) - ]), - (author_count && $.make('span', { className: 'NB-classifier-tag-count' }, [ - '× ', - author_count - ])) - ]); - $authors.push($author); + + var $author = this.make_classifier(author, author, 'author', author_count); $authors.push($author); } return $authors; }, @@ -546,58 +533,83 @@ var classifier = { if (!tag) continue; - var input_attrs = { - type: 'checkbox', - name: opinion+'tag', - value: tag, - id: 'classifier_tag_'+t - }; - - if (tag in this.user_classifiers.tags && this.user_classifiers.tags[tag] == this.score) { - input_attrs['checked'] = 'checked'; - } - - var $tag = $.make('span', { className: 'NB-classifier-container NB-classifier-tag-container' }, [ - $.make('span', { className: 'NB-classifier NB-classifier-tag' }, [ - $.make('input', input_attrs), - $.make('label', { 'for': 'classifier_tag_'+t }, [ - $.make('b', 'Tag: '), - $.make('span', tag) - ]) - ]), - (tag_count && $.make('span', { className: 'NB-classifier-tag-count' }, [ - '× ', - tag_count - ])) - ]); + var $tag = this.make_classifier(tag, tag, 'tag', tag_count); $tags.push($tag); } return $tags; }, - - make_publisher: function(publisher, opinion) { - var input_attrs = { - type: 'checkbox', - name: opinion+'publisher', - value: this.feed_id, - id: 'classifier_publisher', - checked: false - }; - if (this.user_classifiers.feeds[this.feed_id] == this.score) { - input_attrs['checked'] = true; + + make_classifier: function(classifier_title, classifier_value, classifier_type, classifier_count) { + var score = 0; + NEWSBLUR.log(['make_classifier', this.user_classifiers, classifier_title, classifier_value, classifier_type, classifier_count]); + if (classifier_value in this.user_classifiers[classifier_type+'s']) { + score = this.user_classifiers[classifier_type+'s'][classifier_value]; } - var $publisher = $.make('div', { className: 'NB-classifier NB-classifier-publisher' }, [ - $.make('input', input_attrs), - $.make('label', { 'for': 'classifier_publisher' }, [ - $.make('img', { className: 'feed_favicon', src: this.google_favicon_url + publisher.feed_link }), - $.make('span', { className: 'feed_title' }, [ - $.make('b', 'Publisher: '), - $.make('span', publisher.feed_title) + var classifier_type_title = Inflector.capitalize(classifier_type=='feed' ? + 'publisher' : + classifier_type); + + var $classifier = $.make('span', { className: 'NB-classifier-container' }, [ + $.make('span', { className: 'NB-classifier NB-classifier-'+classifier_type }, [ + $.make('input', { + type: 'checkbox', + className: 'NB-classifier-input-like', + name: 'like_'+classifier_type, + value: classifier_value + }), + $.make('input', { + type: 'checkbox', + className: 'NB-classifier-input-dislike', + name: 'dislike_'+classifier_type, + value: classifier_value + }), + $.make('div', { className: 'NB-classifier-icon-like' }), + $.make('div', { className: 'NB-classifier-icon-dislike' }, [ + $.make('div', { className: 'NB-classifier-icon-dislike-inner' }) + ]), + $.make('label', [ + (classifier_type == 'feed' && + $.make('img', { + className: 'feed_favicon', + src: this.google_favicon_url + this.feed.feed_link + })), + $.make('b', classifier_type_title+': '), + $.make('span', classifier_title) ]) - ]) + ]), + (classifier_count && $.make('span', { className: 'NB-classifier-count' }, [ + '× ', + classifier_count + ])) ]); + + if (score > 0) { + $classifier.addClass('NB-classifier-like'); + $('.NB-classifier-input-like', $classifier).attr('checked', true); + } else if (score < 0) { + $classifier.addClass('NB-classifier-dislike'); + $('.NB-classifier-input-dislike', $classifier).attr('checked', true); + } + + $('.NB-classifier', $classifier).bind('mouseover', function(e) { + $(e.currentTarget).addClass('NB-classifier-hover-like'); + }).bind('mouseout', function(e) { + $(e.currentTarget).removeClass('NB-classifier-hover-like'); + }); + + $('.NB-classifier-icon-dislike', $classifier).bind('mouseover', function(e) { + $('.NB-classifier', $classifier).addClass('NB-classifier-hover-dislike'); + }).bind('mouseout', function(e) { + $('.NB-classifier', $classifier).removeClass('NB-classifier-hover-dislike'); + }); + + return $classifier; + }, + + make_publisher: function(publisher, opinion) { + var $publisher = this.make_classifier(publisher.feed_title, this.feed_id, 'feed'); return $publisher; }, @@ -800,6 +812,6 @@ var classifier = { }; -NEWSBLUR.ReaderClassifierStory.prototype = classifier; -NEWSBLUR.ReaderClassifierFeed.prototype = classifier; -NEWSBLUR.ReaderClassifierTrainer.prototype = classifier; +NEWSBLUR.ReaderClassifierStory.prototype = classifier_prototype; +NEWSBLUR.ReaderClassifierFeed.prototype = classifier_prototype; +NEWSBLUR.ReaderClassifierTrainer.prototype = classifier_prototype; diff --git a/settings.py b/settings.py index e634a3814..19c7b721c 100644 --- a/settings.py +++ b/settings.py @@ -85,6 +85,7 @@ COMPRESS_JS = { 'all': { 'source_filenames': ( 'js/jquery-1.4.2.js', + 'js/inflector.js', 'js/jquery.json.js', 'js/jquery.easing.js', 'js/jquery.newsblur.js', From 08c31b3645638cc14cc2cc097bc1ec7ce65a5fc1 Mon Sep 17 00:00:00 2001 From: Samuel Clay Date: Tue, 19 Oct 2010 22:41:30 -0400 Subject: [PATCH 02/13] Finished up interaction for new dual-mode classifiers. Still need to serialize classifiers, then perhaps reprocess on the backend to handle both modes at once. --- media/css/reader.css | 42 +++++++-- media/img/reader/thumbs-down.png | Bin 1489 -> 421 bytes media/img/reader/thumbs-up.png | Bin 1388 -> 358 bytes media/js/newsblur/reader_classifier.js | 117 +++++++++++-------------- urls.py | 4 - 5 files changed, 89 insertions(+), 74 deletions(-) diff --git a/media/css/reader.css b/media/css/reader.css index f55437b69..f8456f62e 100644 --- a/media/css/reader.css +++ b/media/css/reader.css @@ -2268,6 +2268,7 @@ background: transparent; text-transform: uppercase; background-color: #F5CD09; position: relative; + border: 1px solid transparent; } .NB-classifiers .NB-classifier input[type=checkbox] { @@ -2316,12 +2317,12 @@ background: transparent; } .NB-classifiers .NB-classifier .NB-classifier-icon-dislike { - width: 26px; - height: 20px; + width: 27px; + height: 22px; position: absolute; - top: 0; - right: 0; - background: transparent url('../img/reader/thumbs-down.png') no-repeat 6px -2px; + top: -1px; + right: -1px; + background: transparent url('../img/reader/thumbs-down.png') no-repeat 5px -1px; } .NB-classifiers .NB-classifier .NB-classifier-icon-dislike-inner { @@ -2331,32 +2332,63 @@ background: transparent; border-left: 1px solid #F5E529; } +.NB-classifiers .NB-classifier.NB-classifier-like { + background-color: #54B54E; + border: 1px solid #202020; + -webkit-box-shadow: 1px 1px 1px #BDC0D7; + -moz-box-shadow: 1px 1px 1px #BDC0D7; + box-shadow: 1px 1px 1px #BDC0D7; +} +.NB-classifiers .NB-classifier.NB-classifier-dislike { + background-color: #C92123; + border: 1px solid #000; + -webkit-box-shadow: 1px 1px 1px #BDC0D7; + -moz-box-shadow: 1px 1px 1px #BDC0D7; + box-shadow: 1px 1px 1px #BDC0D7; +} + .NB-classifiers .NB-classifier.NB-classifier-hover-like { background-color: #54B54E; } +.NB-classifiers .NB-classifier.NB-classifier-dislike.NB-classifier-hover-like { + border: 1px solid transparent; +} +.NB-classifiers .NB-classifier.NB-classifier-like label b, .NB-classifiers .NB-classifier.NB-classifier-hover-like label b { color: white; } +.NB-classifiers .NB-classifier.NB-classifier-like label span, .NB-classifiers .NB-classifier.NB-classifier-hover-like label span { color: white; text-shadow: 1px 1px 0 #254E18; } +.NB-classifiers .NB-classifier.NB-classifier-like .NB-classifier-icon-dislike, .NB-classifiers .NB-classifier.NB-classifier-hover-like .NB-classifier-icon-dislike { opacity: .1; } .NB-classifiers .NB-classifier.NB-classifier-hover-dislike { background-color: #C92123; } +.NB-classifiers .NB-classifier.NB-classifier-like.NB-classifier-hover-dislike { + border: 1px solid transparent; +} +.NB-classifiers .NB-classifier.NB-classifier-dislike.NB-classifier-hover-like.NB-classifier-hover-dislike { + border: 1px solid #000; +} +.NB-classifiers .NB-classifier.NB-classifier-dislike label b, .NB-classifiers .NB-classifier.NB-classifier-hover-dislike label b { color: white; } +.NB-classifiers .NB-classifier.NB-classifier-dislike label span, .NB-classifiers .NB-classifier.NB-classifier-hover-dislike label span { color: white; text-shadow: 1px 1px 0 #7F1012; } +.NB-classifiers .NB-classifier.NB-classifier-dislike .NB-classifier-icon-dislike, .NB-classifiers .NB-classifier.NB-classifier-hover-dislike .NB-classifier-icon-dislike { opacity: 1; } +.NB-classifiers .NB-classifier.NB-classifier-dislike .NB-classifier-icon-like, .NB-classifiers .NB-classifier.NB-classifier-hover-dislike .NB-classifier-icon-like { opacity: .1; } diff --git a/media/img/reader/thumbs-down.png b/media/img/reader/thumbs-down.png index 1b542db7ab2b69454c916960aba1c5d91143c6b1..6756e1d91f944c58a022ae76e521a764bc45b486 100644 GIT binary patch delta 232 zcmV3hM!aiw#Ms4}ag>`1AVu?^oCUyt?-5<<*}ruKaj<;ro;G-yWZPcjx%i zD+g|!+;;Kc`U?lv@87?F-@bj@wr$(Gb?d$j^S7>;v1R%6&C8}&S65e6RaI0}FflPP zGBN_~xpL%EEs#Kj;0+;nChP=yRgMR0yvNqJ&XDuZK6ep0G}TV_#ed45rL zv4V53@r-M3zyM(p1gVSg^|4CM&(%u=DbuUSEnu**uP8`N&Q2{+NJ>r5%(GQeP*6}( z$V{%1*XSQL?w=vZ=5FYR*k9NmQuF&B-gas<2f8 zn`s4PgM{^!6u?SKvTcwn?Gt^BsFg8&zG1D_LH?lN0(@_XcEK%@E z%u_HjS1>X#01`%4hK5!qhCs)Ffs!2;khUpGNwW%aaf8|k1^l#~=$>Fbx5m+O@q z>*W`v>l<2HTIw4Z=^Gj80#)c1SLT%@R_NvxD?xrs^nr6smX zN+65i0P4BK0=Pwa#n8Y52BUsOVu8M)o`F8xWS~YHpr92v#`23o^7C`-utbRsNGFOS zgslkusV<2nsdm8du+TL$&^0m*F|@EUHn%b|jY857QG}-5H$NpatrAJQp{{{Rh=G}v zshO3D2~<0hBB*v7eNaFk1q?XUL4HCLS0E5zDar8gDkv?=0Y^(pvVLk#YHn&?Nii_Y z3{k@@CD|%1zbH4c#4a;8F+EkkATQlUA0dd>eGpdzlLatY>ci6|%<1r`qzMBN?ldtT zVkj*wxnj_704zibJzX3_B&KdXcbl)tK!D{!?$rr-45ClfF3kM@-)lRo(}%mCubf=6 zTlOUU#3pZ1b)(^Pgg&ebxsLQ00!mW AHvj+t diff --git a/media/img/reader/thumbs-up.png b/media/img/reader/thumbs-up.png index 30c31e9b400272e6853698f2dc6aaac2d4601c07..4fdf2d59d8e1be546295dcdf8a0cb89e45893f54 100644 GIT binary patch delta 277 zcmaFE^^9qPL_G&H0|P_X?LTrrin-XyGlYYK4*BR*8G8c2zj1o;Is0L?-NQvU-s{L%-i;4JWnEM{QfdJV#iP2Idv6KA>>m=F|7#~q`Te3~4AdP%Xm!M|n&;E0V-4)%{TyfXM9mt}C*r`ygnOb(m81Ap->Cj;Xaae37bJ6W0^z>90obZ#EToERs1>vCFp3z}E6BVS)kmOB}O#!Pf&0}&BA`zsM!-~PD{bVjC zkN2jVCP5B@hWuo{rk+R)1XUdZr=6uF#^D4`x1IBFUXS|%h>Hkxhzj65fMXcEa6HTM zP8JuF8)U$Wtxr$%^WCAgLQZ`0lYp!^?JQD!_gc^VFYE2Do9LI zig7j{WH(L-8j>z+IbF@TVxKyK{3K~6DvrYCM6H-eF$&^g8R@jB(X5@Ji;*$Whn;+` zW2!Ew>TuvME%BMmJ)lz75+8;{1Or%)Mv7%9&Lyyoyu-tDt}A8yJZK+1q9)}2(K0$q zF;0PT^DZ~_1=k6;O@sFyaP59ivFkZ3pzlTbkh){Nb& zSwiCbRXr)9fSeQuAgw6_KDy-mXMOpq@w33sk}kf>-O`J#JdjOE_X7!^4|La~NGuJzs##fGw1|E!Uonh9;ve9rjJh4GFOlG!kZ&chk^u6KL zsrvfLpSCX}Xny7w`|N7!^Rf(fPD}=jx>=j$zPr{&0Ogz~RJ}Eh;}hZ5Xy{Q(@Ax0r C*@').html(story.story_title).text(); this.$modal = $.make('div', { className: 'NB-classifier NB-modal' }, [ - this.make_modal_intelligence_slider(), $.make('h2', { className: 'NB-modal-title' }), $.make('form', { method: 'post' }, [ (story.story_title && $.make('div', { className: 'NB-modal-field NB-fieldset' }, [ @@ -452,40 +451,6 @@ var classifier_prototype = { $count.html(count + '/' + total); }, - make_modal_intelligence_slider: function() { - var self = this; - var $slider = $.make('div', { className: 'NB-taskbar-intelligence NB-modal-slider' }, [ - $.make('div', { className: 'NB-taskbar-intelligence-indicator NB-taskbar-intelligence-negative' }), - $.make('div', { className: 'NB-taskbar-intelligence-indicator NB-taskbar-intelligence-neutral' }), - $.make('div', { className: 'NB-taskbar-intelligence-indicator NB-taskbar-intelligence-positive' }), - $.make('div', { className: 'NB-intelligence-slider' }) - ]); - - $('.NB-intelligence-slider', $slider).slider({ - range: 'max', - min: 0, - max: 2, - step: 2, - value: this.score + 1, - slide: function(e, ui) { - // self.switch_feed_view_unread_view(ui.value); - self.score = ui.value - 1; - self.make_modal_title(); - $('input[name^=like],input[name^=dislike]', self.$modal).attr('name', function(i, current_name) { - if (self.score == -1) { - return 'dis' + current_name.substr(current_name.indexOf('like_')); - } else if (self.score == 1) { - return current_name.substr(current_name.indexOf('like_')); - } - }); - var $submit = $('input[type=submit]', self.$modal); - $submit.removeClass("NB-disabled").removeAttr('disabled').attr('value', 'Save'); - } - }); - - return $slider; - }, - make_authors: function(authors, opinion) { var $authors = []; @@ -501,19 +466,8 @@ var classifier_prototype = { if (!author) continue; - var input_attrs = { - type: 'checkbox', - name: opinion+'author', - value: author, - id: 'classifier_author_'+a - }; - - if (author in this.user_classifiers.authors - && this.user_classifiers.authors[author] == this.score) { - input_attrs['checked'] = 'checked'; - } - - var $author = this.make_classifier(author, author, 'author', author_count); $authors.push($author); + var $author = this.make_classifier(author, author, 'author', author_count); + $authors.push($author); } return $authors; }, @@ -540,9 +494,13 @@ var classifier_prototype = { return $tags; }, + make_publisher: function(publisher, opinion) { + var $publisher = this.make_classifier(publisher.feed_title, this.feed_id, 'feed'); + return $publisher; + }, + make_classifier: function(classifier_title, classifier_value, classifier_type, classifier_count) { var score = 0; - NEWSBLUR.log(['make_classifier', this.user_classifiers, classifier_title, classifier_value, classifier_type, classifier_count]); if (classifier_value in this.user_classifiers[classifier_type+'s']) { score = this.user_classifiers[classifier_type+'s'][classifier_value]; } @@ -608,20 +566,33 @@ var classifier_prototype = { return $classifier; }, - make_publisher: function(publisher, opinion) { - var $publisher = this.make_classifier(publisher.feed_title, this.feed_id, 'feed'); - return $publisher; - }, - - make_title: function(title, t, opinion) { - var $title = $.make('div', { className: 'NB-classifier NB-classifier-title' }, [ - $.make('input', { type: 'checkbox', name: opinion+'title', value: title, id: 'classifier_title_'+t, checked: 'checked' }), - $.make('label', { 'for': 'classifier_title_'+t }, [ - $.make('b', 'Title: '), - $.make('span', title) - ]) - ]); - return $title; + change_classifier: function($classifier, classifier_opinion) { + var $like = $('.NB-classifier-input-like', $classifier); + var $dislike = $('.NB-classifier-input-dislike', $classifier); + + if (classifier_opinion == 'like') { + if ($classifier.is('.NB-classifier-like')) { + $classifier.removeClass('NB-classifier-like'); + $dislike.attr('checked', false).trigger('change'); + $like.attr('checked', false).trigger('change'); + } else { + $classifier.removeClass('NB-classifier-dislike'); + $classifier.addClass('NB-classifier-like'); + $dislike.attr('checked', false).trigger('change'); + $like.attr('checked', true).trigger('change'); + } + } else if (classifier_opinion == 'dislike') { + if ($classifier.is('.NB-classifier-dislike')) { + $classifier.removeClass('NB-classifier-dislike'); + $like.attr('checked', false).trigger('change'); + $dislike.attr('checked', false).trigger('change'); + } else { + $classifier.removeClass('NB-classifier-like'); + $classifier.addClass('NB-classifier-dislike'); + $like.attr('checked', false).trigger('change'); + $dislike.attr('checked', true).trigger('change'); + } + } }, open_modal: function() { @@ -658,6 +629,10 @@ var classifier_prototype = { }); }, + // ========== + // = Events = + // ========== + handle_text_highlight: function() { var $title_highlight = $('.NB-classifier-title-highlight', this.$modal); var $title = $('.NB-classifier-title-text', this.$modal); @@ -749,6 +724,18 @@ var classifier_prototype = { e.preventDefault(); self.save_publisher(); }); + + var stop = false; + $.targetIs(e, { tagSelector: '.NB-classifier-icon-dislike' }, function($t, $p){ + e.preventDefault(); + stop = true; + self.change_classifier($t.parents('.NB-classifier').eq(0), 'dislike'); + }); + if (stop) return; + $.targetIs(e, { tagSelector: '.NB-classifier' }, function($t, $p){ + e.preventDefault(); + self.change_classifier($t, 'like'); + }); }, serialize_classifier: function() { diff --git a/urls.py b/urls.py index 918cc2527..d88c19989 100644 --- a/urls.py +++ b/urls.py @@ -1,8 +1,6 @@ from django.conf.urls.defaults import * from django.conf import settings from apps.reader import views as reader_views -from django.contrib import admin -admin.autodiscover() urlpatterns = patterns('', url(r'^$', reader_views.index, name='index'), @@ -11,8 +9,6 @@ urlpatterns = patterns('', (r'^classifier/', include('apps.analyzer.urls')), (r'^profile/', include('apps.profile.urls')), (r'^import/', include('apps.feed_import.urls')), - (r'^admin/doc/', include('django.contrib.admindocs.urls')), - (r'^admin/(.*)', admin.site.root) ) if settings.DEVELOPMENT: From 5bcd5eb7308c813ce24c78eab1b1482b80e20c54 Mon Sep 17 00:00:00 2001 From: Samuel Clay Date: Thu, 21 Oct 2010 13:37:36 -0400 Subject: [PATCH 03/13] Serializing and deserializing new classifiers. --- apps/analyzer/views.py | 2 +- media/css/reader.css | 53 +++--- media/js/newsblur/reader.js | 4 +- media/js/newsblur/reader_classifier.js | 232 +++++++++++++------------ templates/base.html | 2 - 5 files changed, 143 insertions(+), 150 deletions(-) diff --git a/apps/analyzer/views.py b/apps/analyzer/views.py index a170c871a..60cd7453d 100644 --- a/apps/analyzer/views.py +++ b/apps/analyzer/views.py @@ -68,7 +68,7 @@ def save_classifier(request): _save_classifier(MClassifierAuthor, 'author') _save_classifier(MClassifierTag, 'tag') _save_classifier(MClassifierTitle, 'title') - _save_classifier(MClassifierFeed, 'publisher') + _save_classifier(MClassifierFeed, 'feed') logging.info(" ---> [%s] Feed training: %s" % (request.user, feed)) diff --git a/media/css/reader.css b/media/css/reader.css index f8456f62e..8fc577c85 100644 --- a/media/css/reader.css +++ b/media/css/reader.css @@ -1866,17 +1866,17 @@ a.NB-splash-link:hover { } .NB-classifier .NB-modal-loading { - margin: 8px 120px 0 0; + margin: 8px 0px 0 0; } -.NB-classifier h2.NB-like { +.NB-modal-classifiers h2.NB-like { color: #007000; } -.NB-classifier h2.NB-dislike { +.NB-modal-classifiers h2.NB-dislike { color: #700000; } -.NB-classifier .NB-classifier-facet-disabled { +.NB-modal-classifiers .NB-classifier-facet-disabled { color: #A0A0A0; } @@ -1885,7 +1885,7 @@ a.NB-splash-link:hover { text-shadow: none; } -.NB-classifier .NB-classifier-title-highlight { +.NB-modal-classifiers .NB-classifier-title-highlight { margin-bottom: 6px; } @@ -1893,57 +1893,45 @@ a.NB-splash-link:hover { margin: 6px 0 0 0; } -.NB-classifier .NB-publisher .NB-classifier-authors input { +.NB-modal-classifiers .NB-publisher .NB-classifier-authors input { float: none; margin: 4px 6px 0 0; } -.NB-classifier .NB-classifier-container { +.NB-modal-classifiers .NB-classifier-container { white-space: nowrap; float: left; display: block; margin: 2px 6px 6px 0; } -.NB-classifier .NB-classifier-container .NB-classifier { +.NB-modal-classifiers .NB-classifier-container .NB-classifier { margin: 0 2px 0 0; } -.NB-classifier .NB-classifier-tag { - background-color: #E0E0FF; - padding: 2px 6px 2px 0px; -} - -.NB-classifier .NB-classifier-tag input[type=checkbox] { - margin: 0px 4px 0px; - float: none; -} - -.NB-classifier .NB-classifier-tag label { -} - .NB-classifier .NB-classifier-count { font-size: 10px; font-weight: bold; margin: 0 6px 0 2px; } -.NB-classifier .NB-modal-title .NB-classifier-like { +.NB-modal-classifiers .NB-modal-title .NB-classifier-title-like { color: #3D931B; + padding-left: 20px; + background: transparent url('../img/reader/thumbs-up.png') no-repeat 0 6px; + } -.NB-classifier .NB-modal-title .NB-classifier-dislike { +.NB-modal-classifiers .NB-modal-title .NB-classifier-title-dislike { color: #932C15; + padding-right: 20px; + background: transparent url('../img/reader/thumbs-down.png') no-repeat right 2px; } .simplemodal-wrap { overflow: auto; } -.NB-classifiers { -} - - /* ====================== */ /* = Classifier Trainer = */ /* ====================== */ @@ -1971,7 +1959,7 @@ a.NB-splash-link:hover { .NB-modal-trainer .NB-classifier-trainer-counts { float: right; color: #606060; - font-size: 17px; + font-size: 14px; } .NB-modal-trainer .NB-trainer-points li { @@ -2143,12 +2131,17 @@ a.NB-splash-link:hover { padding: 0 18px 18px 0; } -.NB-manage .NB-classifier-like { +.NB-manage .NB-classifier-title-like { color: #3D931B; + padding-left: 20px; + background: transparent url('../img/reader/thumbs-up.png') no-repeat 0 0; + } -.NB-manage .NB-classifier-dislike { +.NB-manage .NB-classifier-title-dislike { color: #932C15; + padding-left: 20px; + background: transparent url('../img/reader/thumbs-down.png') no-repeat 0 0; } .NB-manage .NB-manage-classifier { diff --git a/media/js/newsblur/reader.js b/media/js/newsblur/reader.js index 1efd0cfa9..fe5cad30b 100644 --- a/media/js/newsblur/reader.js +++ b/media/js/newsblur/reader.js @@ -2696,7 +2696,7 @@ self.model.classifiers.titles[value] = score; } else if (name == 'author') { self.model.classifiers.authors[value] = score; - } else if (name == 'publisher') { + } else if (name == 'feed') { self.model.classifiers.feeds[feed_id] = score; } } else { @@ -2706,7 +2706,7 @@ delete self.model.classifiers.titles[value]; } else if (name == 'author' && self.model.classifiers.authors[value] == score) { delete self.model.classifiers.authors[value]; - } else if (name == 'publisher' && self.model.classifiers.feeds[feed_id] == score) { + } else if (name == 'feed' && self.model.classifiers.feeds[feed_id] == score) { delete self.model.classifiers.feeds[feed_id]; } } diff --git a/media/js/newsblur/reader_classifier.js b/media/js/newsblur/reader_classifier.js index c15480803..1d697faa2 100644 --- a/media/js/newsblur/reader_classifier.js +++ b/media/js/newsblur/reader_classifier.js @@ -11,7 +11,7 @@ NEWSBLUR.ReaderClassifierTrainer = function(options) { 'modal_loaded': false }; this.cache = {}; - this.trainer_iterator = 0; + this.trainer_iterator = -1; this.feed_id = null; this.options = $.extend({}, defaults, options); this.score = this.options['score']; @@ -35,7 +35,7 @@ NEWSBLUR.ReaderClassifierFeed = function(feed_id, options) { }; this.cache = {}; this.feed_id = feed_id; - this.trainer_iterator = 0; + this.trainer_iterator = -1; this.options = $.extend({}, defaults, options); this.score = this.options['score']; this.model = NEWSBLUR.AssetModel.reader(); @@ -71,7 +71,6 @@ var classifier_prototype = { this.make_trainer_intro(); this.get_feeds_trainer(); - this.handle_select_checkboxes(); this.handle_cancel(); this.handle_select_title(); this.open_modal(); @@ -89,7 +88,6 @@ var classifier_prototype = { this.find_story_and_feed(); this.make_modal_feed(); this.make_modal_title(); - this.handle_select_checkboxes(); this.handle_cancel(); this.handle_select_title(); this.open_modal(); @@ -109,7 +107,6 @@ var classifier_prototype = { this.make_modal_story(); this.make_modal_title(); this.handle_text_highlight(); - this.handle_select_checkboxes(); this.handle_cancel(); this.handle_select_title(); this.open_modal(); @@ -118,34 +115,29 @@ var classifier_prototype = { load_previous_feed_in_trainer: function() { var trainer_data_length = this.trainer_data.length; - var trainer_data = this.trainer_data[this.trainer_iterator]; - this.trainer_iterator = this.trainer_iterator - 1; - if (this.trainer_iterator < 1) { + var trainer_data = this.trainer_data[this.trainer_iterator]; + NEWSBLUR.log(['load_previous_feed_in_trainer', this.trainer_iterator, trainer_data]); + if (!trainer_data || this.trainer_iterator < 0) { this.make_trainer_intro(); - this.load_feeds_trainer(null, this.trainer_data); - } - - // Show only feeds, not the trainer intro if going backwards. - if (this.trainer_iterator > 0 && this.trainer_iterator <= trainer_data_length) { + this.reload_modal(); + } else { + this.feed_id = trainer_data['feed_id']; this.load_feed(trainer_data); } }, load_next_feed_in_trainer: function(backwards) { var trainer_data_length = this.trainer_data.length; - var trainer_data = this.trainer_data[this.trainer_iterator]; - - this.feed_id = trainer_data['feed_id']; - this.trainer_iterator = this.trainer_iterator + 1; - if (this.trainer_iterator > trainer_data_length) { + var trainer_data = this.trainer_data[this.trainer_iterator]; + NEWSBLUR.log(['load_next_feed_in_trainer', this.trainer_iterator, trainer_data]); + if (!trainer_data || this.trainer_iterator >= trainer_data_length) { this.make_trainer_outro(); + this.reload_modal(); this.load_feeds_trainer(null, this.trainer_data); - } - - // Show only feeds, not the trainer intro if going backwards. - if (this.trainer_iterator > 0 && this.trainer_iterator <= trainer_data_length) { + } else { + this.feed_id = trainer_data['feed_id']; this.load_feed(trainer_data); } }, @@ -164,13 +156,16 @@ var classifier_prototype = { this.$modal = this.cache[this.feed_id]; } + this.reload_modal(); + }, + + reload_modal: function() { this.flags.modal_loading = setInterval(_.bind(function() { if (this.flags.modal_loaded) { clearInterval(this.flags.modal_loading); $('.NB-modal').empty().append(this.$modal.children()); this.$modal = $('.NB-modal'); // This is bonkers. I shouldn't have to reattach like this $(window).trigger('resize.simplemodal'); - this.handle_select_checkboxes(); this.handle_cancel(); } }, this), 125); @@ -185,10 +180,15 @@ var classifier_prototype = { NEWSBLUR.log(['data', data]); this.trainer_data = data; - - $begin.text('Begin Training') - .addClass('NB-modal-submit-green') - .removeClass('NB-disabled'); + + if (!data || !data.length) { + this.make_trainer_outro(); + this.reload_modal(); + } else { + $begin.text('Begin Training') + .addClass('NB-modal-submit-green') + .removeClass('NB-disabled'); + } }, find_story_and_feed: function() { @@ -223,7 +223,7 @@ var classifier_prototype = { make_trainer_intro: function() { var self = this; - this.$modal = $.make('div', { className: 'NB-classifier NB-modal NB-modal-trainer'}, [ + this.$modal = $.make('div', { className: 'NB-modal-classifiers NB-modal NB-modal-trainer'}, [ $.make('h2', { className: 'NB-modal-title' }, 'Intelligence Trainer'), $.make('h3', { className: 'NB-modal-subtitle' }, 'Here\'s what to do:'), $.make('ol', { className: 'NB-trainer-points' }, [ @@ -269,7 +269,7 @@ var classifier_prototype = { make_trainer_outro: function() { var self = this; - this.$modal = $.make('div', { className: 'NB-classifier NB-modal NB-modal-trainer'}, [ + this.$modal = $.make('div', { className: 'NB-modal-classifiers NB-modal NB-modal-trainer'}, [ $.make('h2', { className: 'NB-modal-title' }, 'Congratulations! You\'re done.'), $.make('h3', { className: 'NB-modal-subtitle' }, 'Here\'s what happens next:'), $.make('ol', { className: 'NB-trainer-points' }, [ @@ -313,11 +313,11 @@ var classifier_prototype = { // NEWSBLUR.log(['Make feed', feed, this.feed_authors, this.feed_tags]); - this.$modal = $.make('div', { className: 'NB-classifier NB-modal ' + (this.options['training'] && 'NB-modal-trainer') }, [ + this.$modal = $.make('div', { className: 'NB-modal-classifiers NB-modal ' + (this.options['training'] && 'NB-modal-trainer') }, [ $.make('div', { className: 'NB-modal-loading' }), - (this.options['training'] && $.make('div', { className: 'NB-classifier-trainer-counts' })), $.make('h2', { className: 'NB-modal-title' }, ''), $.make('h2', { className: 'NB-modal-subtitle' }, [ + (this.options['training'] && $.make('div', { className: 'NB-classifier-trainer-counts' })), $.make('img', { className: 'NB-modal-feed-image feed_favicon', src: this.google_favicon_url + this.feed.feed_link }), $.make('span', { className: 'NB-modal-feed-title' }, this.feed.feed_title) ]), @@ -345,7 +345,7 @@ var classifier_prototype = { $.make('input', { name: 'score', value: this.score, type: 'hidden' }), $.make('input', { name: 'feed_id', value: this.feed_id, type: 'hidden' }), $.make('a', { href: '#', className: 'NB-modal-submit-button NB-modal-submit-back' }, $.entity('«') + ' Back'), - $.make('a', { href: '#', className: 'NB-modal-submit-button NB-modal-submit-green NB-modal-submit-save' }, 'Save & Next '+$.entity('»')), + $.make('a', { href: '#', className: 'NB-modal-submit-button NB-modal-submit-green NB-modal-submit-next NB-modal-submit-save' }, 'Save & Next '+$.entity('»')), $.make('a', { href: '#', className: 'NB-modal-submit-button NB-modal-submit-close' }, 'Close') ])), (!this.options['training'] && $.make('div', { className: 'NB-modal-submit' }, [ @@ -356,11 +356,7 @@ var classifier_prototype = { ' or ', $.make('a', { href: '#', className: 'NB-modal-cancel' }, 'cancel') ])) - ]).bind('submit', function(e) { - e.preventDefault(); - self.save_publisher(); - return false; - }) + ]) ) ]); }, @@ -429,24 +425,23 @@ var classifier_prototype = { make_modal_title: function() { var $modal_title = $('.NB-modal-title', this.$modal); - if (this.flags['publisher']) { - if (this.score == 1) { - $modal_title.html('What do you like about this site?'); - } else if (this.score == -1) { - $modal_title.html('What do you dislike about this site?'); - } - } else if (this.flags['story']) { - if (this.score == 1) { - $modal_title.html('What do you like about this story?'); - } else if (this.score == -1) { - $modal_title.html('What do you dislike about this story?'); - } - } + var $title = $.make('div', [ + 'What do you ', + $.make('b', { className: 'NB-classifier-title-like' }, 'like'), + ' and ', + $.make('b', { className: 'NB-classifier-title-dislike' }, 'dislike'), + ' about this ', + (this.flags['publisher'] && 'site'), + (this.flags['story'] && 'story'), + '?' + ]); + + $modal_title.html($title); }, make_modal_trainer_count: function() { var $count = $('.NB-classifier-trainer-counts', this.$modal); - var count = this.trainer_iterator; + var count = this.trainer_iterator + 1; var total = this.trainer_data.length; $count.html(count + '/' + total); }, @@ -501,6 +496,7 @@ var classifier_prototype = { make_classifier: function(classifier_title, classifier_value, classifier_type, classifier_count) { var score = 0; + NEWSBLUR.log(['classifiers', this.user_classifiers, classifier_value, this.user_classifiers[classifier_type+'s']]); if (classifier_value in this.user_classifiers[classifier_type+'s']) { score = this.user_classifiers[classifier_type+'s'][classifier_value]; } @@ -515,7 +511,7 @@ var classifier_prototype = { type: 'checkbox', className: 'NB-classifier-input-like', name: 'like_'+classifier_type, - value: classifier_value + value: classifier_value }), $.make('input', { type: 'checkbox', @@ -544,10 +540,10 @@ var classifier_prototype = { ]); if (score > 0) { - $classifier.addClass('NB-classifier-like'); + $('.NB-classifier', $classifier).addClass('NB-classifier-like'); $('.NB-classifier-input-like', $classifier).attr('checked', true); } else if (score < 0) { - $classifier.addClass('NB-classifier-dislike'); + $('.NB-classifier', $classifier).addClass('NB-classifier-dislike'); $('.NB-classifier-input-dislike', $classifier).attr('checked', true); } @@ -570,29 +566,40 @@ var classifier_prototype = { var $like = $('.NB-classifier-input-like', $classifier); var $dislike = $('.NB-classifier-input-dislike', $classifier); + var $save = $('.NB-modal-submit-save', this.$modal); + var $close = $('.NB-modal-submit-close', this.$modal); + var $back = $('.NB-modal-submit-back', this.$modal); + if (classifier_opinion == 'like') { if ($classifier.is('.NB-classifier-like')) { $classifier.removeClass('NB-classifier-like'); - $dislike.attr('checked', false).trigger('change'); - $like.attr('checked', false).trigger('change'); + $dislike.attr('checked', false); + $like.attr('checked', false); } else { $classifier.removeClass('NB-classifier-dislike'); $classifier.addClass('NB-classifier-like'); - $dislike.attr('checked', false).trigger('change'); - $like.attr('checked', true).trigger('change'); + $dislike.attr('checked', false); + $like.attr('checked', true); } } else if (classifier_opinion == 'dislike') { if ($classifier.is('.NB-classifier-dislike')) { $classifier.removeClass('NB-classifier-dislike'); - $like.attr('checked', false).trigger('change'); - $dislike.attr('checked', false).trigger('change'); + $like.attr('checked', false); + $dislike.attr('checked', false); } else { $classifier.removeClass('NB-classifier-like'); $classifier.addClass('NB-classifier-dislike'); - $like.attr('checked', false).trigger('change'); - $dislike.attr('checked', true).trigger('change'); + $like.attr('checked', false); + $dislike.attr('checked', true); } } + + if (this.options['training']) { + $close.val('Save & Close'); + } else { + $save.removeClass("NB-disabled").removeAttr('disabled').attr('value', 'Save'); + } + NEWSBLUR.log(['change_classifier', classifier_opinion, $classifier, $like.is(':checked'), $dislike.is(':checked')]); }, open_modal: function() { @@ -671,22 +678,6 @@ var classifier_prototype = { }); }, - handle_select_checkboxes: function() { - var self = this; - var $save = $('.NB-modal-submit-save', this.$modal); - var $close = $('.NB-modal-submit-close', this.$modal); - var $back = $('.NB-modal-submit-back', this.$modal); - - $('input', this.$modal).change(function() { - // var count = $('input:checked', self.$modal).length; - if (self.options['training']) { - $close.val('Save & Close'); - } else { - $save.removeClass("NB-disabled").removeAttr('disabled').attr('value', 'Save'); - } - }); - }, - handle_cancel: function() { var $cancel = $('.NB-modal-cancel', this.$modal); @@ -699,31 +690,41 @@ var classifier_prototype = { handle_clicks: function(elem, e) { var self = this; - $.targetIs(e, { tagSelector: '.NB-modal-submit-begin' }, function($t, $p){ - e.preventDefault(); - self.load_next_feed_in_trainer(); - }); + if (this.options['training']) { + $.targetIs(e, { tagSelector: '.NB-modal-submit-begin' }, function($t, $p){ + e.preventDefault(); + self.load_next_feed_in_trainer(); + }); + $.targetIs(e, { tagSelector: '.NB-modal-submit-save.NB-modal-submit-next' }, function($t, $p){ + e.preventDefault(); + self.save_publisher(true); + self.load_next_feed_in_trainer(); + }); - $.targetIs(e, { tagSelector: '.NB-modal-submit-save:not(.NB-modal-submit-begin)' }, function($t, $p){ - e.preventDefault(); - self.save_publisher(true); - self.load_next_feed_in_trainer(); - }); + $.targetIs(e, { tagSelector: '.NB-modal-submit-back' }, function($t, $p){ + e.preventDefault(); + self.load_previous_feed_in_trainer(); + }); - $.targetIs(e, { tagSelector: '.NB-modal-submit-back' }, function($t, $p){ - e.preventDefault(); - self.load_previous_feed_in_trainer(); - }); + $.targetIs(e, { tagSelector: '.NB-modal-submit-close' }, function($t, $p){ + e.preventDefault(); + self.save_publisher(); + }); - $.targetIs(e, { tagSelector: '.NB-modal-submit-close' }, function($t, $p){ - e.preventDefault(); - self.save_publisher(); - }); - - $.targetIs(e, { tagSelector: '.NB-modal-submit-end' }, function($t, $p){ - e.preventDefault(); - self.save_publisher(); - }); + $.targetIs(e, { tagSelector: '.NB-modal-submit-end' }, function($t, $p){ + e.preventDefault(); + NEWSBLUR.reader.force_feeds_refresh(); + // NEWSBLUR.reader.open_feed(self.feed_id, true); + // TODO: Update counts in active feed. + $.modal.close(); + }); + } else { + $.targetIs(e, { tagSelector: '.NB-modal-submit-save:not(.NB-modal-submit-next)' }, function($t, $p){ + e.preventDefault(); + self.save_publisher(); + return false; + }); + } var stop = false; $.targetIs(e, { tagSelector: '.NB-classifier-icon-dislike' }, function($t, $p){ @@ -739,21 +740,21 @@ var classifier_prototype = { }, serialize_classifier: function() { - var checked_data = $('input', this.$modal).serialize(); - - var $unchecked = $('input[type=checkbox]:not(:checked)', this.$modal); - $unchecked.attr('checked', true); - $unchecked.each(function() { - $(this).attr('name', 'remove_' + $(this).attr('name')); + var data = []; + $('.NB-classifier', this.$modal).each(function() { + if ($('.NB-classifier-input-like, .NB-classifier-input-dislike', this).is(':checked')) { + data.push([$('input:checked', this).attr('name'), $('.NB-classifier-input-like', this).val()]); + } else { + data.push(['remove_'+$('.NB-classifier-input-like', this).attr('name'), $('.NB-classifier-input-like', this).val()]); + } }); - - var unchecked_data = $unchecked.serialize(); - $unchecked.each(function() { - $(this).attr('name', $(this).attr('name').replace(/^remove_/, '')); - }); - $unchecked.attr('checked', false); - - var data = [checked_data, unchecked_data].join('&'); + data.push(['feed_id', this.feed_id]); + if (this.story_id) { + data.push(['story_id', this.story_id]); + } + data = _.map(data, function(c) { + return [c[0], '=', c[1]].join(''); + }).join('&'); return data; }, @@ -775,7 +776,8 @@ var classifier_prototype = { this.model.save_classifier_publisher(data, function() { if (!keep_modal_open) { NEWSBLUR.reader.force_feeds_refresh(); - NEWSBLUR.reader.load_feed(self.feed_id, null, true); + // NEWSBLUR.reader.open_feed(self.feed_id, true); + // TODO: Update counts in active feed. $.modal.close(); } }); diff --git a/templates/base.html b/templates/base.html index d381d0418..38f26bc78 100644 --- a/templates/base.html +++ b/templates/base.html @@ -1,6 +1,4 @@ {% load compressed utils_tags %} - {% block title %}NewsBlur{% endblock %} From b6b8bc67cfd66beaec54e54fe6bedb6827b84082 Mon Sep 17 00:00:00 2001 From: Samuel Clay Date: Thu, 21 Oct 2010 13:39:47 -0400 Subject: [PATCH 04/13] HTML5 doctype. --- templates/base.html | 1 + 1 file changed, 1 insertion(+) diff --git a/templates/base.html b/templates/base.html index 38f26bc78..3239b5744 100644 --- a/templates/base.html +++ b/templates/base.html @@ -1,4 +1,5 @@ {% load compressed utils_tags %} + {% block title %}NewsBlur{% endblock %} From 02964a57750f944ca8ee59a2aa064d175a6e31cf Mon Sep 17 00:00:00 2001 From: Samuel Clay Date: Thu, 21 Oct 2010 13:48:08 -0400 Subject: [PATCH 05/13] Internet Explorer fix for Array.indexOf(). Now using _.contains() instead. --- media/js/newsblur/assetmodel.js | 4 ++-- media/js/newsblur/reader.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/media/js/newsblur/assetmodel.js b/media/js/newsblur/assetmodel.js index a352c9173..ea1effb13 100644 --- a/media/js/newsblur/assetmodel.js +++ b/media/js/newsblur/assetmodel.js @@ -443,10 +443,10 @@ NEWSBLUR.AssetModel.Reader.prototype = { var folders = NEWSBLUR.Preferences.collapsed_folders; var changed = false; - if (is_collapsed && NEWSBLUR.Preferences.collapsed_folders.indexOf(folder_title) == -1) { + if (is_collapsed && _.contains(NEWSBLUR.Preferences.collapsed_folders, folder_title)) { NEWSBLUR.Preferences.collapsed_folders.push(folder_title); changed = true; - } else if (!is_collapsed && NEWSBLUR.Preferences.collapsed_folders.indexOf(folder_title) != -1) { + } else if (!is_collapsed && _.contains(NEWSBLUR.Preferences.collapsed_folders, folder_title)) { NEWSBLUR.Preferences.collapsed_folders = _.without(folders, folder_title); changed = true; } diff --git a/media/js/newsblur/reader.js b/media/js/newsblur/reader.js index fe5cad30b..0bb6f82e6 100644 --- a/media/js/newsblur/reader.js +++ b/media/js/newsblur/reader.js @@ -618,7 +618,7 @@ ]), $.make('ul', { className: 'folder' }) ]).css({'display': 'none'}); - var is_collapsed = NEWSBLUR.Preferences.collapsed_folders.indexOf(o) != -1; + var is_collapsed = _.contains(NEWSBLUR.Preferences.collapsed_folders, o); (function($feeds, $folder, is_collapsed, collapsed_parent) { setTimeout(function() { From 0cf370cd21266ec702a696a479911981355cc7d2 Mon Sep 17 00:00:00 2001 From: Samuel Clay Date: Thu, 21 Oct 2010 13:50:43 -0400 Subject: [PATCH 06/13] Updating Underscore.js --- media/js/underscore.js | 298 +++++++++++++++++++++-------------------- 1 file changed, 155 insertions(+), 143 deletions(-) diff --git a/media/js/underscore.js b/media/js/underscore.js index 24e59d1c6..3105f4d84 100644 --- a/media/js/underscore.js +++ b/media/js/underscore.js @@ -1,26 +1,24 @@ -// Underscore.js -// (c) 2010 Jeremy Ashkenas, DocumentCloud Inc. -// Underscore is freely distributable under the terms of the MIT license. -// Portions of Underscore are inspired by or borrowed from Prototype.js, -// Oliver Steele's Functional, and John Resig's Micro-Templating. -// For all details and documentation: -// http://documentcloud.github.com/underscore +// (c) 2010 Jeremy Ashkenas, DocumentCloud Inc. +// Underscore is freely distributable under the MIT license. +// Portions of Underscore are inspired or borrowed from Prototype, +// Oliver Steele's Functional, and John Resig's Micro-Templating. +// For all details and documentation: +// http://documentcloud.github.com/underscore (function() { - // ------------------------- Baseline setup --------------------------------- - // Establish the root object, "window" in the browser, or "global" on the server. + // Baseline setup + // -------------- + + // Establish the root object, `window` in the browser, or `global` on the server. var root = this; - // Save the previous value of the "_" variable. + // Save the previous value of the `_` variable. var previousUnderscore = root._; // Establish the object that gets thrown to break out of a loop iteration. var breaker = typeof StopIteration !== 'undefined' ? StopIteration : '__break__'; - // Quick regexp-escaping function, because JS doesn't have RegExp.escape(). - var escapeRegExp = function(s) { return s.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1'); }; - // Save bytes in the minified (but not gzipped) version: var ArrayProto = Array.prototype, ObjProto = Object.prototype; @@ -31,7 +29,8 @@ hasOwnProperty = ObjProto.hasOwnProperty, propertyIsEnumerable = ObjProto.propertyIsEnumerable; - // All ECMA5 native implementations we hope to use are declared here. + // All **ECMAScript 5** native function implementations that we hope to use + // are declared here. var nativeForEach = ArrayProto.forEach, nativeMap = ArrayProto.map, @@ -48,21 +47,22 @@ // Create a safe reference to the Underscore object for use below. var _ = function(obj) { return new wrapper(obj); }; - // Export the Underscore object for CommonJS. + // Export the Underscore object for **CommonJS**. if (typeof exports !== 'undefined') exports._ = _; - // Export underscore to global scope. + // Export Underscore to the global scope. root._ = _; // Current version. - _.VERSION = '1.0.4'; + _.VERSION = '1.1.2'; - // ------------------------ Collection Functions: --------------------------- + // Collection Functions + // -------------------- - // The cornerstone, an each implementation. - // Handles objects implementing forEach, arrays, and raw objects. - // Delegates to JavaScript 1.6's native forEach if available. - var each = _.forEach = function(obj, iterator, context) { + // The cornerstone, an `each` implementation, aka `forEach`. + // Handles objects implementing `forEach`, arrays, and raw objects. + // Delegates to **ECMAScript 5**'s native `forEach` if available. + var each = _.each = _.forEach = function(obj, iterator, context) { try { if (nativeForEach && obj.forEach === nativeForEach) { obj.forEach(iterator, context); @@ -80,36 +80,42 @@ }; // Return the results of applying the iterator to each element. - // Delegates to JavaScript 1.6's native map if available. + // Delegates to **ECMAScript 5**'s native `map` if available. _.map = function(obj, iterator, context) { if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context); var results = []; each(obj, function(value, index, list) { - results.push(iterator.call(context, value, index, list)); + results[results.length] = iterator.call(context, value, index, list); }); return results; }; - // Reduce builds up a single result from a list of values, aka inject, or foldl. - // Delegates to JavaScript 1.8's native reduce if available. - _.reduce = function(obj, memo, iterator, context) { - if (nativeReduce && obj.reduce === nativeReduce) return obj.reduce(_.bind(iterator, context), memo); + // **Reduce** builds up a single result from a list of values, aka `inject`, + // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available. + _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) { + if (nativeReduce && obj.reduce === nativeReduce) { + if (context) iterator = _.bind(iterator, context); + return obj.reduce(iterator, memo); + } each(obj, function(value, index, list) { memo = iterator.call(context, memo, value, index, list); }); return memo; }; - // The right-associative version of reduce, also known as foldr. Uses - // Delegates to JavaScript 1.8's native reduceRight if available. - _.reduceRight = function(obj, memo, iterator, context) { - if (nativeReduceRight && obj.reduceRight === nativeReduceRight) return obj.reduceRight(_.bind(iterator, context), memo); - var reversed = _.clone(_.toArray(obj)).reverse(); - return _.reduce(reversed, memo, iterator, context); + // The right-associative version of reduce, also known as `foldr`. + // Delegates to **ECMAScript 5**'s native `reduceRight` if available. + _.reduceRight = _.foldr = function(obj, iterator, memo, context) { + if (nativeReduceRight && obj.reduceRight === nativeReduceRight) { + if (context) iterator = _.bind(iterator, context); + return obj.reduceRight(iterator, memo); + } + var reversed = (_.isArray(obj) ? obj.slice() : _.toArray(obj)).reverse(); + return _.reduce(reversed, iterator, memo, context); }; - // Return the first value which passes a truth test. - _.detect = function(obj, iterator, context) { + // Return the first value which passes a truth test. Aliased as `detect`. + _.find = _.detect = function(obj, iterator, context) { var result; each(obj, function(value, index, list) { if (iterator.call(context, value, index, list)) { @@ -121,12 +127,13 @@ }; // Return all the elements that pass a truth test. - // Delegates to JavaScript 1.6's native filter if available. - _.filter = function(obj, iterator, context) { + // Delegates to **ECMAScript 5**'s native `filter` if available. + // Aliased as `select`. + _.filter = _.select = function(obj, iterator, context) { if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context); var results = []; each(obj, function(value, index, list) { - iterator.call(context, value, index, list) && results.push(value); + if (iterator.call(context, value, index, list)) results[results.length] = value; }); return results; }; @@ -135,14 +142,15 @@ _.reject = function(obj, iterator, context) { var results = []; each(obj, function(value, index, list) { - !iterator.call(context, value, index, list) && results.push(value); + if (!iterator.call(context, value, index, list)) results[results.length] = value; }); return results; }; // Determine whether all of the elements match a truth test. - // Delegates to JavaScript 1.6's native every if available. - _.every = function(obj, iterator, context) { + // Delegates to **ECMAScript 5**'s native `every` if available. + // Aliased as `all`. + _.every = _.all = function(obj, iterator, context) { iterator = iterator || _.identity; if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context); var result = true; @@ -153,8 +161,9 @@ }; // Determine if at least one element in the object matches a truth test. - // Delegates to JavaScript 1.6's native some if available. - _.some = function(obj, iterator, context) { + // Delegates to **ECMAScript 5**'s native `some` if available. + // Aliased as `any`. + _.some = _.any = function(obj, iterator, context) { iterator = iterator || _.identity; if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context); var result = false; @@ -164,8 +173,9 @@ return result; }; - // Determine if a given value is included in the array or object using '==='. - _.include = function(obj, target) { + // Determine if a given value is included in the array or object using `===`. + // Aliased as `contains`. + _.include = _.contains = function(obj, target) { if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1; var found = false; each(obj, function(value) { @@ -174,20 +184,20 @@ return found; }; - // Invoke a method with arguments on every item in a collection. + // Invoke a method (with arguments) on every item in a collection. _.invoke = function(obj, method) { - var args = _.rest(arguments, 2); + var args = slice.call(arguments, 2); return _.map(obj, function(value) { return (method ? value[method] : value).apply(value, args); }); }; - // Convenience version of a common use case of map: fetching a property. + // Convenience version of a common use case of `map`: fetching a property. _.pluck = function(obj, key) { return _.map(obj, function(value){ return value[key]; }); }; - // Return the maximum item or (item-based computation). + // Return the maximum element or (element-based computation). _.max = function(obj, iterator, context) { if (!iterator && _.isArray(obj)) return Math.max.apply(Math, obj); var result = {computed : -Infinity}; @@ -234,7 +244,7 @@ return low; }; - // Convert anything iterable into a real, live array. + // Safely convert anything iterable into a real, live array. _.toArray = function(iterable) { if (!iterable) return []; if (iterable.toArray) return iterable.toArray(); @@ -248,20 +258,21 @@ return _.toArray(obj).length; }; - // -------------------------- Array Functions: ------------------------------ + // Array Functions + // --------------- - // Get the first element of an array. Passing "n" will return the first N - // values in the array. Aliased as "head". The "guard" check allows it to work - // with _.map. - _.first = function(array, n, guard) { + // Get the first element of an array. Passing **n** will return the first N + // values in the array. Aliased as `head`. The **guard** check allows it to work + // with `_.map`. + _.first = _.head = function(array, n, guard) { return n && !guard ? slice.call(array, 0, n) : array[0]; }; - // Returns everything but the first entry of the array. Aliased as "tail". - // Especially useful on the arguments object. Passing an "index" will return - // the rest of the values in the array from that index onward. The "guard" - // check allows it to work with _.map. - _.rest = function(array, index, guard) { + // Returns everything but the first entry of the array. Aliased as `tail`. + // Especially useful on the arguments object. Passing an **index** will return + // the rest of the values in the array from that index onward. The **guard** + // check allows it to work with `_.map`. + _.rest = _.tail = function(array, index, guard) { return slice.call(array, _.isUndefined(index) || guard ? 1 : index); }; @@ -277,32 +288,33 @@ // Return a completely flattened version of an array. _.flatten = function(array) { - return _.reduce(array, [], function(memo, value) { + return _.reduce(array, function(memo, value) { if (_.isArray(value)) return memo.concat(_.flatten(value)); - memo.push(value); + memo[memo.length] = value; return memo; - }); + }, []); }; // Return a version of the array that does not contain the specified value(s). _.without = function(array) { - var values = _.rest(arguments); + var values = slice.call(arguments, 1); return _.filter(array, function(value){ return !_.include(values, value); }); }; // Produce a duplicate-free version of the array. If the array has already // been sorted, you have the option of using a faster algorithm. - _.uniq = function(array, isSorted) { - return _.reduce(array, [], function(memo, el, i) { - if (0 == i || (isSorted === true ? _.last(memo) != el : !_.include(memo, el))) memo.push(el); + // Aliased as `unique`. + _.uniq = _.unique = function(array, isSorted) { + return _.reduce(array, function(memo, el, i) { + if (0 == i || (isSorted === true ? _.last(memo) != el : !_.include(memo, el))) memo[memo.length] = el; return memo; - }); + }, []); }; // Produce an array that contains every item shared between all the // passed-in arrays. _.intersect = function(array) { - var rest = _.rest(arguments); + var rest = slice.call(arguments, 1); return _.filter(_.uniq(array), function(item) { return _.every(rest, function(other) { return _.indexOf(other, item) >= 0; @@ -313,17 +325,17 @@ // Zip together multiple lists into a single array -- elements that share // an index go together. _.zip = function() { - var args = _.toArray(arguments); + var args = slice.call(arguments); var length = _.max(_.pluck(args, 'length')); var results = new Array(length); - for (var i = 0; i < length; i++) results[i] = _.pluck(args, String(i)); + for (var i = 0; i < length; i++) results[i] = _.pluck(args, "" + i); return results; }; - // If the browser doesn't supply us with indexOf (I'm looking at you, MSIE), + // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**), // we need this function. Return the position of the first occurence of an // item in an array, or -1 if the item is not included in the array. - // Delegates to JavaScript 1.8's native indexOf if available. + // Delegates to **ECMAScript 5**'s native `indexOf` if available. _.indexOf = function(array, item) { if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item); for (var i = 0, l = array.length; i < l; i++) if (array[i] === item) return i; @@ -331,7 +343,7 @@ }; - // Delegates to JavaScript 1.6's native lastIndexOf if available. + // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available. _.lastIndexOf = function(array, item) { if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item); var i = array.length; @@ -340,36 +352,40 @@ }; // Generate an integer Array containing an arithmetic progression. A port of - // the native Python range() function. See: - // http://docs.python.org/library/functions.html#range + // the native Python `range()` function. See + // [the Python documentation](http://docs.python.org/library/functions.html#range). _.range = function(start, stop, step) { - var a = _.toArray(arguments); - var solo = a.length <= 1; - var start = solo ? 0 : a[0], stop = solo ? a[0] : a[1], step = a[2] || 1; - var len = Math.ceil((stop - start) / step); - if (len <= 0) return []; - var range = new Array(len); - for (var i = start, idx = 0; true; i += step) { - if ((step > 0 ? i - stop : stop - i) >= 0) return range; - range[idx++] = i; + var args = slice.call(arguments), + solo = args.length <= 1, + start = solo ? 0 : args[0], + stop = solo ? args[0] : args[1], + step = args[2] || 1, + len = Math.max(Math.ceil((stop - start) / step), 0), + idx = 0, + range = new Array(len); + while (idx < len) { + range[idx++] = start; + start += step; } + return range; }; - // ----------------------- Function Functions: ------------------------------ + // Function (ahem) Functions + // ------------------ - // Create a function bound to a given object (assigning 'this', and arguments, - // optionally). Binding with arguments is also known as 'curry'. + // Create a function bound to a given object (assigning `this`, and arguments, + // optionally). Binding with arguments is also known as `curry`. _.bind = function(func, obj) { - var args = _.rest(arguments, 2); + var args = slice.call(arguments, 2); return function() { - return func.apply(obj || {}, args.concat(_.toArray(arguments))); + return func.apply(obj || {}, args.concat(slice.call(arguments))); }; }; // Bind all of an object's methods to that object. Useful for ensuring that // all callbacks defined on an object belong to it. _.bindAll = function(obj) { - var funcs = _.rest(arguments); + var funcs = slice.call(arguments, 1); if (funcs.length == 0) funcs = _.functions(obj); each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); }); return obj; @@ -388,14 +404,14 @@ // Delays a function for the given number of milliseconds, and then calls // it with the arguments supplied. _.delay = function(func, wait) { - var args = _.rest(arguments, 2); + var args = slice.call(arguments, 2); return setTimeout(function(){ return func.apply(func, args); }, wait); }; // Defers a function, scheduling it to run after the current call stack has // cleared. _.defer = function(func) { - return _.delay.apply(_, [func, 1].concat(_.rest(arguments))); + return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1))); }; // Returns the first function passed as an argument to the second, @@ -403,7 +419,7 @@ // conditionally execute the original function. _.wrap = function(func, wrapper) { return function() { - var args = [func].concat(_.toArray(arguments)); + var args = [func].concat(slice.call(arguments)); return wrapper.apply(wrapper, args); }; }; @@ -411,9 +427,9 @@ // Returns a function that is the composition of a list of functions, each // consuming the return value of the function that follows. _.compose = function() { - var funcs = _.toArray(arguments); + var funcs = slice.call(arguments); return function() { - var args = _.toArray(arguments); + var args = slice.call(arguments); for (var i=funcs.length-1; i >= 0; i--) { args = [funcs[i].apply(this, args)]; } @@ -421,14 +437,15 @@ }; }; - // ------------------------- Object Functions: ------------------------------ + // Object Functions + // ---------------- // Retrieve the names of an object's properties. - // Delegates to ECMA5's native Object.keys + // Delegates to **ECMAScript 5**'s native `Object.keys` _.keys = nativeKeys || function(obj) { if (_.isArray(obj)) return _.range(0, obj.length); var keys = []; - for (var key in obj) if (hasOwnProperty.call(obj, key)) keys.push(key); + for (var key in obj) if (hasOwnProperty.call(obj, key)) keys[keys.length] = key; return keys; }; @@ -438,13 +455,14 @@ }; // Return a sorted list of the function names available on the object. - _.functions = function(obj) { + // Aliased as `methods` + _.functions = _.methods = function(obj) { return _.filter(_.keys(obj), function(key){ return _.isFunction(obj[key]); }).sort(); }; // Extend a given object with all the properties in passed-in object(s). _.extend = function(obj) { - each(_.rest(arguments), function(source) { + each(slice.call(arguments, 1), function(source) { for (var prop in source) obj[prop] = source[prop]; }); return obj; @@ -452,12 +470,12 @@ // Create a (shallow-cloned) duplicate of an object. _.clone = function(obj) { - if (_.isArray(obj)) return obj.slice(0); - return _.extend({}, obj); + return _.isArray(obj) ? obj.slice() : _.extend({}, obj); }; // Invokes interceptor with the obj, and then returns obj. - // The primary purpose of this method is to "tap into" a method chain, in order to perform operations on intermediate results within the chain. + // The primary purpose of this method is to "tap into" a method chain, in + // order to perform operations on intermediate results within the chain. _.tap = function(obj, interceptor) { interceptor(obj); return obj; @@ -519,7 +537,7 @@ // Is a given variable an arguments object? _.isArguments = function(obj) { - return obj && obj.callee; + return !!(obj && obj.callee); }; // Is a given value a function? @@ -568,9 +586,10 @@ return typeof obj == 'undefined'; }; - // -------------------------- Utility Functions: ---------------------------- + // Utility Functions + // ----------------- - // Run Underscore.js in noConflict mode, returning the '_' variable to its + // Run Underscore.js in *noConflict* mode, returning the `_` variable to its // previous owner. Returns a reference to the Underscore object. _.noConflict = function() { root._ = previousUnderscore; @@ -582,7 +601,7 @@ return value; }; - // Run a function n times. + // Run a function **n** times. _.times = function (n, iterator, context) { for (var i = 0; i < n; i++) iterator.call(context, i); }; @@ -611,51 +630,44 @@ // By default, Underscore uses ERB-style template delimiters, change the // following template settings to use alternative delimiters. _.templateSettings = { - start : '<%', - end : '%>', - interpolate : /<%=(.+?)%>/g + evaluate : /<%([\s\S]+?)%>/g, + interpolate : /<%=([\s\S]+?)%>/g }; - // JavaScript templating a-la ERB, pilfered from John Resig's - // "Secrets of the JavaScript Ninja", page 83. - // Single-quote fix from Rick Strahl's version. - // With alterations for arbitrary delimiters. + // JavaScript micro-templating, similar to John Resig's implementation. + // Underscore templating handles arbitrary delimiters, preserves whitespace, + // and correctly escapes quotes within interpolated code. _.template = function(str, data) { var c = _.templateSettings; - var endMatch = new RegExp("'(?=[^"+c.end.substr(0, 1)+"]*"+escapeRegExp(c.end)+")","g"); - var fn = new Function('obj', - 'var p=[],print=function(){p.push.apply(p,arguments);};' + - 'with(obj){p.push(\'' + - str.replace(/[\r\t\n]/g, " ") - .replace(endMatch,"\t") - .split("'").join("\\'") - .split("\t").join("'") - .replace(c.interpolate, "',$1,'") - .split(c.start).join("');") - .split(c.end).join("p.push('") - + "');}return p.join('');"); - return data ? fn(data) : fn; + var tmpl = 'var __p=[],print=function(){__p.push.apply(__p,arguments);};' + + 'with(obj||{}){__p.push(\'' + + str.replace(/'/g, "\\'") + .replace(c.interpolate, function(match, code) { + return "'," + code.replace(/\\'/g, "'") + ",'"; + }) + .replace(c.evaluate || null, function(match, code) { + return "');" + code.replace(/\\'/g, "'") + .replace(/[\r\n\t]/g, ' ') + "__p.push('"; + }) + .replace(/\r/g, '\\r') + .replace(/\n/g, '\\n') + .replace(/\t/g, '\\t') + + "');}return __p.join('');"; + var func = new Function('obj', tmpl); + return data ? func(data) : func; }; - // ------------------------------- Aliases ---------------------------------- - - _.each = _.forEach; - _.foldl = _.inject = _.reduce; - _.foldr = _.reduceRight; - _.select = _.filter; - _.all = _.every; - _.any = _.some; - _.head = _.first; - _.tail = _.rest; - _.methods = _.functions; - - // ------------------------ Setup the OOP Wrapper: -------------------------- + // The OOP Wrapper + // --------------- // If Underscore is called as a function, it returns a wrapped object that // can be used OO-style. This wrapper holds altered versions of all the // underscore functions. Wrapped objects may be chained. var wrapper = function(obj) { this._wrapped = obj; }; + // Expose `wrapper.prototype` as `_.prototype` + _.prototype = wrapper.prototype; + // Helper function to continue chaining intermediate results. var result = function(obj, chain) { return chain ? _(obj).chain() : obj; @@ -664,7 +676,7 @@ // A method to easily add functions to the OOP wrapper. var addToWrapper = function(name, func) { wrapper.prototype[name] = function() { - var args = _.toArray(arguments); + var args = slice.call(arguments); unshift.call(args, this._wrapped); return result(func.apply(_, args), this._chain); }; From 7d5f160b93828786fcdc3c2307850146caae7b6a Mon Sep 17 00:00:00 2001 From: Samuel Clay Date: Thu, 21 Oct 2010 18:52:25 -0400 Subject: [PATCH 07/13] Adding shift+j and shift+k to move between feeds. Thanks to Jim Moran for the suggestion. --- media/js/newsblur/reader.js | 41 ++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/media/js/newsblur/reader.js b/media/js/newsblur/reader.js index 0bb6f82e6..5afe5ba46 100644 --- a/media/js/newsblur/reader.js +++ b/media/js/newsblur/reader.js @@ -471,40 +471,39 @@ } }, - show_next_feed: function(direction) { + show_next_feed: function(direction, $current_feed) { var $feed_list = this.$s.$feed_list; - var $current_feed = $('.selected', $feed_list); + var $current_feed = $current_feed || $('.selected', $feed_list); var $next_feed, scroll; + var $feeds = $('.feed', $feed_list); if (!$current_feed.length) { $current_feed = $('.feed:first', $feed_list); $next_feed = $current_feed; - } else if (direction == 1) { - $next_feed = $current_feed.next('.feed'); - } else if (direction == -1) { - $next_feed = $current_feed.prev('.feed'); - } - - if (!$next_feed.length) { - if (direction == 1) { - $next_feed = $current_feed.parents('.folder').next('.folder').find('.feed:first'); - } else if (direction == -1) { - $next_feed = $current_feed.parents('.folder').prev('.folder').find('.feed:last'); - } + } else { + $feeds.each(function(i) { + if (this == $current_feed[0]) { + current_feed = i; + return false; + } + }); + $next_feed = $feeds.eq(current_feed+direction); } var feed_id = $next_feed.data('feed_id'); - if (feed_id) { + if (feed_id && feed_id == this.active_feed) { + this.show_next_feed(direction, $next_feed); + } else if (feed_id) { var position = $feed_list.scrollTop() + $next_feed.offset().top - $next_feed.outerHeight(); - var showing = $feed_list.height(); + var showing = $feed_list.height() - 100; if (position > showing) { scroll = position; } else { scroll = 0; } $feed_list.scrollTop(scroll); - // this.open_feed(feed_id); + this.open_feed(feed_id, false, $next_feed); } }, @@ -3681,6 +3680,14 @@ $document.bind('keydown', 'k', function(e) { e.preventDefault(); self.show_next_story(-1); + }); + $document.bind('keydown', 'shift+j', function(e) { + e.preventDefault(); + self.show_next_feed(1); + }); + $document.bind('keydown', 'shift+k', function(e) { + e.preventDefault(); + self.show_next_feed(-1); }); $document.bind('keydown', 'left', function(e) { e.preventDefault(); From 8062a67628c6ea9307ae56c1831fa999b32f59e8 Mon Sep 17 00:00:00 2001 From: Samuel Clay Date: Thu, 21 Oct 2010 19:36:03 -0400 Subject: [PATCH 08/13] Finishing up look and feel of classifiers. Also added shift+j and shift+k to keyboard shortcuts modal. --- media/css/reader.css | 57 ++++++++++++++++++++------ media/js/newsblur/reader.js | 8 ++++ media/js/newsblur/reader_classifier.js | 8 ++-- media/js/newsblur/reader_keyboard.js | 38 +++++++++++++++-- 4 files changed, 90 insertions(+), 21 deletions(-) diff --git a/media/css/reader.css b/media/css/reader.css index 8fc577c85..020e473f4 100644 --- a/media/css/reader.css +++ b/media/css/reader.css @@ -2256,7 +2256,7 @@ background: transparent; display: block; margin: 2px 6px 6px 0; cursor: pointer; - padding: 0 34px 0 26px; + padding: 0 30px 0 26px; font-size: 12px; text-transform: uppercase; background-color: #F5CD09; @@ -2307,6 +2307,7 @@ background: transparent; position: absolute; left: 6px; top: 2px; + opacity: .2; } .NB-classifiers .NB-classifier .NB-classifier-icon-dislike { @@ -2316,24 +2317,25 @@ background: transparent; top: -1px; right: -1px; background: transparent url('../img/reader/thumbs-down.png') no-repeat 5px -1px; + opacity: .2; } .NB-classifiers .NB-classifier .NB-classifier-icon-dislike-inner { margin: 4px 4px 0 0; width: 18px; height: 13px; - border-left: 1px solid #F5E529; + border-left: 1px solid #EBEBE1; } .NB-classifiers .NB-classifier.NB-classifier-like { - background-color: #54B54E; + background-color: #34912E; border: 1px solid #202020; -webkit-box-shadow: 1px 1px 1px #BDC0D7; -moz-box-shadow: 1px 1px 1px #BDC0D7; box-shadow: 1px 1px 1px #BDC0D7; } .NB-classifiers .NB-classifier.NB-classifier-dislike { - background-color: #C92123; + background-color: #A90103; border: 1px solid #000; -webkit-box-shadow: 1px 1px 1px #BDC0D7; -moz-box-shadow: 1px 1px 1px #BDC0D7; @@ -2341,7 +2343,10 @@ background: transparent; } .NB-classifiers .NB-classifier.NB-classifier-hover-like { - background-color: #54B54E; + background-color: #54A54E; +} +.NB-classifiers .NB-classifier.NB-classifier-like.NB-classifier-hover-like { + background-color: #34912E; } .NB-classifiers .NB-classifier.NB-classifier-dislike.NB-classifier-hover-like { border: 1px solid transparent; @@ -2359,14 +2364,48 @@ background: transparent; .NB-classifiers .NB-classifier.NB-classifier-hover-like .NB-classifier-icon-dislike { opacity: .1; } +.NB-classifiers .NB-classifier.NB-classifier-dislike .NB-classifier-icon-dislike, +.NB-classifiers .NB-classifier.NB-classifier-hover-dislike .NB-classifier-icon-dislike { + opacity: 1; +} +.NB-classifiers .NB-classifier.NB-classifier-dislike .NB-classifier-icon-like, +.NB-classifiers .NB-classifier.NB-classifier-hover-dislike .NB-classifier-icon-like { + opacity: .1; +} +.NB-classifiers .NB-classifier.NB-classifier-dislike.NB-classifier-hover-like .NB-classifier-icon-like { + opacity: 1; +} +.NB-classifiers .NB-classifier.NB-classifier-dislike.NB-classifier-hover-like .NB-classifier-icon-dislike { + opacity: .1; +} +.NB-classifiers .NB-classifier.NB-classifier-hover-like.NB-classifier-hover-dislike .NB-classifier-icon-dislike { + opacity: 1; +} +.NB-classifiers .NB-classifier.NB-classifier-hover-like.NB-classifier-hover-dislike .NB-classifier-icon-like { + opacity: .1; +} +.NB-classifiers .NB-classifier.NB-classifier-like .NB-classifier-icon-like, +.NB-classifiers .NB-classifier.NB-classifier-hover-like .NB-classifier-icon-like, +.NB-classifiers .NB-classifier.NB-classifier-dislike .NB-classifier-icon-dislike, +.NB-classifiers .NB-classifier.NB-classifier-hover-dislike .NB-classifier-icon-dislike { + opacity: 1; +} .NB-classifiers .NB-classifier.NB-classifier-hover-dislike { background-color: #C92123; } .NB-classifiers .NB-classifier.NB-classifier-like.NB-classifier-hover-dislike { border: 1px solid transparent; } +.NB-classifiers .NB-classifier.NB-classifier-like.NB-classifier-hover-like.NB-classifier-hover-dislike { + background-color: #C92123; +} .NB-classifiers .NB-classifier.NB-classifier-dislike.NB-classifier-hover-like.NB-classifier-hover-dislike { border: 1px solid #000; + background-color: #A90103; +} +.NB-classifiers .NB-classifier.NB-classifier-dislike .NB-classifier-icon-dislike-inner, +.NB-classifiers .NB-classifier.NB-classifier-hover-dislike .NB-classifier-icon-dislike-inner { + border-left-color: #C17C52; } .NB-classifiers .NB-classifier.NB-classifier-dislike label b, .NB-classifiers .NB-classifier.NB-classifier-hover-dislike label b { @@ -2377,14 +2416,6 @@ background: transparent; color: white; text-shadow: 1px 1px 0 #7F1012; } -.NB-classifiers .NB-classifier.NB-classifier-dislike .NB-classifier-icon-dislike, -.NB-classifiers .NB-classifier.NB-classifier-hover-dislike .NB-classifier-icon-dislike { - opacity: 1; -} -.NB-classifiers .NB-classifier.NB-classifier-dislike .NB-classifier-icon-like, -.NB-classifiers .NB-classifier.NB-classifier-hover-dislike .NB-classifier-icon-like { - opacity: .1; -} /* =================== */ /* = Mouse Indicator = */ /* =================== */ diff --git a/media/js/newsblur/reader.js b/media/js/newsblur/reader.js index 5afe5ba46..52451c63e 100644 --- a/media/js/newsblur/reader.js +++ b/media/js/newsblur/reader.js @@ -3688,6 +3688,14 @@ $document.bind('keydown', 'shift+k', function(e) { e.preventDefault(); self.show_next_feed(-1); + }); + $document.bind('keydown', 'shift+down', function(e) { + e.preventDefault(); + self.show_next_feed(1); + }); + $document.bind('keydown', 'shift+up', function(e) { + e.preventDefault(); + self.show_next_feed(-1); }); $document.bind('keydown', 'left', function(e) { e.preventDefault(); diff --git a/media/js/newsblur/reader_classifier.js b/media/js/newsblur/reader_classifier.js index 1d697faa2..42abbc8dd 100644 --- a/media/js/newsblur/reader_classifier.js +++ b/media/js/newsblur/reader_classifier.js @@ -547,15 +547,15 @@ var classifier_prototype = { $('.NB-classifier-input-dislike', $classifier).attr('checked', true); } - $('.NB-classifier', $classifier).bind('mouseover', function(e) { + $('.NB-classifier', $classifier).bind('mouseenter', function(e) { $(e.currentTarget).addClass('NB-classifier-hover-like'); - }).bind('mouseout', function(e) { + }).bind('mouseleave', function(e) { $(e.currentTarget).removeClass('NB-classifier-hover-like'); }); - $('.NB-classifier-icon-dislike', $classifier).bind('mouseover', function(e) { + $('.NB-classifier-icon-dislike', $classifier).bind('mouseenter', function(e) { $('.NB-classifier', $classifier).addClass('NB-classifier-hover-dislike'); - }).bind('mouseout', function(e) { + }).bind('mouseleave', function(e) { $('.NB-classifier', $classifier).removeClass('NB-classifier-hover-dislike'); }); diff --git a/media/js/newsblur/reader_keyboard.js b/media/js/newsblur/reader_keyboard.js index 0cd9bd9c7..c1ebb4b2c 100644 --- a/media/js/newsblur/reader_keyboard.js +++ b/media/js/newsblur/reader_keyboard.js @@ -24,8 +24,9 @@ NEWSBLUR.ReaderKeyboard.prototype = { $.make('div', { className: 'NB-keyboard-shortcut' }, [ $.make('div', { className: 'NB-keyboard-shortcut-explanation' }, 'Next story'), $.make('div', { className: 'NB-keyboard-shortcut-key' }, [ - '↓', - $.make('span', 'or'), + '↓' + ]), + $.make('div', { className: 'NB-keyboard-shortcut-key' }, [ 'j' ]), $.make('div', { className: 'NB-keyboard-shortcut-image' }, [ @@ -35,8 +36,9 @@ NEWSBLUR.ReaderKeyboard.prototype = { $.make('div', { className: 'NB-keyboard-shortcut NB-last' }, [ $.make('div', { className: 'NB-keyboard-shortcut-explanation' }, 'Previous story'), $.make('div', { className: 'NB-keyboard-shortcut-key' }, [ - '↑', - $.make('span', 'or'), + '↑' + ]), + $.make('div', { className: 'NB-keyboard-shortcut-key' }, [ 'k' ]), $.make('div', { className: 'NB-keyboard-shortcut-image' }, [ @@ -44,6 +46,34 @@ NEWSBLUR.ReaderKeyboard.prototype = { ]) ]) ]), + $.make('div', { className: 'NB-keyboard-group' }, [ + $.make('div', { className: 'NB-keyboard-shortcut' }, [ + $.make('div', { className: 'NB-keyboard-shortcut-explanation' }, 'Next site'), + $.make('div', { className: 'NB-keyboard-shortcut-key' }, [ + 'shift', + $.make('span', '+'), + '↓' + ]), + $.make('div', { className: 'NB-keyboard-shortcut-key' }, [ + 'shift', + $.make('span', '+'), + 'j' + ]) + ]), + $.make('div', { className: 'NB-keyboard-shortcut NB-last' }, [ + $.make('div', { className: 'NB-keyboard-shortcut-explanation' }, 'Prev. site'), + $.make('div', { className: 'NB-keyboard-shortcut-key' }, [ + 'shift', + $.make('span', '+'), + '↑' + ]), + $.make('div', { className: 'NB-keyboard-shortcut-key' }, [ + 'shift', + $.make('span', '+'), + 'k' + ]) + ]) + ]), $.make('div', { className: 'NB-keyboard-group' }, [ $.make('div', { className: 'NB-keyboard-shortcut' }, [ $.make('div', { className: 'NB-keyboard-shortcut-explanation' }, 'Switch views'), From 90b57f31ce2b9744a806af09529067030ffc206d Mon Sep 17 00:00:00 2001 From: Samuel Clay Date: Thu, 21 Oct 2010 23:32:07 -0400 Subject: [PATCH 09/13] Adding titles to trainer. Removing feed manager. It's functionality is now compeltely rolled into the intelligence trainer. Big YAY for deleting old code. --- media/css/reader.css | 4 +- media/js/newsblur/reader.js | 17 +- media/js/newsblur/reader_classifier.js | 55 ++- media/js/newsblur/reader_manage_feed.js | 424 ------------------------ 4 files changed, 53 insertions(+), 447 deletions(-) delete mode 100644 media/js/newsblur/reader_manage_feed.js diff --git a/media/css/reader.css b/media/css/reader.css index 020e473f4..a83c4ab45 100644 --- a/media/css/reader.css +++ b/media/css/reader.css @@ -768,8 +768,8 @@ background: transparent; margin-left: 24px; } -#story_titles .NB-feedbar .NB-feedbar-manage-feed { - background: transparent url("../img/icons/silk/cog.png") no-repeat center center; +#story_titles .NB-feedbar .NB-feedbar-train-feed { + background: transparent url("../img/icons/silk/bricks.png") no-repeat center center; width: 16px; height: 16px; /* display: none;*/ diff --git a/media/js/newsblur/reader.js b/media/js/newsblur/reader.js index 52451c63e..4bbf0aeef 100644 --- a/media/js/newsblur/reader.js +++ b/media/js/newsblur/reader.js @@ -670,7 +670,7 @@ $.make('img', { className: 'feed_favicon', src: this.google_favicon_url + feed.feed_link }), $.make('span', { className: 'feed_title' }, [ feed.feed_title, - $.make('span', { className: 'NB-feedbar-manage-feed', title: 'Manage Intelligence' }), + $.make('span', { className: 'NB-feedbar-train-feed', title: 'Train Intelligence' }), (type == 'story' && $.make('span', { className: 'NB-feedbar-statistics', title: 'Statistics' })) ]), (type == 'story' && $.make('div', { className: 'NB-feedbar-last-updated' }, [ @@ -2312,10 +2312,6 @@ $.make('div', { className: 'NB-menu-manage-image' }), $.make('div', { className: 'NB-menu-manage-title' }, 'Intelligence trainer') ]), - $.make('li', { className: 'NB-menu-manage-feed NB-menu-manage-feed-manage' }, [ - $.make('div', { className: 'NB-menu-manage-image' }), - $.make('div', { className: 'NB-menu-manage-title' }, 'Intelligence manager') - ]), $.make('li', { className: 'NB-menu-separator' }), $.make('li', { className: 'NB-menu-manage-feed NB-menu-manage-delete NB-menu-manage-feed-delete' }, [ $.make('div', { className: 'NB-menu-manage-image' }), @@ -3261,10 +3257,10 @@ $.targetIs(e, { tagSelector: '.NB-feedbar-statistics' }, function($t, $p){ self.open_feed_statistics_modal(); }); - $.targetIs(e, { tagSelector: '.NB-feedbar-manage-feed' }, function($t, $p){ + $.targetIs(e, { tagSelector: '.NB-feedbar-train-feed' }, function($t, $p){ e.preventDefault(); if (!$('.NB-task-manage').hasClass('NB-disabled')) { - self.open_manage_feed_modal(); + self.open_feed_intelligence_modal(1, this.active_feed, true); } }); @@ -3334,13 +3330,6 @@ self.show_manage_menu('site', $t); } }); - $.targetIs(e, { tagSelector: '.NB-menu-manage-feed-manage' }, function($t, $p){ - e.preventDefault(); - if (!$t.hasClass('NB-disabled')) { - var feed_id = $t.parents('.NB-menu-manage').data('feed_id'); - self.open_manage_feed_modal(feed_id); - } - }); $.targetIs(e, { tagSelector: '.NB-menu-manage-feed-train' }, function($t, $p){ e.preventDefault(); if (!$t.hasClass('NB-disabled')) { diff --git a/media/js/newsblur/reader_classifier.js b/media/js/newsblur/reader_classifier.js index 42abbc8dd..a4e877712 100644 --- a/media/js/newsblur/reader_classifier.js +++ b/media/js/newsblur/reader_classifier.js @@ -309,7 +309,6 @@ var classifier_prototype = { make_modal_feed: function() { var self = this; var feed = this.feed; - var opinion = (this.score == 1 ? 'like_' : 'dislike_'); // NEWSBLUR.log(['Make feed', feed, this.feed_authors, this.feed_tags]); @@ -323,22 +322,28 @@ var classifier_prototype = { ]), (this.options['feed_loaded'] && $.make('form', { method: 'post', className: 'NB-publisher' }, [ + (!_.isEmpty(this.user_classifiers.titles) && $.make('div', { className: 'NB-modal-field NB-fieldset NB-classifiers' }, [ + $.make('h5', 'Titles and Phrases'), + $.make('div', { className: 'NB-classifier-titles NB-fieldset-fields NB-classifiers' }, + this.make_user_titles() + ) + ])), (this.feed_authors.length && $.make('div', { className: 'NB-modal-field NB-fieldset NB-classifiers' }, [ $.make('h5', 'Authors'), $.make('div', { className: 'NB-classifier-authors NB-fieldset-fields NB-classifiers' }, - this.make_authors(this.feed_authors, opinion) + this.make_authors(this.feed_authors).concat(this.make_user_authors()) ) ])), (this.feed_tags.length && $.make('div', { className: 'NB-modal-field NB-fieldset NB-classifiers' }, [ $.make('h5', 'Categories & Tags'), $.make('div', { className: 'NB-classifier-tags NB-fieldset-fields NB-classifiers' }, - this.make_tags(this.feed_tags, opinion) + this.make_tags(this.feed_tags).concat(this.make_user_tags()) ) ])), $.make('div', { className: 'NB-modal-field NB-fieldset NB-classifiers' }, [ $.make('h5', 'Everything by This Publisher'), $.make('div', { className: 'NB-fieldset-fields NB-classifiers' }, - this.make_publisher(feed, opinion) + this.make_publisher(feed) ) ]), (this.options['training'] && $.make('div', { className: 'NB-modal-submit' }, [ @@ -446,6 +451,18 @@ var classifier_prototype = { $count.html(count + '/' + total); }, + make_user_titles: function() { + var $titles = []; + var titles = _.keys(this.user_classifiers.titles); + + _.each(titles, _.bind(function(title) { + var $title = this.make_classifier(title, title, 'title'); + $titles.push($title); + }, this)); + + return $titles; + }, + make_authors: function(authors, opinion) { var $authors = []; @@ -467,7 +484,19 @@ var classifier_prototype = { return $authors; }, - make_tags: function(tags, opinion) { + make_user_authors: function() { + var $authors = []; + var user_authors = _.keys(this.user_classifiers.authors); + var feed_authors = _.map(this.feed_authors, function(author) { return author[0]; }); + var authors = _.reduce(user_authors, function(memo, author, i) { + if (!_.contains(feed_authors, author)) return memo.concat(author); + return memo; + }, []); + + return this.make_authors(authors); + }, + + make_tags: function(tags) { var $tags = []; for (var t in tags) { @@ -489,6 +518,18 @@ var classifier_prototype = { return $tags; }, + make_user_tags: function() { + var $tags = []; + var user_tags = _.keys(this.user_classifiers.tags); + var feed_tags = _.map(this.feed_tags, function(tag) { return tag[0]; }); + var tags = _.reduce(user_tags, function(memo, tag, i) { + if (!_.contains(feed_tags, tag)) return memo.concat(tag); + return memo; + }, []); + + return this.make_tags(tags); + }, + make_publisher: function(publisher, opinion) { var $publisher = this.make_classifier(publisher.feed_title, this.feed_id, 'feed'); return $publisher; @@ -496,7 +537,7 @@ var classifier_prototype = { make_classifier: function(classifier_title, classifier_value, classifier_type, classifier_count) { var score = 0; - NEWSBLUR.log(['classifiers', this.user_classifiers, classifier_value, this.user_classifiers[classifier_type+'s']]); + // NEWSBLUR.log(['classifiers', this.user_classifiers, classifier_value, this.user_classifiers[classifier_type+'s']]); if (classifier_value in this.user_classifiers[classifier_type+'s']) { score = this.user_classifiers[classifier_type+'s'][classifier_value]; } @@ -599,7 +640,7 @@ var classifier_prototype = { } else { $save.removeClass("NB-disabled").removeAttr('disabled').attr('value', 'Save'); } - NEWSBLUR.log(['change_classifier', classifier_opinion, $classifier, $like.is(':checked'), $dislike.is(':checked')]); + // NEWSBLUR.log(['change_classifier', classifier_opinion, $classifier, $like.is(':checked'), $dislike.is(':checked')]); }, open_modal: function() { diff --git a/media/js/newsblur/reader_manage_feed.js b/media/js/newsblur/reader_manage_feed.js deleted file mode 100644 index 00dd686db..000000000 --- a/media/js/newsblur/reader_manage_feed.js +++ /dev/null @@ -1,424 +0,0 @@ -NEWSBLUR.ReaderManageFeed = function(feed_id, options) { - var defaults = {}; - - this.options = $.extend({}, defaults, options); - this.model = NEWSBLUR.AssetModel.reader(); - this.feed_id = feed_id; - this.google_favicon_url = 'http://www.google.com/s2/favicons?domain_url='; - this.counters = { - 'classifier': 0 - }; - this.runner(); -}; - -NEWSBLUR.ReaderManageFeed.prototype = { - - runner: function() { - this.feeds = this.model.get_feeds(); - - if (!this.feed_id) { - // No feed selected, so just choose a random feed. - var feeds_list = []; - for (var f in this.feeds) { - feeds_list.push(f); - } - this.feed_id = feeds_list[Math.round(Math.random() * 1000 % (feeds_list.length-1))]; - if (!this.feed_id) this.feed_id = f; - } - this.feed = this.model.get_feed(this.feed_id); - - if (this.feed_id) { - this.make_modal(); - this.initialize_feed(); - this.handle_cancel(); - this.open_modal(); - this.load_feed_classifier(); - - this.$manage.bind('click', $.rescope(this.handle_click, this)); - this.$manage.bind('change', $.rescope(this.handle_change, this)); - this.$manage.bind('keyup', $.rescope(this.handle_keyup, this)); - } - }, - - initialize_feed: function(feed_id) { - if (feed_id) this.feed_id = feed_id; - this.feed = this.model.get_feed(this.feed_id); - $('.NB-modal-title', this.$manage).html(this.feed['feed_title']); - $('input[name=feed_id]', this.$manage).val(this.feed_id); - $('input[name=rename_title]', this.$manage).val(this.feed['feed_title']); - }, - - make_modal: function() { - var self = this; - - this.$manage = $.make('div', { className: 'NB-manage NB-modal' }, [ - $.make('form', { method: 'post', className: 'NB-manage-form' }, [ - $.make('div', { className: 'NB-manage-container'}, [ - $.make('div', { className: 'NB-modal-loading' }), - $.make('h2', { className: 'NB-modal-title' }), - $.make('div', { className: 'NB-manage-field' }, [ - $.make('div', { className: 'NB-fieldset' }, [ - $.make('h5', [ - 'What you ', - $.make('span', { className: 'NB-classifier-like' }, 'like') - ]), - $.make('div', { className: 'NB-manage-classifier NB-manage-classifier-likes NB-fieldset-fields' }) - ]), - $.make('div', { className: 'NB-fieldset' }, [ - $.make('h5', [ - 'What you ', - $.make('span', { className: 'NB-classifier-dislike' }, 'dislike') - ]), - $.make('div', { className: 'NB-manage-classifier NB-manage-classifier-dislikes NB-fieldset-fields' }) - ]), - $.make('div', { className: 'NB-fieldset' }, [ - $.make('h5', 'Management'), - $.make('div', { className: 'NB-manage-management NB-fieldset-fields NB-modal-submit' }, [ - $.make('div', { className: 'NB-manage-rename' }, [ - $.make('label', { className: 'NB-manage-rename-label', 'for': 'id_rename' }, "Feed Title: "), - $.make('input', { name: 'rename_title', id: 'id_rename' }) - ]), - $.make('input', { type: 'submit', value: 'Fetch and refresh this site', className: 'NB-modal-submit-green NB-modal-submit-retry' }), - $.make('div', { className: 'NB-manage-delete' }, [ - $.make('input', { type: 'submit', value: 'Delete this site', className: 'NB-modal-submit-green NB-modal-submit-delete' }), - $.make('a', { className: 'NB-delete-confirm', href: '#' }, "Yes, delete this feed!"), - $.make('a', { className: 'NB-delete-cancel', href: '#' }, "cancel") - ]) - ]) - ]) - ]) - ]), - $.make('div', { className: 'NB-modal-feed-chooser-container'}, [ - this.make_feed_chooser() - ]), - $.make('div', { className: 'NB-modal-submit' }, [ - $.make('input', { name: 'feed_id', type: 'hidden' }), - $.make('input', { type: 'submit', disabled: 'true', className: 'NB-modal-submit-save NB-modal-submit-green NB-disabled', value: 'Check what you like above...' }), - ' or ', - $.make('a', { href: '#', className: 'NB-modal-cancel' }, 'cancel') - ]) - ]).bind('submit', function(e) { - e.preventDefault(); - self.save(); - return false; - }) - ]); - - }, - - make_feed_chooser: function() { - var $chooser = $.make('select', { name: 'feed', className: 'NB-modal-feed-chooser' }); - - for (var f in this.feeds) { - var feed = this.feeds[f]; - var $option = $.make('option', { value: feed.id }, feed.feed_title); - $option.appendTo($chooser); - - if (feed.id == this.feed_id) { - $option.attr('selected', true); - } - } - - $('option', $chooser).tsort(); - return $chooser; - }, - - make_classifiers: function(classifiers, score) { - var $classifiers = $.make('div'); - var i = this.counters['classifier']; - var opinion = (score == 1 ? 'like_' : 'dislike_'); - - // Tags - var $tags = $.make('div', { className: 'NB-classifiers NB-classifier-tags'}); - for (var t in classifiers.tags) { - if (classifiers.tags[t] == score) { - var $tag = this.make_tag(t, i++, opinion); - $tags.append($tag); - } - } - - // Authors - var $authors = $.make('div', { className: 'NB-classifiers NB-classifier-authors'}); - for (var fa in classifiers.authors) { - if (classifiers.authors[fa] == score) { - var $author = this.make_author(fa, i++, opinion); - $authors.append($author); - } - } - - // Titles - var $titles = $.make('div', { className: 'NB-classifiers NB-classifier-titles'}); - for (var t in classifiers.titles) { - if (classifiers.titles[t] == score) { - var $title = this.make_title(t, i++, opinion); - $titles.append($title); - } - } - - // Publisher - var $publishers = $.make('div', { className: 'NB-classifiers NB-classifier-publishers'}); - for (var feed_id in classifiers.feeds) { - if (classifiers.feeds[feed_id] == score) { - var $publisher = this.make_publisher(feed_id, i++, opinion); - $publishers.append($publisher); - } - } - - $classifiers.append($tags); - $classifiers.append($authors); - $classifiers.append($titles); - $classifiers.append($publishers); - - if (!$('.NB-classifier', $classifiers).length) { - var $empty_classifier = $.make('div', { className: 'NB-classifier-empty' }, [ - 'No opinions yet. Use the ', - $.make('img', { src: NEWSBLUR.Globals.MEDIA_URL + 'img/reader/thumbs-down.png', className: 'NB-dislike' }), - $.make('img', { src: NEWSBLUR.Globals.MEDIA_URL + 'img/reader/thumbs-up.png', className: 'NB-like' }), - ' buttons next to stories.' - ]); - $classifiers.append($empty_classifier); - } - - this.counters['classifier'] = i; - return $classifiers; - }, - - make_author: function(feed_author, i, opinion) { - var $author = $.make('span', { className: 'NB-classifier NB-classifier-author' }, [ - $.make('input', { type: 'checkbox', name: opinion+'author', value: feed_author, id: 'classifier_author_'+i, checked: 'checked' }), - $.make('label', { 'for': 'classifier_author_'+i }, [ - $.make('b', 'Author: '), - $.make('span', feed_author) - ]) - ]); - return $author; - }, - - make_tag: function(tag, t, opinion) { - var $tag = $.make('span', { className: 'NB-classifier-tag-container' }, [ - $.make('span', { className: 'NB-classifier NB-classifier-tag' }, [ - $.make('input', { type: 'checkbox', name: opinion+'tag', value: tag, id: 'classifier_tag_'+t, checked: 'checked' }), - $.make('label', { 'for': 'classifier_tag_'+t }, [ - $.make('b', 'Tag: '), - $.make('span', tag) - ]) - ]) - ]); - return $tag; - }, - - make_publisher: function(feed_id, i, opinion) { - var publisher = this.model.get_feed(feed_id); - var $publisher = $.make('div', { className: 'NB-classifier NB-classifier-publisher' }, [ - $.make('input', { type: 'checkbox', name: opinion+'publisher', value: this.feed_id, id: 'classifier_publisher', checked: 'checked' }), - $.make('label', { 'for': 'classifier_publisher' }, [ - $.make('img', { className: 'feed_favicon', src: this.google_favicon_url + publisher.feed_link }), - $.make('span', { className: 'feed_title' }, [ - $.make('b', 'Publisher: '), - $.make('span', publisher.feed_title) - ]) - ]) - ]); - return $publisher; - }, - - make_title: function(title, t, opinion) { - var $title = $.make('div', { className: 'NB-classifier NB-classifier-title' }, [ - $.make('input', { type: 'checkbox', name: opinion+'title', value: title, id: 'classifier_title_'+t, checked: 'checked' }), - $.make('label', { 'for': 'classifier_title_'+t }, [ - $.make('b', 'Title: '), - $.make('span', title) - ]) - ]); - return $title; - }, - - load_feed_classifier: function() { - var $loading = $('.NB-modal-loading', this.$manage); - $loading.addClass('NB-active'); - - this.model.get_feed_classifier(this.feed_id, $.rescope(this.post_load_feed_classifier, this)); - }, - - post_load_feed_classifier: function(e, classifiers) { - var $loading = $('.NB-modal-loading', this.$manage); - $loading.removeClass('NB-active'); - - var $likes = $('.NB-manage-classifier-likes'); - var $classifiers_likes = this.make_classifiers(classifiers.payload, 1); - $likes.empty().append($classifiers_likes); - - var $dislikes = $('.NB-manage-classifier-dislikes'); - var $classifiers_dislikes = this.make_classifiers(classifiers.payload, -1); - $dislikes.empty().append($classifiers_dislikes); - - $('.NB-classifier', this.$manage).corner('14px'); - }, - - open_modal: function() { - var self = this; - - this.$manage.modal({ - 'minWidth': 600, - 'maxWidth': 600, - 'overlayClose': true, - 'onOpen': function (dialog) { - dialog.overlay.fadeIn(200, function () { - dialog.container.fadeIn(200); - dialog.data.fadeIn(200); - }); - }, - 'onShow': function(dialog) { - $('#simplemodal-container').corner('6px'); - // $('.NB-classifier-tag', self.$manage).corner('4px'); - }, - 'onClose': function(dialog) { - dialog.data.hide().empty().remove(); - dialog.container.hide().empty().remove(); - dialog.overlay.fadeOut(200, function() { - dialog.overlay.empty().remove(); - $.modal.close(); - }); - $('.NB-modal-holder').empty().remove(); - } - }); - }, - - handle_cancel: function() { - var $cancel = $('.NB-modal-cancel', this.$manage); - - $cancel.click(function(e) { - e.preventDefault(); - $.modal.close(); - }); - }, - - serialize_classifier: function() { - var checked_data = $('input', this.$manage).serialize(); - var $unchecked = $('input[type=checkbox]:not(:checked)', this.$manage); - $unchecked.attr('checked', true); - $unchecked.each(function() { - $(this).attr('name', 'remove_' + $(this).attr('name')); - }); - var unchecked_data = $unchecked.serialize(); - $unchecked.each(function() { - $(this).attr('name', $(this).attr('name').replace(/^remove_/, '')); - }); - $unchecked.attr('checked', false); - - var data = [checked_data, unchecked_data].join('&'); - return data; - }, - - save: function() { - var self = this; - var $save = $('.NB-modal-submit-save', this.$manage); - var data = this.serialize_classifier(); - - NEWSBLUR.reader.update_opinions(this.$manage, this.feed_id); - - $save.text('Saving...').addClass('NB-disabled').attr('disabled', true); - this.model.save_classifier_publisher(data, function() { - NEWSBLUR.reader.force_feed_refresh(self.feed_id); - $.modal.close(); - }); - }, - - save_retry_feed: function() { - var self = this; - var $loading = $('.NB-modal-loading', this.$manage); - $loading.addClass('NB-active'); - - $('.NB-modal-submit-retry', this.$manage).addClass('NB-disabled').attr('value', 'Fetching...'); - this.model.save_exception_retry(this.feed_id, function() { - NEWSBLUR.reader.force_feed_refresh(self.feed_id, function() { - if (NEWSBLUR.reader.active_feed == self.feed_id) { - NEWSBLUR.reader.open_feed(self.feed_id, true); - } - $.modal.close(); - }, true); - }); - }, - - delete_feed: function() { - var $loading = $('.NB-modal-loading', this.$manage); - $loading.addClass('NB-active'); - var feed_id = this.feed_id; - - this.model.delete_publisher(feed_id, function() { - NEWSBLUR.reader.delete_feed(feed_id); - $.modal.close(); - }); - }, - - handle_click: function(elem, e) { - var self = this; - - $.targetIs(e, { tagSelector: '.NB-modal-submit-delete' }, function($t, $p){ - e.preventDefault(); - - var $confirm = $('.NB-delete-confirm', self.$manage); - var $cancel = $('.NB-delete-cancel', self.$manage); - var $delete = $('.NB-modal-submit-delete', self.$manage); - - $delete.animate({'opacity': 0}, {'duration': 500}); - $confirm.fadeIn(500); - $cancel.fadeIn(500); - }); - - $.targetIs(e, { tagSelector: '.NB-delete-cancel' }, function($t, $p){ - e.preventDefault(); - - var $confirm = $('.NB-delete-confirm', self.$manage); - var $cancel = $('.NB-delete-cancel', self.$manage); - var $delete = $('.NB-modal-submit-delete', self.$manage); - - $delete.css({'opacity': 1}); - $confirm.css({'display': 'none'}); - $cancel.css({'display': 'none'}); - }); - - $.targetIs(e, { tagSelector: '.NB-delete-confirm' }, function($t, $p){ - e.preventDefault(); - - self.delete_feed(); - }); - - $.targetIs(e, { tagSelector: 'input', childOf: '.NB-classifier' }, function($t, $p) { - var $submit = $('.NB-modal-submit-save', self.$manage); - $submit.removeClass("NB-disabled").removeAttr('disabled').attr('value', 'Save'); - }); - - $.targetIs(e, { tagSelector: '.NB-modal-submit-retry' }, function($t, $p) { - e.preventDefault(); - - self.save_retry_feed(); - }); - }, - - handle_change: function(elem, e) { - var self = this; - - $.targetIs(e, { tagSelector: '.NB-modal-feed-chooser' }, function($t, $p){ - var feed_id = $t.val(); - self.initialize_feed(feed_id); - self.load_feed_classifier(); - }); - - $.targetIs(e, { tagSelector: 'input[type=checkbox]', childOf: '.NB-classifier' }, function($t, $p) { - var $submit = $('.NB-modal-submit-save', self.$manage); - $submit.removeClass("NB-disabled").removeAttr('disabled').attr('value', 'Save'); - }); - }, - - handle_keyup: function(elem, e) { - var self = this; - - $.targetIs(e, { tagSelector: 'input', childOf: '.NB-manage-rename' }, function($t, $p) { - if ($t.val() != self.feed.feed_title) { - var $submit = $('.NB-modal-submit-save', self.$manage); - $submit.removeClass("NB-disabled").removeAttr('disabled').attr('value', 'Save'); - } - }); - } -}; \ No newline at end of file From 516f08d6be450312db85a543acafa933dcd62f9f Mon Sep 17 00:00:00 2001 From: Samuel Clay Date: Fri, 22 Oct 2010 00:16:34 -0400 Subject: [PATCH 10/13] Final touches to the new classifiers. Title highlighting now controls the new-style title classifier in story view. --- media/js/newsblur/reader_classifier.js | 47 ++++++-------------------- 1 file changed, 11 insertions(+), 36 deletions(-) diff --git a/media/js/newsblur/reader_classifier.js b/media/js/newsblur/reader_classifier.js index a4e877712..3c3715fc6 100644 --- a/media/js/newsblur/reader_classifier.js +++ b/media/js/newsblur/reader_classifier.js @@ -72,7 +72,6 @@ var classifier_prototype = { this.make_trainer_intro(); this.get_feeds_trainer(); this.handle_cancel(); - this.handle_select_title(); this.open_modal(); this.$modal.parent().bind('click.reader_classifer', $.rescope(this.handle_clicks, this)); @@ -89,7 +88,6 @@ var classifier_prototype = { this.make_modal_feed(); this.make_modal_title(); this.handle_cancel(); - this.handle_select_title(); this.open_modal(); this.$modal.parent().bind('click.reader_classifer', $.rescope(this.handle_clicks, this)); @@ -108,7 +106,6 @@ var classifier_prototype = { this.make_modal_title(); this.handle_text_highlight(); this.handle_cancel(); - this.handle_select_title(); this.open_modal(); this.$modal.parent().bind('click.reader_classifer', $.rescope(this.handle_clicks, this)); }, @@ -354,7 +351,6 @@ var classifier_prototype = { $.make('a', { href: '#', className: 'NB-modal-submit-button NB-modal-submit-close' }, 'Close') ])), (!this.options['training'] && $.make('div', { className: 'NB-modal-submit' }, [ - $.make('input', { name: 'score', value: this.score, type: 'hidden' }), $.make('input', { name: 'story_id', value: this.story_id, type: 'hidden' }), $.make('input', { name: 'feed_id', value: this.feed_id, type: 'hidden' }), $.make('input', { type: 'submit', disabled: 'true', className: 'NB-modal-submit-save NB-modal-submit-green NB-disabled', value: 'Check what you like above...' }), @@ -377,20 +373,14 @@ var classifier_prototype = { // HTML entities decoding. story.story_title = $('
').html(story.story_title).text(); - this.$modal = $.make('div', { className: 'NB-classifier NB-modal' }, [ + this.$modal = $.make('div', { className: 'NB-modal-classifiers NB-modal' }, [ $.make('h2', { className: 'NB-modal-title' }), $.make('form', { method: 'post' }, [ (story.story_title && $.make('div', { className: 'NB-modal-field NB-fieldset' }, [ $.make('h5', 'Story Title'), $.make('div', { className: 'NB-fieldset-fields NB-classifiers' }, [ $.make('input', { type: 'text', value: story.story_title, className: 'NB-classifier-title-highlight' }), - $.make('div', { className: 'NB-classifier NB-classifier-title NB-classifier-facet-disabled' }, [ - $.make('input', { type: 'checkbox', name: opinion+'title', value: '', id: 'classifier_title' }), - $.make('label', { 'for': 'classifier_title' }, [ - $.make('b', 'Look for: '), - $.make('span', { className: 'NB-classifier-title-text' }, 'Highlight phrases to look for in future stories') - ]) - ]) + this.make_classifier('Highlight phrases to look for in future stories', '', 'title') ]) ])), (story.story_authors && $.make('div', { className: 'NB-modal-field NB-fieldset' }, [ @@ -412,7 +402,6 @@ var classifier_prototype = { ) ]), $.make('div', { className: 'NB-modal-submit' }, [ - $.make('input', { name: 'score', value: this.score, type: 'hidden' }), $.make('input', { name: 'story_id', value: this.story_id, type: 'hidden' }), $.make('input', { name: 'feed_id', value: this.feed_id, type: 'hidden' }), $.make('input', { type: 'submit', disabled: 'true', className: 'NB-modal-submit-save NB-modal-submit-green NB-disabled', value: 'Check what you like above...' }), @@ -682,19 +671,21 @@ var classifier_prototype = { // ========== handle_text_highlight: function() { + var self = this; var $title_highlight = $('.NB-classifier-title-highlight', this.$modal); var $title = $('.NB-classifier-title-text', this.$modal); - var $title_checkbox = $('#classifier_title', this.$modal); - + var $title_classifier = $title.parents('.NB-classifier').eq(0); + var $title_checkboxs = $('.NB-classifier-input-like, .NB-classifier-input-dislike', $title_classifier); + var update = function() { var text = $.trim($(this).getSelection().text); - if ($title.text() != text && text.length) { - $title_checkbox.attr('checked', 'checked').change(); + if (text.length && $title.text() != text) { $title.text(text); - $title_checkbox.parents('.NB-classifier-facet-disabled') - .removeClass('NB-classifier-facet-disabled'); - $title_checkbox.val(text); + $title_checkboxs.val(text); + if (!$title_classifier.is('.NB-classifier-like,.NB-classifier-dislike')) { + self.change_classifier($title.parents('.NB-classifier').eq(0), 'like'); + } } }; @@ -703,22 +694,6 @@ var classifier_prototype = { .mousedown(update).mouseup(update).mousemove(update); }, - handle_select_title: function() { - var $title_checkbox = $('#classifier_title', this.$modal); - var $title = $('.NB-classifier-title-text', this.$modal); - var $title_highlight = $('.NB-classifier-title-highlight', this.$modal); - - $title_checkbox.change(function() {; - if ($title.parents('.NB-classifier-facet-disabled').length) { - var text = $title_highlight.val(); - $title.text(text); - $title_checkbox.parents('.NB-classifier-facet-disabled') - .removeClass('NB-classifier-facet-disabled'); - $title_checkbox.val(text); - } - }); - }, - handle_cancel: function() { var $cancel = $('.NB-modal-cancel', this.$modal); From 8dee466fbd5c2859d1061649e632e2a1032cb694 Mon Sep 17 00:00:00 2001 From: Samuel Clay Date: Fri, 22 Oct 2010 00:19:22 -0400 Subject: [PATCH 11/13] Removing feed manager for good. --- settings.py | 1 - 1 file changed, 1 deletion(-) diff --git a/settings.py b/settings.py index 19c7b721c..602af1a00 100644 --- a/settings.py +++ b/settings.py @@ -114,7 +114,6 @@ COMPRESS_JS = { 'js/newsblur/reader.js', 'js/newsblur/reader_classifier.js', 'js/newsblur/reader_add_feed.js', - 'js/newsblur/reader_manage_feed.js', 'js/newsblur/reader_mark_read.js', 'js/newsblur/reader_preferences.js', 'js/newsblur/reader_statistics.js', From 3d17e18dfc59b9dd1ffaf8e809112f5c4347e9ce Mon Sep 17 00:00:00 2001 From: Samuel Clay Date: Fri, 22 Oct 2010 00:21:57 -0400 Subject: [PATCH 12/13] Refreshing thumbs up/down images. --- media/css/reader.css | 20 +++++++++--------- .../{thumbs-down.png => thumbs_down.png} | Bin .../reader/{thumbs-up.png => thumbs_up.png} | Bin 3 files changed, 10 insertions(+), 10 deletions(-) rename media/img/reader/{thumbs-down.png => thumbs_down.png} (100%) rename media/img/reader/{thumbs-up.png => thumbs_up.png} (100%) diff --git a/media/css/reader.css b/media/css/reader.css index a83c4ab45..01e9854d5 100644 --- a/media/css/reader.css +++ b/media/css/reader.css @@ -883,12 +883,12 @@ background: transparent; #story_titles .NB-feedbar .NB-feed-like { right: 24px; - background: transparent url('../img/reader/thumbs-up.png') no-repeat 0 0; + background: transparent url('../img/reader/thumbs_up.png') no-repeat 0 0; } #story_titles .NB-feedbar .NB-feed-dislike { right: 4px; - background: transparent url('../img/reader/thumbs-down.png') no-repeat 0 -4px; + background: transparent url('../img/reader/thumbs_down.png') no-repeat 0 -4px; } #story_titles .feed .unread_count.unread_count_full { @@ -974,12 +974,12 @@ background: transparent; #story_titles .NB-story-like { left: 22px; - background: transparent url('../img/reader/thumbs-up.png') no-repeat 2px 0; + background: transparent url('../img/reader/thumbs_up.png') no-repeat 2px 0; } #story_titles .NB-story-dislike { left: 0px; - background: transparent url('../img/reader/thumbs-down.png') no-repeat 4px -4px; + background: transparent url('../img/reader/thumbs_down.png') no-repeat 4px -4px; } #story_titles .story.read { @@ -1918,14 +1918,14 @@ a.NB-splash-link:hover { .NB-modal-classifiers .NB-modal-title .NB-classifier-title-like { color: #3D931B; padding-left: 20px; - background: transparent url('../img/reader/thumbs-up.png') no-repeat 0 6px; + background: transparent url('../img/reader/thumbs_up.png') no-repeat 0 6px; } .NB-modal-classifiers .NB-modal-title .NB-classifier-title-dislike { color: #932C15; padding-right: 20px; - background: transparent url('../img/reader/thumbs-down.png') no-repeat right 2px; + background: transparent url('../img/reader/thumbs_down.png') no-repeat right 2px; } .simplemodal-wrap { @@ -2134,14 +2134,14 @@ a.NB-splash-link:hover { .NB-manage .NB-classifier-title-like { color: #3D931B; padding-left: 20px; - background: transparent url('../img/reader/thumbs-up.png') no-repeat 0 0; + background: transparent url('../img/reader/thumbs_up.png') no-repeat 0 0; } .NB-manage .NB-classifier-title-dislike { color: #932C15; padding-left: 20px; - background: transparent url('../img/reader/thumbs-down.png') no-repeat 0 0; + background: transparent url('../img/reader/thumbs_down.png') no-repeat 0 0; } .NB-manage .NB-manage-classifier { @@ -2303,7 +2303,7 @@ background: transparent; .NB-classifiers .NB-classifier .NB-classifier-icon-like { width: 16px; height: 16px; - background: transparent url('../img/reader/thumbs-up.png') no-repeat 0 0; + background: transparent url('../img/reader/thumbs_up.png') no-repeat 0 0; position: absolute; left: 6px; top: 2px; @@ -2316,7 +2316,7 @@ background: transparent; position: absolute; top: -1px; right: -1px; - background: transparent url('../img/reader/thumbs-down.png') no-repeat 5px -1px; + background: transparent url('../img/reader/thumbs_down.png') no-repeat 5px -1px; opacity: .2; } diff --git a/media/img/reader/thumbs-down.png b/media/img/reader/thumbs_down.png similarity index 100% rename from media/img/reader/thumbs-down.png rename to media/img/reader/thumbs_down.png diff --git a/media/img/reader/thumbs-up.png b/media/img/reader/thumbs_up.png similarity index 100% rename from media/img/reader/thumbs-up.png rename to media/img/reader/thumbs_up.png From 0127a923c3161f9bbf33978c82b5f84812e59a25 Mon Sep 17 00:00:00 2001 From: Samuel Clay Date: Fri, 22 Oct 2010 00:25:02 -0400 Subject: [PATCH 13/13] Updating thumbs in trainer to use new renamed thumbs. --- media/js/newsblur/reader_classifier.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/media/js/newsblur/reader_classifier.js b/media/js/newsblur/reader_classifier.js index 3c3715fc6..cd821618d 100644 --- a/media/js/newsblur/reader_classifier.js +++ b/media/js/newsblur/reader_classifier.js @@ -249,8 +249,8 @@ var classifier_prototype = { $.make('li', [ $.make('b', 'Don\'t worry if you don\'t know what you like right now.'), ' Just skip the site. You can click the ', - $.make('img', { src: NEWSBLUR.Globals.MEDIA_URL + '/img/reader/thumbs-up.png', style: 'vertical-align: middle;padding: 0 8px 0 2px', width: 14, height: 20 }), - $.make('img', { src: NEWSBLUR.Globals.MEDIA_URL + '/img/reader/thumbs-down.png', style: 'vertical-align: top; padding: 0', width: 14, height: 20 }), + $.make('img', { src: NEWSBLUR.Globals.MEDIA_URL + '/img/reader/thumbs_up.png', style: 'vertical-align: middle;padding: 0 8px 0 2px', width: 14, height: 20 }), + $.make('img', { src: NEWSBLUR.Globals.MEDIA_URL + '/img/reader/thumbs_down.png', style: 'vertical-align: top; padding: 0', width: 14, height: 20 }), ' buttons next to stories as you read them.' ]) ]), @@ -274,8 +274,8 @@ var classifier_prototype = { $.make('img', { src: NEWSBLUR.Globals.MEDIA_URL + '/img/reader/sample_classifier_tag.png', style: 'float: right', width: 135, height: 20 }), $.make('b', 'You can change your opinions.'), ' You can click the ', - $.make('img', { src: NEWSBLUR.Globals.MEDIA_URL + '/img/reader/thumbs-up.png', style: 'vertical-align: middle;padding: 0 8px 0 2px', width: 14, height: 20 }), - $.make('img', { src: NEWSBLUR.Globals.MEDIA_URL + '/img/reader/thumbs-down.png', style: 'vertical-align: top; padding: 0', width: 14, height: 20 }), + $.make('img', { src: NEWSBLUR.Globals.MEDIA_URL + '/img/reader/thumbs_up.png', style: 'vertical-align: middle;padding: 0 8px 0 2px', width: 14, height: 20 }), + $.make('img', { src: NEWSBLUR.Globals.MEDIA_URL + '/img/reader/thumbs_down.png', style: 'vertical-align: top; padding: 0', width: 14, height: 20 }), ' buttons next to stories as you read them.' ]), $.make('li', [