Skip to content

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also .

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also .
...
  • 7 commits
  • 11 files changed
  • 0 commit comments
  • 1 contributor
View
3 README.md
@@ -1,5 +1,4 @@
-AngelHack Fall 2012
hvid.io
=======
-Hvid.io
+4th place at AngelHack Paris Fall 2012
View
8 public/javascripts/coffee-script.min.js
8 additions, 0 deletions not shown because the diff is too large. Please use a local Git client to view these changes.
View
560 public/javascripts/eventemitter2.js
@@ -0,0 +1,560 @@
+;!function(exports, undefined) {
+
+ var isArray = Array.isArray ? Array.isArray : function _isArray(obj) {
+ return Object.prototype.toString.call(obj) === "[object Array]";
+ };
+ var defaultMaxListeners = 10;
+
+ function init() {
+ this._events = {};
+ if (this._conf) {
+ configure.call(this, this._conf);
+ }
+ }
+
+ function configure(conf) {
+ if (conf) {
+
+ this._conf = conf;
+
+ conf.delimiter && (this.delimiter = conf.delimiter);
+ conf.maxListeners && (this._events.maxListeners = conf.maxListeners);
+ conf.wildcard && (this.wildcard = conf.wildcard);
+ conf.newListener && (this.newListener = conf.newListener);
+
+ if (this.wildcard) {
+ this.listenerTree = {};
+ }
+ }
+ }
+
+ function EventEmitter(conf) {
+ this._events = {};
+ this.newListener = false;
+ configure.call(this, conf);
+ }
+
+ //
+ // Attention, function return type now is array, always !
+ // It has zero elements if no any matches found and one or more
+ // elements (leafs) if there are matches
+ //
+ function searchListenerTree(handlers, type, tree, i) {
+ if (!tree) {
+ return [];
+ }
+ var listeners=[], leaf, len, branch, xTree, xxTree, isolatedBranch, endReached,
+ typeLength = type.length, currentType = type[i], nextType = type[i+1];
+ if (i === typeLength && tree._listeners) {
+ //
+ // If at the end of the event(s) list and the tree has listeners
+ // invoke those listeners.
+ //
+ if (typeof tree._listeners === 'function') {
+ handlers && handlers.push(tree._listeners);
+ return [tree];
+ } else {
+ for (leaf = 0, len = tree._listeners.length; leaf < len; leaf++) {
+ handlers && handlers.push(tree._listeners[leaf]);
+ }
+ return [tree];
+ }
+ }
+
+ if ((currentType === '*' || currentType === '**') || tree[currentType]) {
+ //
+ // If the event emitted is '*' at this part
+ // or there is a concrete match at this patch
+ //
+ if (currentType === '*') {
+ for (branch in tree) {
+ if (branch !== '_listeners' && tree.hasOwnProperty(branch)) {
+ listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i+1));
+ }
+ }
+ return listeners;
+ } else if(currentType === '**') {
+ endReached = (i+1 === typeLength || (i+2 === typeLength && nextType === '*'));
+ if(endReached && tree._listeners) {
+ // The next element has a _listeners, add it to the handlers.
+ listeners = listeners.concat(searchListenerTree(handlers, type, tree, typeLength));
+ }
+
+ for (branch in tree) {
+ if (branch !== '_listeners' && tree.hasOwnProperty(branch)) {
+ if(branch === '*' || branch === '**') {
+ if(tree[branch]._listeners && !endReached) {
+ listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], typeLength));
+ }
+ listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i));
+ } else if(branch === nextType) {
+ listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i+2));
+ } else {
+ // No match on this one, shift into the tree but not in the type array.
+ listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i));
+ }
+ }
+ }
+ return listeners;
+ }
+
+ listeners = listeners.concat(searchListenerTree(handlers, type, tree[currentType], i+1));
+ }
+
+ xTree = tree['*'];
+ if (xTree) {
+ //
+ // If the listener tree will allow any match for this part,
+ // then recursively explore all branches of the tree
+ //
+ searchListenerTree(handlers, type, xTree, i+1);
+ }
+
+ xxTree = tree['**'];
+ if(xxTree) {
+ if(i < typeLength) {
+ if(xxTree._listeners) {
+ // If we have a listener on a '**', it will catch all, so add its handler.
+ searchListenerTree(handlers, type, xxTree, typeLength);
+ }
+
+ // Build arrays of matching next branches and others.
+ for(branch in xxTree) {
+ if(branch !== '_listeners' && xxTree.hasOwnProperty(branch)) {
+ if(branch === nextType) {
+ // We know the next element will match, so jump twice.
+ searchListenerTree(handlers, type, xxTree[branch], i+2);
+ } else if(branch === currentType) {
+ // Current node matches, move into the tree.
+ searchListenerTree(handlers, type, xxTree[branch], i+1);
+ } else {
+ isolatedBranch = {};
+ isolatedBranch[branch] = xxTree[branch];
+ searchListenerTree(handlers, type, { '**': isolatedBranch }, i+1);
+ }
+ }
+ }
+ } else if(xxTree._listeners) {
+ // We have reached the end and still on a '**'
+ searchListenerTree(handlers, type, xxTree, typeLength);
+ } else if(xxTree['*'] && xxTree['*']._listeners) {
+ searchListenerTree(handlers, type, xxTree['*'], typeLength);
+ }
+ }
+
+ return listeners;
+ }
+
+ function growListenerTree(type, listener) {
+
+ type = typeof type === 'string' ? type.split(this.delimiter) : type.slice();
+
+ //
+ // Looks for two consecutive '**', if so, don't add the event at all.
+ //
+ for(var i = 0, len = type.length; i+1 < len; i++) {
+ if(type[i] === '**' && type[i+1] === '**') {
+ return;
+ }
+ }
+
+ var tree = this.listenerTree;
+ var name = type.shift();
+
+ while (name) {
+
+ if (!tree[name]) {
+ tree[name] = {};
+ }
+
+ tree = tree[name];
+
+ if (type.length === 0) {
+
+ if (!tree._listeners) {
+ tree._listeners = listener;
+ }
+ else if(typeof tree._listeners === 'function') {
+ tree._listeners = [tree._listeners, listener];
+ }
+ else if (isArray(tree._listeners)) {
+
+ tree._listeners.push(listener);
+
+ if (!tree._listeners.warned) {
+
+ var m = defaultMaxListeners;
+
+ if (typeof this._events.maxListeners !== 'undefined') {
+ m = this._events.maxListeners;
+ }
+
+ if (m > 0 && tree._listeners.length > m) {
+
+ tree._listeners.warned = true;
+ console.error('(node) warning: possible EventEmitter memory ' +
+ 'leak detected. %d listeners added. ' +
+ 'Use emitter.setMaxListeners() to increase limit.',
+ tree._listeners.length);
+ console.trace();
+ }
+ }
+ }
+ return true;
+ }
+ name = type.shift();
+ }
+ return true;
+ };
+
+ // By default EventEmitters will print a warning if more than
+ // 10 listeners are added to it. This is a useful default which
+ // helps finding memory leaks.
+ //
+ // Obviously not all Emitters should be limited to 10. This function allows
+ // that to be increased. Set to zero for unlimited.
+
+ EventEmitter.prototype.delimiter = '.';
+
+ EventEmitter.prototype.setMaxListeners = function(n) {
+ this._events || init.call(this);
+ this._events.maxListeners = n;
+ if (!this._conf) this._conf = {};
+ this._conf.maxListeners = n;
+ };
+
+ EventEmitter.prototype.event = '';
+
+ EventEmitter.prototype.once = function(event, fn) {
+ this.many(event, 1, fn);
+ return this;
+ };
+
+ EventEmitter.prototype.many = function(event, ttl, fn) {
+ var self = this;
+
+ if (typeof fn !== 'function') {
+ throw new Error('many only accepts instances of Function');
+ }
+
+ function listener() {
+ if (--ttl === 0) {
+ self.off(event, listener);
+ }
+ fn.apply(this, arguments);
+ };
+
+ listener._origin = fn;
+
+ this.on(event, listener);
+
+ return self;
+ };
+
+ EventEmitter.prototype.emit = function() {
+
+ this._events || init.call(this);
+
+ var type = arguments[0];
+
+ if (type === 'newListener' && !this.newListener) {
+ if (!this._events.newListener) { return false; }
+ }
+
+ // Loop through the *_all* functions and invoke them.
+ if (this._all) {
+ var l = arguments.length;
+ var args = new Array(l - 1);
+ for (var i = 1; i < l; i++) args[i - 1] = arguments[i];
+ for (i = 0, l = this._all.length; i < l; i++) {
+ this.event = type;
+ this._all[i].apply(this, args);
+ }
+ }
+
+ // If there is no 'error' event listener then throw.
+ if (type === 'error') {
+
+ if (!this._all &&
+ !this._events.error &&
+ !(this.wildcard && this.listenerTree.error)) {
+
+ if (arguments[1] instanceof Error) {
+ throw arguments[1]; // Unhandled 'error' event
+ } else {
+ throw new Error("Uncaught, unspecified 'error' event.");
+ }
+ return false;
+ }
+ }
+
+ var handler;
+
+ if(this.wildcard) {
+ handler = [];
+ var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice();
+ searchListenerTree.call(this, handler, ns, this.listenerTree, 0);
+ }
+ else {
+ handler = this._events[type];
+ }
+
+ if (typeof handler === 'function') {
+ this.event = type;
+ if (arguments.length === 1) {
+ handler.call(this);
+ }
+ else if (arguments.length > 1)
+ switch (arguments.length) {
+ case 2:
+ handler.call(this, arguments[1]);
+ break;
+ case 3:
+ handler.call(this, arguments[1], arguments[2]);
+ break;
+ // slower
+ default:
+ var l = arguments.length;
+ var args = new Array(l - 1);
+ for (var i = 1; i < l; i++) args[i - 1] = arguments[i];
+ handler.apply(this, args);
+ }
+ return true;
+ }
+ else if (handler) {
+ var l = arguments.length;
+ var args = new Array(l - 1);
+ for (var i = 1; i < l; i++) args[i - 1] = arguments[i];
+
+ var listeners = handler.slice();
+ for (var i = 0, l = listeners.length; i < l; i++) {
+ this.event = type;
+ listeners[i].apply(this, args);
+ }
+ return (listeners.length > 0) || this._all;
+ }
+ else {
+ return this._all;
+ }
+
+ };
+
+ EventEmitter.prototype.on = function(type, listener) {
+
+ if (typeof type === 'function') {
+ this.onAny(type);
+ return this;
+ }
+
+ if (typeof listener !== 'function') {
+ throw new Error('on only accepts instances of Function');
+ }
+ this._events || init.call(this);
+
+ // To avoid recursion in the case that type == "newListeners"! Before
+ // adding it to the listeners, first emit "newListeners".
+ this.emit('newListener', type, listener);
+
+ if(this.wildcard) {
+ growListenerTree.call(this, type, listener);
+ return this;
+ }
+
+ if (!this._events[type]) {
+ // Optimize the case of one listener. Don't need the extra array object.
+ this._events[type] = listener;
+ }
+ else if(typeof this._events[type] === 'function') {
+ // Adding the second element, need to change to array.
+ this._events[type] = [this._events[type], listener];
+ }
+ else if (isArray(this._events[type])) {
+ // If we've already got an array, just append.
+ this._events[type].push(listener);
+
+ // Check for listener leak
+ if (!this._events[type].warned) {
+
+ var m = defaultMaxListeners;
+
+ if (typeof this._events.maxListeners !== 'undefined') {
+ m = this._events.maxListeners;
+ }
+
+ if (m > 0 && this._events[type].length > m) {
+
+ this._events[type].warned = true;
+ console.error('(node) warning: possible EventEmitter memory ' +
+ 'leak detected. %d listeners added. ' +
+ 'Use emitter.setMaxListeners() to increase limit.',
+ this._events[type].length);
+ console.trace();
+ }
+ }
+ }
+ return this;
+ };
+
+ EventEmitter.prototype.onAny = function(fn) {
+
+ if(!this._all) {
+ this._all = [];
+ }
+
+ if (typeof fn !== 'function') {
+ throw new Error('onAny only accepts instances of Function');
+ }
+
+ // Add the function to the event listener collection.
+ this._all.push(fn);
+ return this;
+ };
+
+ EventEmitter.prototype.addListener = EventEmitter.prototype.on;
+
+ EventEmitter.prototype.off = function(type, listener) {
+ if (typeof listener !== 'function') {
+ throw new Error('removeListener only takes instances of Function');
+ }
+
+ var handlers,leafs=[];
+
+ if(this.wildcard) {
+ var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice();
+ leafs = searchListenerTree.call(this, null, ns, this.listenerTree, 0);
+ }
+ else {
+ // does not use listeners(), so no side effect of creating _events[type]
+ if (!this._events[type]) return this;
+ handlers = this._events[type];
+ leafs.push({_listeners:handlers});
+ }
+
+ for (var iLeaf=0; iLeaf<leafs.length; iLeaf++) {
+ var leaf = leafs[iLeaf];
+ handlers = leaf._listeners;
+ if (isArray(handlers)) {
+
+ var position = -1;
+
+ for (var i = 0, length = handlers.length; i < length; i++) {
+ if (handlers[i] === listener ||
+ (handlers[i].listener && handlers[i].listener === listener) ||
+ (handlers[i]._origin && handlers[i]._origin === listener)) {
+ position = i;
+ break;
+ }
+ }
+
+ if (position < 0) {
+ return this;
+ }
+
+ if(this.wildcard) {
+ leaf._listeners.splice(position, 1)
+ }
+ else {
+ this._events[type].splice(position, 1);
+ }
+
+ if (handlers.length === 0) {
+ if(this.wildcard) {
+ delete leaf._listeners;
+ }
+ else {
+ delete this._events[type];
+ }
+ }
+ }
+ else if (handlers === listener ||
+ (handlers.listener && handlers.listener === listener) ||
+ (handlers._origin && handlers._origin === listener)) {
+ if(this.wildcard) {
+ delete leaf._listeners;
+ }
+ else {
+ delete this._events[type];
+ }
+ }
+ }
+
+ return this;
+ };
+
+ EventEmitter.prototype.offAny = function(fn) {
+ var i = 0, l = 0, fns;
+ if (fn && this._all && this._all.length > 0) {
+ fns = this._all;
+ for(i = 0, l = fns.length; i < l; i++) {
+ if(fn === fns[i]) {
+ fns.splice(i, 1);
+ return this;
+ }
+ }
+ } else {
+ this._all = [];
+ }
+ return this;
+ };
+
+ EventEmitter.prototype.removeListener = EventEmitter.prototype.off;
+
+ EventEmitter.prototype.removeAllListeners = function(type) {
+ if (arguments.length === 0) {
+ !this._events || init.call(this);
+ return this;
+ }
+
+ if(this.wildcard) {
+ var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice();
+ var leafs = searchListenerTree.call(this, null, ns, this.listenerTree, 0);
+
+ for (var iLeaf=0; iLeaf<leafs.length; iLeaf++) {
+ var leaf = leafs[iLeaf];
+ leaf._listeners = null;
+ }
+ }
+ else {
+ if (!this._events[type]) return this;
+ this._events[type] = null;
+ }
+ return this;
+ };
+
+ EventEmitter.prototype.listeners = function(type) {
+ if(this.wildcard) {
+ var handlers = [];
+ var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice();
+ searchListenerTree.call(this, handlers, ns, this.listenerTree, 0);
+ return handlers;
+ }
+
+ this._events || init.call(this);
+
+ if (!this._events[type]) this._events[type] = [];
+ if (!isArray(this._events[type])) {
+ this._events[type] = [this._events[type]];
+ }
+ return this._events[type];
+ };
+
+ EventEmitter.prototype.listenersAny = function() {
+
+ if(this._all) {
+ return this._all;
+ }
+ else {
+ return [];
+ }
+
+ };
+
+ if (typeof define === 'function' && define.amd) {
+ define(function() {
+ return EventEmitter;
+ });
+ } else {
+ exports.EventEmitter2 = EventEmitter;
+ }
+
+}(typeof process !== 'undefined' && typeof process.title !== 'undefined' && typeof exports !== 'undefined' ? exports : window);
View
354 public/javascripts/hvidio.coffee
@@ -0,0 +1,354 @@
+(->
+ loader = undefined
+ socket = undefined
+ scroller = undefined
+ $main = $("#main")
+ $form = $("#form")
+ $keyword = $("#keyword")
+ $results = $("#results")
+ $player = $("#player")
+ $close = $("#close")
+ $header = $("#header")
+ $clickjack = $("#clickjack")
+ window.hvidio =
+ init: ->
+
+ @videos = {}
+
+ # Loader
+ loader = new CanvasLoader("loading")
+ loader.setColor "#99CC32"
+ loader.setDiameter 32
+ loader.setDensity 32
+ loader.setRange 0.6
+ loader.setSpeed 1
+
+ # load the hashtag
+ if window.location.hash
+ setTimeout (->
+ $("#keyword").val window.location.hash.substr(1)
+ $("#form").submit()
+ ), 200
+ else
+ $keyword.focus()
+
+ jQuery.timeago.settings.allowFuture = true
+
+ # socket
+ socket = io.connect("http://" + window.location.host)
+ socket.on "connect", ->
+ SearchStream.com_init socket
+
+
+ # toggle main window
+ $clickjack.on "click", (e) ->
+ hvidio.show()
+ e.stopPropagation()
+ e.preventDefault()
+
+
+ #$close.on('click', function(e) {
+ $main.on "click", (e) ->
+ hvidio.hide()
+ e.stopPropagation()
+ e.preventDefault()
+
+ $keyword.on "click", (e) ->
+ e.stopPropagation()
+
+ $results.on "click", ".play", (e) ->
+
+ #hvidio.play($(this).attr('href')).hide();
+ hvidio.play $(this).attr("href")
+
+ #e.stopPropagation();
+ e.preventDefault()
+
+ $(window).on "resize", ->
+ hvidio.resize()
+
+
+ # search
+ $form.on "submit", (e) ->
+ keyword = $keyword.val()
+ hvidio.search keyword
+ window.location.hash = "#" + keyword
+ e.preventDefault()
+
+
+ #keyCodes
+ $(document).bind "keydown", (e) ->
+ tag = e.target.tagName.toLowerCase()
+ if tag isnt "input" and tag isnt "textarea"
+ switch e.keyCode
+ when 27 # esc
+ hvidio.toggle()
+ e.preventDefault()
+ when 37 # left arrow
+ hvidio.prev()
+ e.preventDefault()
+ when 38 # up arrow
+ hvidio.prev()
+ e.preventDefault()
+ when 39 # right arrow
+ hvidio.next()
+ e.preventDefault()
+ when 40 # down arrow
+ hvidio.next()
+ e.preventDefault()
+ when 9 # tab
+ hvidio.show()
+ $keyword.focus().select()
+ e.preventDefault()
+
+ $main.addClass "bounceIn"
+ this
+
+ initScroller: (force) ->
+ if not scroller or force
+ $results.mCustomScrollbar()
+ scroller = true
+ else
+ $results.mCustomScrollbar "update"
+ this
+
+ search: (keyword) ->
+ if keyword
+ @keyword = keyword
+ console.log this
+ hvidio.loading true
+ hvidio.fetch keyword, (data) ->
+ $main.addClass "large"
+ #console.log data[0].msgs.length, data[0].provider, data[0].msgs[0].provider, data[0].msgs[0].text
+ hvidio.templatize "#videosTemplate",
+ search: urlify(keyword)
+ videos: data
+ , "#results"
+
+ #hvidio.loading(false);
+ hvidio.play data[0].embed
+ hvidio.initScroller true
+ $close.fadeIn 5000
+
+ this
+
+ insert_video: (container, pos, video) ->
+ $html = $(hvidio.templatize("#videoTemplate",
+ video: video
+ ))
+ #console.log $("#{container} > li").length
+ elem = $("#{container} > li:eq(#{pos})")
+ if elem.length
+ elem.before $html
+ #console.log $("#{container} > li").length, $("time", elem).attr("datetime"), " < ", video.date, elem, elem[0], $html[0]
+ else
+ $("#{container} > li:eq(#{pos - 1})").after $html
+ $html.css("visibility", "visible").hide().fadeIn "fast"
+
+ video_reduce: (video) ->
+ video.dom_id = video.id.replace "/", "-"
+ msg = video.msg
+ video.msg = null
+ delete video.msg
+ video.msgs = []
+ event = if @videos[@keyword][video.dom_id]?
+ "video.update"
+ else
+ @videos[@keyword][video.dom_id] = video
+ "video.new"
+ video = @videos[@keyword][video.dom_id]
+ video.msgs.push msg
+
+ # Get More recent date
+ post_date = (new Date(msg.post_date)).valueOf()
+ last_date = (new Date(video.date)).valueOf()
+ if not video.date or (post_date > last_date)
+ #console.log "MORE RECENT DATE" if video.date
+ video.date = (new Date(msg.post_date)).toISOString()
+
+ #console.log "videos ", event, video.id
+ video.score = (video.score or 1) + msg.score
+
+ [ event, video ]
+
+
+ get_video_score: (video) ->
+
+ #- video.msgs.length
+ -(new Date(video.date)).valueOf()
+
+ fetch: (@keyword, callback) ->
+ obs = new OrderByScore()
+ @videos[@keyword] = {}
+ @counter = 0
+
+ #
+ # video.order_score = _.reduce(video.msgs, function(memo, num) {
+ # return (memo + (parseInt(num.votes) + 1)) || 1;
+ # }, 0);
+ #
+ #(video.msgs[video.msgs.length - 1].votes || 1);
+ search = SearchStream(@keyword).on("data", (video) =>
+ console.log "Video.date", video.date
+ search.emit @video_reduce(video)...
+
+ ).on("video.new", (video) =>
+
+ video.msg = video.msgs[0]
+ #console.log "Video.new", video.date, (new Date(video.date)).valueOf(), @get_video_score(video)
+ video.order_score = @get_video_score(video)
+ pos = obs.get_pos(video.order_score)
+ #video.date = video.msgs[0].post_date
+ # ????
+ video.embed = video.embed.substr(0, tmppos) unless (tmppos = video.embed.indexOf("?")) is -1
+ $("#counter").text ++@counter
+
+ if typeof search.initiated is "undefined"
+ search.initiated = true
+ scroll = false
+ callback [video]
+ else
+ @insert_video "#video-list-" + urlify(@keyword), pos, video
+ hvidio.initScroller()
+
+ ).on("video.update", (video) =>
+
+ tmp_score = @get_video_score(video)
+
+ unless tmp_score is video.order_score
+ obs.remove_score video.order_score
+ video.order_score = tmp_score
+ pos = obs.get_pos(video.order_score)
+
+ unless $("#video-list-#{urlify(@keyword)} > li:eq(#{pos})").attr("id") is video.dom_id
+ #console.log "score != ?", tmp_score, video.order_score
+ $("#" + video.dom_id).fadeOut().remove()
+ @insert_video "#video-list-" + urlify(@keyword), pos, video
+
+ #console.log "update", video.dom_id, video.order_score, video.date
+ $tip = $("#" + video.dom_id + " .tip")
+ score = parseInt($tip.text()) or 1
+ newScore = score + 1
+ $tip.text newScore + "+"
+ $tip.addClass "incremented animated bounce"
+ if video.date isnt $("##{video.dom_id} time").attr("datetime")
+ $("##{video.dom_id} time").attr "datetime", video.date
+
+ ).on("finished", ->
+ console.log "FINISHED"
+ hvidio.loading false
+ )
+
+ #
+ # self.order(
+ # search.videos_by_date()
+ # //search.videos_by_posts()
+ # );
+ #
+ this
+
+ templatize: (template, data, output) ->
+ tmpl = $(template).html()
+ html = _.template(tmpl, data)
+ $(output).html html if output
+ _.defer ->
+ $("time").timeago()
+ hvidio.resize()
+ hvidio.fadeImg()
+ html
+
+ loading: (bool) ->
+
+ #console.log("loader", loader);
+ if bool
+ loader.show()
+ else
+ loader.hide()
+ this
+
+ toggle: ->
+ if $main.is(":visible")
+ hvidio.hide()
+ else
+ hvidio.show()
+ this
+
+ show: ->
+ $main.removeClass "bounceIn fadeOutUp fadeOutDown"
+ $main.addClass("fadeInUp").show()
+ this
+
+ hide: ->
+ $main.removeClass "bounceIn fadeOutUp fadeOutDown"
+ $main.addClass "fadeOutDown"
+ setTimeout (->
+ $main.hide()
+ ), 500
+ this
+
+ fadeImg: (html) ->
+ $("#results img").each ->
+ $(this).on "load", ->
+ $(this).css("visibility", "visible").hide().fadeIn "slow"
+
+
+ this
+
+ play: (embed) ->
+ $results.find(".video").removeClass "current"
+ $results.find("a[href=\"" + embed + "\"]").closest(".video").addClass "current"
+ if embed.indexOf("?") is -1
+ embed += "?"
+ else
+ embed += "&"
+ embed += "wmode=transparent&autoplay=1&autohide=1"
+ $player.attr "src", embed
+ this
+
+ jump: (index) ->
+ embed = $(".video").eq(index).find(".play").attr("href")
+ hvidio.play embed
+
+ next: ->
+ index = $(".current").index(".video")
+ index++
+ if index > $(".video").size() - 1
+ index = 0
+ $results.mCustomScrollbar "scrollTo", 0
+ hvidio.jump index
+
+ prev: ->
+ index = $(".current").index(".video")
+ index--
+ if index < 0
+ index = $(".video").size() - 1
+ $results.mCustomScrollbar "scrollTo", 20000
+ hvidio.jump index
+
+ resize: ->
+
+ # Adjusts result div height
+ mh = $main.height()
+ hh = $header.outerHeight()
+ $results.outerHeight mh - hh - 20
+
+ # Adjusts/centers result list
+ mw = $main.width()
+ ew = $results.find("li").outerWidth(true)
+ rw = (Math.floor(mw / ew)) * ew
+ $results.find(".video-list").width rw
+
+
+ # Extra scripts
+ urlify = (str) ->
+ str.replace(/\s/g, "_").replace(/:/g, "-").replace(/\\/g, "-").replace(/\//g, "-").replace(/[^a-zA-Z0-9\-_]+/g, "").replace(/-{2,}/g, "-").toLowerCase()
+
+ _underscore_template = _.template
+ _.template = (str, data) ->
+ _underscore_template str.replace(/<%\s*include\s*(.*?)\s*%>/g, (match, templateId) ->
+ el = $("#" + templateId)
+ (if el then el.html() else "")
+ ), data
+)()
+$ ->
+ hvidio.init()
View
74 public/javascripts/hvidio.js
@@ -168,6 +168,7 @@
hvidio.fetch(keyword, function(data) {
$main.addClass('large');
+ console.log(data[0].msgs.length, data[0].provider, data[0].msgs[0].provider, data[0].msgs[0].text );
hvidio.templatize('#videosTemplate', { search: urlify(keyword), videos: data }, '#results');
hvidio
@@ -182,6 +183,7 @@
return this;
},
+<<<<<<< HEAD
order: function(videos) {
console.log("order", videos, this.keyword, $('#results'));
hvidio.templatize('#videosTemplate', { search: urlify(this.keyword), videos: videos }, '#results');
@@ -190,50 +192,112 @@
.loading(false)
.play(videos[0].embed)
.initScroller(true);
+=======
+ insert_video: function(container, pos, video) {
+ var $html = $(hvidio.templatize('#videoTemplate', { video: video }));
+
+ elem = $(container + " > li:eq("+pos+")")
+ if ( elem.length ) {
+ elem.before($html);
+ } else {
+ $(container + " > li:eq("+(pos - 1)+")").after($html);
+ }
+ $html.css('visibility','visible').hide().fadeIn('fast');
+ },
+ get_video_score: function(video) {
+ //return - video.msgs.length;
+ return - (new Date(video.date)).valueOf();
+>>>>>>> live-reordering
},
fetch: function(keyword, callback) {
var self = this;
+ obs = new OrderByScore();
+ var videos = {};
+
search = Search(keyword)
- .on("video.new", function() {
+ .reduce(function(video) {
+ })
+ .on("video.new", function(video) {
var pos;
+<<<<<<< HEAD
+=======
+ video.msg = video.msgs[0];
+ /*
+ video.score = _.reduce(video.msgs, function(memo, num) {
+ return (memo + (parseInt(num.votes) + 1)) || 1;
+ }, 0);
+*/
+ video.score = self.get_video_score(video);
+ var pos = obs.get_pos(video.score);
+
+ video.date = video.msgs[0].post_date;
+>>>>>>> live-reordering
- if ((pos = this.embed.indexOf("?")) != -1) {
- this.embed = this.embed.substr(0, pos);
+ if ((pos = video.embed.indexOf("?")) != -1) {
+ video.embed = video.embed.substr(0, pos);
}
$('#counter').text(++counter);
if (typeof search.initiated == "undefined") {
search.initiated = true;
+<<<<<<< HEAD
callback([this]);
} else {
var html = hvidio.templatize('#videoTemplate', { video: this }),
$mylist = $("#video-list-" + urlify(keyword)),
$html = $(html);
+=======
+ scroll = false;
- $mylist.append($html);
+ callback([video]);
+ } else {
+>>>>>>> live-reordering
+
+ self.insert_video("#video-list-" + urlify(keyword), pos, video);
hvidio.initScroller();
- $html.css('visibility','visible').hide().fadeIn('slow');
}
+<<<<<<< HEAD
}).on("video.update", function() {
console.log("update", this.dom_id);
var $tip = $('#' + this.dom_id + ' .tip');
+=======
+ }).on("video.update", function(video) {
+ var tmp_score = self.get_video_score(video);
+ if (tmp_score != video.score) {
+ obs.remove_score(video.score);
+ video.score = tmp_score
+ var pos = obs.get_pos(video.score);
+ if ($("#video-list-" + urlify(keyword) + " > li:eq("+pos+")").attr("id") != video.dom_id) {
+ console.log("score != ?", tmp_score, video.score)
+ $('#' + video.dom_id).fadeOut().remove()
+ self.insert_video("#video-list-" + urlify(keyword), pos, video);
+ }
+ }
+
+ console.log("update", video.dom_id, video.provider, video.msgs[0].provider, video.msgs.length, video.msgs[0].text);
+ var $tip = $('#' + video.dom_id + ' .tip'),
+ score = parseInt($tip.text()) || 1,
+ newScore = score + 1; //(video.msgs[video.msgs.length - 1].votes || 1);
+>>>>>>> live-reordering
$tip.text(this.score + '+');
$tip.addClass('incremented animated bounce');
}).on("finished", function() {
console.log("FINISHED");
hvidio.loading(false);
+ /*
self.order(
search.videos_by_date()
//search.videos_by_posts()
);
+ */
});
return this;
View
99 public/javascripts/live-search.coffee
@@ -1,85 +1,58 @@
-window.Search = class Search
+window.OrderByScore = class OrderByScore
+ constructor: () ->
+ @scores = []
+ @scores_hit = {}
+
+ get_pos: (score) ->
+ pos = _(@scores).sortedIndex score
+ unless @scores[pos]
+ @scores[pos] = score
+ else if (@scores[pos] != score) and (@scores[pos+1] != score)
+ @scores.splice(pos, 0, score)
+
+ @scores_hit[score] or= 0
+ @scores_hit[score]++
+
+ console.log "get_pos", score, pos#, @scores
+ pos
+
+ remove_score: (score) ->
+ @scores_hit[score]--
+ if @scores_hit[score] == 0
+ @scores = _(@scores).without score
+
+window.SearchStream = class SearchStream
+
instances = {}
+
constructor: (search_term, opts) ->
- if @constructor.name is "Search"
+ if @constructor.name is "SearchStream"
@search_term = search_term
- @videos = {}
- @events or= []
+ @ee = new EventEmitter2()
my_timer = null
search_me = =>
- unless Search.socket?.emit?
+ unless SearchStream.socket?.emit?
my_timer = setInterval(search_me, 100) unless my_timer
else
clearInterval(my_timer) if my_timer
- finished = _(@events).filter((e) -> e.finished?).pop().finished
- Search.socket.emit "search", @search_term, finished
+ SearchStream.socket.emit "search", @search_term, =>
+ @ee.emit "finished"
_.defer search_me
- #instances[search_term] = @
else
- return instances[search_term] or= new Search(search_term, opts)
-
- video_reduce: (video) ->
- msg = video.msg
- delete video.msg
- video.dom_id = video.id.replace "/", "-"
- video.msgs = []
-
- (@videos[video.id] or= video).msgs.push msg
-
- # Jay: was here
- @videos[video.id] = (@videos[video.id] or= video)
- @videos[video.id].date = msg.post_date;
- @videos[video.id].score = (@videos[video.id].score || 1) + msg.score;
-
- console.log "videos ", Object.keys(@videos).length
- @when _(@videos).keys().length, video.id
-
- videos_by_posts: ->
- _(@videos).sortBy (v) -> - v.msgs.length
-
- videos_by_date: ->
- _(@videos).sortBy (v) -> - (new Date(v.date)).valueOf()
-
- videos_ids: -> _(@videos).keys()
-
- when: (num, cb) ->
- if _.isFunction cb
- @events.push
- num: num
- callback: cb
- else if @events.length > 0
- for i in [0..@events.length - 1]
- if @events[i]?.num? and @events[i].num == num
- cb = @events[i].callback
- @events.splice i, 1
- @when_done = true
- cb.call @
- else if @when_done and @events[i]?["video.new"]?
- if (not @last_videos_length) or (@last_videos_length < num)
- @events[i]["video.new"].call @videos[cb]
- else if @when_done and @events[i]?["video.update"]?
- if (not @last_videos_length) or (@last_videos_length == num)
- @events[i]["video.update"].call @videos[cb]
- @last_videos_length = num
- @
+ return instances[search_term] or= new SearchStream(search_term, opts)
- on: (msg, cb) ->
- if _.isFunction cb
- event = {}
- event[msg] = cb
- @when_done = true unless @events.length
- @events.push event
- @
+ on: (msg, cb) -> @ee.on msg, cb
+ emit: (msg, data...) -> @ee.emit msg, data...
@com_init: (socket) ->
console.log "handling init"
socket.on "search_result", (res) =>
- @get(res.search_term)?.video_reduce video for video in res.videos
+ @get(res.search_term)?.ee.emit "data", res.data
- Search.socket = socket
+ SearchStream.socket = socket
@get: (search_term) -> instances[search_term]
View
2 public/stylesheets/style.css
@@ -273,7 +273,7 @@ p.tagline {
font-size: 10px;
}
#results .video .video-cell img.preview {
- visibility: hidden;
+ /*visibility: hidden;*/
width: 210px;
height: 135px;
}
View
2 public/stylesheets/style.less
@@ -328,7 +328,7 @@ p.tagline {
}
img.preview {
- visibility: hidden;
+ //visibility: hidden;
width: 210px;
height: 135px;
}
View
4 server.coffee
@@ -33,9 +33,7 @@ require('zappajs') ->
message: (video) =>
@emit search_result:
search_term: @data
- videos: [
- video
- ]
+ data: video
exit: ->
console.log "exit #{worker}"
deferred.resolve()
View
8 views/layout.jade
@@ -10,13 +10,17 @@ html
body
block content
+
script(src='/socket.io/socket.io.js')
+ script(src='/javascripts/eventemitter2.js')
script(src='/javascripts/jquery.min.js')
script(src='/javascripts/jquery.timeago.min.js')
script(src='/javascripts/jquery.mousewheel.min.js')
script(src='/javascripts/jquery.ui.min.js')
script(src='/javascripts/jquery.mcustomscrollbar.min.js')
script(src='/javascripts/underscore.min.js')
script(src='/javascripts/canvasloader.min.js')
- script(src='/javascripts/live-search.js')
- script(src='/javascripts/hvidio.js')
+ //script(src='/javascripts/live-search.js')
+ script(src='/javascripts/coffee-script.min.js')
+ script(src='/javascripts/live-search.coffee',type="text/coffeescript")
+ script(src='/javascripts/hvidio.coffee',type="text/coffeescript")
View
2 workers/twitter_search_worker.coffee
@@ -14,7 +14,7 @@ tc = new ntwitter
video_search = (search, opts = {}) ->
_(opts).defaults
include_entities: on
- rpp: 50
+ rpp: 20
result_type: "recent"
#lang: "fr"

No commit comments for this range

Something went wrong with that request. Please try again.