]> git.parisson.com Git - telemeta.git/commitdiff
Added marker permission javascript side, changed some code structure because of the...
authorriccardo <riccardo@parisson.com>
Fri, 11 Mar 2011 18:47:50 +0000 (19:47 +0100)
committerriccardo <riccardo@parisson.com>
Fri, 11 Mar 2011 18:47:50 +0000 (19:47 +0100)
telemeta/htdocs/css/telemeta.css
telemeta/htdocs/images/edit_marker.png
telemeta/htdocs/timeside/src/controller.js
telemeta/htdocs/timeside/src/marker.js
telemeta/htdocs/timeside/src/markermap.js
telemeta/htdocs/timeside/src/player.js
telemeta/htdocs/timeside/src/ruler.js
telemeta/htdocs/timeside/src/timeside.js

index 6ff7219730b565f3964d42a42868f4f069087918..e41fa931a51bc337571e67936f2815c8b4dd2876 100644 (file)
@@ -13,7 +13,7 @@ body {
 }
 
 a:link, a:visited {
-/*     border-bottom:1px dotted #BBB; */
+    /*     border-bottom:1px dotted #BBB; */
     color: #BB0000;
     text-decoration:none;
 }
@@ -194,27 +194,27 @@ ul.continents ul li a { line-height: 1.8em; }
 input, textarea, select { margin: 2px }
 input, select { vertical-align: middle }
 input[type=button], input[type=submit], input[type=reset] {
- background: #f2f2f2;
- color: #444;
- border: 3px double #ccc;
- padding: .1em .5em;
- font-weight: bold;
- cursor: pointer;
   background: #f2f2f2;
   color: #444;
   border: 3px double #ccc;
   padding: .1em .5em;
   font-weight: bold;
   cursor: pointer;
 }
 input[type=button]:hover, input[type=submit]:hover, input[type=reset]:hover {
- background: #8D8C94;
- color: #fff;
   background: #8D8C94;
   color: #fff;
 }
 input[type=button][disabled], input[type=submit][disabled],
 input[type=reset][disabled] {
- background: #f6f6f6;
- border-style: solid;
- color: #999;
   background: #f6f6f6;
   border-style: solid;
   color: #999;
 }
 input[type=text], input[type=password], input.textwidget, textarea { border: 1px solid #ccc; }
 input[type=text], input[type=password], input.textwidget { padding: .25em .1em }
 input[type=text]:focus, input[type=password]:focus, input.textwidget:focus, textarea:focus {
-   border-color: #aaa;
+    border-color: #aaa;
 }
 option { border-bottom: 1px dotted #d7d7d7; }
 fieldset { border: 1px solid #d7d7d7; padding: .5em; margin: 0 }
@@ -227,12 +227,12 @@ label.disabled { color: #d7d7d7 }
 .buttons form, .buttons form div { display: inline }
 .buttons input { margin: 1em .5em .1em 0 }
 .inlinebuttons input {
- font-size: 70%;
- border-width: 1px;
- border-style: dotted;
- margin: 0;
- padding: 0.1em;
- background: none;
   font-size: 70%;
   border-width: 1px;
   border-style: dotted;
   margin: 0;
   padding: 0.1em;
   background: none;
 }
 
 /* Quick search */
@@ -377,19 +377,19 @@ form.login .submit {
 .nav h2, .nav hr { display: none }
 .nav ul { font-size: 14px; list-style: none; margin: 0px; text-align: left; }
 .nav li {
- display: inline;
- padding: 0em;
- white-space: nowrap;
   display: inline;
   padding: 0em;
   white-space: nowrap;
 }
 .nav li.last { border-right: 1px solid #000000; }
 
 /* Main navigation bar  (borrowed from Trac) */
 #menu {
- background-color: #6a0307 ;
- font: normal verdana,'Bitstream Vera Sans',helvetica,arial,sans-serif;
- padding: 0em 0em 0.75em 0em;
- border-bottom: .5em solid #6a0307;
- border-top: .7em solid #6a0307; 
   background-color: #6a0307 ;
   font: normal verdana,'Bitstream Vera Sans',helvetica,arial,sans-serif;
   padding: 0em 0em 0.75em 0em;
   border-bottom: .5em solid #6a0307;
+    border-top: .7em solid #6a0307;
 }
 
 #menu li { background-color: #6a0307; padding: .5em 0; }
@@ -404,10 +404,10 @@ form.login .submit {
 #menu li.last { border-right: 0px solid #000;  }
 
 #menu :link, #menu :visited {
- border-bottom: none;
- color: #FFF;
- font-weight: bold;
- padding: .2em 20px;
   border-bottom: none;
   color: #FFF;
   font-weight: bold;
   padding: .2em 20px;
 }
 * html #menu :link, * html #menu :visited { background-position: 1px 0 }
 /*
@@ -426,17 +426,17 @@ form.login .submit {
 #menu .active :link:hover, #menu .active :visited:hover {
  background-color: #FFF;
  color: #6a0307;
-    
+
 }*/
 #menu .active, #menu :link:hover, #menu :visited:hover{
-   background-color: #FFF;
- color: #6a0307;
- text-decoration:none;
- border-bottom: .4em solid #FFF;
- border-top: 2px solid #FFF;
+    background-color: #FFF;
   color: #6a0307;
   text-decoration:none;
   border-bottom: .4em solid #FFF;
   border-top: 2px solid #FFF;
     background-color: #FFF;
     /*border-bottom: .5em solid #6a0307;*/
-    
+
     -webkit-border-top-left-radius:5px 5px;
     moz-border-radius-topleft: 5px 5px;
     border-top-left-radius: 5px 5px;
@@ -448,14 +448,14 @@ form.login .submit {
 
 /* Footer (borrowed from Trac) */
 #footer {
-  background: #6a0307;
-  clear: both;
-  color: #FFF;
-  font-size: 10px;
-  border-top: 1px solid;
-  height: 31px;
-  padding: 0.5em;
-  margin-top: 2.5em;
+    background: #6a0307;
+    clear: both;
+    color: #FFF;
+    font-size: 10px;
+    border-top: 1px solid;
+    height: 31px;
+    padding: 0.5em;
+    margin-top: 2.5em;
 }
 #footer :link, #footer :visited { color: #FFF; }
 #footer hr { display: none }
@@ -463,15 +463,15 @@ form.login .submit {
 #footer #telemeta_powered:hover { background: transparent }
 #footer p { margin: 0 }
 #footer p.left {
-  float: left;
-  margin-left: 1em;
-  padding: 0 1em;
-  border-left: 1px solid #d7d7d7;
-  border-right: 1px solid #d7d7d7;
+    float: left;
+    margin-left: 1em;
+    padding: 0 1em;
+    border-left: 1px solid #d7d7d7;
+    border-right: 1px solid #d7d7d7;
 }
 #footer p.right {
-  float: right;
-  text-align: right;
+    float: right;
+    text-align: right;
 }
 
 /* Homepage */
@@ -707,8 +707,8 @@ table.listing thead th a {
 }
 table.listing th.asc a, table.listing th.desc a { font-weight: bold }
 table.listing th.asc a, table.listing th.desc a {
- background-position: 100% 50%;
- background-repeat: no-repeat;
   background-position: 100% 50%;
   background-repeat: no-repeat;
 }
 table.listing th.asc a { background-image: url(../images/asc.png) }
 table.listing th.desc a { background-image: url(../images/desc.png) }
@@ -724,7 +724,7 @@ table.listing tbody td.tmp {
     width: 100%;
 }
 table.listing tbody td a:hover, table.listing tbody th a:hover {
- background-color: transparent;
   background-color: transparent;
 }
 table.listing tbody tr { border-top: 1px solid #ddd }
 table.listing tbody tr.even { background-color: #fcfcfc }
@@ -831,3 +831,93 @@ a.image-link {
     border-bottom: 1px solid #ffffff;
     z-index: 10;
 }
+
+.markersdivButton{
+    /*padding: 0.3em 0.8em 0.8em 0.8em;
+    margin: 0 0 1.5em 1.5em;*/
+
+    -moz-border-radius: 6px 6px 6px 6px;
+    -webkit-border-radius: 6px 6px 6px 6px;
+    border-radius: 6px 6px 6px 6px;
+}
+
+.markersdivUneditable{
+    border: 0px !important;
+}
+
+.markersdivIndexLabel{
+    color: #fff;
+    background-image:url("/images/marker_tiny.png");
+    background-repeat:no-repeat;
+    background-position:center center;
+    font-size: 90%;
+    font-weight:bold;
+    display:inline-block;
+    width:3ex;
+    text-align: center;
+    font-family: monospace;
+    margin-right:2ex;
+}
+.markersdivOffset{
+    margin-right:1ex;
+    font-style: italic;
+}
+.markersdivTopElement{
+    vertical-align:middle;
+}
+.markersdivTitle{
+    font-weight:bold;
+    margin:0;
+    padding:0;
+    /*margin-right:margin*/
+}
+.markersdivEdit, .markersdivEdit:hover, .markersdivEdit:visited,
+.markersdivEdit:link, .markersdivEdit:link:hover, .markersdivEdit:visited:hover{
+    font-weight:bold;
+    border:1px dotted #333333;
+    float:right;
+    color:#000;
+    background-image: url('/images/edit_marker.png');
+    background-repeat:no-repeat;
+    background-position: center left;
+    border:2px solid #666;
+    height:1ex;
+    padding:0px 1ex 2ex 3ex; /*top right bottom left*/
+    font-size: 70%;
+    margin-left: 1ex;
+    margin-right:1ex;
+    position:relative;
+    top:-0.5ex;
+}
+.markersdivDelete{
+    border:0px;
+    float:right;
+    background-image: url('/images/del_marker.png');
+    background-repeat: no-repeat;
+    background-position: center center;
+    padding:1ex 1ex 1ex 1ex;/*top right bottom left. The padding is only to show the element */
+}
+.markersdivDescription{
+    margin:1ex 0px 0ex 0px; /*top right bottom left*/
+    font-family: sans-serif;
+    padding:0;
+    width:100%;
+}
+.markersdivSave, .markersdivSave:hover, .markersdivSave:visited,
+.markersdivSave:link, .markersdivSave:link:hover, .markersdivSave:visited:hover{
+    background-color: #087714;
+    color: #fff;
+    font-weight: bold;
+    padding: 0.3em 0.8em 0.3em 0.8em;
+    /*here below the 3 lines to properly display top margin without <br> or including the element ina  div*/
+    display: block;
+    margin-top: 1ex;
+    width:3ex;
+    /* margin:1ex 0px 0px 0px;*/ /*top right bottom left*/
+}
+
+.markerdiv{
+    padding:1ex 1ex 1.2ex 1ex;  /*top right bottom left*/
+    border: 1px solid #aaaaaa;
+    margin-bottom: 1ex;
+}
index b40bbae45fb66ab56b54cb6a3cbec355a2887be3..277a9005a2045f34d3939c000289af71ff188568 100644 (file)
Binary files a/telemeta/htdocs/images/edit_marker.png and b/telemeta/htdocs/images/edit_marker.png differ
index 1abaa3f51b3fb27d2e90a917e6627c7be3bcd1e8..9a7fd174a35ec351f69a9657bf475eb8cfa43759 100644 (file)
@@ -14,17 +14,20 @@ TimeSide(function($N) {
             this.configure(cfg, {
                 player: null,
                 soundProvider: null,
-                map: null
+                map: null,
+                divmarkers:[]
             });
             if (this.cfg.player && !$N.isInstanceOf(this.cfg.player, 'Player')) {
                 this.cfg.player = new $N.Player(this.cfg.player);
             }
             this._setupPlayer();
+        //setting the divmarkers
+        //this.cfg.map.observe('add')
             
         },
 
         _setupPlayer: function() {
-            this.attach(this.updateMarkersDiv);
+            
             this.cfg.player
             .setSoundProvider(this.cfg.soundProvider)
             .setMarkerMap(this.cfg.map)
@@ -32,10 +35,16 @@ TimeSide(function($N) {
             .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();
+
+            this.cfg.map.observe('add',this.attach(this._onMarkerMapAdd));
+            this.cfg.map.observe('remove',this.attach(this._onMarkerMapRemove));
+            this.cfg.map.observe('moved',this.attach(this._onMarkerMapMoved));
             
         },
 
@@ -44,24 +53,96 @@ TimeSide(function($N) {
             this.cfg.soundProvider.seek(data.offset);
         },
 
-
+        //called whenever a marker is moved in the ruler BUT NOT in the map
         _onMarkerMove: function(e, data) {
             if (this.cfg.map) {
                 $N.Util.selectMarkerTab(); //defined in utils.js
-                this.cfg.map.move(this.cfg.map.byId(data.id), data.offset);
+                this.cfg.map.move(data.index, data.offset);
+            //this will fire the method below
+            }
+        },
+
+        _onMarkerMapMoved:function(e, data){
+            var from = data.fromIndex;
+            var to = data.toIndex;
+            if(from===to){
+                //just update the div in order to show the new time offset
+                //and start edit
+                this.cfg.divmarkers[from].setIndex(to);
+                return;
             }
+            this.cfg.player.ruler.move(from,to);
+            var m = this.cfg.divmarkers.splice(from,1)[0]; //remove
+            this.cfg.divmarkers.splice(to,0,m); //add
+            this.updateIndices(from,to);
         },
 
+        //called whenever a marker is added to the ruler BUT NOT in the map
         _onMarkerAdd: function(e, data) {
             if (this.cfg.map) {
                 $N.Util.selectMarkerTab(); //defined in mediaitem|_detail.html
+                var idx = this.cfg.map.add(data.offset); //this will call the method below _onMarkerMapAdd,
+                //which btw adds a new div to divmarkers
+                //now update the indices for the div (which also sets the event bindings as clicks etc...
+                this.updateIndices(idx);
+            }
+        },
+        //fired from markermap, attached as listener above in
+        //this.cfg.map.observe('add',this.attach(this._onMarkerMapAdd));
+        //this method basically adds the html elements, but updateIndices must be called elsewhere after this function
+        //(see _onMarkerAdd and loadHTTP)
+        _onMarkerMapAdd: function(e, data) {
+            if (this.cfg.map) {
+                //$N.Util.selectMarkerTab(); //defined in mediaitem|_detail.html
+                //this.refreshMarkersText(this.cfg.map);
+                //var idx = this.cfg.map.add(data.offset);
+                //alert('df');
+                var idx = data.index;
+                var divMarker = new $N.DivMarker(this.cfg.map);
+                this.cfg.divmarkers.splice(idx,0, divMarker);
+                this.cfg.player.ruler.add(data.marker, idx);
+            }
+        },
+
+        //fired from markermap, attached as listener above in
+        //this.cfg.map.observe('add',this.attach(this._onMarkerMapAdd));
+        _onMarkerMapRemove: function(e, data) {
+            if (this.cfg.map) {
+                //$N.Util.selectMarkerTab(); //defined in mediaitem|_detail.html
                 //this.refreshMarkersText(this.cfg.map);
-                this.cfg.map.addNew(data.offset);
-            //this.updateMarkersDiv(this.cfg.map, data.offset);
+                //var idx = this.cfg.map.add(data.offset);
+                //alert('df');
+                var idx = data.index;
+                var divRemoved = this.cfg.divmarkers.splice(idx,1)[0]; //there is only one element removed
+                divRemoved.remove();
+                this.cfg.player.ruler.remove(idx);
+                if(idx<this.cfg.divmarkers.length){
+                    //we might have removed the last index, in this case idx==this.cfg.divmarkers.length
+                    //no need to update and to enter this if
+                    this.updateIndices(idx);
+                }
+            }
+        },
 
+        updateIndices: function(from, to){
+            if(from===undefined || from==null){
+                from = 0;
             }
+            if(to==undefined || to ==null){
+                to = this.cfg.divmarkers.length-1;
+            }
+            if(to<from){
+                var tmp = to;
+                to=from;
+                from=tmp;
+            }
+            for(var i = from; i <= to; i++){
+                this.cfg.divmarkers[i].setIndex(i);
+            }
+            this.cfg.player.ruler.updateMarkerIndices(from,to);
         },
 
+
         loadHTTP: function(){
 
             //itemid is the item (spund file) name
@@ -74,6 +155,7 @@ TimeSide(function($N) {
             //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 map = this.cfg.map;
+            var update = this.updateIndices;
             var me = this;
             $.ajax({
                 type: "POST",
@@ -83,30 +165,27 @@ TimeSide(function($N) {
                 dataType: "json",
                 success: function(data) {
                     if(data){
-                        if(data.result){
+                        if(data.result && data.result.length>0){
                             var result = data.result;
                             
                             for(var i =0; i< result.length; i++){
-                                var marker = {
-                                    id: result[i].public_id,
-                                    offset: result[i].time,
-                                    desc: result[i].description
-                                };
-                                map.add(marker);
+                                map.add(result[i]);
                             }
-                            //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();
-                            //setUpTabs(); //which hides the marker div. Call with argument 1 to set up marker div
-                            //as visible as startup
+                            //we call now updateindices
+                            update.apply(me);
+                            
                         }
                         
                     }
-                    //me._setupPlayer();
+                    //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();
+                //setUpTabs(); //which hides the marker div. Call with argument 1 to set up marker div
+                //as visible as startup
                 }
             });
-            //var g = 9;
+        //var g = 9;
         }
 
     
index 5805dc03269358732f46cf14d53d3a877658d86e..bd54550e7cb5141b38b07c3d5636d5bc38e4e222 100644 (file)
@@ -27,20 +27,28 @@ TimeSide(function($N, $J) {
                 fontSize: 10,
                 zIndex: null,
                 className: [null, 'required'],
-                id: null,
+                index: null,
                 tooltip: null,
                 canMove: false
             });
             this.cfg.rulerLayout = $J(this.cfg.rulerLayout);
             this.cfg.viewer = $J(this.cfg.viewer);
 
-            this.id = cfg.id;
             this.width = this.cfg.viewer.width();
             this.painter = new jsGraphics(this.cfg.viewer.get(0));
             this._create();
             if(this.cfg.canMove){
                 this._observeMouseEvents();
             }
+            //if it is the pointer, cfg.index is undefined
+            if(cfg.index !== undefined && cfg.className!='pointer'){
+                this.setIndex(cfg.index);
+            }
+        },
+
+        setIndex: function(index){
+            this.index = index;
+            this.setText(index+1);
         },
 
         free: function($super) {
@@ -220,7 +228,7 @@ TimeSide(function($N, $J) {
             if (this.mouseDown) {
                 this.mouseDown = false;
                 this.fire('move', {
-                    id: this.id,
+                    index: this.index,
                     offset: this.position,
                     finish: true
                 });
index 9d857be5317dc025aef2ab5ac36ad283149ed6a9..3b4deeda7606fbdc0fe30c7685aa4f56f3821099 100644 (file)
@@ -18,544 +18,158 @@ TimeSide(function($N, $J) {
             }
             this.markers = markers;
         },
-        //static constant variables to retireve the Marker Html Elements (MHE)
-        //to be used with the function below getHtmElm, eg:
-        //getHtmElm(marker, this.MHE_OFFSET_LABEL)
-        MHE_INDEX_LABEL:'indexLabel',
-        MHE_OFFSET_LABEL:'offsetLabel',
-        MHE_DESCRIPTION_TEXT:'descriptionText',
-        MHE_DESCRIPTION_LABEL:'descriptionLabel',
-        MHE_EDIT_BUTTON:'editButton',
-        MHE_OK_BUTTON:'okButton',
-        MHE_DELETE_BUTTON:'deleteButton',
-        //static constant variables for edit mode:
-        EDIT_MODE_SAVED:0,
-        EDIT_MODE_EDIT_TEXT:1,
-        EDIT_MODE_MARKER_MOVED:2,
-        //authentication ,sg
-        AUTHENTICATION_MSG :"You must be logged in and have the permission to edit/add/delete markers",
+   
+        get: function(index){
+            return this.markers[index];
 
-        //function to retreve html elements in the edit div associated with marker:
-        getHtmElm: function(marker, elementName){
-            //return marker.div.children('[name="'+elementName+'"]');
-            //children returns only the first level children, we must use:
-            return marker.div.find('*[name="'+elementName+'"]');
-        },
-
-        //        toArray: function() {
-        //            return [].concat(this.markers);
-        //        },
-        //
-        //        byIndex: function(index) {
-        //            return this.markers[index];
-        //        },
-        //
-
-        //used by controller._onMarkerMove
-        byId: function(id) {
-            var marker = null;
-            for (var i in this.markers) {
-                if (this.markers[i].id == id) {
-                    marker = this.markers[i];
-                    break;
-                }
-            }
-            return marker;
-        },
-
-        indexOf: function(marker) {
-            var index = null;
-            for (var i in this.markers) {
-                if (this.markers[i].id == marker.id) {
-                    index = parseInt(i);
-                    break;
-                }
-            }
-            return index;
         },
 
 
-        addNew: function(offset){
-            var id = this.uniqid();
-            var marker = {
-                id: id,
-                offset: offset,
-                desc: undefined,
-                isNew: true
-            };
-            this.add(marker, this.EDIT_MODE_EDIT_TEXT);
-        },
-
-        //editMode is optional, in case it defaults to
-        //EDIT_MODE_SAVED:0
-        add: function(marker, editMode) {
-            var idx = this.insertionIndex(marker);
+        add: function(obj) {
+            var marker = this.createMarker(obj);
+            var idx = this.indexOf(marker);
+            
             //adding the div
-            marker.div = this.createDiv(marker,idx);
+            //marker.div = this.createDiv(marker,idx);
             //setting focus and label description
             //set label description
-            this.setLabelDescription(marker);
+            //this.setLabelDescription(marker);
             //finally, set the focus to the text
             //this.getHtmElm(marker,this.MHE_DESCRIPTION_TEXT).focus();
 
 
             this.markers.splice(idx,0,marker);
-            //calls core.js $N.attachFunction
-            //which calls ruler.js onMapAdd
+            //notifies controller.onMarkerMapAdd
             this.fire('add', {
                 marker: marker,
                 index: idx
             });
-            this.fireRefreshLabels(idx+1,this.markers.length);
+            //this.fireRefreshLabels(idx+1,this.markers.length);
             //this._reorder(marker.offset);
-            this.fireEditMode(marker,editMode);
-            return marker;
+            //this.fireEditMode(marker);
+            return idx;
         },
-
-        remove: function(marker) {
-            if (marker) {
-                var i = this.indexOf(marker);
-                this.markers.splice(i, 1);
-                marker.div.remove();
-                this.fire('remove', {
-                    marker: marker
-                });
-
-                this.fireRefreshLabels(i,this.markers.length);
-                this.removeHTTP(marker);
-
+        //argument is either an object loaded from server or a number specifying the marker offset
+        createMarker: function(argument){
+            var marker = null;
+            if(typeof argument == 'object'){
+                var editable = CURRENT_USER_NAME === argument.author;
+                marker = {
+                    id: argument.public_id,
+                    offset: argument.time,
+                    desc: argument.description,
+                    title: argument.title,
+                    author: argument.author,
+                    isEditable: editable,
+                    isSaved: true
+
+                };
+            }else if(typeof argument == 'number'){
+                marker = {
+                    id: undefined, //before was: this.uniqid(),
+                    //now an undefined id means: not saved on server (see sendHTTP below)
+                    offset: parseFloat(argument),
+                    desc: "",
+                    title: "",
+                    author: CURRENT_USER_NAME,
+                    isEditable: true,
+                    isSaved: false
+                };
             }
             return marker;
-        },
-        //        compare: function(marker1, marker2) {
-        //            if (marker1.offset > marker2.offset){
-        //                return 1;
-        //            }
-        //            if (marker1.offset < marker2.offset){
-        //                return -1;
-        //            }
-        //            return 0;
-        //        },
 
-        move: function(marker, offset) {
-            if(offset===marker.offset){
-                return;
-            }
-            var oldIndex = this.indexOf(marker);
-            marker.offset = offset;
-            //marker.offset = offset;
-            var newIndex = this.insertionIndex(marker);
-            //change marker time
-            //$($( marker.div.children()[0] ).children()[1]).html(this.formatMarkerOffset(offset));
-            this.getHtmElm(marker,this.MHE_OFFSET_LABEL).html(this.formatMarkerOffset(offset));
-            //            marker.div[this.MHE_OFFSET_LABEL].html(this.formatMarkerOffset(offset));
-            if(newIndex>oldIndex){
-                newIndex--;
-            }
-            //fire edit mode
-            this.fireEditMode(marker, this.EDIT_MODE_MARKER_MOVED);
-
-            if(newIndex==oldIndex){
-                return;
-            }
-            var l = this.markers.length;
-            this.markers.splice(oldIndex,1);
-            this.markers.splice(newIndex,0,marker);
-            //The .detach() method is the same as .remove(), except that .detach() keeps
-            //all jQuery data associated with the removed elements.
-            //This method is useful when removed elements are to be reinserted into the DOM at a later time.
-            marker.div.detach();
-            if(newIndex==l-1){
-                this.divContainer.append(marker.div);
-            }else{
-                $( this.divContainer.children()[newIndex] ).before(marker.div);
-            }
-            //$($( marker.div.children()[1] )).focus();
-
-            //this.getHtmElm(marker,this.MHE_DESCRIPTION_TEXT).focus();
-            //this.getHtmElm(marker,this.MHE_DESCRIPTION_TEXT).select();
-            var i1= Math.min(oldIndex,newIndex);
-            var i2= Math.max(oldIndex,newIndex);
-            //var mrks = this.markers;
-
-            this.fireRefreshLabels(i1,i2+1);
-            
-
-           
-            
-        //this._reorder(offset);
         },
 
-        fireRefreshLabels: function(firstIndex,lastIndex){
-            if(lastIndex<=firstIndex){
-                return;
-            }
-            for (var i=firstIndex; i <lastIndex;i++) {
-                //calls ruler _onMapIndexChange
-                this.fire('indexchange', {
-                    marker: this.markers[i],
-                    index: i
+        remove: function(index) {
+            var marker = this.get(index);
+            if (marker) {
+                if(marker.isSaved){
+                    this.removeHTTP(marker);
+                }
+                this.markers.splice(index, 1);
+                //notifies controller.js
+                this.fire('remove', {
+                    index: index
                 });
-                //update label element
-                this.getHtmElm(this.markers[i], this.MHE_INDEX_LABEL).html(i+1);
-            //                this.markers[i].div['labelIndex'].html(i+1)
-            // $($( this.markers[i].div.children()[0] ).children()[0]).html(i+1);
-
             }
+            return marker;
         },
 
-        insertionIndex: function(marker){
-            var index = 0;
-            var l = this.markers.length;
-            while (index<l && this.markers[index].offset <= marker.offset) {
-                index ++;
-            }
-            //markers.splice(index,0,marker);
-            return index;
-        },
-
-        
-
-        each: function(callback) {
-            $J(this.markers).each(callback);
-        },
-
-        //creates a new div. By default, text is hidden and edit button is visible
-        createDiv: function(marker,insertionIndex){
-            var div = this.divContainer;
-            var markerDiv;
-            if(div){
-                var indexLabel, descriptionText, offsetLabel, deleteButton, okButton, header, editButton, descriptionLabel;
-                var margin = '1ex';
-
-                //index label
-                indexLabel = $J('<span/>')
-                .attr('name', this.MHE_INDEX_LABEL)
-                .css({
-                    color:'#fff',
-                    backgroundImage:'url("/images/marker_tiny.png")',
-                    backgroundRepeat:'no-repeat',
-                    backgroundPosition:'center center',
-                    fontSize: '90%',
-                    fontWeight:'bold',
-                    display:'inline-block',
-                    width:'3ex',
-                    textAlign: 'center',
-                    fontFamily: 'monospace'
-                })
-                .html(insertionIndex+1);
-
-                //offset label
-                offsetLabel = $J('<span/>')
-                .attr('name', this.MHE_OFFSET_LABEL)
-                .css({
-                    marginLeft:margin,
-                    marginRight:margin
-                })
-                .html(this.formatMarkerOffset(marker.offset));
-                
-                //description label
-                descriptionLabel = $J('<span/>')
-                .attr("name",this.MHE_DESCRIPTION_LABEL)
-                .attr('title',marker.desc ? marker.desc : "")
-                .css({
-                    fontWeight:'bold',
-                    marginRight:margin
-                })
-
-                //close button
-                deleteButton = $J('<a/>')
-                .attr('title','delete marker')
-                .attr('name', this.MHE_DELETE_BUTTON)
-                .attr("href","#")
-                .append($J('<img/>').attr("src","/images/del_marker.png").css({
-                    width:'1em'
-                }))
-                .css({
-                    fontWeight:'bold',
-                    //border:'1px dotted #333333',
-                    float:'right',
-                    color:'white'
-                });
-
-                //var bRadius = '4px 4px 4px 4px';
-                //edit button
-                editButton = $J('<a/>')
-                .attr('title','edit marker description')
-                .attr('name', this.MHE_EDIT_BUTTON)
-                .attr("href","#")
-                .append($J('<img/>').attr("src","/images/edit_marker.png").css({
-                    width:'6.5ex'
-                }))
-                .css({
-                    float:'right',
-                    marginRight:margin,
-                });
-                //                .append($J('<span/>').html("EDIT").css({
-                //                    fontSize:'70%',
-                //                    fontWeight:'bold',
-                //                    verticalAlign:'top',
-                //                    color:'#000000',
-                //                    textAlign:'center',
-                //                    margin:'0px',
-                //                    /*border:'1px solid red',*/
-                //                    position:'relative',
-                //                    top:'-0.6ex',
-                //                    padding:'0px'
-                //                }))
-                //                .css({
-                //                    float:'right',
-                //                    height:'1.7ex',
-                //                    marginRight:margin,
-                //                    border:'2px solid #333333',
-                //                    '-webkit-border-radius':bRadius,
-                //                    'moz-border-radius': bRadius,
-                //                    'border-radius': bRadius,
-                //                    paddingLeft:'10px',
-                //                    paddingRight:'10px',
-                //                    paddingTop:'0px',
-                //                    paddingBottom:'0px',
-                //                    backgroundColor:'#FFFFF0'
-                //                });
+        move: function(markerIndex, newOffset){
+            var newIndex = this.indexOf(newOffset);
             
-                //add all elements to header:
-                header = $J('<div/>')
-                .append(indexLabel)
-                .append(offsetLabel)
-                .append(descriptionLabel)
-                .append(deleteButton)
-                .append(editButton);
-
-                //description text
-                descriptionText = $J('<textarea/>')
-                .attr("name", this.MHE_DESCRIPTION_TEXT)
-                .val(marker.desc ? marker.desc : "")
-                .css({
-                    margin:0,
-                    padding:0,
-                    width:'100%'
-                });
-            
-                //ok button
-                okButton = $J('<a/>')
-                .attr("name", this.MHE_OK_BUTTON)
-                .attr('title','save marker description and offset')
-                .css({
-                    display:'none',
-                    marginTop:'0.5ex'
-                })
-                .attr("href","#")
-                .append($J('<img/>').attr("src","/images/marker_ok_green.png").css({
-                    width:'3em'
-                }))
-            
-                //create marker div and append all elements
-                markerDiv = $J('<div/>')
-                .append(header)
-                .append(descriptionText)
-                .append(okButton)
-                .css({
-                    paddingBottom:'1em',
-                    paddingTop:'1ex',
-                    paddingLeft:'1ex',
-                    paddingRight:'1ex',
-                    //borderTop: '1px solid #666666',
-                    borderBottom: '1px solid #999999'
-                });
-
-                //ACTIONS TO BUTTONS:
-                ////first define this keyword inside functions
-                var klass = this;
-                //reference to fireEditMode
-                var func_fem = this.fireEditMode;
-                var editModeEditText = this.EDIT_MODE_EDIT_TEXT;
-                //action for edit
-                editButton.unbind('click').click( function(){
-                    if(CURRENT_USER_NAME){
-                        func_fem.apply(klass,[marker,editModeEditText,editButton, descriptionText,
-                            descriptionLabel, okButton]);
-                    }else{
-                        alert(klass.AUTHENTICATION_MSG);
-                    }
-                    return false; //avoid scrolling of the page on anchor click
-                });
-
-                //action for ok button
-                var editModeSaved = this.EDIT_MODE_SAVED;
-                var func_send = this.sendHTTP;
-                okButton.unbind('click').click( function(){
-                    if(CURRENT_USER_NAME){
-                        if(marker.desc !== descriptionText.val()){ //strict equality needed. See note below
-                            marker.desc = descriptionText.val();
-                            func_send(marker);
-                        }
-                        func_fem.apply(klass,[marker,editModeSaved,editButton, descriptionText,
-                            descriptionLabel, okButton]);
-                    }else{
-                        alert(klass.AUTHENTICATION_MSG);
-                    }
-                    return false; //avoid scrolling of the page on anchor click
-                });
-
-                //action for removing
-                var remove = this.remove;
-                //reference the class (this) as within the function below this will refer to the document
-                
-                deleteButton.unbind('click').click( function(){
-                    if(CURRENT_USER_NAME){
-                        remove.apply(klass,[marker]);
-                    }else{
-                        alert(klass.AUTHENTICATION_MSG);
-                    }
-                    return false; //avoid scrolling of the page on anchor click
-                });
-                
-                //insert the new div created
-                var divLen = div.children().length;
-                div.append(markerDiv);
-                if(insertionIndex==divLen){
-                    div.append(markerDiv);
-                }else{
-                    $( div.children()[insertionIndex] ).before(markerDiv);
-                }
-
+            //if we moved left to right, the insertion index is actually
+            //newIndex-1, as we must also consider to remove the current index markerIndex, so:
+            if(newIndex>markerIndex){
+                newIndex--;
             }
-            return markerDiv;
+            //this way, we are sure that if markerIndex==newIndex we do not have to move,
+            //and we can safely first remove the marker then add it at the newIndex without
+            //checking if we moved left to right or right to left
+            var marker = this.markers[markerIndex];
+            marker.offset = newOffset;
+            marker.isSaved = marker.isEditable ? false : true;
+            if(newIndex != markerIndex){
+                this.markers.splice(markerIndex,1);
+                this.markers.splice(newIndex,0,marker);
+            }
+            this.fire('moved', {
+                fromIndex: markerIndex,
+                toIndex: newIndex
+            });
         },
-
-        //sets the edit mode in the div associated to marker. Last 4 arguments are optional
-        fireEditMode: function(marker, editMode, editButton, descriptionText,
-            descriptionLabel, okButton,deleteButton){
-            var e = this.getHtmElm;
-            if(editButton == undefined){
-                editButton = e(marker,this.MHE_EDIT_BUTTON);
-            }
-            if(descriptionLabel == undefined){
-                descriptionLabel = e(marker,this.MHE_DESCRIPTION_LABEL);
-            }
-            if(descriptionText == undefined){
-                descriptionText = e(marker,this.MHE_DESCRIPTION_TEXT);
-            }
-            if(okButton == undefined){
-                okButton = e(marker,this.MHE_OK_BUTTON);
-            }
-            if(deleteButton == undefined){
-                deleteButton = e(marker,this.MHE_DELETE_BUTTON);
-            }
-            var speed = 400; //fast is 200 slow is 600 (see jQuery help)
-            var klass = this;
-
-            //if user is not authenticated and does not have the necessary permission, we reset editmode to undefined
-            //we treat this case below (last else)
-            if(!(CURRENT_USER_NAME)){
-                editMode = undefined;
-            }
-            //var editModeSaved = this.EDIT_MODE_SAVED;
-            if(editMode == this.EDIT_MODE_EDIT_TEXT){ //edit text
-                descriptionLabel.hide(); //without arguments, otherwise alignement problems arise (in chrome)
-                editButton.hide(speed);
-                descriptionText.show(speed, function(){
-                    this.select();
-                });
-                okButton.show(speed);
-
-            }else if(editMode == this.EDIT_MODE_MARKER_MOVED){
-                if(!descriptionText.is(':visible')){
-                    editButton.show(speed, function(){
-                        descriptionLabel.show();
-                    });
-                }
-                //if then a user types the edit button, this function is called with
-                //editMode=1 (this.EDIT_MODE_EDIT_TEXT). Which means (see okbutton click binding above) marker will be saved
-                //ONLY if text is different from marker.desc. However, as the offset has changed we want to
-                //save IN ANY CASE, so we set marker.desc undefined. This way, text will be always different and
-                //we will save the marker in any case
-                marker.desc = undefined;
-                //descriptionText.hide(speed);
-                okButton.show(speed);
-            }else{
-                if(!(CURRENT_USER_NAME)){
-                    editButton.hide();
-                    deleteButton.hide();
-                    descriptionLabel.show();
+        //
+        //The core search index function: returns insertionIndex if object is found according to comparatorFunction,
+        //(-insertionIndex-1) if object is not found. This assures that if the returned
+        //number is >=0, the array contains the element, otherwise not and the element can be inserted at
+        //-insertionIndex-1
+        insertionIndex: function(object){
+            var offset;
+            if(typeof object == 'object'){
+                offset = object.offset;
+            }else if(typeof object == 'number'){
+                offset = object;
+            }else{ //to be sure...
+                offset = parseFloat(object);
+            }
+            var pInt = parseInt; //reference to parseInt (to increase algorithm performances)
+            var comparatorFunction = function(a,b){
+                return (a<b ? -1 : (a>b ? 1 : 0));
+            };
+            var data = this.markers;
+            var low = 0;
+            var high = data.length-1;
+
+            while (low <= high) {
+                //int mid = (low + high) >>> 1;
+                var mid = pInt((low + high)/2);
+                var midVal = data[mid];
+                var cmp = comparatorFunction(midVal.offset,offset);
+                if (cmp < 0){
+                    low = mid + 1;
+                }else if (cmp > 0){
+                    high = mid - 1;
                 }else{
-                    var function_sld = klass.setLabelDescription;
-                    editButton.show(speed, function(){
-                        function_sld.apply(klass,[marker]);
-                        descriptionLabel.show();
-                    });
+                    return mid; // key found
                 }
-                descriptionText.hide(speed);
-                okButton.hide(speed);
             }
+            return -(low + 1);  // key not found
         },
-
-
-        //sets the length of the label description. Note that all elements must be visible.
-        //Therefore, we call $N.Util.setUpTabs() once all markers have been loaded
-        setLabelDescription: function(marker){
-            var mDiv = marker.div;
-            var e = this.getHtmElm;
-            var space = mDiv.width()-e(marker, this.MHE_INDEX_LABEL).outerWidth(true)-e(marker, this.MHE_OFFSET_LABEL).outerWidth(true)-
-            e(marker, this.MHE_EDIT_BUTTON).outerWidth(true)-e(marker, this.MHE_DELETE_BUTTON).outerWidth(true);
-            //space is the space available for the label. Decrease it of 20% in order to keep the extra space for
-            //zooming in. This does not assures indefinitely that we won't have overlaps or overflows but gives us
-            //some zoom increase without them. Note: css overflow property does not work
-            space = space - 0.1*space;
-            var labelDesc = e(marker, this.MHE_DESCRIPTION_LABEL);
-            var str='';
-            labelDesc.html(str);
-            if(space>0 && marker.desc && marker.desc.length>0){
-                var string = marker.desc;
-                labelDesc.html(string);
-                var id=string.length-1;
-                while(id>=0 && labelDesc.outerWidth(true)>=space){
-                    str = id==0 ? "" : string.substring(0,id);
-                    labelDesc.html(str);
-                    id--;
-                }
-            }
-            //we did not reach the end? in case, add dots
-            if(str.length>3 && str.length<marker.desc.length){
-                //workaround: add dots at the beginning, calculate the space, then move them at end
-                str = "..." + str;
-                labelDesc.html(str);
-                //so dots are at the beginning and we can remove safely the last character
-                id = str.length-1;
-                while(id>=0 && labelDesc.outerWidth(true)>=space){
-                    //var chr = string.substring(0,id);
-                    //str += chr==' ' ? '&nbsp;' : chr;
-                    str = id==0 ? "" : str.substring(0,id);
-                    labelDesc.html(str);
-                    id--;
-                }
-                //move dots at the end, if we didnt erase dots as well (space too short)
-                if(str.length>3){
-                    str = str.substring(3,str.length)+"...";
-                }else if(str.length<3){ //zero, one or two dots might be confusing, remove them
-                    str = '';
-                }
-                labelDesc.html(str);
-            }
-
+        //indexOf is the same as insertionIndex, but returns a positive number.
+        //in other words, it is useful when we do not want to know if obj is already present
+        //in the map, but only WHERE WOULD be inserted obj in the map. obj can be a marker
+        //or an offset (time). In the latter case a dummy marker with that offset will be considered
+       indexOf: function(obj){
+           var idx = this.insertionIndex(obj);
+           return idx<0 ? -idx-1 : idx;
+       },
+        each: function(callback) {
+            $J(this.markers).each(callback);
         },
-
-        formatMarkerOffset: function(markerOffset){
-            //marker offset is in float format second.decimalPart
-            var hours = parseInt(markerOffset/(60*24));
-            markerOffset-=hours*(60*24);
-            var minutes = parseInt(markerOffset/(60));
-            markerOffset-=minutes*(60);
-            var seconds = parseInt(markerOffset);
-            markerOffset-=seconds;
-            var msec = Math.round(markerOffset*100); //show only centiseconds
-            //(use 1000* to show milliseconds)
-            var format = (hours<10 ? "0"+hours : hours )+":"+
-            (minutes<10 ? "0"+minutes : minutes )+":"+
-            (seconds<10 ? "0"+seconds : seconds )+"."+
-            (msec<10 ? "0"+msec : msec );
-            return format;
+        length: function(){
+            return this.markers ? this.markers.length : 0;
         },
+       
 
         sendHTTP: function(marker){
 
@@ -569,10 +183,17 @@ TimeSide(function($N, $J) {
             //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":[{"item_id":"'+ itemid+'", "public_id": "'+marker.id+'", "time": "'+
             //            marker.offset+'","description": "'+marker.desc+'"}], "method":"telemeta.add_marker","jsonrpc":"1.0"}';
-            var isNew = marker.isNew;
-            var method = isNew ? "telemeta.add_marker" : "telemeta.update_marker";
-            var data2send = '{"id":"jsonrpc", "params":[{"item_id":"'+ itemid+'", "public_id": "'+marker.id+'", "time": "'+
-            marker.offset+'","description": "'+marker.desc+'"}], "method":"'+method+'","jsonrpc":"1.0"}';
+           
+            var isSaved = marker.id !== undefined;
+            if(!isSaved){
+                marker.id=this.uniqid(); //defined in core;
+            }
+            var method = isSaved ? "telemeta.update_marker" : "telemeta.add_marker";
+            var data2send = '{"id":"jsonrpc", "params":[{"item_id":"'+ itemid+
+            '", "public_id": "'+marker.id+'", "time": "'+marker.offset+
+            '", "author": "'+marker.author+
+            '", "title": "'+marker.title+
+            '","description": "'+marker.desc+'"}], "method":"'+method+'","jsonrpc":"1.0"}';
 
 
             $.ajax({
@@ -581,8 +202,8 @@ TimeSide(function($N, $J) {
                 contentType: "application/json",
                 data: data2send,
                 success: function(){
-                    if(isNew){
-                        marker.isNew = false;
+                    if(!isSaved){
+                        marker.isSaved = true;
                     }
                 }
             });
index 067bf3cb08c0f9e78db0844dc39b95e36f455c58..14bc8da25359850fdbc24e04f46d139d168b1605 100644 (file)
@@ -84,164 +84,188 @@ TimeSide(function($N, $J) {
             }
         },
 
-    draw: function() {
-        this.debug('drawing');
-        $N.domReady(this.attach(this._setupInterface));
-        return this;
-    },
-
-    _setupInterface: function() {
-        this.elements = $N.Util.loadUI(this.container, this.skeleton, this.defaultContents);
-
-        // IE apparently doesn't send the second mousedown on double click:
-        var jump = $J.browser.msie ? 'mousedown dblclick' : 'mousedown';
-        this.elements.rewind.attr('href', '#').bind(jump, this.attach(this._onRewind))
-        .click(function() {
-            return false;
-        });
-        this.elements.forward.attr('href', '#').bind(jump, this.attach(this._onForward))
-        .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));
+        draw: function() {
+            this.debug('drawing');
+            $N.domReady(this.attach(this._setupInterface));
+            return this;
+        },
+
+        _setupInterface: function() {
+            this.elements = $N.Util.loadUI(this.container, this.skeleton, this.defaultContents);
+
+            // IE apparently doesn't send the second mousedown on double click:
+            var jump = $J.browser.msie ? 'mousedown dblclick' : 'mousedown';
+            this.elements.rewind.attr('href', '#').bind(jump, this.attach(this._onRewind))
+            .click(function() {
+                return false;
+            });
+            this.elements.forward.attr('href', '#').bind(jump, this.attach(this._onForward))
+            .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));
         
-        //assigning title string to all anchors???????
-        this.elements.control.find('a').add(this.elements.setMarker)
-        .attr('href', '#')
-        .each(function(i, a){
-            a = $J(a);
-            if (!a.attr('title'))
-                a.attr('title', a.text());
-        });
+            //assigning title string to all anchors???????
+            this.elements.control.find('a').add(this.elements.setMarker)
+            .attr('href', '#')
+            .each(function(i, a){
+                a = $J(a);
+                if (!a.attr('title'))
+                    a.attr('title', a.text());
+            });
             
-        //this.elements.markerControl.find('a').attr('href', '#');
-        if (this.map) {
-            //configureMarkersDiv();
-            this.elements.setMarker.bind('click', this.attach(this._onSetMarker));
-        //this.elements.setMarker2.bind('click', this.attach(this._onSetMarker2));
-        //this.elements.textMarker.attr('type', 'text');
-        //this.elements.textMarker.bind('click', this.attach(this._onSetMarker2));
+            //this.elements.markerControl.find('a').attr('href', '#');
+            if (this.map && CURRENT_USER_NAME) {
+                //configureMarkersDiv();
+                this.elements.setMarker.bind('click', this.attach(this._onSetMarker));
+            //this.elements.setMarker2.bind('click', this.attach(this._onSetMarker2));
+            //this.elements.textMarker.attr('type', 'text');
+            //this.elements.textMarker.bind('click', this.attach(this._onSetMarker2));
           
-        } else {
-            this.elements.setMarker.remove();
-        }
-        //creating the ruler
-        this.ruler = new $N.Ruler({
-            viewer: this.elements.viewer,
-            map: this.map,
-            soundProvider: this.soundProvider
-        });
-        //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
-        //arg is a function to execute each time the event is triggered
-        this.ruler
-        .observe('markermove', this.forwardEvent)
-        .observe('markeradd', this.forwardEvent)
-        .observe('move', this.forwardEvent)
-        .draw();
-        this.refreshImage();
-        this.resize();
-        var resizeTimer = null;
-        $J(window).resize(this.attach(function() {
-            if (resizeTimer)
-                clearTimeout(resizeTimer);
-            resizeTimer = setTimeout(this.attach(this.resize), 100);
-        }));
-    //this.container.resize(this.attach(this.resize)); // Can loop ?
-    },
-
-    resize: function(overrideHeight) {
-        this.debug("resizing");
-        var height;
-        if (overrideHeight === true) {
-            this.debug("override height");
-            height = this.elements.image.css('height', 'auto').height();
-        } else {
-            height = this.elements.wave.height();
-            this.debug("wave height:" + height);
-            if (!height) {
-                this.elements.image.one('load', this.attach(function() {
-                    this.resize(true);
-                    this.debug("image loaded");
-                }));
-                height = this.elements.image.height();
+            } else {
+                this.elements.setMarker.remove();
+            }
+            //creating the ruler
+            this.ruler = new $N.Ruler({
+                viewer: this.elements.viewer,
+                //map: this.map,
+                soundProvider: this.soundProvider
+            });
+            //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
+            //arg is a function to execute each time the event is triggered
+            this.ruler
+            .observe('markermove', this.forwardEvent)
+            .observe('markeradd', this.forwardEvent)
+            .observe('move', this.forwardEvent)
+            .draw();
+            this.refreshImage();
+            this.resize();
+            var resizeTimer = null;
+            $J(window).resize(this.attach(function() {
+                if (resizeTimer)
+                    clearTimeout(resizeTimer);
+                resizeTimer = setTimeout(this.attach(this.resize), 100);
+            }));
+        //this.container.resize(this.attach(this.resize)); // Can loop ?
+        },
+
+        resize: function(overrideHeight) {
+            this.debug("resizing");
+            var height;
+            if (overrideHeight === true) {
+                this.debug("override height");
+                height = this.elements.image.css('height', 'auto').height();
+            } else {
+                height = this.elements.wave.height();
+                this.debug("wave height:" + height);
+                if (!height) {
+                    this.elements.image.one('load', this.attach(function() {
+                        this.resize(true);
+                        this.debug("image loaded");
+                    }));
+                    height = this.elements.image.height();
+                }
             }
-        }
 
-        var elements = this.elements.image
-        .add(this.elements.imageContainer)
-        .add(this.elements.imageCanvas);
+            var elements = this.elements.image
+            .add(this.elements.imageContainer)
+            .add(this.elements.imageCanvas);
 
-        elements.css('width', 'auto'); // for IE6
+            elements.css('width', 'auto'); // for IE6
 
-        if (!height)
-            height = 200;
-        var style = {
-            width: this.elements.wave.width(),
-            height: height
-        }
-        elements.css(style);
-        this.imageWidth = style.width;
-        this.imageHeight = style.height;
-        this.refreshImage();
-        this.ruler.resize();
-        return this;
-    },
-
-    _onRewind: function() {
-        var offset = 0;
-        if (this.map) {
-            var position = 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;
+            if (!height)
+                height = 200;
+            var style = {
+                width: this.elements.wave.width(),
+                height: height
             }
-        }
-        this.fire('move', {
-            offset: offset
-        });
-        return false;
-    },
-
-    _onForward: function() {
-        var offset = this.soundProvider.getDuration();
-        if (this.map) {
-            var marker = this.map.getNext(this.soundProvider.getPosition());
-            if (marker) {
-                offset = marker.offset;
+            elements.css(style);
+            this.imageWidth = style.width;
+            this.imageHeight = style.height;
+            this.refreshImage();
+            this.ruler.resize();
+            return this;
+        },
+
+        _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 idx = this.map.indexOf(position)-1;
+                if(idx>=0){
+                    var marker = this.map.get(idx);
+                    if(marker){
+                        offset = marker.offset;
+                    }
+                }
             }
-        }
-        this.fire('move', {
-            offset: offset
-        });
-        return false;
-    },
-
-    _onPlay: function() {
-        this.fire('play');
-        return false;
-    },
-
-    _onPause: function() {
-        this.fire('pause');
-        return false;
-    },
-
-    _onSetMarker: function() {
-        if (this.map) {
-            this.fire('markeradd', {
-                offset: this.soundProvider.getPosition()
+            this.fire('move', {
+                offset: offset
+            });
+            return false;
+        },
+
+        _onForward: function() {
+            var offset = this.soundProvider.getDuration();
+            if (this.map) {
+                var position = parseFloat(this.soundProvider.getPosition());
+                var idx = this.map.insertionIndex(position);
+                if(idx>=0){ //the pointer is exactly on a marker, increase by one
+                    //otherwise the index is the marker itself and we wouldn't move ahead
+                    idx++;
+                }else{
+                    //we are not on a pointer, get the index of the marker
+                    //(see markermap insertionindex)
+                    idx = -idx-1;
+                }
+                if(idx>=0){
+                    var marker = this.map.get(idx);
+                    if(marker){
+                        offset = marker.offset;
+                    }
+                }
+            //            var marker = this.map.getNext(this.soundProvider.getPosition());
+            //            if (marker) {
+            //                offset = marker.offset;
+            //            }
+            }
+            this.fire('move', {
+                offset: offset
+            });
+            return false;
+        },
+
+        _onPlay: function() {
+            this.fire('play');
+            return false;
+        },
+
+        _onPause: function() {
+            this.fire('pause');
+            return false;
+        },
+
+        _onSetMarker: function() {
+            if (this.map) {
+                this.fire('markeradd', {
+                    offset: this.soundProvider.getPosition()
                 });
+            }
+            return false;
         }
-        return false;
-    }
     });
 
-$N.notifyScriptLoad();
+    $N.notifyScriptLoad();
 
-    });
+});
index de52191b9c4dc23edadc880fa584ddce8967800f..5fcd6329fa8c8049424027f1b278838b290c3433 100644 (file)
@@ -30,7 +30,7 @@ TimeSide(function($N, $J) {
             this.configure(cfg, {
                 viewer: [null, 'required'],
                 fontSize: 10,
-                map: null,
+                //map: null,
                 soundProvider: [null, 'required']
             });
             this.cfg.viewer = $J(this.cfg.viewer);
@@ -39,13 +39,13 @@ TimeSide(function($N, $J) {
             this._setDuration(this.cfg.soundProvider.getDuration());
             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._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.cfg.soundProvider.observe('update', this.attach(this._onSoundProviderUpdate));
         },
@@ -217,20 +217,20 @@ TimeSide(function($N, $J) {
             }
 
             this._createPointer();
-            this._drawMarkers();
+        //this._drawMarkers();
         },
 
-        _drawMarkers: function() {
-            if (this.cfg.map) {
-                $J(this.markers).each(function(i, m) {
-                    m.clear();
-                });
-                this.markers = new Array();
-                this.cfg.map.each(this.attach(function(i, m) {
-                    this.markers.push(this._drawMarker(m, i));
-                }));
-            }
-        },
+        //        _drawMarkers: function() {
+        //            if (this.cfg.map) {
+        //                $J(this.markers).each(function(i, m) {
+        //                    m.clear();
+        //                });
+        //                this.markers = new Array();
+        //                this.cfg.map.each(this.attach(function(i, m) {
+        //                    this.markers.push(this._drawMarker(m, i));
+        //                }));
+        //            }
+        //        },
 
         _createPointer: function() {
             if (this.pointer) {
@@ -349,7 +349,7 @@ TimeSide(function($N, $J) {
         },
 
         _observeMouseEvents: function(element) {
-             if(!(CURRENT_USER_NAME)){
+            if(!(CURRENT_USER_NAME)){
                 return;
             }
             element
@@ -377,16 +377,16 @@ TimeSide(function($N, $J) {
                 viewer: this.waveContainer,
                 fontSize: this.cfg.fontSize,
                 className: 'marker',
-                id: marker.id,
+                index: index,
                 tooltip: 'Move marker',
-                canMove: CURRENT_USER_NAME
+                canMove: marker.isEditable
             });
-            if(CURRENT_USER_NAME){
+            if(marker.isEditable){
                 m.observe('move', this.attach(this._onMarkerMove))
             }
             //m.observe('move', this.attach(this._onMarkerMove))
             m
-            .setText(index + 1)
+            //.setText(index + 1)
             .move(pixelOffset)
             .show();
             return m;
@@ -396,37 +396,42 @@ TimeSide(function($N, $J) {
             if (data.finish) {
                 var offset = data.offset / this.width * this.duration;
                 this.fire('markermove', {
-                    id: data.id,
+                    index: data.index,
                     offset: offset
                 });
             }
         },
 
-        _onMapAdd: function(e, data) {
-            this.markers.push(this._drawMarker(data.marker, data.index));
+        add: function(marker, index){
+            this.markers.splice(index, 0, this._drawMarker(marker, index));
+            //this.markers.push(this._drawMarker(marker, index));
         },
 
+        //        _onMapAdd2: function(e, data) {
+        //            this.markers.push(this._drawMarker(data.marker, data.index));
+        //        },
 
-        _onMapRemove: function(e, data) {
-            $J(this.markers).each(this.attach(function(i, m) {
-                if (m.id == data.marker.id) {
-                    m.clear();
-                    this.markers.splice(i, 1);
-                }
-            }));
+        remove: function(index){
+            var rulermarker = this.markers[index];
+            rulermarker.clear();
+            this.markers.splice(index, 1);
+        },
+        
+        //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
         },
 
-        _onMapIndexChange: function(e, data) {
-            $J(this.markers).each(this.attach(function(i, m) {
-                if (m.id == data.marker.id) {
-                    m.setText(data.index + 1);
-                    return false;
-                }
-            }));
+        updateMarkerIndices:function(fromIndex, toIndex){
+            for(var i=fromIndex; i<=toIndex; i++){
+                this.markers[i].setIndex(i);
+            }
         },
 
         _onDoubleClick: function(evt) {
-            if (this.cfg.map && CURRENT_USER_NAME) {
+            //if (this.cfg.map && CURRENT_USER_NAME) {
+            if (CURRENT_USER_NAME) {
                 var offset = (evt.pageX - this.container.offset().left)
                 / this.width * this.duration;
                 this.fire('markeradd', {
@@ -445,3 +450,24 @@ TimeSide(function($N, $J) {
     $N.notifyScriptLoad();
 
 });
+
+//        _onMapRemove: function(e, data) {
+        //            $J(this.markers).each(this.attach(function(i, m) {
+        //                if (m.id == data.marker.id) {
+        //                    m.clear();
+        //                    this.markers.splice(i, 1);
+        //                }
+        //            }));
+        //        },
+
+        //        onMapMove: function(fromIndex, toIndex) {
+        //            var min = Math.min(fromIndex, toIndex);
+        //            var max = Math.max(fromIndex, toIndex);
+        //            this.updateMarkerIndices(min,max);
+        ////            $J(this.markers).each(this.attach(function(i, m) {
+        ////                if (m.id == data.marker.id) {
+        ////                    m.setText(data.index + 1);
+        ////                    return false;
+        ////                }
+        ////            }));
+        //        },
index dffefa183c84401660b4cbccb5bb82a851b9d37f..fe4cf976032b6cc4d4fb8792355d27d92578a43e 100644 (file)
@@ -111,7 +111,7 @@ TimeSide(function($N, $J) {
                     $N.loadScripts(root, ['core.js'], function() {
                         $N.loadScripts(root, ['util.js'], function() {
                             var scripts = ['controller.js', 'marker.js', 'markerlist.js',
-                            'markermap.js', 'player.js', 'ruler.js',
+                            'markermap.js', 'player.js', 'ruler.js','divmarker.js',
                             'soundprovider.js'];
                                                        
                             $N.loadScripts(root, scripts, function() {