--- /dev/null
--- /dev/null
++/**
++ * TimeSide - Web Audio Components
++ * Copyright (c) 2008-2009 Samalyse
++ * Author: Olivier Guilyardi <olivier samalyse com>
++ * License: GNU General Public License version 2.0
++ */
++
++TimeSide(function($N) {
++
++ $N.Class.create("Controller", $N.Core, {
++
++ initialize: function($super, cfg) {
++ $super();
++ this.configure(cfg, {
++ player: null,
++ soundProvider: 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();
++ this.loadHTTP();
++
++ },
++
++ _setupPlayer: function() {
++ this.debug('_setupPlayer');
++ this.cfg.player
++ .setMarkerMap(this.cfg.map)
++ .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))
++ ._setupInterface();
++
++ 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));
++
++ },
++
++ //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(data.index, data.offset);
++ //this will fire the method below
++ }
++ },
++
++ _onMarkerMapMoved:function(e, data){
++ var from = data.fromIndex;
++ var to = data.toIndex;
++ this.cfg.divmarkers.move(from,to); //new array method see application.js
++ this.cfg.player.ruler.markers.move(from,to);
++ this.updateIndices(from,data.newIndex);
++ this.divFocus(data.newIndex);
++ },
++
++ divFocus: function(divIndex){
++ if(this.cfg.divmarkers){
++ var max = this.cfg.divmarkers.length;
++ for (var i = 0; i < max; i++) {
++ if(i==divIndex){
++ this.cfg.divmarkers[i].focusOn();
++ }else{
++ this.cfg.divmarkers[i].focusOff();
++ }
++ }
++ }
++ },
++ //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);
++ this.divFocus(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) {
++
++ var idx = data.index;
++ this.cfg.divmarkers.splice(idx,0, new $N.DivMarker(this.cfg.map));
++ this.cfg.player.ruler.onMapAdd(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) {
++ 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);
++ this.updateIndices(idx);
++
++ }
++ },
++
++ updateIndices: function(from, to){
++ if(from===undefined || from==null){
++ from = 0;
++ }
++ var len = this.cfg.divmarkers.length-1;
++ if(from>len){
++ return;
++ }
++ if(to==undefined || to ==null){
++ to = len;
++ }
++ if(to<from){
++ var tmp = to;
++ to=from;
++ from=tmp;
++ }
++ for(var i = from; i <= to; i++){
++ this.cfg.divmarkers[i].updateMarkerIndex(i);
++ }
++ this.cfg.player.ruler.updateMarkerIndices(from,to);
++ },
++
++
++ loadHTTP: function(){
++ 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;
++ 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]);
++ }
++ //we call now updateindices
++ updateIndices.apply(me);
++ tabIndex = result.length>0 ? 1 : 0;
++ }
++
++ }
++ util.setUpTabs.apply(util, [tabIndex]);
++ };
++ json([itemId],"telemeta.get_markers", onSuccess);
++ }
++ });
++
++ $N.notifyScriptLoad();
++
++});
--- /dev/null
--- /dev/null
++/**
++ * TimeSide - Web Audio Components
++ * Copyright (c) 2008-2009 Samalyse
++ * Author: Olivier Guilyardi <olivier samalyse com>
++ * License: GNU General Public License version 2.0
++ */
++
++TimeSide(function($N, $J) {
++
++ $N.extend = function(destination, source) {
++ for (var property in source){
++ destination[property] = source[property];
++ }
++ return destination;
++ };
++
++ $N.objectKeys = function(object) {
++ var keys = [];
++ for (var property in object){
++ keys.push(property);
++ }
++ return keys;
++ };
++
++ $N.argumentNames = function(method) {
++ var names = method.toString().match(/^[\s\(]*function[^(]*\(([^\)]*)\)/)[1]
++ .replace(/\s+/g, '').split(',');
++ return names.length == 1 && !names[0] ? [] : names;
++ };
++
++ $N.argsToArray = function(args) {
++ var length = args.length || 0, result = new Array(length);
++ while (length--){
++ result[length] = args[length];
++ }
++ return result;
++ };
++
++ $N.wrapFunction = function(wrapper, method) {
++ return function() {
++ var args = $N.argsToArray(arguments);
++ return wrapper.apply(this, [$N.attachFunction(this, method)].concat(args));
++ }
++ };
++
++ $N.attachFunction = function() {
++ if (arguments.length < 3 && (typeof arguments[1] == 'undefined')){
++ return arguments[0];
++ }
++ var args = $N.argsToArray(arguments);
++ var object = args.shift();
++ var method = args.shift();
++ return function() {
++ var _args = $N.argsToArray(arguments);
++ return method.apply(object, args.concat(_args));
++ }
++ };
++
++ $N.attachAsEventListener = function() {
++ var args = $N.argsToArray(arguments), object = args.shift();
++ var method = args.shift();
++ return function(event) {
++ return method.apply(object, [event || window.event].concat(args));
++ }
++ };
++
++ $N.isInstanceOf = function(obj, className) {
++ if (typeof obj == 'object' && obj.__class__) {
++ var c = obj.__class__;
++ if (c.__name__ == className) {
++ return true;
++ }
++ while (c = c.__super__) {
++ if (c.__name__ == className) {
++ return true;
++ }
++ }
++ }
++ return false;
++ }
++
++ $N.Class = {
++ create: function() {
++ var parent = null, className = null;
++ var properties = $N.argsToArray(arguments)
++ if (typeof properties[0] == "string"){
++ className = properties.shift();
++ }
++ if (typeof properties[0] == "function"){
++ parent = properties.shift();
++ }
++
++ function klass() {
++ this.initialize.apply(this, arguments);
++ }
++ //Merge the contents of $N.Class.Methods into klass:
++ $N.extend(klass, $N.Class.Methods);
++ klass.__name__ = className;
++ klass.__super__ = parent;
++ klass.__subclasses__ = [];
++
++ if (parent) {
++ var subclass = function() { };
++ subclass.prototype = parent.prototype;
++ klass.prototype = new subclass;
++ parent.__subclasses__.push(klass);
++ }
++
++ klass.prototype.__class__ = klass;
++ for (var i = 0; i < properties.length; i++){
++ klass.addMethods(properties[i]);
++ }
++
++ if (!klass.prototype.initialize){
++ klass.prototype.initialize = function () {};
++
++ }
++
++ klass.prototype.constructor = klass;
++
++ if (className) {
++ $N[className] = klass;
++ }
++ return klass;
++ }
++ };
++
++ $N.Class.Methods = {
++ addMethods: function(source) {
++ var ancestor = this.__super__ && this.__super__.prototype;
++ var properties = $N.objectKeys(source);
++
++ if (!$N.objectKeys({
++ toString: true
++ }).length){
++ properties.push("toString", "valueOf");
++ }
++ for (var i = 0, length = properties.length; i < length; i++) {
++ var property = properties[i], value = source[property];
++ if (ancestor && (typeof value == 'function') &&
++ $N.argumentNames(value)[0] == "$super") {
++ var method = value;
++ value = $N.wrapFunction(method, (function(m) {
++ return function() {
++ return ancestor[m].apply(this, arguments)
++ };
++ })(property));
++
++ value.valueOf = $N.attachFunction(method, method.valueOf);
++ value.toString = $N.attachFunction(method, method.toString);
++ }
++ this.prototype[property] = value;
++ }
++
++ return this;
++ }
++ };
++
++ $N.Core = $N.Class.create("Core", {
++ eventContainer: null,
++ eventPrefix: '',
++ cfg: {},
++
++ initialize: function() {
++ this.debug("new instance");
++ $N.registerInstance(this);
++ this.eventContainer = $J('<div/>');
++ this.forwardEvent = this.attach(this._forwardEvent);
++ },
++
++ free: function() {
++ this.eventContainer = null;
++ },
++
++ configure: function(config, defaults) {
++ if (!config){
++ config = {};
++
++ }
++ for (k in defaults) {
++ var value = null, flags = [];
++
++ if (defaults[k] && typeof defaults[k][0] !== 'undefined') {
++ value = defaults[k][0];
++ if (defaults[k][1]) {
++ flags = defaults[k][1].split(",");
++ }
++ } else {
++ value = defaults[k];
++ }
++
++ if (typeof config[k] !== 'undefined'){
++ value = config[k];
++ }
++
++ var source = this;
++ $J(flags).each(function(i, flag) {
++ switch (flag) {
++ case 'required':
++ if (value === null)
++ throw new $N.RequiredOptionError(source, k);
++ break;
++ /*
++ case 'element':
++ value = $J(value);
++ break;
++ */
++
++ }
++ });
++
++ this.cfg[k] = value;
++ }
++ return this;
++ },
++
++ observe: function(eventName, handler) {
++ this.eventContainer.bind(this.eventPrefix + eventName, handler);
++ return this;
++ },
++
++ fire: function(eventName, data) {
++ if (!data){
++ data = {};
++
++ }
++ this.eventContainer.trigger(this.eventPrefix + eventName, data);
++ return this;
++ },
++
++ _forwardEvent: function(e, data) {
++ if (!data){
++ data = {};
++
++ }
++ this.eventContainer.trigger(e.type, data);
++ return this;
++ },
++
++ _textWidth: function(text, fontSize) {
++ var ratio = 3/5;
++ return text.length * ratio * fontSize;
++ },
++
++ debug: function(message) {
++ if ($N.debugging && typeof console != 'undefined' && console.log) {
++ console.log('TimeSide.' + this.__class__.__name__ + ': ' + message);
++ }
++ },
++
++ attach: function(method) {
++ return $N.attachFunction(this, method);
++ },
++
++ attachWithEvent: function(method) {
++ return $N.attachAsEventListener(this, method);
++ },
++
++ uniqid: function() {
++ d = new Date();
++ return new String(d.getTime() + '' + Math.floor(Math.random() * 1000000)).substr(0, 18);
++ }
++ });
++
++ $N.Class.create("Exception", {
++ _source: null,
++ _message: null,
++
++ initialize: function(source, message) {
++ this._source = source;
++ this._message = message;
++ },
++ toString: function() {
++ return this.__class__.__name__ + " from TimeSide." + this._source.__class__.__name__
++ + ": " + this._message;
++ }
++ });
++
++ $N.Class.create("RequiredOptionError", $N.Exception, {
++ initialize: function($super, source, optionName) {
++ $super(source, "missing '" + optionName + "' required option");
++ }
++ });
++
++ $N.Class.create("RequiredArgumentError", $N.Exception, {
++ initialize: function($super, source, optionName) {
++ $super(source, "missing '" + optionName + "' required argument");
++ }
++ });
++
++ $N.notifyScriptLoad();
++
++});
--- /dev/null
--- /dev/null
++/**
++ * TimeSide - Web Audio Components
++ * Copyright (c) 2008-2009 Samalyse
++ * Author: Olivier Guilyardi <olivier samalyse com>
++ * License: GNU General Public License version 2.0
++ */
++
++TimeSide(function($N) {
++
++$N.Class.create("MarkerList", $N.Core, {
++ initialize: function($super, cfg) {
++ $super();
++ this.cfg = this.configure(cfg, {
++ container: null,
++ map: null
++ });
++ },
++
++ _buildItem: function(marker) {
++ var dt = new Element('dt');
++ var time = $N.Util.makeTimeLabel(marker.offset);
++
++
++ },
++
++ _setupInterface: function() {
++ }
++});
++
++$N.notifyScriptLoad();
++
++});
--- /dev/null
--- /dev/null
++/**
++ * TimeSide - Web Audio Components
++ * Copyright (c) 2008-2009 Samalyse
++ * Author: Olivier Guilyardi <olivier samalyse com>
++ * License: GNU General Public License version 2.0
++ */
++
++TimeSide(function($N) {
++
++ $N.Class.create("SoundProvider", $N.Core, {
++ sound: null,
++ timer: null,
++ buggyPosition: null,
++ isDurationForced: false,
++ state: {
++ position: null,
++ duration: null,
++ playing: false,
++ buffering: false
++ },
++ lastState: null,
++
++ initialize: function($super, cfg) {
++ $super();
++ this.configure(cfg, {
++ source: null,
++ duration: null
++ });
++ this.sound = this.cfg.source;
++ if (this.cfg.duration) {
++ this.forceDuration(this.cfg.duration);
++ }
++ 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) {
++ this.sound = null;
++ $super();
++ },
++
++ play: function() {
++ if (this.sound) {
++ //it seems that, if sound is played until its end
++ //playing sound again resets the volume to 100, even though
++ //sound.volume is at the right value. We use this trick which seems to work:
++ this.sound.setVolume(this.sound.volume);
++ if (!this.sound.playState) {
++ this.sound.play();
++ //console.log(this.getVolume());
++ } else if (this.sound.paused) {
++ this.sound.resume();
++ }
++ }
++ return this;
++ },
++
++ pause: function() {
++ if (this.sound){
++ this.sound.pause();
++ }
++ return this;
++ },
++
++ setVolume: function(volume) {
++ if(typeof volume != 'number'){
++ return this;
++ }
++ volume = volume<0 ? 0 : volume >100 ? 100 : parseInt(volume);
++ if (this.sound && this.sound.volume!==volume){
++ this.sound.setVolume(volume);
++ }
++ this.fire('volume',{'volume':volume});
++ return this;
++ },
++
++ getVolume: function() {
++ return this.sound.volume;
++ },
++
++ seek: function(offset) {
++ if (this.sound) {
++ this.sound.setPosition(offset * 1000);
++ if (!this.state.playing) {
++ //it's not always a number. When not playing it is a string
++ //(sound manager?)
++ var offs = typeof offset == "number" ? offset : parseFloat(offset);
++ this.buggyPosition = this.sound.position / 1000;
++ this.state.position = offs;
++ }
++ }
++ return this;
++ },
++
++ isPlaying: function() {
++ return this.state.playing;
++ },
++
++ getPosition: function() {
++ if (this.state.position == null){
++ this._retrieveState();
++ }
++ return this.state.position;
++ },
++
++ getDuration: function() {
++ if (this.state.duration == null){
++ this._retrieveState();
++ }
++ return this.state.duration;
++ },
++
++ forceDuration: function(duration) {
++ this.state.duration = duration;
++ this.isDurationForced = true;
++ },
++
++ isBuffering: function() {
++ return this.state.buffering;
++ },
++
++ _retrieveState: function() {
++ if (this.sound) {
++ this.state.playing = (this.sound.playState && !this.sound.paused);
++ if (this.state.playing) {
++ var position = this.sound.position / 1000;
++ if (position != this.buggyPosition) {
++ this.state.position = position;
++ this.buggyPosition = null;
++ }
++ }
++ if (!this.isDurationForced) {
++ if (this.sound.readyState == 1) {
++ this.state.duration = this.sound.durationEstimate / 1000;
++ } else {
++ this.state.duration = this.sound.duration / 1000;
++ }
++ }
++ this.state.buffering = (this.sound.readyState == 1 && this.state.position > this.sound.duration / 1000);
++ }
++ },
++
++ _update: function() {
++ this._retrieveState();
++ var updated = false;
++ var k;
++ if (this.lastState) {
++ for (k in this.state) {
++ if (this.state[k] != this.lastState[k]) {
++ updated = true;
++ break;
++ }
++ }
++ } else {
++ this.lastState = {};
++ 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');
++ }
++ }
++ },
++
++ setSource: function(source) {
++ this.debug("setting source");
++ this.sound = source;
++ return this;
++ }
++
++ });
++
++ $N.notifyScriptLoad();
++
++});
--- /dev/null
--- /dev/null
++/**
++ * TimeSide - Web Audio Components
++ * Copyright (c) 2008-2009 Samalyse
++ * Author: Olivier Guilyardi <olivier samalyse com>
++ * License: GNU General Public License version 2.0
++ */
++
++TimeSide(function($N, $J) {
++
++ $N.Util = {
++ _loadChild: function(container, tag, className, index, contents) {
++ var p = $N.cssPrefix;
++ var element = container.find('.' + p + className);
++ if (!element.length) {
++ element = $J(document.createElement(tag)).addClass(p + className);
++ if (contents[className]) {
++ element.text(contents[className]);
++ }
++ var children = container.children();
++ if (index < children.length) {
++ children.eq(index).before(element);
++ } else {
++ container.append(element);
++ }
++ }
++ return element;
++ },
++
++ _loadUI: function(container, skeleton, contents) {
++ var i = 0;
++ var elements = {};
++ with ($N.Util) {
++ if (skeleton[0]) {
++ $J(skeleton).each((function(i, selector) {
++ var s = selector.split('.');
++ elements[$N.Util.camelize(s[1])] = _loadChild(container, s[0], s[1], i++, contents);
++ }));
++ } else {
++ for (key in skeleton) {
++ var s = key.split('.');
++ var e = _loadChild(container, s[0], s[1], i++, contents);
++ elements[$N.Util.camelize(s[1])] = e;
++ $N.extend(elements, _loadUI(e, skeleton[key], contents));
++
++ }
++ }
++ }
++ return elements;
++ },
++
++ loadUI: function(container, skeleton, contents) {
++ return $N.Util._loadUI($J(container), skeleton, contents);
++ },
++
++ makeTimeLabel: function(offset) {
++ var minutes = Math.floor(offset / 60);
++ if (minutes < 10)
++ minutes = '0' + minutes;
++ var seconds = Math.floor(offset % 60);
++ if (seconds < 10)
++ seconds = '0' + seconds;
++ return minutes + ':' + seconds;
++ },
++
++ camelize: function(str) {
++ var parts = str.split('-'), len = parts.length;
++ if (len == 1) return parts[0];
++
++ var camelized = str.charAt(0) == '-'
++ ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
++ : parts[0];
++
++ for (var i = 1; i < len; i++)
++ camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
++
++ return camelized;
++ },
++
++ 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
++ var tabPaddingTop ='.8ex'; //padding top of each tab. Increasing it will increase also the tab height, so
++ //compensate by decreasing tabHeight, in case. In any case, must be lower or equal to tabContainerHeight-tabHeight
++ var tabWidth = '12ex'; //width of each tab. Each tab from index 1 to n will be at left=n*tabWidth
++ var tabBottom ='-1px'; //bottom of each tab. Must be equal and opposite to the border of the div below the tab
++
++ //retrieve tab container:
++ var tabContainer = $("#tabs_container"); //change if tabContainer has to be retrieved diferently
++ //retrieve the tabs by checking the elements whose class name starts with "tab_"
++ //var tabs = $('a[class^="tab_"]'); //change if the tabs have to be determined differently.
++ var tabs = tabContainer.find('a[id^="tab_"]');
++ //function that retrieves the div relative to a tab (the div will be set visible.invisible according to tab click):
++ var tab2div = function(tab){
++ return $("#"+tab.attr("name"));
++ //ie, returns the element whose id is equal to the tab name.
++ //change here if div has to be determined differently
++ };
++ var selectedTabClassName = "tab_selected"; //change if needed
++ var unselectedTabClassName = "tab_unselected"; //change if needed
++ var tabClicked = function(index) {
++ for(var i=0; i<tabs.length; i++){
++ var t = $(tabs[i]);
++ if(i===index){
++ t.removeClass(unselectedTabClassName).addClass(selectedTabClassName);
++ tab2div(t).fadeIn('slow');
++ }else{
++ t.removeClass(selectedTabClassName).addClass(unselectedTabClassName);
++ tab2div(t).hide();
++ }
++ }
++ return false; //returning false avoids scroll of the anchor to the top of the page
++ //if the tab is an anchor, of course
++ };
++ //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',
++ 'height':tabContainerHeight
++ });
++ //tabs default css:
++ tabs.css({
++ 'display':'', //reset the default value
++ 'position':'absolute',
++ 'height':tabHeight,
++ 'bottom':tabBottom,
++ 'paddingTop':tabPaddingTop,
++ 'width':tabWidth,
++ 'color': '#000000',
++ 'left':0, //this will be overridden for tabs from 1 to n (see below)
++ 'textAlign':'center'
++ });
++ //setting the left property for all tabs from 1 to n
++ var left = parseFloat(tabWidth); //note that 40%, 33.3ex will be converted
++ //succesfully to 40 and 33.3 respectively
++ if(!isNaN(left)){
++ //retrieve the unit
++ var s = new String(left);
++ var unit = '';
++ if(s.length<tabWidth.length){
++ unit = tabWidth.substring(s.length,tabWidth.length);
++ }
++ for(var i=1; i<tabs.length; i++){
++ $(tabs[i]).css('left',(left*i)+unit);
++ }
++ }
++
++ for (var i=0;i<tabs.length;i++){
++ // introduce a new scope (round brackets)
++ //otherwise i is retrieved from the current scope and will be always equal to tabs.length
++ //due to this loop
++ (function(tabIndex){
++ $(tabs[i]).click(function(){
++ return tabClicked(tabIndex);
++ });
++ })(i);
++ }
++
++ this.setRoundBorder(tabs,'5px','5px',[0,1]);
++
++ if(!(selIndex)){
++ selIndex = 0;
++ }
++ $(tabs[selIndex]).trigger("click");
++ },
++
++ selectMarkerTab: function(){
++ $('#tab_markers').trigger("click");
++ },
++ //set cross browser round borders.
++ //elements: the html element or elements (jQuery syntax)
++ //hRadius the horizontal radius, or the horizontal vertical radius if the latter is omitted (see below)
++ //vRadius OPTIONAL the vertical radius. If missing, it defaults to hRadius
++ //angles: OTPIONAL. An array object of the corner indices where to apply radius. Indices are
++ // considered clockwise starting from the top left corner,ie:
++ // 0=topleft, 1 topright, 2 bottomright, 3 bottomleft
++ // If missing, it defaults to [0,1,2,3] (all indices)
++ setRoundBorder: function(elements, hRadius, vRadius, whichAngles){
++ if(!(vRadius)){
++ vRadius = hRadius;
++ }
++ var cssVal = hRadius+' '+vRadius;
++ if(!(whichAngles)){
++ whichAngles = [0,1,2,3];
++ }
++ $(elements).each(function(){
++ var element = $(this);
++ for(var i=0; i<whichAngles.length; i++){
++ var keys=[];
++ if(whichAngles[i]===0){
++ keys=['-webkit-border-top-left-radius','moz-border-radius-topleft','border-top-left-radius'];
++ }else if(whichAngles[i]===1){
++ keys=['-webkit-border-top-right-radius','moz-border-radius-topright','border-top-right-radius'];
++ }else if(whichAngles[i]===2){
++ keys=['-webkit-border-bottom-right-radius','moz-border-radius-bottomright','border-bottom-right-radius'];
++ }else if(whichAngles[i]===3){
++ keys=['-webkit-border-bottom-left-radius','moz-border-radius-bottomleft','border-bottom-left-radius'];
++ }
++ if(keys){
++ for(var j=0; j<keys.length; j++){
++ element.css(keys[j],cssVal);
++ }
++ }
++ // element.css('-webkit-border-top-left-radius',hRadius+' '+vRadius);
++ // element.css('moz-border-radius-topleft',hRadius+' '+vRadius);
++ // element.css('border-top-left-radius',hRadius+' '+vRadius);
++ }
++ });
++
++ }
++
++
++ }
++
++ $N.notifyScriptLoad();
++
++});