]> git.parisson.com Git - telemeta.git/commitdiff
Important modification in mediaitem_detail page, which loads in parallel with the...
authorriccardo <riccardo@parisson.com>
Tue, 5 Apr 2011 17:53:56 +0000 (19:53 +0200)
committerriccardo <riccardo@parisson.com>
Tue, 5 Apr 2011 17:53:56 +0000 (19:53 +0200)
20 files changed:
setup.py [deleted file]
telemeta/htdocs/css/telemeta.css
telemeta/htdocs/images/dialog-error.png [new file with mode: 0644]
telemeta/htdocs/images/wait_small.gif [new file with mode: 0644]
telemeta/htdocs/js/application.js
telemeta/htdocs/js/playerUtils.js
telemeta/htdocs/timeside/demo/index.html
telemeta/htdocs/timeside/skins/lab/style.css
telemeta/htdocs/timeside/src/controller.js
telemeta/htdocs/timeside/src/divmarker.js
telemeta/htdocs/timeside/src/player.js
telemeta/htdocs/timeside/src/playlist.js
telemeta/htdocs/timeside/src/ruler.js
telemeta/htdocs/timeside/src/rulermarker.js
telemeta/htdocs/timeside/src/soundprovider.js
telemeta/htdocs/timeside/src/timeside.js
telemeta/htdocs/timeside/src/util.js
telemeta/templates/telemeta_default/base.html
telemeta/templates/telemeta_default/collection_detail.html
telemeta/templates/telemeta_default/mediaitem_detail.html

diff --git a/setup.py b/setup.py
deleted file mode 100644 (file)
index 17602bd..0000000
--- 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.
-"""
-)
index 9989cedfd2175ab2ffddd96eeeb003d23d2180ae..ff6daaeffce1f6eadadd202ad945de0eb90d191a 100644 (file)
@@ -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 (file)
index 0000000..a296fef
Binary files /dev/null and b/telemeta/htdocs/images/dialog-error.png differ
diff --git a/telemeta/htdocs/images/wait_small.gif b/telemeta/htdocs/images/wait_small.gif
new file mode 100644 (file)
index 0000000..a401a20
Binary files /dev/null and b/telemeta/htdocs/images/wait_small.gif differ
index b2f62ed277a39e30d072a26c6dd61214d3db8e81..918601cabb2b1408994a7cd3527ce6f0bedf94ef 100644 (file)
@@ -43,6 +43,12 @@ function foldInfoBlocks() {
         return false; \r
     });\r
 }\r
+//returns the full path of the current url location removing the last slash '/' followed by one or more '#', if any\r
+function urlNormalized(){\r
+    var sPath = window.location.href;\r
+    sPath = sPath.replace(/\/#*$/,"");\r
+    return sPath;\r
+}\r
 \r
 \r
 function setSelectedMenu(){\r
@@ -98,6 +104,7 @@ $(document).ready(function() {
 });\r
 \r
 //****************************************************************************\r
+//json(param, method, onSuccesFcn(data, textStatus, jqXHR), onErrorFcn(jqXHR, textStatus, errorThrown))\r
 //global function to senbd/retrieve data with the server\r
 //\r
 //param: the data to be sent or retrieved.\r
@@ -211,6 +218,7 @@ var popup={
                 position: 'absolute',\r
                 overflow:'auto', //necessary to properly display the content\r
                 display: 'none',\r
+                border: '1px solid #e1e1e1',\r
                 zIndex:1000\r
             });\r
             if(this.className){\r
@@ -294,6 +302,7 @@ var popup={
     },\r
 \r
     show:function(content, optionalEvent){\r
+        consolelog("showing popup:"+optionalEvent);\r
         //if showing, hide\r
         if(this.isShowing()){\r
             this.hide();\r
@@ -354,7 +363,7 @@ var popup={
         var windowH = wdow.height();\r
         var windowW = wdow.width();\r
         var position = div.offset();\r
-        var shadowOffset=5;\r
+        var shadowOffset=2;\r
         var size = {\r
             width:div.outerWidth(true)+shadowOffset,\r
             height:div.outerHeight(true)+shadowOffset\r
@@ -363,8 +372,8 @@ var popup={
             position = invokerElement.offset();\r
             position.top+=  invokerElement.outerHeight(true);\r
         }else{\r
-            position.top = (windowH-size.height)/2;\r
-            position.left = (windowW-size.width)/2;\r
+            position.top = wdow.scrollTop()+ (windowH-size.height)/2;\r
+            position.left = wdow.scrollLeft()+(windowW-size.width)/2;\r
         }\r
         //position div. This must be done immediately cause here below we want to get the div  offset\r
         //(div position in absolute - ie, document's - coordinates)\r
@@ -385,7 +394,7 @@ var popup={
         var divPadding = {\r
             left: div.outerWidth()-div.width(),\r
             top:div.outerHeight()-div.height()\r
-            }; //setting width on a div means the width(),\r
+        }; //setting width on a div means the width(),\r
         //but calculations here are made according to outerWidth(true), so we need this variable (se below)\r
 \r
         div.css({\r
@@ -401,26 +410,10 @@ var popup={
                 });\r
             }\r
         }\r
-        var divShadow = this._cfg_.divShadow().insertAfter(div);\r
-        //        //position div shadow:\r
-        //        var divShadow = this._cfg_.divShadow().css({\r
-        //            'top': (position.top+shadowOffset),\r
-        //            'left': (position.left+shadowOffset),\r
-        //            'width': div.outerWidth(true),\r
-        //            'height': div.outerHeight(true)\r
-        //        }).insertAfter(div).fadeTo(0,0.4);\r
-        //\r
-        //        //set focus to the first input component, if any. Otherwise try with anchors, otherwise do nothing\r
-        //        var inputs = $J(div).find(':input');\r
-        //        if(inputs && inputs[0]){\r
-        //            inputs[0].focus();\r
-        //        }else{\r
-        //            inputs = $J(div).find('a');\r
-        //            if(inputs && inputs[0]){\r
-        //                inputs[0].focus();\r
-        //            }\r
-        //        }\r
-        //\r
+        //var divShadow = this._cfg_.divShadow().insertAfter(div);\r
+\r
+        var divShadow = div.clone(false,false).empty().css({'zIndex':999,'borderColor':'#000','display':'none','backgroundColor':'#000'}).insertAfter(div);\r
+        \r
         //store the divs to be removed\r
         this._cfg_.divsToDelete = [div,divShadow];\r
         //add a listener to the document. If one of the content children is clicked/keypressed,\r
@@ -431,15 +424,12 @@ var popup={
             hide.apply(me);\r
             e.stopPropagation();\r
         });\r
-        div.show(300, function(){ //400: basically in between fast (200) and slow (600)\r
+        div.show(300, function(){ //basically in between fast (200) and slow (600)\r
             //position div shadow:\r
-            divShadow.css({\r
-                'top': (position.top+shadowOffset),\r
-                'left': (position.left+shadowOffset),\r
-                'width': div.outerWidth(true),\r
-                'height': div.outerHeight(true)\r
-            }).fadeTo(0,0.4);\r
-\r
+            divShadow.show();\r
+            consolelog(div.outerHeight(true)+" "+div.outerHeight(false));\r
+            consolelog(divShadow.outerHeight(true)+" "+divShadow.outerHeight(false));\r
+            \r
             //set focus to the first input component, if any. Otherwise try with anchors, otherwise do nothing\r
             var inputs = $J(div).find(':input');\r
             if(inputs && inputs[0]){\r
@@ -450,6 +440,16 @@ var popup={
                     inputs[0].focus();\r
                 }\r
             }\r
+\r
+            divShadow.fadeTo(0,0.4, function(){\r
+                divShadow.css({\r
+                'top': (position.top+shadowOffset),\r
+                'left': (position.left+shadowOffset),\r
+                'width': div.outerWidth(true),\r
+                'height': div.outerHeight(true)\r
+            });\r
+\r
+            });\r
         });\r
         return false; //to avoid scrolling if we clicked on an anchor\r
     },\r
@@ -491,8 +491,11 @@ var popup={
                 return onCancel();\r
             }\r
         };\r
-        var subdiv = $J('<div/>').css({'padding':'1ex','float':'right'}).\r
-            append(\r
+        var subdiv = $J('<div/>').css({\r
+            'padding':'1ex',\r
+            'float':'right'\r
+        }).\r
+        append(\r
             $J('<a/>').\r
             html('Ok').\r
             addClass('component_icon').\r
@@ -521,3 +524,72 @@ var popup={
     }\r
 \r
 }\r
+\r
+\r
+//function loadScripts(scriptArrayName, callback){\r
+//     if(!(scriptArrayName) && callback){\r
+//         callback();\r
+//         return;\r
+//     }\r
+//     var len = scriptArrayName.length;\r
+//     var script = function(i){\r
+//         if(i>=len){\r
+//             if(callback){\r
+//                callback();\r
+//                return;\r
+//             }\r
+//         }\r
+//         jQuery.getScript(scriptArrayName[i], function(){script(i+1)});\r
+//     };\r
+//     script(0);\r
+//}\r
+\r
+function loadScripts(scriptArray, callback, loadInSeries){\r
+    loadInSeries = false;\r
+    if(!scriptArray){\r
+        if(callback){\r
+            callback();\r
+        }\r
+        return;\r
+    }\r
+    var len = scriptArray.length;\r
+    var $J = jQuery;\r
+    var time = new Date().getTime();\r
+    if(loadInSeries){\r
+        var load = function(i){\r
+            if(i<len){\r
+                consolelog("loading "+scriptArray[i]+" "+new Date().getTime());\r
+                $J.getScript(scriptArray[i],function(){\r
+                    load(i+1);\r
+                });\r
+            }else if(callback){\r
+                consolelog("EXECUTING CALLBACK ELAPSED TIME:"+(new Date().getTime()-time));\r
+                callback();\r
+            }\r
+        };\r
+        load(0);\r
+    }else{\r
+        var count=0;\r
+        var s;\r
+        for(var i=0; i <len; i++){\r
+            s = scriptArray[i];\r
+            consolelog("loading "+s+" "+new Date().getTime());\r
+            $J.getScript(s, function(){\r
+                count++;\r
+                if(count==len && callback){\r
+                    consolelog("EXECUTING CALLBACK ELAPSED TIME:"+(new Date().getTime()-time));\r
+                    callback();\r
+                }\r
+            });\r
+        }\r
+    }\r
+}\r
+\r
+function consolelog(text){\r
+    if(typeof console != 'undefined'){\r
+        var c = console;\r
+        if (c.log) {\r
+            c.log(text);\r
+        }\r
+    }\r
+}
\ No newline at end of file
index ce50fc01ac632faecf940bc7099f6b6164a6f4e0..2cf4b632fc2d8ec021f38646f1e2ba8ebb035e87 100644 (file)
@@ -1,12 +1,14 @@
-var sound = null;
-var soundUrl = null;
-var soundEngineReady = false;
+//var sound = null;
+//var soundUrl = null;
+//var soundEngineReady = false;
 var map;
-var provider;
+//var provider;
 var player;
 var player_image_url = null;
+var controller;
 
 function togglePlayerMaximization() {
+    consolelog('entered togglePlayerMaximization');
     var view = $('#player');
     $('#player_maximized, #player_minimized').css('display', 'none');
     var ctr;
@@ -27,23 +29,35 @@ function togglePlayerMaximization() {
     }, 100);
 }
 
-function load_sound() {
-    if (!sound && soundUrl && soundEngineReady) {
-        sound = soundManager.createSound({
-            id: 'sound',
-            url: soundUrl
-        });
-        
-        TimeSide.load(function() {
-            provider.setSource(sound);
-            player.updateVolumeAnchor(provider.getVolume());
-        });
+function change_visualizer_clicked(){
+    var $J = jQuery;
+    var form = $J("#visualizer_id_form");
+    //var img = jQuery("<img/>").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('<tr><td>'+elm.attr('name')+'</td><td>'+elm.attr('value')+'</td><td>'
+                    +elm.attr('unit')+'</td></tr>');
+                });
+                //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("<img src='/images/dialog-error.png' style='vertical-align:middle'/><span class='login-error'>Error loading analyzer</span>");
         }
-        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);
+    }
+}
index f3977e22f602942a5aa660497df2de0e64bac7c5..4a1e2ad845b3596ac8ed95e2c0cf70837a00cecf 100755 (executable)
@@ -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;
 }
index 8afcb591feaefde06341d3819527bf4f2ef094b0..90918a25bf58cd6a4d2db50cee7acaf294ff6760 100755 (executable)
@@ -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;
 
 }
     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;
 }
 
index 859fd49682601a7576313bae3c39872cab9a6e38..706d1c915e2ca2ed99814a4e3aee6d884e37eaf5 100644 (file)
@@ -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();
index 64e2b053699c45dd5c789603314a5fee3cc57a7b..86cea4193ddc226296490c32cedc16cf60083d50 100644 (file)
@@ -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('<div/>')
                 .append(this.e_header)
                 .append(this.e_descriptionText)
+                .attr('tabIndex',0)
                 //.append(this.e_okButton)
                 .append($J('<div/>') //.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();
index cb59878e4084441b3ba2ab7f2489dc297b10298c..cc254a12c9c877c41697e9e44d47b10643939fe5 100644 (file)
@@ -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; i<ticks.length; i++){
                 if(vol<=ticks[i]){
                     //var index = i;
                     var volume = i*20;
-                    this.soundProvider.setVolume(volume);
+                    this.setSoundVolume(volume);
+                    this.debug('setting volume'+volume);
                     return false;
                 }
             }
-            this.soundProvider.setVolume(100);
-//            var g = 9;
-//            console.log(event.layerX);
+            this.setSoundVolume(100);
+            //            var g = 9;
+            //            console.log(event.layerX);
             return false;
         },
 
-        onVolumeChanged: function(e, data){
-           this.updateVolumeAnchor(data.volume);
-        },
+        //TODO: remove unused
+        //        onVolumeChanged: function(e, data){
+        //           this.updateVolumeAnchor(data.volume);
+        //        },
 
-        updateVolumeAnchor: function(volume){
+        setSoundVolume: function(volume){
+            
+            if(typeof volume != 'number'){ //note: typeof for primitive values, instanceof for the rest
+                //see topic http://stackoverflow.com/questions/472418/why-is-4-not-an-instance-of-number
+                volume = 100;
+            }
+            if(volume<0){
+                volume = 0;
+            }
+            if(volume>100){
+                volume = 100;
+            }
+            this.cfg.sound.setVolume(volume);
+            //update the anchor image:
             var indices = [20,40,60,80,100,100000];
+            
             for(var i=0; i <indices.length; i++){
                 if(volume<indices[i]){
                     var pos = -28*i;
-                    pos = '0px '+ pos+ 'px !important';
+                    pos = '0px '+ pos+ 'px'; //DO NOT SET !important as in FF3 DOES NOT WORK!!!!!
                     this.elements.volume.css('backgroundPosition',pos);
                     return;
                 }
             }
-         // this.elements.volume.css('backgroundPosition','0px 0px !important')
+        // this.elements.volume.css('backgroundPosition','0px 0px !important')
 
         },
 
@@ -319,7 +380,7 @@ TimeSide(function($N, $J) {
         _onSetMarker: function() {
             if (this.map) {
                 this.fire('markeradd', {
-                    offset: this.soundProvider.getPosition()
+                    offset: this.getSoundPosition()
                 });
             }
             return false;
index e29ae858922382ec61d055c764a5716eee713bfd..6a8c6b297429f10d0e42105aa7fc7208182c8bb6 100644 (file)
@@ -2,69 +2,39 @@
 
 var playlistUtils = {
     playlists : {},
-    initialize: function(dictionary){
-        this.playlists = dictionary;
-    },
-    addPlayList: function(name, id){
+    
+    addPlaylist: function(name, id){
         this.playlists[name]=id;
     },
-    
-    //    add : function(event){
-    //
-    //        var $J = jQuery;
-    //
-    //        var dText = $('<input/>')
-    //        .attr('type','text').val("");
-    //        var tText = $('<input/>')
-    //        .attr('type','text').val("");
-    //
-    //        var table = $J('<table/>')
-    //        .append($J('<tr/>')
-    //            .append($J('<td/>').html('title'))
-    //            .append($J('<td/>').append(tText)))
-    //        .append($J('<tr/>')
-    //            .append($J('<td/>').html('description'))
-    //            .append($J('<td/>').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('<div/>').append(
-    //            $J('<a/>').
-    //            html('Cancel').
-    //            css('float','right').
-    //            addClass('mediaitem_button').
-    //            addClass('mediaitem_button_cancel').
-    //            attr('href','#').
-    //            click(function(){
-    //                return onCancel();
-    //            })
-    //            ).append(
-    //            $J('<a/>').
-    //            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('<div/>').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('<div/>').addClass("_popup_add_to_playlist");
+        var addToPlaylist = this.addToPlaylist;
+        for(var p in this.playlists){
+            var id = this.playlists[p];
+
+            var a =  $J('<a/>').
+            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('<div/>').html('<a style="border:0" class="component_icon button icon_ok">Ok</span>'));
-            setTimeout(function(){p.hide()},600);
+            if(optionalOkMessage){
+                p.show(jQuery('<div/>').addClass("icon_ok").addClass("component_icon").html(optionalOkMessage));
+                setTimeout(function(){
+                    p.hide();
+                },1000);
+            }else{
+                p.hide(); //to be sure
+            }
         });
     }
 
index 1ce82fb5987f8d2b09b960edab094d6319fe92df..f6891a12d7f6c736940b9c10396501b33d6310f1 100644 (file)
@@ -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('<div/>')
@@ -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();
index 5dd49c37bd708e27b1be9c5643d617bcc3af9a73..3304f4ecc8f7fdcaca6759bde8377c47f168d61f 100644 (file)
@@ -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,
index b0e7592310224b96173ea8466ea64dbfeedceec3..d51959c0394a22540c4bb97e90fec85daaa6c6d7 100644 (file)
@@ -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');
             }
         },
 
index beb915eb8e9caa87edf999cdb88687d93d48628e..19055133c7a032c666556488a5026a5c1cbc2e94 100644 (file)
@@ -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;
index 668419887b4269fc667c62b81aeccc66dddcfaa7..221eff1a1169a208eecc885bf10002d6b8a51655 100755 (executable)
@@ -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) {
                 }
             });
 
-        },
+        }
         
 
     }
index fe00eaedf7beb9a2038bc3e9f9b948e2303220ec..0c008816ab8bf52af19df05d136e5fadb5fa7d24 100644 (file)
@@ -85,7 +85,9 @@
 <div id="submenu">
 {% block submenu %}{% endblock %}
 </div>
-
+<div id="content_header">
+{% block content_header %}{% endblock %}
+</div>
 <div id="content">
 {% block content %}{% endblock %}
 <div class="nett"></div>
index 1dd57e011420ea2cd54eba149edbba6a04d23a46..6c9ccc94a7f9723ce1e3571faffacc4a7576b0b3 100644 (file)
@@ -8,9 +8,25 @@
 <script src="{% url telemeta-js "swfobject.js" %}" type="text/javascript"></script>
 <script src="{% url telemeta-timeside "src/playlist.js" %}" type="text/javascript"></script>
 <script>
+    var setupPlaylist = function(){
+        {% if user.is_authenticated %}
+        var p = playlistUtils;
+        {% for playlist in playlists %}
+        p.addPlaylist('{{ playlist.playlist.title }}','{{playlist.playlist.public_id}}');
+        {% endfor %}
+
+        {% endif %}
+        {% if collection %}
+        var anchor = jQuery('#_add_to_playlist');
+        if(anchor.length){
+        anchor.click(function(evtObj_){
+            p.showPopupAddToPlaylist(evtObj_,'collection','{{collection.public_id}}','Collection added to selected playlist');return false;
+        });
+        }
+        {% endif %}
+    };
     jQuery(document).ready(function(){
-        var content = $('#_popup_add_to_playlist').clone(true,true);
-        $('#_add_to_playlist').click(function(e){return popup.show(content,e)});
+        setupPlaylist();
     });
 </script>
 {% endblock %}
      {% endif %}
     {% if user.is_authenticated %}
     <a href=# id ="_add_to_playlist" class="component_icon button icon_add">{% trans "Add to playlist" %}</a>
-    <div id="_popup_add_to_playlist" style="display:none">
-        {% for playlist in playlists %}
-          <a href="#" class="component_icon list_item icon_playlist"
-             onclick="playlistUtils.addToPlaylist('{{playlist.playlist.public_id}}','collection','{{collection.pk}}');">{{ playlist.playlist.title }}</a>
-        {% endfor %}
-     </div>
     {% endif %}
     {% endblock tools %}
     
index 7b598c3906733d024114788dbcb34028ee51e38f..fb7d6e9193771d3843ff01e7040c50f7bd434302 100644 (file)
@@ -9,69 +9,98 @@
 <link rel="stylesheet" type="text/css" href="{% url telemeta-timeside "css/timeside.css" %}" />
       <link rel="stylesheet" type="text/css" href="{% url telemeta-timeside "skins/lab/style.css" %}" />
       <link rel="stylesheet" type="text/css" href="{% url telemeta-css "player.css" %}" />
-{% endblock %}
+      {% endblock %}
 
-{% block extra_javascript %}
-<script src="{% url telemeta-js "wz_jsgraphics.js" %}" type="text/javascript"></script>
+      {% block extra_javascript %}
+      <!--<script src="{% url telemeta-js "wz_jsgraphics.js" %}" type="text/javascript"></script>-->
 <script src="{% url telemeta-js "soundmanager2.js" %}" type="text/javascript"></script>
-<script src="{% url telemeta-timeside "src/timeside.js" %}" type="text/javascript"></script>
-<script src="{% url telemeta-js "playerUtils.js" %}" type="text/javascript"></script>
 <script src="{% url telemeta-timeside "src/playlist.js" %}" type="text/javascript"></script>
 <script type="text/javascript">
     soundManager.url = '{% url telemeta-swf "./" %}';
     soundManager.flashVersion = 9;
     soundManager.useMovieStar = true; // enable MP4/M4A/AAC
     soundManager.debugMode = false;
-    set_player_image_url('{% url telemeta-item-visualize item.public_id,visualizer_id,"WIDTH","HEIGHT" %}');
-    load_player({{ item.approx_duration.as_seconds }});
+    soundManager.allowPolling = true;
 
-    jQuery(document).ready(function(){
-        var content = $('#_popup_add_to_playlist').clone(true,true);
-        $('#_add_to_playlist').click(function(e){return popup.show(content,e)});
-    });
+    var setupPlaylist = function(){
+        {% if user.is_authenticated %}
+        var p = playlistUtils;
+        {% for playlist in playlists %}
+        p.addPlaylist('{{ playlist.playlist.title }}','{{playlist.playlist.public_id}}');
+        {% endfor %}
 
+        {% endif %}
+        {% if item %}
+        var anchor = jQuery('#_add_to_playlist');
+        if(anchor.length){
+            anchor.click(function(evtObj_){
+                p.showPopupAddToPlaylist(evtObj_,'item','{{item.public_id}}','item added to selected playlist');return false;
+            });
+        }
+        {% endif %}
+    };
+    
     {% if item %}
-        var ITEM_PUBLIC_ID = '{{item.public_id}}';
+    var ITEM_PUBLIC_ID = '{{item.public_id}}';
     {% endif %}
+
+    var scripts = ["{% url telemeta-js "wz_jsgraphics.js" %}",
+        //"{% url telemeta-timeside "src/playlist.js" %}",
+        "{% url telemeta-timeside "src/timeside.js" %}","{% url telemeta-js "playerUtils.js" %}"];
+
+    var _sound_manager_loaded=false;
+    var _jQuery_loaded = false;
+
+    jQuery(document).ready(function(){
+        _jQuery_loaded=true;
+        if(_sound_manager_loaded){
+            loadScripts(scripts, function(){loadPlayer('{% url telemeta-item-analyze-xml item.public_id %}',$('.ts-wave a').attr('href'));setupPlaylist()});
+        }
+    });
+    //$('.ts-wave a').attr('href')
+    soundManager.onready(function() {
+        _sound_manager_loaded=true;
+        if(_jQuery_loaded){
+            loadScripts(scripts, function(){loadPlayer('{% url telemeta-item-analyze-xml item.public_id %}',$('.ts-wave a').attr('href'));setupPlaylist()});
+        }
+    });
     
 </script>
+<!--item.approx_duration-->
 
 {% endblock %}
 
 
 {% if item %}
 {% block submenu %}
-<div>
-    {% block tools %}
-     <a href="{% url telemeta-item-dublincore item.public_id %}" class="component_icon button icon_dublin_core">Dublin Core</a>
-    {% if user.is_authenticated and perms.telemeta.change_mediaitem %}
-     <a href="{% url telemeta-item-edit item.public_id %}" class="component_icon button icon_edit">{% trans "Edit" %}</a>
-     <a href="{% url telemeta-item-copy item.public_id %}" class="component_icon button icon_copy">{% trans "Copy" %}</a>
-    {% endif %}
-    {% if user.is_authenticated %}
-     
-     <a id="_add_to_playlist" href=# class="component_icon button icon_add">{% trans "Add to playlist" %}</a>
-     <div id="_popup_add_to_playlist" style="display:none">
-        {% for playlist in playlists %}
-          <a href="#" class="component_icon list_item icon_playlist"
-             onclick="playlistUtils.addToPlaylist('{{playlist.playlist.public_id}}','item','{{item.pk}}');">{{ playlist.playlist.title }}</a>
-        {% endfor %}
-     </div>
 
+{% endblock %}
 
+{% block content_header %}
+<table><tr><td>
+            <h3><img src="images/item.png" style="vertical-align:middle" /> Item : {{ item }}</h3>
+        </td><td class="rightcol">
+            {% block tools %}
+            {% if user.is_authenticated and perms.telemeta.change_mediaitem %}
+            <a href="{% url telemeta-item-edit item.public_id %}" class="component_icon button icon_edit">{% trans "Edit" %}</a>
+            <a href="{% url telemeta-item-copy item.public_id %}" class="component_icon button icon_copy">{% trans "Copy" %}</a>
+            {% endif %}
+            {% if user.is_authenticated %}
+            <a id="_add_to_playlist" href='#' class="component_icon button icon_add">{% trans "Add to playlist" %}</a>
 
-    {% endif %}
-     <a href="{% url telemeta-item-detail previous %}" class="component_icon button icon_previous">{% trans "Previous" %}</a>
-    <a href="{% url telemeta-item-detail next %}" class="component_icon button icon_next">{% trans "Next" %}</a>
-    {% endblock tools %}
-</div>
+            {% endif %}
+            <a href="{% url telemeta-item-detail previous %}" class="component_icon button icon_previous">{% trans "Previous" %}</a>
+            <a href="{% url telemeta-item-detail next %}" class="component_icon button icon_next">{% trans "Next" %}</a>
+            <a href="{% url telemeta-item-dublincore item.public_id %}" class="component_icon button icon_dublin_core">Dublin Core</a>
+            {% endblock tools %}
+        </td></tr></table>
 {% endblock %}
 
 {% block content %}
-<h3><img src="images/item.png" style="vertical-align:middle" /> Item : {{ item }}</h3>
+<!--<div id="div_title" style="padding-bottom:2ex;padding-right:362px"><h3><img src="images/item.png" style="vertical-align:middle" /> Item : {{ item }}</h3></div>-->
 
 <div class="{% if item.file %}{% if item.public_access == 'full' or public_access or user.is_staff %}with-rightcol{% endif %}{% endif %}">
-   {% if item.file %}
+    {% if item.file %}
     {% if public_access or user.is_staff %}
     <div id="player_maximized" class="ts-skin-lab">
         <a href="#" class="toggle">Minimize</a>
         </div>
 
         <div id="tabs_container">
-            <!--            <ul class="tabs_" >
-                            <li><a href="#">Analysis</a></li>
-                            <li><a href="#">Markers</a></li>
-                        </ul>-->
-            <a id="tab_analysis" name ="analyzer_div_id" href="#">{% trans "Analysis" %}</a>
-            <a id="tab_markers" name="markers_div_id" href="#">{% trans "Markers" %}</a>
+            <!-- this div will be hidden when everything is fully loaded-->
+            <span id="loading_span" href="#"><img style="vertical-align:middle" src="/images/wait.gif"/>&nbsp;
+                <span id="loading_span_text">Loading...</span></span>
+            <a id="tab_analysis" style="display:none" name ="analyzer_div_id" href="#">{% trans "Analysis" %}</a>
+            <a id="tab_markers" style="display:none" name="markers_div_id" href="#">{% trans "Markers" %}</a>
         </div>
-        <!--<div class="tab_container_">-->
-        <!--        <div id="tab1" class="tab_content">
-                    Content
-                </div>
-                <div id="tab2" class="tab_content">
-                   Content
-                </div>
-            </div>-->
+
         <div class="markers" id="markers_div_id"></div>
 
         <div class="analyzer" id="analyzer_div_id">
                     <td>{% trans "Value" %}</td>
                     <td>{% trans "Unit" %}</td>
                 </tr>
-                {% for analyser in analysers %}
+               <!-- {% for analyser in analysers %}
                 <tr class="analyzer-line">
                     <td>
                         {{ analyser.name }}
                         {{ analyser.unit }}
                     </td>
                 </tr>
-                {% endfor %}
+                {% endfor %}-->
             </table>
         </div>
         <!--</div>-->
             <p><img src="images/download.png" style="vertical-align:middle" /> {% trans "Download:" %}
                 {% for format in export_formats %}
                 <a href="{% url telemeta-item-export item.public_id,format.extension %}">
-                <img src="images/{{ format.extension }}.png" style="vertical-align:middle" alt="{{ format.extension }}" /></a>
+                    <img src="images/{{ format.extension }}.png" style="vertical-align:middle" alt="{{ format.extension }}" /></a>
                 {% endfor %}</p>
         </div>
         {% endif %}
     </div>
     {% endif %}
     {% endif %}
-    
+
     {% block infos %}
     <div class="infos">
         {% block general_info %}
         </div>
         {% endblock technical_data %}
     </div>
-  {% endblock infos %}
+    {% endblock infos %}
 </div> <!-- with-rightcol -->
 {% endblock %}
 {% else %}