From 54d8fd5a7121ba9b9db2a36de4bcd654d68a09dd Mon Sep 17 00:00:00 2001 From: riccardo Date: Tue, 5 Apr 2011 19:53:56 +0200 Subject: [PATCH] Important modification in mediaitem_detail page, which loads in parallel with the player setup, allowing to visualize the page immediately. The player setup, on the other hand, loads function in series: analyzer->player->markers, allowing to have control over the load chain, eg, display error messages etc... Moreover, decreased the number of javascript files to load (controller also can be removed, graphics maybe), fixed some bug relative to popup and playerlist, added "add to playlist" to each markerdiv. Still to be set the focus on each div, and to (possibly) modify mediaitm_detail template, as the submenudiv has problems with the new content_header div when in edit or copy mode --- setup.py | 83 ------ telemeta/htdocs/css/telemeta.css | 47 ++- telemeta/htdocs/images/dialog-error.png | Bin 0 -> 1445 bytes telemeta/htdocs/images/wait_small.gif | Bin 0 -> 4035 bytes telemeta/htdocs/js/application.js | 140 ++++++--- telemeta/htdocs/js/playerUtils.js | 277 ++++++++++++++---- telemeta/htdocs/timeside/demo/index.html | 4 +- telemeta/htdocs/timeside/skins/lab/style.css | 16 +- telemeta/htdocs/timeside/src/controller.js | 64 ++-- telemeta/htdocs/timeside/src/divmarker.js | 17 +- telemeta/htdocs/timeside/src/player.js | 183 ++++++++---- telemeta/htdocs/timeside/src/playlist.js | 106 +++---- telemeta/htdocs/timeside/src/ruler.js | 230 +++++++++------ telemeta/htdocs/timeside/src/rulermarker.js | 12 +- telemeta/htdocs/timeside/src/soundprovider.js | 23 +- telemeta/htdocs/timeside/src/timeside.js | 6 +- telemeta/htdocs/timeside/src/util.js | 13 +- telemeta/templates/telemeta_default/base.html | 4 +- .../telemeta_default/collection_detail.html | 26 +- .../telemeta_default/mediaitem_detail.html | 129 ++++---- 20 files changed, 856 insertions(+), 524 deletions(-) delete mode 100644 setup.py create mode 100644 telemeta/htdocs/images/dialog-error.png create mode 100644 telemeta/htdocs/images/wait_small.gif diff --git a/setup.py b/setup.py deleted file mode 100644 index 17602bd2..00000000 --- a/setup.py +++ /dev/null @@ -1,83 +0,0 @@ -# -*- coding: utf-8 -*- -from distutils.core import setup -from distutils.command.install import INSTALL_SCHEMES -import os -import sys - -def fullsplit(path, result=None): - """ - Split a pathname into components (the opposite of os.path.join) in a - platform-neutral way. - """ - if result is None: - result = [] - head, tail = os.path.split(path) - if head == '': - return [tail] + result - if head == path: - return result - return fullsplit(head, [tail] + result) - -# Tell distutils to put the data_files in platform-specific installation -# locations. See here for an explanation: -# http://groups.google.com/group/comp.lang.python/browse_thread/thread/35ec7b2fed36eaec/2105ee4d9e8042cb -for scheme in INSTALL_SCHEMES.values(): - scheme['data'] = scheme['purelib'] - -# Compile the list of packages available, because distutils doesn't have -# an easy way to do this. -packages, data_files = [], [] -root_dir = os.path.dirname(__file__) -if root_dir != '': - os.chdir(root_dir) -telemeta_dir = 'telemeta' - -for dirpath, dirnames, filenames in os.walk(telemeta_dir): - # Ignore dirnames that start with '.' - for i, dirname in enumerate(dirnames): - if dirname.startswith('.'): del dirnames[i] - if '__init__.py' in filenames: - packages.append('.'.join(fullsplit(dirpath))) - elif filenames: - data_files.append([dirpath, [os.path.join(dirpath, f) for f in filenames]]) - -# Dynamically calculate the version based on telemeta.VERSION. -version = __import__('telemeta').__version__ - -setup( - name = "telemeta", - url = "/http://svn.parisson.org/telemeta", - description = "web frontend to backup, transcode and tag any audio content with metadata", - author = ["Guillaume Pellerin, Olivier Guilyardi"], - author_email = ["pellerin@parisson.com","olivier@samalyse.com"], - version = version, - packages = packages, - data_files = data_files, - long_description = """ -Telemeta is a web audio archiving program which introduces useful and secure methods to -backup, index, transcode, analyse and publish any digitalized audio file with its metadata. -It is dedicated to professionnals who wants to easily backup and publish documented sounds -from collections of vinyls, magnetic tapes or audio CDs over a strong database, in accordance -with open standards. - -Here are the main features of Telemeta: - - * Secure archiving, editing and publishing of audio files over internet. - * User friendly web frontend including workflows and high level search methods - * Smart dynamical and skinnable audio player (thanks to Timeside and soundmanager2) - * "On the fly" analyzing, transcoding and metadata embedding based on an easy plugin architecture - * Multi-format support : FLAC, OGG, MP3, WAV and more - * GEO Navigator for audio geolocalization - * DublinCore compatibility - * OAI-PMH data provider - * XML serialized backup - * Strong SQL backend - -The Telemeta data model is based on 'collections' and 'items'. A collection is described -by its metadata and includes original audio items (sounds) and its own metadata. This -existing model has been designed to fit the one of the French Centre of Etnomusicology (CREM) -but could be easily adapted/overrided to sue other data structures. - -See http://telemeta.org for more informations. -""" -) diff --git a/telemeta/htdocs/css/telemeta.css b/telemeta/htdocs/css/telemeta.css index 9989cedf..ff6daaef 100644 --- a/telemeta/htdocs/css/telemeta.css +++ b/telemeta/htdocs/css/telemeta.css @@ -54,8 +54,17 @@ a img { border: none; } } #content { + margin-top: 1em; + margin-bottom: 0em; +} + +#content, #content_header { position: relative; - margin: 1em 2em 0em 2em; + margin-left: 2em; + margin-right: 2em; +} +#content_header { + top:-.45em; /*must be header.margin_bottom (0.9em)*/ } #content ul, #content ul ul, #content ol { @@ -76,7 +85,7 @@ a img { border: none; } #content li a { padding: .1em 0; } -#content h3 { +#content h3, #content_header h3 { color: #6a0307; font-weight: bold; display: inline; @@ -100,12 +109,15 @@ a img { border: none; } #submenu { position: relative; margin: 5px 2em 0; - height:3ex; + /*height:3ex;*/ /*no longer used, and it also shifts up the bottom content*/ z-index: 10; } -#submenu h3, #submenu div { +/*#submenu h3, #submenu div { min-height: 1.6em; -} +}*/ + + + #submenu h3 { margin-right: 80px; } @@ -121,13 +133,27 @@ a img { border: none; } font-weight: bold; }*/ +#content_header table{ + width:100%; +} +#content_header table td{ + vertical-align: bottom; +} + +#content_header td.rightcol a{ + display:inline-block; + margin-top:0.5ex; +} +#content_header td.rightcol { + width:374px; /*must be width+2*padding, see #rightcol below*/ +} #rightcol { + width: 362px; /**if u change this, change also width #content_header td.rightcol, see above*/ + padding: 6px; /**if u change this, change also width #content_header td.rightcol, see above*/ position: relative; z-index: 1; float: right; - width: 362px; border: 1px solid #999; - padding: 6px; background-color: #eee; -moz-border-radius: 8px 8px 8px 8px; -webkit-border-radius: 8px 8px 8px 8px; @@ -1013,7 +1039,6 @@ a.image-link { padding:.7ex .7ex .7ex .7ex; background-color: #f9f9f9; /*#626262;*/ color:#444; - /*border: 1px solid #eee;*/ text-decoration: none; margin:0; } @@ -1030,10 +1055,12 @@ a.image-link { .button, .button:visited, .button:hover{ font-weight: bold; - border-top: 1px solid #e1e1e1 !important; + border: 1px solid #e1e1e1; + +/* border-top: 1px solid #e1e1e1 !important; border-left: 1px solid #e1e1e1 !important; border-right: 1px solid #e1e1e1 !important; - border-bottom: 1px solid #e1e1e1 !important; + border-bottom: 1px solid #e1e1e1 !important;*/ } .button:hover{ diff --git a/telemeta/htdocs/images/dialog-error.png b/telemeta/htdocs/images/dialog-error.png new file mode 100644 index 0000000000000000000000000000000000000000..a296fefbf17e558ae46c24ad2501cf447e31216c GIT binary patch literal 1445 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 literal 0 HcmV?d00001 diff --git a/telemeta/htdocs/js/application.js b/telemeta/htdocs/js/application.js index b2f62ed2..918601ca 100644 --- a/telemeta/htdocs/js/application.js +++ b/telemeta/htdocs/js/application.js @@ -43,6 +43,12 @@ function foldInfoBlocks() { return false; }); } +//returns the full path of the current url location removing the last slash '/' followed by one or more '#', if any +function urlNormalized(){ + var sPath = window.location.href; + sPath = sPath.replace(/\/#*$/,""); + return sPath; +} function setSelectedMenu(){ @@ -98,6 +104,7 @@ $(document).ready(function() { }); //**************************************************************************** +//json(param, method, onSuccesFcn(data, textStatus, jqXHR), onErrorFcn(jqXHR, textStatus, errorThrown)) //global function to senbd/retrieve data with the server // //param: the data to be sent or retrieved. @@ -211,6 +218,7 @@ var popup={ position: 'absolute', overflow:'auto', //necessary to properly display the content display: 'none', + border: '1px solid #e1e1e1', zIndex:1000 }); if(this.className){ @@ -294,6 +302,7 @@ var popup={ }, show:function(content, optionalEvent){ + consolelog("showing popup:"+optionalEvent); //if showing, hide if(this.isShowing()){ this.hide(); @@ -354,7 +363,7 @@ var popup={ var windowH = wdow.height(); var windowW = wdow.width(); var position = div.offset(); - var shadowOffset=5; + var shadowOffset=2; var size = { width:div.outerWidth(true)+shadowOffset, height:div.outerHeight(true)+shadowOffset @@ -363,8 +372,8 @@ var popup={ position = invokerElement.offset(); position.top+= invokerElement.outerHeight(true); }else{ - position.top = (windowH-size.height)/2; - position.left = (windowW-size.width)/2; + position.top = wdow.scrollTop()+ (windowH-size.height)/2; + position.left = wdow.scrollLeft()+(windowW-size.width)/2; } //position div. This must be done immediately cause here below we want to get the div offset //(div position in absolute - ie, document's - coordinates) @@ -385,7 +394,7 @@ var popup={ var divPadding = { left: div.outerWidth()-div.width(), top:div.outerHeight()-div.height() - }; //setting width on a div means the width(), + }; //setting width on a div means the width(), //but calculations here are made according to outerWidth(true), so we need this variable (se below) div.css({ @@ -401,26 +410,10 @@ var popup={ }); } } - var divShadow = this._cfg_.divShadow().insertAfter(div); - // //position div shadow: - // var divShadow = this._cfg_.divShadow().css({ - // 'top': (position.top+shadowOffset), - // 'left': (position.left+shadowOffset), - // 'width': div.outerWidth(true), - // 'height': div.outerHeight(true) - // }).insertAfter(div).fadeTo(0,0.4); - // - // //set focus to the first input component, if any. Otherwise try with anchors, otherwise do nothing - // var inputs = $J(div).find(':input'); - // if(inputs && inputs[0]){ - // inputs[0].focus(); - // }else{ - // inputs = $J(div).find('a'); - // if(inputs && inputs[0]){ - // inputs[0].focus(); - // } - // } - // + //var divShadow = this._cfg_.divShadow().insertAfter(div); + + var divShadow = div.clone(false,false).empty().css({'zIndex':999,'borderColor':'#000','display':'none','backgroundColor':'#000'}).insertAfter(div); + //store the divs to be removed this._cfg_.divsToDelete = [div,divShadow]; //add a listener to the document. If one of the content children is clicked/keypressed, @@ -431,15 +424,12 @@ var popup={ hide.apply(me); e.stopPropagation(); }); - div.show(300, function(){ //400: basically in between fast (200) and slow (600) + div.show(300, function(){ //basically in between fast (200) and slow (600) //position div shadow: - divShadow.css({ - 'top': (position.top+shadowOffset), - 'left': (position.left+shadowOffset), - 'width': div.outerWidth(true), - 'height': div.outerHeight(true) - }).fadeTo(0,0.4); - + divShadow.show(); + consolelog(div.outerHeight(true)+" "+div.outerHeight(false)); + consolelog(divShadow.outerHeight(true)+" "+divShadow.outerHeight(false)); + //set focus to the first input component, if any. Otherwise try with anchors, otherwise do nothing var inputs = $J(div).find(':input'); if(inputs && inputs[0]){ @@ -450,6 +440,16 @@ var popup={ inputs[0].focus(); } } + + divShadow.fadeTo(0,0.4, function(){ + divShadow.css({ + 'top': (position.top+shadowOffset), + 'left': (position.left+shadowOffset), + 'width': div.outerWidth(true), + 'height': div.outerHeight(true) + }); + + }); }); return false; //to avoid scrolling if we clicked on an anchor }, @@ -491,8 +491,11 @@ var popup={ return onCancel(); } }; - var subdiv = $J('
').css({'padding':'1ex','float':'right'}). - append( + var subdiv = $J('
').css({ + 'padding':'1ex', + 'float':'right' + }). + append( $J(''). html('Ok'). addClass('component_icon'). @@ -521,3 +524,72 @@ var popup={ } } + + +//function loadScripts(scriptArrayName, callback){ +// if(!(scriptArrayName) && callback){ +// callback(); +// return; +// } +// var len = scriptArrayName.length; +// var script = function(i){ +// if(i>=len){ +// if(callback){ +// callback(); +// return; +// } +// } +// jQuery.getScript(scriptArrayName[i], function(){script(i+1)}); +// }; +// script(0); +//} + +function loadScripts(scriptArray, callback, loadInSeries){ + loadInSeries = false; + if(!scriptArray){ + if(callback){ + callback(); + } + return; + } + var len = scriptArray.length; + var $J = jQuery; + var time = new Date().getTime(); + if(loadInSeries){ + var load = function(i){ + if(i").attr("src","/images/wait.gif").css('verticalAlign','middle'); - // sound.load(); // Auto-loading overloads the Django test server + var visId = $J("#visualizer_id"); + visId.attr("disabled","disabled"); + var img = $J(form.children()[0]); + var src = undefined; + if(img.attr('src')){ + src = img.attr('src'); + img.attr("src","/images/wait_small.gif"); } + + //form.append(img); + setTimeout(function(){ + change_visualizer(); + //img.remove(); + setTimeout(function(){ + if(src){ + img.attr('src',src); + } + visId.removeAttr("disabled"); + },300); + },600); } function change_visualizer() { + consolelog('playerUtils.changeVisualizer'); set_player_image_url($('#visualizer_id').get(0).value); if (player){ player.refreshImage(); @@ -51,61 +65,117 @@ function change_visualizer() { return false; } -function load_player(duration) { - $(document).ready(function () { - if (!$('#player').length){ - return; + + + +function loadPlayer(analizerUrl, soundUrl){ + var $J = jQuery; + var msgElm = $J('#loading_span_text'); //element to show messages + if(msgElm){ + msgElm.html('Loading analyzer...'); + } + var url = urlNormalized(); + var tableBody = $J('#analyzer_div_id').find('table').find('tbody:last'); + var load_player = this.load_player; + $J.ajax({ + url: analizerUrl, //'analyze/xml', + dataType: 'xml', + success: function(data){ + //populatetable + $J.each($J(data).find('data'),function(index,element){ + var elm = $J(element); + tableBody.append(''+elm.attr('name')+''+elm.attr('value')+'' + +elm.attr('unit')+''); + }); + //loaded analizer, loading player + if(msgElm){ + msgElm.html('Loading player...'); + } + var duration = $J(data).find('#duration').attr('value'); + duration = duration.split(":"); + consolelog('analyzer loaded, duration: '+duration); + //format duration + var pin = parseInt; + var pfl = parseFloat; + var timeInMSecs=pin(duration[0])*3600+pin(duration[1])*60+pfl(duration[2]); + timeInMSecs = Math.round(timeInMSecs*1000); + load_player(soundUrl, timeInMSecs); + }, + error:function(){ + msgElm.parent().html(""); } - soundUrl = $('.ts-wave a').attr('href'); - - $('.ts-wave a img').insertAfter('.ts-wave a'); - $('.ts-wave a').remove(); - - TimeSide.load(function() { - map = new TimeSide.MarkerMap(); - provider = new TimeSide.SoundProvider({ - duration: duration - }); - player = new TimeSide.Player('#player', { - image: get_player_image_src - }); - controller = new TimeSide.Controller({ - player: player, - soundProvider: provider, - map: map - }); - change_visualizer(); - player.resize(); - }); + }); +} + - $('#visualizer_id').change(change_visualizer); - $('#visualizer_id_form').submit(change_visualizer); +//loads a player WAITING for the sound identified by soundUrl to be FULLY LOADED!!!! +function load_player(soundUrl, durationInMsecs) { +// if (!$('#player').length){ +// return; +// } + consolelog('PlayerUtils.load_player: '+soundUrl+' '+durationInMsecs); + var load_player2 = this.load_player2; - $('#player_maximized .toggle, #player_minimized .toggle').click(function() { - togglePlayerMaximization(); - this.blur(); - return false; + //this variable can be changed to load a sound immediately or not + var loadImmediately = true; + if(durationInMsecs){ + loadImmediately = false; + } + var sound = soundManager.createSound({ + id: 'sound', + autoLoad: loadImmediately, + url: soundUrl, + onload: function() { //formerly was: whileloading + //PROBLEM/BUG: on chrome and firefox whileloading is the same as onload, + //ie it is not called at regular interval but when the whole file has loaded + if(loadImmediately){ + consolelog('entering while loading setting up---------------'+this.bytesLoaded+' of '+this.bytesTotal); + loadImmediately=false; + load_player2(this, this.duration); + } + } + }); + if(!loadImmediately){ + load_player2(sound,durationInMsecs); + } +} +//NOTE: the sound MUST be FULLY LOADED!!!!!! otherwise the duration is null. This method is called from load_player +function load_player2(sound, durationInMsec) { + if (!$('#player').length){ + return; + } + consolelog("entered load_player2"); + + $('.ts-wave a img').insertAfter('.ts-wave a'); + $('.ts-wave a').remove(); + + TimeSide.load(function() { + map = new TimeSide.MarkerMap(); + + player = new TimeSide.Player('#player', { + image: get_player_image_src, + 'sound': sound, + 'soundDurationInMsec': durationInMsec }); + change_visualizer(); + controller = new TimeSide.Controller({ + player: player, + map: map + }); + }); - load_sound(); - }); - - //old code valid for old version: - // soundManager.onload = function() { - // soundEngineReady = true; - // load_sound(); - // } - //replaced by: - soundManager.onready(function() { - // SM2 is ready to go! - //alert('okkkk'); - map.debug('loaded sound manager'); - soundEngineReady = true; - load_sound(); // soundManager.createSound(), etc. + var change_visualizer_click = change_visualizer_clicked; + $('#visualizer_id').change(change_visualizer_click); + //$('#visualizer_id_form').submit(change_visualizer_clicked); + + $('#player_maximized .toggle, #player_minimized .toggle').click(function() { + togglePlayerMaximization(); + this.blur(); + return false; }); -} +} function set_player_image_url(str) { player_image_url = str; } @@ -118,5 +188,86 @@ function get_player_image_src(width, height) { return src; } +//====================================================================== +//OLD STUFF +//====================================================================== +//TODO REMOVE NOTE: the sound MUST be FULLY LOADED!!!!!! otherwise the duration is null. This method is called from load_player +function load_player2Old(sound) { + if (!$('#player').length){ + return; + } + consolelog("entered load_player2"); + // sound = soundManager.createSound({ + // id: 'sound', + // url: soundUrl + // }); + //soundUrl = $('.ts-wave a').attr('href'); + + $('.ts-wave a img').insertAfter('.ts-wave a'); + $('.ts-wave a').remove(); + + TimeSide.load(function() { + map = new TimeSide.MarkerMap(); + // provider = new TimeSide.SoundProvider({ + // duration: sound.duration + // }); + // provider.setSource(sound); + player = new TimeSide.Player('#player', { + image: get_player_image_src, + 'sound': sound + }); + change_visualizer(); + controller = new TimeSide.Controller({ + player: player, + //soundProvider: provider, + map: map + }); + //change_visualizer(); + //player.resize(); + //player.updateVolumeAnchor(provider.getVolume()); + }); + + // $('#visualizer_id').change(change_visualizer); + // $('#visualizer_id_form').submit(change_visualizer); + $('#visualizer_id').change(change_visualizer_clicked); + $('#visualizer_id_form').submit(change_visualizer_clicked); + + $('#player_maximized .toggle, #player_minimized .toggle').click(function() { + togglePlayerMaximization(); + this.blur(); + return false; + }); + + +} + +//TODO: REMOVE loads a player WAITING for the sound identified by soundUrl to be FULLY LOADED!!!! +function load_playerOld(soundUrl) { + if (!$('#player').length){ + return; + } + consolelog('PlayerUtils.load_player: '+soundUrl); + var callback = this.load_player2; + + //this variable can be changed to load a sound immediately or not + var loadImmediately = true; + var sound = soundManager.createSound({ + id: 'sound', + autoLoad: loadImmediately, + url: soundUrl, + whileloading: function() { + //PROBLEM/BUG: on chrome and firefox whileloading is the same as onload, + //ie it is not called at regular interval but when the whole file has loaded + if(loadImmediately){ + consolelog('entering while loading setting up---------------'+this.bytesLoaded+' of '+this.bytesTotal); + loadImmediately=false; + callback(this); + } + } + }); + if(!loadImmediately){ + callback(sound); + } +} diff --git a/telemeta/htdocs/timeside/demo/index.html b/telemeta/htdocs/timeside/demo/index.html index f3977e22..4a1e2ad8 100755 --- a/telemeta/htdocs/timeside/demo/index.html +++ b/telemeta/htdocs/timeside/demo/index.html @@ -30,8 +30,8 @@ function diff_array(a1, a2) { function log_globals(label) { var g = get_globals(); if (log_globals.cache && label && typeof console != 'undefined') { - console.log(label + ':'); - console.log(diff_array(log_globals.cache, g)); + consolelog(label + ':'); + consolelog(diff_array(log_globals.cache, g)); } log_globals.cache = g; } diff --git a/telemeta/htdocs/timeside/skins/lab/style.css b/telemeta/htdocs/timeside/skins/lab/style.css index 8afcb591..90918a25 100755 --- a/telemeta/htdocs/timeside/skins/lab/style.css +++ b/telemeta/htdocs/timeside/skins/lab/style.css @@ -26,9 +26,9 @@ } .ts-pointer{ border: 1px solid #a10006 !important; - -moz-border-radius: .5ex !important; - -webkit-border-radius: .5ex !important; - border-radius: .5ex !important; + -moz-border-radius: 1ex !important; + -webkit-border-radius: 1ex !important; + border-radius: 1ex !important; color: #6A0307 !important; } @@ -73,15 +73,15 @@ height /**/:28px; /* for IE5/Win only */ margin-right: 0px; } - -.ts-skin-lab .ts-player .ts-control .ts-playback a:hover { +/*commented, apparently not used anymore, and it messes up the volume icon*/ +/*.ts-skin-lab .ts-player .ts-control .ts-playback a:hover { background-position: 0 -28px; -} +}*/ -.ts-volume { +.ts-volume, .ts-volume:hover, .ts-volume:visited { background-image: url('img/volume.png'); background-repeat: no-repeat; - background-position: 0px 0px !important; + /*background-position: 0px 0px !important;*/ width:60px !important; } diff --git a/telemeta/htdocs/timeside/src/controller.js b/telemeta/htdocs/timeside/src/controller.js index 859fd496..706d1c91 100644 --- a/telemeta/htdocs/timeside/src/controller.js +++ b/telemeta/htdocs/timeside/src/controller.js @@ -23,24 +23,26 @@ TimeSide(function($N) { this._setupPlayer(); //setting the divmarkers //this.cfg.map.observe('add') + this.loadHTTP(); }, _setupPlayer: function() { - + this.debug('_setupPlayer'); this.cfg.player - .setSoundProvider(this.cfg.soundProvider) + //.setSoundProvider(this.cfg.soundProvider) .setMarkerMap(this.cfg.map) - .observe('play', $N.attachFunction(this.cfg.soundProvider, this.cfg.soundProvider.play)) - .observe('pause', $N.attachFunction(this.cfg.soundProvider, this.cfg.soundProvider.pause)) - .observe('move', this.attach(this._onMove)) +// .observe('play', $N.attachFunction(this.cfg.soundProvider, this.cfg.soundProvider.play)) +// .observe('pause', $N.attachFunction(this.cfg.soundProvider, this.cfg.soundProvider.pause)) +// .observe('move', this.attach(this._onMove)) .observe('markeradd', this.attach(this._onMarkerAdd)) //player markermove listens for changes of ruler markermove which listens //foir changes in each marker move .observe('markermove', this.attach(this._onMarkerMove)) - .draw(); - this.loadHTTP(); +// .draw(); + ._setupInterface(); + //this.loadHTTP(); this.cfg.map.observe('add',this.attach(this._onMarkerMapAdd)); this.cfg.map.observe('remove',this.attach(this._onMarkerMapRemove)); @@ -49,9 +51,9 @@ TimeSide(function($N) { }, - _onMove: function(e, data) { - this.cfg.soundProvider.seek(data.offset); - }, +// _onMove: function(e, data) { +// this.cfg.soundProvider.seek(data.offset); +// }, //called whenever a marker is moved in the ruler BUT NOT in the map _onMarkerMove: function(e, data) { @@ -144,31 +146,18 @@ TimeSide(function($N) { loadHTTP: function(){ - - //itemid is the item (spund file) name - var sPath = window.location.pathname; - //remove last "/" or last "/#", if any... - sPath = sPath.replace(/\/#*$/,""); - var itemid = sPath.substring(sPath.lastIndexOf('/') + 1); - - //WARNING: use single quotes for the whole string!! - //see http://stackoverflow.com/questions/4809157/i-need-to-pass-a-json-object-to-a-javascript-ajax-method-for-a-wcf-call-how-can - var data2send = '{"id":"jsonrpc","params":["'+itemid+'"], "method":"telemeta.get_markers","jsonrpc":"1.0"}'; + var itemId = ITEM_PUBLIC_ID; var map = this.cfg.map; var updateIndices = this.updateIndices; + //var setTabs = $N.Util.setUpTabs; + var util = $N.Util; var me = this; - $.ajax({ - type: "POST", - url: '/json/', - contentType: "application/json", - data: data2send, - dataType: "json", - success: function(data) { + var onSuccess = function(data) { var tabIndex = 0; if(data){ if(data.result && data.result.length>0){ var result = data.result; - + for(var i =0; i< result.length; i++){ map.add(result[i]); } @@ -176,21 +165,14 @@ TimeSide(function($N) { updateIndices.apply(me); tabIndex = result.length>0 ? 1 : 0; } - + } - //We call mediaitem_detail.setUpTabs from controller once all markers have been loaded - //this because setLabelDescription, which sets the label text according to the div width, - //needs to have all elements visible. - $N.Util.setUpTabs(tabIndex); - //setUpTabs(); //which hides the marker div. Call with argument 1 to set up marker div - //as visible as startup - } - }); - //var g = 9; + util.setUpTabs.apply(util, [tabIndex]); +// setTabs(tabIndex); + }; + //json(param, method, onSuccesFcn(data, textStatus, jqXHR), onErrorFcn(jqXHR, textStatus, errorThrown)) + json([itemId],"telemeta.get_markers", onSuccess); } - - - }); $N.notifyScriptLoad(); diff --git a/telemeta/htdocs/timeside/src/divmarker.js b/telemeta/htdocs/timeside/src/divmarker.js index 64e2b053..86cea419 100644 --- a/telemeta/htdocs/timeside/src/divmarker.js +++ b/telemeta/htdocs/timeside/src/divmarker.js @@ -23,6 +23,7 @@ TimeSide(function($N, $J) { me:null, markerMap:null, + initialize: function($super, markermap) { $super(); //sets the fields required???? see ruler.js createPointer @@ -108,6 +109,7 @@ TimeSide(function($N, $J) { markerDiv = $J('
') .append(this.e_header) .append(this.e_descriptionText) + .attr('tabIndex',0) //.append(this.e_okButton) .append($J('
') //.css('margin','1ex 0ex 0.1ex 0ex') .append(this.e_okButton)) @@ -167,7 +169,8 @@ TimeSide(function($N, $J) { this.e_editButton.unbind('click').hide(); return false; } - + + var remove = map.remove; this.e_deleteButton.unbind('click').click( function(){ if(!(marker.isSavedOnServer) || confirm('delete the marker permanently?')){ @@ -176,7 +179,9 @@ TimeSide(function($N, $J) { return false; //avoid scrolling of the page on anchor click }) - + this.e_addplaylistButton.unbind('click').bind('click',function(evtObj_){ + playlistUtils.showPopupAddToPlaylist(evtObj_,'marker',""+marker.id,'marker added to selected playlist');return false; + }); //notifies controller.js // this.fire('remove', { // index: index @@ -196,7 +201,13 @@ TimeSide(function($N, $J) { eB.hide(); utw.apply(divmarker,[tText]); }; - + +// dText.unbind('focus').focus(function(){this.debug('dText focus')}); +// tText.unbind('focus').focus(function(){this.debug('tText focus')}); +// dText.unbind('blur').blur(function(){this.debug('dText blur')}); +// tText.unbind('blur').blur(function(){this.debug('tText blur')}); + + this.e_editButton.unbind('click').click( function(){ startEdit(); divmarker.focusOn(); diff --git a/telemeta/htdocs/timeside/src/player.js b/telemeta/htdocs/timeside/src/player.js index cb59878e..cc254a12 100644 --- a/telemeta/htdocs/timeside/src/player.js +++ b/telemeta/htdocs/timeside/src/player.js @@ -34,11 +34,11 @@ TimeSide(function($N, $J) { }, elements: {}, ruler: null, - soundProvider: null, map: null, container: null, imageWidth: null, imageHeight: null, + soundPosition: 0, initialize: function($super, container, cfg) { $super(); @@ -46,21 +46,22 @@ TimeSide(function($N, $J) { throw new $N.RequiredArgumentError(this, 'container'); } this.container = $J(container); + this.configure(cfg, { - image: null + image: null, + sound:null, + soundDurationInMsec:0 }); + //if(this.cfg.sound && this.cfg.sound.) }, free: function($super) { this.elements = null; this.container = null; + //this.sound.destruct(); //should be called here? $super(); }, - setSoundProvider: function(soundProvider) { - this.soundProvider = soundProvider; - return this; - }, setMarkerMap: function(map) { this.map = map; @@ -85,13 +86,27 @@ TimeSide(function($N, $J) { } }, - draw: function() { - this.debug('drawing'); - $N.domReady(this.attach(this._setupInterface)); - return this; - }, + // draw: function() { + // this.debug('drawing'); + // $N.domReady(this.attach(this._setupInterface)); + // return this; + // }, _setupInterface: function() { + consolelog('player _setupInterface sound.readyState:'+this.cfg.sound.readyState); //handle also cases 0 and 2???? + //0 = uninitialised + //1 = loading + //2 = failed/error + //3 = loaded/success + if(this.cfg.sound.readyState==1){ + var rsz = this.resize; + //attach an event when fully loaded and repaint all. + //For the moment we will display the ruler and other stuff + //based on durationEstimate property + this.cfg.sound.options.onload = function() { + rsz(); + } + } this.elements = $N.Util.loadUI(this.container, this.skeleton, this.defaultContents); // IE apparently doesn't send the second mousedown on double click: @@ -104,13 +119,14 @@ TimeSide(function($N, $J) { .click(function() { return false; }); - this.elements.pause.attr('href', '#').bind('click', this.attach(this._onPause)); - this.elements.play.attr('href', '#').bind('click', this.attach(this._onPlay)); + // - this.elements.volume.attr('href', '#').click(function(){return false;}).bind('mousedown', this.attach( + this.elements.volume.attr('href', '#').click(function(){ + return false; + }).bind('mousedown', this.attach( function(e){ if(e.which===1){ //left button - this.changeVolume(e); + this.setVolume(e); } return false; } @@ -139,11 +155,13 @@ TimeSide(function($N, $J) { this.elements.setMarker.remove(); } //creating the ruler - this.ruler = new $N.Ruler({ + var ruler = new $N.Ruler({ viewer: this.elements.viewer, //map: this.map, - soundProvider: this.soundProvider + sound: this.cfg.sound, + soundDurationInMsec: this.cfg.soundDurationInMsec }); + this.ruler = ruler; //bind events to the ruler (see function observe in core.js, I guess, //which overrides jQuery bind function): //the first arg is basically the event name, the second @@ -151,20 +169,39 @@ TimeSide(function($N, $J) { this.ruler .observe('markermove', this.forwardEvent) .observe('markeradd', this.forwardEvent) - .observe('move', this.forwardEvent) + //.observe('move', this.forwardEvent) .draw(); this.refreshImage(); - //this.resize(); //will be called in Timeside.load. - var resizeTimer = null; - $J(window).resize(this.attach(function() { - if (resizeTimer){ - clearTimeout(resizeTimer); + this.resize(); + +// var resizeTimer = null; +// $J(window).resize(this.attach(function() { +// if (resizeTimer){ +// clearTimeout(resizeTimer); +// } +// resizeTimer = setTimeout(this.attach(this.resize), 100); +// })); + + this.setSoundVolume(this.getSoundVolume()); + //finally, binds events to play and pause. At the end cause this.ruler has to be fully initialized + var sound = this.cfg.sound; + this.elements.pause.attr('href', '#').bind('click', function(){ + sound.pause(); + return false; + }); + //var r = this.ruler; + this.elements.play.attr('href', '#').bind('click', function(){ + consolelog('playstate'+sound.playState); + if(sound.playState!=1 || sound.paused){ + sound.play({ + whileplaying: function(){ + ruler._movePointer(this.position/1000); + //consolelog(this.ruler); + } + }); } - resizeTimer = setTimeout(this.attach(this.resize), 100); - })); - //_updateVolumeChanged(this.soundProvider.getVolume()); - this.soundProvider.observe('volume',this.attach(this.onVolumeChanged)); - //this.container.resize(this.attach(this.resize)); // Can loop ? + return false; + }); }, resize: function(overrideHeight) { @@ -205,19 +242,32 @@ TimeSide(function($N, $J) { this.ruler.resize(); return this; }, + //sound object methods + + getSoundPosition :function(){ + //note that this.cfg.sound.position is buggy. If we did not play, calling this.cfg.sound.setPosition(p) + //stores the position, but this.cfg.position returns zero. + //otherwise (we did play at least once) this.cfg.sound.position returns the good value + //to overcome this problem, we return the ruler position, NOTE that it is in seconds + return this.ruler.pointerPos; + // var s = this.cfg.sound; + // return s ? s.position/1000 : 0; + }, + + getSoundVolume :function(){ + var s = this.cfg.sound; + return s ? s.volume : 0; + }, + + getSoundDuration :function(){ + var s = this.cfg.sound; + return s ? s.duration/1000 : 0; + }, _onRewind: function() { var offset = 0; if (this.map) { - var position = parseFloat(this.soundProvider.getPosition()); - // var marker = this.map.getPrevious(position); - // if (marker && this.soundProvider.isPlaying() - // && position - marker.offset < this.ruler.getUnitDuration()) - // marker = this.map.getPrevious(marker.offset) - // if (marker) { - // offset = marker.offset; - // } - // + var position = parseFloat(this.getSoundPosition()); var idx = this.map.indexOf(position)-1; if(idx>=0){ var marker = this.map.get(idx); @@ -226,16 +276,14 @@ TimeSide(function($N, $J) { } } } - this.fire('move', { - offset: offset - }); + this.ruler._movePointerAndUpdateSoundPosition(offset); return false; }, _onForward: function() { - var offset = this.soundProvider.getDuration(); + var offset = this.getSoundDuration(); if (this.map) { - var position = parseFloat(this.soundProvider.getPosition()); + var position = parseFloat(this.getSoundPosition()); var idx = this.map.insertionIndex(position); if(idx>=0){ //the pointer is exactly on a marker, the index is the marker itself //so increase by one otherwise and we wouldn't move ahead @@ -260,49 +308,62 @@ TimeSide(function($N, $J) { offset = marker.offset; } } - // var marker = this.map.getNext(this.soundProvider.getPosition()); - // if (marker) { - // offset = marker.offset; - // } } - this.fire('move', { - offset: offset - }); + this.ruler._movePointerAndUpdateSoundPosition(offset); + return false; }, - changeVolume: function(event){ + //notified from a click event on the anchor + setVolume: function(event){ + var ticks = [18,26,33,40,47]; var vol = event.layerX; for(var i=0; i100){ + volume = 100; + } + this.cfg.sound.setVolume(volume); + //update the anchor image: var indices = [20,40,60,80,100,100000]; + for(var i=0; i ') - // .attr('type','text').val(""); - // var tText = $('') - // .attr('type','text').val(""); - // - // var table = $J('') - // .append($J('') - // .append($J('') - // .append($J(' - {% for analyser in analysers %} +
').html('title')) - // .append($J('').append(tText))) - // .append($J('
').html('description')) - // .append($J('').append(dText))); - // - // var onOk= function(){ - // var pl = [{ - // "public_id":uniqid(), - // "title":tText.val(), - // "description":dText.val(), - // user:CURRENT_USER_NAME - // }]; - // json(pl,'telemeta.add_playlist',function(){ - // window.location.reload(); - // },true); - // }; - // var onCancel= function(){ - // popup.hide(); - // return false; - // }; - // var subdiv = $J('
').append( - // $J(''). - // html('Cancel'). - // css('float','right'). - // addClass('mediaitem_button'). - // addClass('mediaitem_button_cancel'). - // attr('href','#'). - // click(function(){ - // return onCancel(); - // }) - // ).append( - // $J(''). - // html('Ok'). - // css('float','right'). - // addClass('mediaitem_button'). - // addClass('mediaitem_button_ok'). - // attr('href','#'). - // click(function(){ - // return onOk(); - // }) - // ); - // //popupDialog(element,table,onOk); - // popup.show($J('
').append(table).append(subdiv), event); - // }, + + /*shows the popup for adding an item to the playlist*/ + showPopupAddToPlaylist: function(event,resourceType,objectId, optionalMessage){ + var $J = jQuery; + var content = $J('
').addClass("_popup_add_to_playlist"); + var addToPlaylist = this.addToPlaylist; + for(var p in this.playlists){ + var id = this.playlists[p]; + + var a = $J(''). + attr('href','#'). + addClass("component_icon"). + addClass("list_item icon_playlist"). + html(p). + //by wrapping the addToPlaylist function in order to accept the id variable as an argument + //we avoid calling the function with id = number_of_playlists for all anchors + //by returning another function (basically create another closure) we avoid executing the function + //immediately + click(function(id_){ + return function(){ + addToPlaylist(id_,resourceType,objectId,optionalMessage); + return false; + } + }(id) + ); + content.append(a); + } + return popup.show(content,event); + }, add : function(dictionary){ @@ -92,8 +62,10 @@ var playlistUtils = { window.location.reload(); }); }, + //resourceType can be: 'collection', 'item', 'marker' - addToPlaylist: function(playlistId,resourceType,objectId){ + addToPlaylist: function(playlistId,resourceType,objectId, optionalOkMessage){ + consolelog(playlistId) var send = { 'public_id':uniqid(), 'resource_type':resourceType, @@ -101,8 +73,14 @@ var playlistUtils = { }; json([playlistId,send],'telemeta.add_playlist_resource',function(){ var p = popup; - p.show(jQuery('
').html('Ok')); - setTimeout(function(){p.hide()},600); + if(optionalOkMessage){ + p.show(jQuery('
').addClass("icon_ok").addClass("component_icon").html(optionalOkMessage)); + setTimeout(function(){ + p.hide(); + },1000); + }else{ + p.hide(); //to be sure + } }); } diff --git a/telemeta/htdocs/timeside/src/ruler.js b/telemeta/htdocs/timeside/src/ruler.js index 1ce82fb5..f6891a12 100644 --- a/telemeta/htdocs/timeside/src/ruler.js +++ b/telemeta/htdocs/timeside/src/ruler.js @@ -31,23 +31,49 @@ TimeSide(function($N, $J) { viewer: [null, 'required'], fontSize: 10, //map: null, - soundProvider: [null, 'required'] + sound: [null, 'required'], + soundDurationInMsec:0 }); this.cfg.viewer = $J(this.cfg.viewer); this.container = this.cfg.viewer.find('.' + $N.cssPrefix + 'ruler'); this.waveContainer = this.cfg.viewer.find('.' + $N.cssPrefix + 'image-canvas'); - this._setDuration(this.cfg.soundProvider.getDuration()); + + //this.duration = this.cfg.sound.duration/1000; //TODO: improve this function!! + //note that soundmanager2 returns the duration in milliseconds, while here we compute the + //layout according to the duration in seconds. Changing all functions it's a pain and it's useless' + + //initialize duration. If sound autoLoad=false, duration is zero and we must use durationEstimate + //this.duration = this.cfg.sound.duration ? this.cfg.sound.duration : this.cfg.sound.durationEstimate; + //this + this.duration = this.cfg.soundDurationInMsec/1000; + consolelog('duration - - '+this.cfg.sound.duration); + consolelog('duration -E- '+this.cfg.sound.bytesTotal); + var imgContainer = this.cfg.viewer.find('.' + $N.cssPrefix + 'image-container'); // for IE this._observeMouseEvents(this.waveContainer.add(imgContainer)); - //if (this.cfg.map) { - // this.cfg.map - //.observe('add', this.attach(this._onMapAdd)) - //.observe('remove', this.attach(this._onMapRemove)) - //.observe('indexchange', this.attach(this._onMapIndexChange)); - //} + + //this is a workaround: when moving the marker the first time sound.setPosition seems not to work + //after playing the first time, it works. Or after having set position explicitly, apparently + //this.cfg.sound.setPosition(0); + // this.sp = this._setPosition; + + // this.cfg.sound.whileplaying(function(){ + // sp(this.position/1000); + // }); + // this.cfg.sound.onfinish(function(){ //when it reaches the end (naturally) force pointer to be at the end + // sp(this.duration); + // }); + + //if (this.cfg.map) { + // this.cfg.map + //.observe('add', this.attach(this._onMapAdd)) + //.observe('remove', this.attach(this._onMapRemove)) + //.observe('indexchange', this.attach(this._onMapIndexChange)); + //} - this.cfg.soundProvider.observe('update', this.attach(this._onSoundProviderUpdate)); + //this.cfg.soundProvider.observe('update', this.attach(this._onSoundProviderUpdate)); + //this.cfg.soundProvider.observe('play', this.attach(this._onSoundProviderPlaying)); }, free: function($super) { @@ -60,11 +86,14 @@ TimeSide(function($N, $J) { _computeLayout: function() { this.width = this.waveContainer.width(); - this.debug('container width: ' + this.width); var i, ii = this.sectionSteps.length; this.timeLabelWidth = this._textWidth('00:00', this.cfg.fontSize); for (i = 0; i < ii; i++) { + // this.debug('step: ' +i+' duration: '+this.sectionSteps[i][0]); + // this.debug('step: ' +i+' subdivision: '+this.sectionSteps[i][1]); + // this.debug('labelsNum: ' +i+' labelsNum (this.duration/duration): '+Math.floor(this.duration / duration)); + var duration = this.sectionSteps[i][0]; var subDivision = this.sectionSteps[i][1]; var labelsNum = Math.floor(this.duration / duration); @@ -72,6 +101,9 @@ TimeSide(function($N, $J) { this.fullSectionDuration = duration; this.sectionSubDivision = subDivision; this.sectionsNum = Math.floor(this.duration / this.fullSectionDuration); + this.debug('(in _computeLayout) this.fullSectionDuration: ' + this.fullSectionDuration); + this.debug('(in _computeLayout) sectionsNum: ' +this.sectionsNum); + this.debug('(in _computeLayout) duration: ' +this.duration); break; } } @@ -82,29 +114,41 @@ TimeSide(function($N, $J) { }, resize: function() { - var pointerVisible = this.pointer && this.pointer.isVisible(); + // var pointerVisible = this.pointer && this.pointer.isVisible(); + // this.debug('resizing (pointer visible: :'+pointerVisible+':'); + // alert(this.pointer.isVisible()); this._computeLayout(); + this.draw(); - if (pointerVisible) { - this.setPosition(this.cfg.soundProvider.getPosition()); - this.setBuffering(this.cfg.soundProvider.isBuffering() && this.cfg.soundProvider.isPlaying()); - this.pointer.show(); + if(this.pointer){ + if(!this.pointer.isVisible()){ + this.pointer.show(); + } + // } + // if (pointerVisible) { + // this.setPosition(this.cfg.soundProvider.getPosition()); + // this.setBuffering(this.cfg.soundProvider.isBuffering() && this.cfg.soundProvider.isPlaying()); + + this._movePointer(this.cfg.sound.position/1000); + this.setBuffering(this.cfg.sound.isBuffering && this.cfg.sound.playState==1); + //Note that playState = 1 may not always guarantee that sound is being heard, given buffering and autoPlay status. + //(from soundmanager2 tutorial) } }, - _setDuration: function(duration) { - this.duration = duration; - this._computeLayout(); - }, - - setDuration: function(duration) { - if (duration == 0) - duration = 60; - if (this.duration != duration) { - this._setDuration(duration); - this.draw(); - } - }, +// _setDuration: function(duration) { +// this.debug('duration setting ruler: ' + duration); +// this.duration = duration; +// this._computeLayout(); +// }, +// +// setDuration: function(durationInMillisecs) { +// var duration = durationInMillisecs ? durationInMillisecs/1000 : 60; +// if (this.duration != duration) { +// this._setDuration(duration); +// this.draw(); +// } +// }, _createSection: function(timeOffset, pixelWidth) { var section = $J('
') @@ -272,36 +316,26 @@ TimeSide(function($N, $J) { .observe('move', this.attach(this._onPointerMove)); }, - _movePointer: function(offset) { - if (offset < 0){ - offset = 0; - }else if (offset > this.duration){ - offset = this.duration; - } - pixelOffset = offset / this.duration * this.width; - if (this.pointer) { - this.pointer.move(pixelOffset); - this.pointer.setText($N.Util.makeTimeLabel(offset)); - } - this.pointerPos = offset; - }, + // _setPosition: function(offset) { + // this._movePointer(offset); + //// if (this.pointer) { + //// this.pointer.show(); + //// } + // }, + + - _setPosition: function(offset) { - this._movePointer(offset); - if (this.pointer) { - this.pointer.show(); - } - }, + - setPosition: function(offset) { - if (!this.mouseDown) { - this._setPosition(offset); - } - }, + // setPosition: function(offset) { + // if (!this.mouseDown) { + // this._setPosition(offset); + // } + // }, - shiftPosition: function(delta) { - this.setPosition(this.pointerPos + delta); - }, + // shiftPosition: function(delta) { + // this.setPosition(this.pointerPos + delta); + // }, hidePointer: function() { if (this.pointer) @@ -324,40 +358,63 @@ TimeSide(function($N, $J) { _onMouseDown: function(evt) { this.mouseDown = true; this._onMouseMove(evt); - evt.preventDefault(); - }, - - _onPointerMove: function(evt, data) { - this.mouseDown = true; - this._setPosition(data.offset / this.width * this.duration); - if(data.finish) { - this.fire('move', { - offset: this.pointerPos - }); - this.mouseDown = false; - } - return false; + evt.preventDefault(); //If this method is called, the default action of the event will not be triggered. }, + _onMouseMove: function(evt) { if (this.mouseDown) { var pixelOffset = evt.pageX - this.container.offset().left; - this._setPosition(pixelOffset / this.width * this.duration); + this._movePointerAndUpdateSoundPosition(pixelOffset / this.width * this.duration); + //moves the pointer and fires onPointerMove return false; } }, _onMouseUp: function(evt) { - if (this.mouseDown) { this.mouseDown = false; - this.fire('move', { - offset: this.pointerPos - }); - return false; + this.debug('_onMouseUp:'+this.pointerPos+' '+this.cfg.sound.position); + //this.debug("mousedup"+this.cfg.sound.position) + } + return false; + }, + //called while playing, does not update sound position + _movePointer: function(offset) { + + if (offset < 0){ + offset = 0; + }else if (offset > this.duration){ + offset = this.duration; + } + var pixelOffset = offset / this.duration * this.width; + if (this.pointer) { + this.pointer.move(pixelOffset); //does NOT fire any move method + this.pointer.setText($N.Util.makeTimeLabel(offset)); + } + this.pointerPos = offset; + }, + //called by everything else than playing, same as _movePointer but updates also the sound position accordingly + _movePointerAndUpdateSoundPosition: function(offset) { + this._movePointer(offset) + this.cfg.sound.setPosition(parseInt(1000*this.pointerPos)); + }, + + _onPointerMove: function(evt, data) { + //this.debug('_onPointerMove:'+ this.pointerPos+' '+this.cfg.sound.position); + + this.mouseDown = true; + this._movePointerAndUpdateSoundPosition(data.offset / this.width * this.duration); + if(data.finish) { + // this.fire('move', { + // offset: this.pointerPos + // }); + this.mouseDown = false; } + return false; }, + _observeMouseEvents: function(element) { if(!(CURRENT_USER_NAME)){ return; @@ -381,7 +438,7 @@ TimeSide(function($N, $J) { } pixelOffset = marker.offset / this.duration * this.width; - + m = new $N.RulerMarker({ rulerLayout: this.layout.get(0), viewer: this.waveContainer, @@ -391,6 +448,7 @@ TimeSide(function($N, $J) { tooltip: 'Move marker', canMove: marker.isEditable }); + if(marker.isEditable){ m.observe('move', this.attach(this._onMarkerMove)) } @@ -428,10 +486,10 @@ TimeSide(function($N, $J) { }, //it is assured that fromIndex!=toIndex and fromIndex!=toIndex+1 (see markermap.move) -// move: function(fromIndex, toIndex){ -// var m = this.markers.splice(fromIndex,1)[0]; //remove -// this.markers.splice(toIndex,0,m); //add -// }, + // move: function(fromIndex, toIndex){ + // var m = this.markers.splice(fromIndex,1)[0]; //remove + // this.markers.splice(toIndex,0,m); //add + // }, updateMarkerIndices:function(fromIndex, toIndex){ for(var i=fromIndex; i<=toIndex; i++){ @@ -447,13 +505,15 @@ TimeSide(function($N, $J) { offset: offset }); } - }, - - _onSoundProviderUpdate: function(e) { - this.setDuration(this.cfg.soundProvider.getDuration()); - this.setPosition(this.cfg.soundProvider.getPosition()); - this.setBuffering(this.cfg.soundProvider.isBuffering() && this.cfg.soundProvider.isPlaying()); } + + // , _onSoundProviderUpdate: function(e) { + // this.debug("spupdate"); + // + // //this.setDuration(this.cfg.soundProvider.getDuration()); + // this.setPosition(this.cfg.soundProvider.getPosition()); + // this.setBuffering(this.cfg.soundProvider.isBuffering() && this.cfg.soundProvider.isPlaying()); + // } }); $N.notifyScriptLoad(); diff --git a/telemeta/htdocs/timeside/src/rulermarker.js b/telemeta/htdocs/timeside/src/rulermarker.js index 5dd49c37..3304f4ec 100644 --- a/telemeta/htdocs/timeside/src/rulermarker.js +++ b/telemeta/htdocs/timeside/src/rulermarker.js @@ -17,6 +17,7 @@ TimeSide(function($N, $J) { nodes: null, mouseDown: false, blinkAnimation: null, + mouseDownOffset:0, initialize: function($super, cfg) { $super(); @@ -44,6 +45,7 @@ TimeSide(function($N, $J) { if(cfg.index !== undefined && cfg.className!='pointer'){ this.setIndex(cfg.index); } + }, setIndex: function(index){ @@ -90,6 +92,7 @@ TimeSide(function($N, $J) { if (this.cfg.tooltip){ this.label.attr('title', this.cfg.tooltip); } + this.cfg.rulerLayout.append(this.label); var height = this.cfg.viewer.height(); @@ -113,6 +116,7 @@ TimeSide(function($N, $J) { .each(function(i, node) { node.originalPosition = parseInt($J(node).css('left')); }); + }, setText: function(text) { @@ -214,13 +218,17 @@ TimeSide(function($N, $J) { _onMouseDown: function(evt) { this.mouseDown = true; - this._onMouseMove(evt); + this.mouseDownOffset = evt.pageX-(this.label.offset().left+this.label.outerWidth(true)/2); + //this._onMouseMove(evt); return false; }, _onMouseMove: function(evt) { if (this.mouseDown) { - var offset = (evt.pageX - this.cfg.rulerLayout.offset().left); + var offset = (evt.pageX - this.cfg.rulerLayout.offset().left)-this.mouseDownOffset; + this.debug(evt.pageX); + this.debug(this.label.outerWidth(true)); + this.debug(this.cfg.rulerLayout.offset().left); this.move(offset); this.fire('move', { //calls move (see above) offset: this.position, diff --git a/telemeta/htdocs/timeside/src/soundprovider.js b/telemeta/htdocs/timeside/src/soundprovider.js index b0e75923..d51959c0 100644 --- a/telemeta/htdocs/timeside/src/soundprovider.js +++ b/telemeta/htdocs/timeside/src/soundprovider.js @@ -33,6 +33,9 @@ TimeSide(function($N) { this.state.position = 0; this.update = this.attach(this._update); this.timer = setInterval(this.update, 43); + this.init=true; + this._update(); + this.init=false; }, free: function($super) { @@ -144,6 +147,7 @@ TimeSide(function($N) { _update: function() { this._retrieveState(); var updated = false; + var k; if (this.lastState) { for (k in this.state) { if (this.state[k] != this.lastState[k]) { @@ -156,10 +160,27 @@ TimeSide(function($N) { updated = true; } if (updated) { + var fireevent = false; for (k in this.state) { + if(k=='position' && this.lastState[k]!==undefined && this.lastState[k]!=this.state[k]){ + //this.lastState[k]!==undefined because otherwise we are initializing + this.debug('fire-play-stop'); + fireevent = true; + }else if(k=='playing' && this.lastState[k] && !this.state[k]){ + //stop playing, fire again to move the cursor REALLY at the end + this.debug('fire-stop'); + fireevent = true; + } + if(this.state[k] != this.lastState[k]){ + this.debug('(soundprovider _update) '+k+': oldVal: '+this.lastState[k]+': val: '+this.state[k]); + } this.lastState[k] = this.state[k]; + + } + if(fireevent){ + this.debug('firing'); + this.fire('update'); } - this.fire('update'); } }, diff --git a/telemeta/htdocs/timeside/src/timeside.js b/telemeta/htdocs/timeside/src/timeside.js index beb915eb..19055133 100644 --- a/telemeta/htdocs/timeside/src/timeside.js +++ b/telemeta/htdocs/timeside/src/timeside.js @@ -102,7 +102,7 @@ TimeSide(function($N, $J) { if (!$N.isLoading) { $N.isLoading = true; var re = /(.*)timeside.js/; - var root = ''; + var root = '/timeside/src/'; //TODO: changed by me!!!!! $J('head script').each(function(i, e) { if ((match = re.exec(e.src))) { root = match[1]; @@ -112,8 +112,8 @@ TimeSide(function($N, $J) { $N.loadScripts(root, ['core.js'], function() { $N.loadScripts(root, ['util.js'], function() { var scripts = ['controller.js', 'rulermarker.js', //'markerlist.js', - 'markermap.js', 'player.js', 'ruler.js','divmarker.js', - 'soundprovider.js']; + 'markermap.js', 'player.js', 'ruler.js','divmarker.js']; + //,'soundprovider.js']; $N.loadScripts(root, scripts, function() { $N.isLoaded = true; diff --git a/telemeta/htdocs/timeside/src/util.js b/telemeta/htdocs/timeside/src/util.js index 66841988..221eff1a 100755 --- a/telemeta/htdocs/timeside/src/util.js +++ b/telemeta/htdocs/timeside/src/util.js @@ -79,6 +79,7 @@ TimeSide(function($N, $J) { setUpTabs:function(selIndex) {//called from within controller.js once all markers have been loaded. //this is because we need all divs to be visible to calculate size. selIndex is optional, it defaults to 0 // + //declare variables: var tabContainerHeight = '5ex'; //height for the tab container var tabHeight = '3.5ex'; //height for the tab. Must be lower than tabContainerHeight @@ -116,6 +117,15 @@ TimeSide(function($N, $J) { }; //end of variables declaration + + //first of all, delete the span shown only onloading + var span = tabContainer.find('#loading_span'); + if(span.length){ + span.remove(); + consolelog('removed span'); + } + + //tabContainer default css: tabContainer.css({ 'position':'relative', @@ -123,6 +133,7 @@ TimeSide(function($N, $J) { }); //tabs default css: tabs.css({ + 'display':'', //reset the default value 'position':'absolute', 'height':tabHeight, 'bottom':tabBottom, @@ -209,7 +220,7 @@ TimeSide(function($N, $J) { } }); - }, + } } diff --git a/telemeta/templates/telemeta_default/base.html b/telemeta/templates/telemeta_default/base.html index fe00eaed..0c008816 100644 --- a/telemeta/templates/telemeta_default/base.html +++ b/telemeta/templates/telemeta_default/base.html @@ -85,7 +85,9 @@ - +
+{% block content_header %}{% endblock %} +
{% block content %}{% endblock %}
diff --git a/telemeta/templates/telemeta_default/collection_detail.html b/telemeta/templates/telemeta_default/collection_detail.html index 1dd57e01..6c9ccc94 100644 --- a/telemeta/templates/telemeta_default/collection_detail.html +++ b/telemeta/templates/telemeta_default/collection_detail.html @@ -8,9 +8,25 @@ {% endblock %} @@ -27,12 +43,6 @@ {% endif %} {% if user.is_authenticated %}
{% trans "Add to playlist" %} - {% endif %} {% endblock tools %} diff --git a/telemeta/templates/telemeta_default/mediaitem_detail.html b/telemeta/templates/telemeta_default/mediaitem_detail.html index 7b598c39..fb7d6e91 100644 --- a/telemeta/templates/telemeta_default/mediaitem_detail.html +++ b/telemeta/templates/telemeta_default/mediaitem_detail.html @@ -9,69 +9,98 @@ -{% endblock %} + {% endblock %} -{% block extra_javascript %} - + {% block extra_javascript %} + - - + {% endblock %} {% if item %} {% block submenu %} -
- {% block tools %} - Dublin Core - {% if user.is_authenticated and perms.telemeta.change_mediaitem %} - {% trans "Edit" %} - {% trans "Copy" %} - {% endif %} - {% if user.is_authenticated %} - - {% trans "Add to playlist" %} - +{% endblock %} +{% block content_header %} +
+

Item : {{ item }}

+
+ {% block tools %} + {% if user.is_authenticated and perms.telemeta.change_mediaitem %} + {% trans "Edit" %} + {% trans "Copy" %} + {% endif %} + {% if user.is_authenticated %} + {% trans "Add to playlist" %} - {% endif %} - {% trans "Previous" %} - {% trans "Next" %} - {% endblock tools %} - + {% endif %} + {% trans "Previous" %} + {% trans "Next" %} + Dublin Core + {% endblock tools %} +
{% endblock %} {% block content %} -

Item : {{ item }}

+
- {% if item.file %} + {% if item.file %} {% if public_access or user.is_staff %}
Minimize @@ -120,21 +149,13 @@
- - +
@@ -144,7 +165,7 @@
{% trans "Value" %} {% trans "Unit" %}
@@ -166,7 +187,7 @@

{% trans "Download:" %} {% for format in export_formats %} - {{ format.extension }} + {{ format.extension }} {% endfor %}

{% endif %} @@ -174,7 +195,7 @@
{% endif %} {% endif %} - + {% block infos %}
{% block general_info %} @@ -284,7 +305,7 @@
{% endblock technical_data %}
- {% endblock infos %} + {% endblock infos %} {% endblock %} {% else %} -- 2.39.5