From bacb1f1e631f8326fce014e8bc791e13a94be2fa Mon Sep 17 00:00:00 2001 From: Harry Bomrah Date: Mon, 2 Jul 2012 21:06:20 +0800 Subject: [PATCH] Timeline ajax loading --- app/assets/javascripts/desktop.js | 2 +- .../javascripts/jquery.tinyscrollbar.js | 211 ++++++++++++++++++ app/assets/javascripts/orbitTimeline.js | 95 ++++++-- app/assets/stylesheets/orbitTimeline.css | 1 - app/controllers/desktop_orbit_controller.rb | 35 ++- app/models/paper.rb | 3 +- app/models/user/user.rb | 3 +- config/routes.rb | 1 + 8 files changed, 327 insertions(+), 24 deletions(-) create mode 100644 app/assets/javascripts/jquery.tinyscrollbar.js diff --git a/app/assets/javascripts/desktop.js b/app/assets/javascripts/desktop.js index 281a0b3d..7bfcb0b5 100644 --- a/app/assets/javascripts/desktop.js +++ b/app/assets/javascripts/desktop.js @@ -7,7 +7,7 @@ //= require jquery //= require jquery_ujs //= require jquery-ui -//= require jquery.tinyscrollbar.min +//= require jquery.tinyscrollbar //= require jquery.miniColors.min //= require bootstrap //= require orbitdesktopAPI diff --git a/app/assets/javascripts/jquery.tinyscrollbar.js b/app/assets/javascripts/jquery.tinyscrollbar.js new file mode 100644 index 00000000..e9aeffde --- /dev/null +++ b/app/assets/javascripts/jquery.tinyscrollbar.js @@ -0,0 +1,211 @@ +/* + * Tiny Scrollbar 1.8 + * http://www.baijs.nl/tinyscrollbar/ + * + * Copyright 2012, Maarten Baijs + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://www.opensource.org/licenses/mit-license.php + * http://www.opensource.org/licenses/gpl-2.0.php + * + * Date: 26 / 07 / 2012 + * Depends on library: jQuery + * + */ +( function( $ ) +{ + $.tiny = $.tiny || { }; + + $.tiny.scrollbar = { + options: { + axis : 'y' // vertical or horizontal scrollbar? ( x || y ). + , wheel : 40 // how many pixels must the mouswheel scroll at a time. + , scroll : true // enable or disable the mousewheel. + , lockscroll : true // return scrollwheel to browser if there is no more content. + , size : 'auto' // set the size of the scrollbar to auto or a fixed number. + , sizethumb : 'auto' // set the size of the thumb to auto or a fixed number. + , onMove : function(){} + } + }; + + $.fn.tinyscrollbar = function( params ) + { + var options = $.extend( {}, $.tiny.scrollbar.options, params ); + + this.each( function() + { + $( this ).data('tsb', new Scrollbar( $( this ), options ) ); + }); + + return this; + }; + + $.fn.tinyscrollbar_update = function(sScroll) + { + return $( this ).data( 'tsb' ).update( sScroll ); + }; + + function Scrollbar( root, options ) + { + var oSelf = this + , oWrapper = root + , oViewport = { obj: $( '.viewport', root ) } + , oContent = { obj: $( '.overview', root ) } + , oScrollbar = { obj: $( '.scrollbar', root ) } + , oTrack = { obj: $( '.track', oScrollbar.obj ) } + , oThumb = { obj: $( '.thumb', oScrollbar.obj ) } + , sAxis = options.axis === 'x' + , sDirection = sAxis ? 'left' : 'top' + , sSize = sAxis ? 'Width' : 'Height' + , iScroll = 0 + , iPosition = { start: 0, now: 0 } + , iMouse = {} + , touchEvents = ( 'ontouchstart' in document.documentElement ) ? true : false + ; + + function initialize() + { + oSelf.update(); + setEvents(); + + return oSelf; + } + + this.update = function( sScroll ) + { + oViewport[ options.axis ] = oViewport.obj[0][ 'offset'+ sSize ]; + oContent[ options.axis ] = oContent.obj[0][ 'scroll'+ sSize ]; + oContent.ratio = oViewport[ options.axis ] / oContent[ options.axis ]; + + oScrollbar.obj.toggleClass( 'disable', oContent.ratio >= 1 ); + + oTrack[ options.axis ] = options.size === 'auto' ? oViewport[ options.axis ] : options.size; + oThumb[ options.axis ] = Math.min( oTrack[ options.axis ], Math.max( 0, ( options.sizethumb === 'auto' ? ( oTrack[ options.axis ] * oContent.ratio ) : options.sizethumb ) ) ); + + oScrollbar.ratio = options.sizethumb === 'auto' ? ( oContent[ options.axis ] / oTrack[ options.axis ] ) : ( oContent[ options.axis ] - oViewport[ options.axis ] ) / ( oTrack[ options.axis ] - oThumb[ options.axis ] ); + + iScroll = ( sScroll === 'relative' && oContent.ratio <= 1 ) ? Math.min( ( oContent[ options.axis ] - oViewport[ options.axis ] ), Math.max( 0, iScroll )) : 0; + iScroll = ( sScroll === 'bottom' && oContent.ratio <= 1 ) ? ( oContent[ options.axis ] - oViewport[ options.axis ] ) : isNaN( parseInt( sScroll, 10 ) ) ? iScroll : parseInt( sScroll, 10 ); + + setSize(); + }; + + function setSize() + { + var sCssSize = sSize.toLowerCase(); + + oThumb.obj.css( sDirection, iScroll / oScrollbar.ratio ); + oContent.obj.css( sDirection, -iScroll ); + iMouse.start = oThumb.obj.offset()[ sDirection ]; + + oScrollbar.obj.css( sCssSize, oTrack[ options.axis ] ); + oTrack.obj.css( sCssSize, oTrack[ options.axis ] ); + oThumb.obj.css( sCssSize, oThumb[ options.axis ] ); + } + + function setEvents() + { + if( ! touchEvents ) + { + oThumb.obj.bind( 'mousedown', start ); + oTrack.obj.bind( 'mouseup', drag ); + } + else + { + oViewport.obj[0].ontouchstart = function( event ) + { + if( 1 === event.touches.length ) + { + start( event.touches[ 0 ] ); + event.stopPropagation(); + } + }; + } + + if( options.scroll && window.addEventListener ) + { + oWrapper[0].addEventListener( 'DOMMouseScroll', wheel, false ); + oWrapper[0].addEventListener( 'mousewheel', wheel, false ); + } + else if( options.scroll ) + { + oWrapper[0].onmousewheel = wheel; + } + } + + function start( event ) + { + var oThumbDir = parseInt( oThumb.obj.css( sDirection ), 10 ); + iMouse.start = sAxis ? event.pageX : event.pageY; + iPosition.start = oThumbDir == 'auto' ? 0 : oThumbDir; + + if( ! touchEvents ) + { + $( document ).bind( 'mousemove', drag ); + $( document ).bind( 'mouseup', end ); + oThumb.obj.bind( 'mouseup', end ); + } + else + { + document.ontouchmove = function( event ) + { + event.preventDefault(); + drag( event.touches[ 0 ] ); + }; + document.ontouchend = end; + } + } + + function wheel( event ) + { + if( oContent.ratio < 1 ) + { + var oEvent = event || window.event + , iDelta = oEvent.wheelDelta ? oEvent.wheelDelta / 120 : -oEvent.detail / 3 + ; + + iScroll -= iDelta * options.wheel; + iScroll = Math.min( ( oContent[ options.axis ] - oViewport[ options.axis ] ), Math.max( 0, iScroll )); + + oThumb.obj.css( sDirection, iScroll / oScrollbar.ratio ); + oContent.obj.css( sDirection, -iScroll ); + + if( options.lockscroll || ( iScroll !== ( oContent[ options.axis ] - oViewport[ options.axis ] ) && iScroll !== 0 ) ) + { + oEvent = $.event.fix( oEvent ); + oEvent.preventDefault(); + } + } + options.onMove.call(this,iScroll); + } + + function drag( event ) + { + if( oContent.ratio < 1 ) + { + if( ! touchEvents ) + { + iPosition.now = Math.min( ( oTrack[ options.axis ] - oThumb[ options.axis ] ), Math.max( 0, ( iPosition.start + ( ( sAxis ? event.pageX : event.pageY ) - iMouse.start)))); + } + else + { + iPosition.now = Math.min( ( oTrack[ options.axis ] - oThumb[ options.axis ] ), Math.max( 0, ( iPosition.start + ( iMouse.start - ( sAxis ? event.pageX : event.pageY ) )))); + } + + iScroll = iPosition.now * oScrollbar.ratio; + oContent.obj.css( sDirection, -iScroll ); + oThumb.obj.css( sDirection, iPosition.now ); + } + } + + function end() + { + $( document ).unbind( 'mousemove', drag ); + $( document ).unbind( 'mouseup', end ); + oThumb.obj.unbind( 'mouseup', end ); + document.ontouchmove = document.ontouchend = null; + } + + return initialize(); + } + +}(jQuery)); \ No newline at end of file diff --git a/app/assets/javascripts/orbitTimeline.js b/app/assets/javascripts/orbitTimeline.js index 5eecb48c..4fc04109 100644 --- a/app/assets/javascripts/orbitTimeline.js +++ b/app/assets/javascripts/orbitTimeline.js @@ -6,57 +6,77 @@ var orbitTimeline = function(dom){ this.dom = $("#"+dom); this.timelineHtml = $("
"); //this.marker = t.timelineHtml.find("#timline_marker"); - this.scale = t.timelineHtml.find("#timeline_scale"); + this.scale = ""; //this.container = t.timelineHtml.find("#t_container"); this.events = new Array; this.monthList = ["","January","February","March","April","May","June","July","August","September","October","November","December"]; + this.dt = new Date(); + this.fromdate = [t.dt.getFullYear(),t.dt.getMonth()+1]; + this.ajaxload = true; this.initialize = function(){ t.dom.html(t.timelineHtml); $("div.scrollbar").hide(); t.constructTimeScale(function(timelineScale){ - console.log(timelineScale); $("#timeline_scale").html(timelineScale); var totalyearwidth =timelineScale.find(".year").length * 100; var totalul = 0; + $(".t_scale").css({"min-width":$(".tinycanvas .viewport").width()+200 + "px"}) for(eve in t.events){ t.makeBubble(t.events[eve]); totalul = $("#scale_wrapper ul").length $(".t_scale").width((totalul*350) + totalyearwidth); } - $('.tinycanvas').tinyscrollbar({ axis: 'x'}); + $('.tinycanvas').tinyscrollbar({ + axis: 'x', + onMove: function(x){ + var limit = $("#timeline_scale").width() - $(".tinycanvas .scrollbar").width(); + if(t.ajaxload){ + if((limit - x) < 10){ + t.eventAjaxLoad(function(){ + var totalul = 0; + for(eve in t.events){ + t.makeBubble(t.events[eve]); + totalul = $("#scale_wrapper ul").length + $(".t_scale").width((totalul*350) + totalyearwidth); + } + $('.tinycanvas').tinyscrollbar_update(x); + }); + } + } + } + }); }); } this.constructTimeScale = function(callbackFn){ - var mon ="",year=""; + var mon ="",year="",formname; var scale = $("
"); - $.getJSON("desktop_orbit/getevents",{"event":"papers"},function(journals){ - $.each(journals,function(x,journal){ - $.each(journal.papers,function(i,paper){ + $.getJSON("desktop_orbit/getevents",{"event":"papers","from":t.fromdate},function(papers){ + $.each(papers,function(i,paper){ var dt = new Date(paper.created_at); var cur_mon = paper.created_at.substr(5,2); var cur_year = dt.getFullYear(); var cdt = paper.created_at.substr(0,7).replace("-",""); - var formname = (cur_mon.charAt(0) == "0"?cur_mon.charAt(1) : cur_mon) - var bubbleData = {"fulldate" : t.monthList[parseInt(formname)] +", " + dt.getDate() + ", " + cur_year,"title":paper.title,"jtitle":journal.title,"coauthors":paper.coauthors,"abstract":paper.abstract,"timestamp":cdt} + formname = (cur_mon.charAt(0) == "0"?cur_mon.charAt(1) : cur_mon) + var bubbleData = {"fulldate" : t.monthList[parseInt(formname)] +", " + dt.getDate() + ", " + cur_year,"title":paper.title,"jtitle":"Harry","coauthors":paper.coauthors,"abstract":paper.abstract,"timestamp":cdt} t.events.push(bubbleData); if(cur_year != year){ year = cur_year; - scale.append($("
"+(year+1)+"
")); + scale.append($("
"+(year+1)+"
")); } if(cur_mon != mon){ mon = cur_mon; - console.log(parseInt(cur_mon)); - scale.append($("
"+t.monthList[parseInt(formname)]+"
")) + var yr = scale.find("div[data-content="+year+"]"); + yr.append($("
"+t.monthList[parseInt(formname)]+"
")) } }); + scale.append($("
"+year+"
")); + t.fromdate = [year,formname-1]; + if(typeof callbackFn == "function"){ + callbackFn.call(this,scale); + } }) - scale.append($("
"+year+"
")); - if(typeof callbackFn == "function"){ - callbackFn.call(this,scale); - } - }); } this.makeBubble = function(bubbleData){ var totalul = $("#scale_wrapper").find("div[data-content="+bubbleData.timestamp+"] ul").length; @@ -87,4 +107,45 @@ var orbitTimeline = function(dom){ }); })//.mouseout(function(){t.oapi.toolPopup("destroy");}) } + this.eventAjaxLoad = function(callbackFn){ + t.events = []; + var mon ="",year="",formname; + var scale = $("#scale_wrapper"); + + t.ajaxload = false; + $.getJSON("desktop_orbit/eventajaxload",{"from":t.fromdate},function(papersArray){ + $.each(papersArray,function(i,pa){ + $.each(pa.papers,function(i,paper){ + var dt = new Date(paper.created_at); + var cur_mon = paper.created_at.substr(5,2); + var cur_year = dt.getFullYear(); + var cdt = paper.created_at.substr(0,7).replace("-",""); + formname = (cur_mon.charAt(0) == "0"?cur_mon.charAt(1) : cur_mon) + var bubbleData = {"fulldate" : t.monthList[parseInt(formname)] +", " + dt.getDate() + ", " + cur_year,"title":paper.title,"jtitle":"Harry","coauthors":paper.coauthors,"abstract":paper.abstract,"timestamp":cdt} + t.events.push(bubbleData); + if(cur_year != year){ + year = cur_year; + if(scale.find("div[data-content="+year+"]").length == 0){ + scale.append($("
"+(year+1)+"
")); + } + } + if(cur_mon != mon){ + mon = cur_mon; + var yr = scale.find("div[data-content="+year+"]"); + yr.append($("
"+t.monthList[parseInt(formname)]+"
")) + } + }); + }); + if(papersArray.length != 0){ + scale.append($("
"+year+"
")); + t.ajaxload = true; + console.log(year); + t.fromdate = [year,formname-1]; + } + if(typeof callbackFn == "function"){ + callbackFn.call(this,scale); + } + }) + + } } \ No newline at end of file diff --git a/app/assets/stylesheets/orbitTimeline.css b/app/assets/stylesheets/orbitTimeline.css index feb007a6..2718b69d 100644 --- a/app/assets/stylesheets/orbitTimeline.css +++ b/app/assets/stylesheets/orbitTimeline.css @@ -1,5 +1,4 @@ .t_scale{ - min-width:2000px; height:516px; bottom:0; } diff --git a/app/controllers/desktop_orbit_controller.rb b/app/controllers/desktop_orbit_controller.rb index 0aaf3a6a..b3b35daf 100644 --- a/app/controllers/desktop_orbit_controller.rb +++ b/app/controllers/desktop_orbit_controller.rb @@ -7,12 +7,41 @@ class DesktopOrbitController< ApplicationController def getevents @event = params["event"] @data = Array.new + @fromdate = params["from"] case @event when "papers" - @journals = current_user.journals - @journals.each do |journal| - @data << {"title"=> journal.title,"papers"=> journal.papers} + @data = current_user.papers.where(:created_at.gt => Date.new(Integer(@fromdate[0]),Integer(@fromdate[1])-1),:created_at.lt => Date.new(Integer(@fromdate[0]),Integer(@fromdate[1])+1)).desc(:created_at) + end + render :json=>@data.to_json + end + + def eventajaxload + @fromdate = params["from"] + @fromdate[0] = Integer(@fromdate[0]) + @fromdate[1] = Integer(@fromdate[1]) + @totalpapers = 0 + @lastpaper = current_user.papers.all.desc(:created_at).last + @data = Array.new + while @totalpapers < 15 + if @lastpaper.created_at > Date.new(@fromdate[0],@fromdate[1]) + break end + if(@fromdate[1] == 12) + @papers = current_user.papers.where(:created_at.gt => Date.new(@fromdate[0],@fromdate[1]),:created_at.lt => Date.new(@fromdate[0]+1,1)).desc(:created_at) + else + @papers = current_user.papers.where(:created_at.gt => Date.new(@fromdate[0],@fromdate[1]),:created_at.lt => Date.new(@fromdate[0],@fromdate[1]+1)).desc(:created_at) + end + if(@papers.length > 0) + @data << {"papers" => @papers} + end + @totalpapers = @totalpapers + @papers.length + + @fromdate[1] = @fromdate[1]-1 + if(@fromdate[1] == 0) + @fromdate[1] = 12 + @fromdate[0] = @fromdate[0] - 1 + end + end render :json=>@data.to_json end diff --git a/app/models/paper.rb b/app/models/paper.rb index b085aaa7..d42e1d53 100644 --- a/app/models/paper.rb +++ b/app/models/paper.rb @@ -9,7 +9,8 @@ class Paper field :coauthors, default: "Allen, Shelly, Eric, Manson, Chris, Clara, Anna, Albee, Vincent, Devin, Chunchi, Ika, Jaoshua, Ray, Matt, Lin, Spen" field :created_at, type: Date, default: ->{12.months.ago} - belongs_to :journal + belongs_to :user + end \ No newline at end of file diff --git a/app/models/user/user.rb b/app/models/user/user.rb index 359a0198..0f808a06 100644 --- a/app/models/user/user.rb +++ b/app/models/user/user.rb @@ -23,7 +23,8 @@ class User has_one :desktop, :autosave => true, :dependent => :destroy has_many :other_accounts, :autosave => true, :dependent => :destroy has_many :journals, :autosave => true, :dependent => :destroy - + has_many :papers, :autosave => true, :dependent => :destroy + belongs_to :role has_and_belongs_to_many :sub_roles accepts_nested_attributes_for :attribute_values, :allow_destroy => true diff --git a/config/routes.rb b/config/routes.rb index 0c96003b..43d6ee87 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -197,6 +197,7 @@ Orbit::Application.routes.draw do match '/desktop_appstore/widgets_settings'=>'desktop_appstore#widgets_settings' match '/desktop_orbit/orbit' => 'desktop_orbit#orbit' + match '/desktop_orbit/eventajaxload'=> 'desktop_orbit#eventajaxload' match '/desktop_orbit/getevents' => 'desktop_orbit#getevents' #match '/desktop_orbit/getevents' => 'desktop_publications#create_journal' #match '/desktop_orbit/getevents' => 'desktop_publications#delete_journal'