//write stylesheet document.write(''); //write channel viewer conatiner document.write('
'); var cvp = { 'errorMessage' : false, //with draw the error message instead of contents if not set to false 'params' : { 'color' : '#055b75', 'radius' : '0px', 'height' : '275px', 'width' : '200px' }, 'dom' : {}, //struct to hold channel view dom elements 'sliderClicked' : false, //on mouse move, if set to true, will measure vertical distance for scrollbar 'mouseY' : 0, //mouseY when slider was clicked 'sliderY' : 0, // 'json' : {}, //cvp JSON 'buildError' : false, //prevents the styles from being redrawn if set to true 'totalChannelItems' : 0, 'buildChannels' : function(json){ var channelContainer, missing; //make sure the JSON for the lobby is has required nodes missing = cvp.arrayDiff(['channels','users'],cvp.arrayKeys(json)); if(missing.length > 0){ throw 'Channel view protocol JSON is invalid for channel. Missing '+(missing.join(',')); } channelContainer = cvp.buildElement('div','cv-channel-container'); if(json.channels.length || json.users.length){ cvp.totalChannelItems += parseInt(json.channels.length); cvp.totalChannelItems += parseInt(json.users.length); cvp.dom.channelContainer.push(channelContainer); for(var i = 0; i < json.channels.length; i++){ var channel = json.channels[i]; missing = cvp.arrayDiff(['channels','users','name'],cvp.arrayKeys(channel)); if(missing.length > 0){ throw 'Channel view protocol JSON is invalid for channel. Missing '+(missing.join(',')); } var hasChildren = (channel.channels.length > 0) || (channel.users.length > 0); var cvChannel = cvp.buildElement('div','cv-channel'); var cvIconArrow = cvp.buildElement('span','cv-icon cv-icon-arrow cv-icon-arrow-'+(hasChildren ? 'down' : 'right')); cvIconArrow.onclick = cvp.toggleCollapse; cvChannel.appendChild(cvIconArrow); var cvIconChannel = cvp.buildElement('span','cv-icon cv-icon-channel'); var cvLabelChannel = cvp.buildElement('span','cv-label cv-label-channel'); cvChannel.appendChild(cvIconChannel); cvChannel.appendChild(cvLabelChannel); cvLabelChannel.appendChild(document.createTextNode(channel.name)); var moreChannels = cvp.buildChannels(channel); if(moreChannels){ cvChannel.appendChild(moreChannels); } channelContainer.appendChild(cvChannel); } for(var i = 0; i < json.users.length; i++){ var user = json.users[i]; if(user.name == undefined){ throw 'Channel view protocol JSON is invalid for user. Missing '+(missing.join(',')); } var cvUser = cvp.buildElement('div','cv-user'); var cvIconUser = cvp.buildElement('span','cv-icon cv-icon-user'); var cvLabelUser = cvp.buildElement('span','cv-label cv-label-user'); cvUser.appendChild(cvIconUser); cvUser.appendChild(cvLabelUser); if(user.onlinesecs){ cvLabelUser.setAttribute('title','Seconds Online: '+user.onlinesecs+'s'); } cvLabelUser.appendChild(document.createTextNode(user.name)); channelContainer.appendChild(cvUser); } return channelContainer; } }, 'buildElement' : function(element,className){ var newElement = document.createElement(element); newElement.setAttribute("class",className); newElement.className = className; return newElement; }, 'draw' :function(){ //wrapper cvp.dom.cv = document.getElementById('cv'); if(cvp.dom.cv == undefined){ throw "Unable to draw cv wrapper"; } if(cvp.dom.cv.firstChild){ while(cvp.dom.cv.firstChild){ cvp.dom.cv.removeChild(cvp.dom.cv.childNodes[0]); } } //header cvp.dom.header = cvp.buildElement('div','cv-header'); cvp.dom.headerLeft = cvp.buildElement('div','cv-header-left'); cvp.dom.headerCenter = cvp.buildElement('div','cv-header-center'); cvp.dom.headerRight = cvp.buildElement('div','cv-header-right'); cvp.dom.headerMumble = cvp.buildElement('a','cv-header-mumble'); cvp.dom.headerMumble.setAttribute('href','http://www.mumble.com'); cvp.dom.header.appendChild(cvp.dom.headerLeft); cvp.dom.header.appendChild(cvp.dom.headerCenter); cvp.dom.header.appendChild(cvp.dom.headerRight); cvp.dom.header.appendChild(cvp.dom.headerMumble); //cv contents cvp.dom.contents = cvp.buildElement('div','cv-contents'); cvp.dom.contentsLeft = cvp.buildElement('div','cv-contents-left'); cvp.dom.contentsCenter = cvp.buildElement('div','cv-contents-center'); cvp.dom.contentsRight = cvp.buildElement('div','cv-contents-right'); cvp.dom.contents.appendChild(cvp.dom.contentsLeft); cvp.dom.contents.appendChild(cvp.dom.contentsCenter); cvp.dom.contents.appendChild(cvp.dom.contentsRight); cvp.dom.lobby = cvp.buildElement('div','cv-lobby'); cvp.dom.contentsCenter.appendChild(cvp.dom.lobby); //cv footer cvp.dom.footer = cvp.buildElement('div','cv-footer'); cvp.dom.footerLeft = cvp.buildElement('div','cv-footer-left'); cvp.dom.footerCenter = cvp.buildElement('div','cv-footer-center'); cvp.dom.footerRight = cvp.buildElement('div','cv-footer-right'); cvp.dom.footerMumble = cvp.buildElement('a','cv-footer-mumble'); cvp.dom.footerMumble.setAttribute('href','http://www.mumble.com'); cvp.dom.footer.appendChild(cvp.dom.footerLeft); cvp.dom.footer.appendChild(cvp.dom.footerCenter); cvp.dom.footer.appendChild(cvp.dom.footerRight); cvp.dom.footer.appendChild(cvp.dom.footerMumble); cvp.dom.footerButtonContainer = cvp.buildElement('div','cv-footer-button-container'); cvp.dom.footerButton = cvp.buildElement('a','cv-footer-button'); cvp.dom.footerButtonContainer.appendChild(cvp.dom.footerButton); cvp.dom.footerButton.appendChild(document.createTextNode('Connect')); cvp.dom.footerButton.title = 'You will need Mumble installed on your computer'; cvp.dom.footerButton.setAttribute('href',cvp.json.x_connecturl); cvp.dom.footer.appendChild(cvp.dom.footerButtonContainer); //scrollbar cvp.dom.scroller = cvp.buildElement('div','cv-scroll'); cvp.dom.slider = cvp.buildElement('div','cv-scroll-slider'); cvp.dom.slider.style.top = '0px'; cvp.dom.slider.onmousedown = cvp.startDrag; cvp.dom.scrollButtonTop = cvp.buildElement('div','cv-scroll-button-top'); cvp.dom.scrollButtonBottom = cvp.buildElement('div','cv-scroll-button-button'); cvp.dom.scroller.appendChild(cvp.dom.slider); cvp.dom.scroller.appendChild(cvp.dom.scrollButtonTop); cvp.dom.scroller.appendChild(cvp.dom.scrollButtonBottom); cvp.dom.contentsCenter.appendChild(cvp.dom.scroller); cvp.dom.scroller.onmouseup = cvp.stopDrag; cvp.dom.scroller.onmousemove = cvp.drag; cvp.dom.cv.appendChild(cvp.dom.header); cvp.dom.cv.appendChild(cvp.dom.contents); cvp.dom.cv.appendChild(cvp.dom.footer); //if there's an error message, draw the error if(cvp.errorMessage){ cvp.error(cvp.errorMessage); } //if the json is valid else if(cvp.json){ cvp.buildContents(); try{ cvp.buildContents(); } catch(ex){ cvp.error(ex); } } }, 'error' : function(message){ if(cvp.dom.contentsCenter.firstChild){ while(cvp.dom.contentsCenter.firstChild){ cvp.dom.contentsCenter.removeChild(cvp.dom.contentsCenter.childNodes[0]); } } cvp.dom.error = cvp.buildElement('div','cv-error'); cvp.dom.error.appendChild(document.createTextNode(message)); cvp.dom.contentsCenter.appendChild(cvp.dom.error); cvp.params.height = 'auto'; cvp.applyStyles(); cvp.dom.contents.style.height = ''; }, 'buildContents' : function(){ var missing = cvp.arrayDiff(['name','root','x_connecturl'],cvp.arrayKeys(cvp.json)); if(missing.length > 0){ throw 'Channel view protocol JSON is invalid. Missing '+(missing.join(',')); } if(cvp.dom.lobby.firstChild){ while(cvp.dom.lobby.firstChild){ cvp.dom.lobby.removeChild(cvp.dom.lobby.childNodes[0]); } } //server name cvp.dom.serverName = cvp.buildElement('a','cv-server-name'); cvp.dom.serverName.setAttribute('href',cvp.json.x_connecturl); cvp.dom.serverName.setAttribute('title','Click to Connect'); cvp.dom.serverName.appendChild(document.createTextNode(cvp.json.name)); cvp.dom.channelContainer = []; cvp.dom.lobby.appendChild(cvp.dom.serverName); //only build the channels if you have users and channels (a completely empty server will cause errors) if(cvp.json.root.channels.length || cvp.json.root.users.length){ cvp.totalChannelItems += parseInt(cvp.json.root.users.length); cvp.totalChannelItems += parseInt(cvp.json.root.channels.length); var channels = cvp.buildChannels(cvp.json.root); cvp.dom.lobby.appendChild(channels); } if(cvp.totalChannelItems == 0){ var divEmptyServer = cvp.buildElement('div','cv-empty-server'); divEmptyServer.appendChild(document.createTextNode('No users connected')); cvp.dom.lobby.appendChild(divEmptyServer); } cvp.applyStyles(); }, 'applyStyles' : function(){ if(cvp.buildError){ return false; } cvp.dom.cv.setAttribute('style','height: '+cvp.params.height+'; width: '+cvp.params.width+'; background-color: '+cvp.params.color+'; -moz-border-radius: '+cvp.params.radius+'; -webkit-border-radius: '+cvp.params.radius+'; border-radius: '+cvp.params.radius+';'); var height = (cvp.dom.cv.offsetHeight - cvp.dom.header.offsetHeight - cvp.dom.footer.offsetHeight); cvp.dom.contents.style.height = height+'px'; cvp.dom.headerLeft.setAttribute('style','-moz-border-radius-topleft: '+cvp.params.radius+'; -webkit-border-top-left-radius: '+cvp.params.radius+'; border-top-left-radius: '+cvp.params.radius+';'); cvp.dom.headerRight.setAttribute('style','-moz-border-radius-topright: '+cvp.params.radius+'; -webkit-border-top-right-radius: '+cvp.params.radius+'; border-top-right-radius: '+cvp.params.radius+';'); cvp.dom.footerLeft.setAttribute('style','-moz-border-radius-bottomleft: '+cvp.params.radius+'; -webkit-border-bottom-left-radius: '+cvp.params.radius+'; border-bottom-left-radius: '+cvp.params.radius+';'); cvp.dom.footerRight.setAttribute('style','-moz-border-radius-bottomright: '+cvp.params.radius+'; -webkit-border-bottom-right-radius: '+cvp.params.radius+'; border-bottom-right-radius: '+cvp.params.radius+';'); if(cvp.dom.scroller && cvp.dom.channelContainer[0] != undefined){ cvp.dom.scroller.style.display = cvp.dom.channelContainer && (cvp.dom.lobby.offsetHeight < cvp.dom.channelContainer[0].offsetHeight) ? 'block' : 'none'; } }, 'toggleCollapse' : function(e){ var item = e.target || e.srcElement; item.parentNode.className = (item.parentNode.className == 'cv-channel-close' ? 'cv-channel' : 'cv-channel-close'); item.className = (item.className == 'cv-icon cv-icon-arrow cv-icon-arrow-down' ? 'cv-icon cv-icon-arrow cv-icon-arrow-right' : 'cv-icon cv-icon-arrow cv-icon-arrow-down'); }, 'startDrag' : function(e){ //make ie play nice e = e || event; //prevent the default action, such as highlighting text if(e.preventDefault){ e.preventDefault(); } cvp.dom.sliderClicked = true; cvp.mouseY = e.clientY; cvp.dom.sliderY = cvp.dom.slider.offsetTop; return false; }, 'stopDrag' : function(e){ //make ie play nice e = e || event; //prevent the default action, such as highlighting text if(e.preventDefault){ e.preventDefault(); } cvp.dom.sliderClicked = false; return false; }, 'drag' : function(e){ //make ie play nice e = e || event; //prevent the default action, such as highlighting text if(e.preventDefault){ e.preventDefault(); } if(cvp.dom.sliderClicked){ var moveY, newSliderTop, percent; moveY = e.clientY - cvp.mouseY; newSliderTop = (cvp.dom.sliderY + moveY); if(newSliderTop < 0){ newSliderTop = 0; } maxTop = cvp.dom.scroller.offsetHeight - cvp.dom.slider.offsetHeight; if(newSliderTop + cvp.dom.slider.offsetHeight > cvp.dom.scroller.offsetHeight){ newSliderTop = maxTop; } percent = newSliderTop / maxTop; cvp.dom.slider.style.top = newSliderTop + 'px'; cvp.dom.lobby.scrollTop = percent * (cvp.dom.lobby.scrollHeight-cvp.dom.lobby.offsetHeight); } return false; }, 'arrayKeys' : function(options){ var keys = []; for(var key in options) { if(options.hasOwnProperty(key)) { //to be safe keys.push(key); } } return keys; }, 'arrayDiff' : function(a, b) { var seen = [], diff = []; for(var i = 0; i < b.length; i++){ seen[b[i]] = true; } for(var i = 0; i < a.length; i++){ if (!seen[a[i]]){ diff.push(a[i]); } } return diff; } } if (window.addEventListener){ window.addEventListener('load',cvp.draw,false); } else if(window.attachEvent) { window.attachEvent("onload",cvp.draw); } else{ window.onload = function (){ cvp.draw() }; }