App-SlideServer

 view release on metacpan or  search on metacpan

share/public/slides.js  view on Meta::CPAN

	this.cur_step= 0;
}
Slide.prototype.parseSteps= function(spec) {
	var show_list= (""+spec).split(',');
	for (var i= 0; i < show_list.length; i++) {
		show_list[i]= show_list[i].split(/-/);
		show_list[i][0]= parseInt(show_list[i][0]);
		if (show_list[i].length > 1)
			show_list[i][1]= parseInt(show_list[i][1]);
	}
	return show_list;
}
Slide.prototype.scaleTo= function(viewport_w, viewport_h) {
	var el_w= $(this.el).innerWidth();
	var el_h= $(this.el).innerHeight();
	var xscale= viewport_w / el_w;
	var yscale= viewport_h / el_h;
	var ypad= parseInt((viewport_h - el_h)/2)+'px';
	// console.log('xscale',xscale,'yscale',yscale,'viewport_w',viewport_w,'el_w',el_w,'viewport_h',viewport_h,'el_h',el_h,'ypad',ypad);
	// Example:
	// 50x10 inside 100x60, xscale=2, yscale=6, pad h with 40, 20 top 20 bottom 
	var scale= (xscale < yscale)? xscale : yscale;
	$(this.el).css('margin', ypad+' 0').css('transform', 'scale('+scale+','+scale+')');
}
Slide.prototype.top= function() { return $(this.el).offset().top }
Slide.prototype.show= function(show) { show? $(this.el).show() : $(this.el).hide(); return this }
Slide.prototype.hide= function() { return this.show(false) }

function _num_is_in_ranges(num, ranges) {
	if (ranges)
		for (var i= 0; i < ranges.length; i++)
			if (num >= ranges[i][0] && (ranges[i].length == 1 || num <= ranges[i][1]))
				return true;
	return false;
}
Slide.prototype.showStep= function(step_num, view_mode) {
	var self= this;
	if (step_num < 0) step_num= this.max_step + 1 + step_num;
	if (step_num < 0) step_num= 0;
	this.steps.each(function() {
		var step= $(this);
		// If a step is not visible, behavior depends on whether we are the presenter
		// and whether the element is temporary.  Non-temporary elements need to remain
		// in the document flow so that the layout of the rest doesn't jump around.
		// But temporary have to be removed from the layout so that they don't occupy
		// space.  Meanwhile the presenter gets to see all hidden elements.
		if (_num_is_in_ranges(step_num, self.parseSteps(this.dataset.step)))
			step.css('visibility','visible').css('position','relative').css('opacity',1);
		else {
			if (view_mode == 'presenter')
				step.css('visibility','visible').css('opacity', .3);
			else
				step.css('visibility','hidden');
			if (step.hasClass('temporary-step'))
				step.css('position','absolute');
		}
	});
	this.cur_step= step_num;
}

function escape_html(unsafe) {
  return (''+unsafe)
    .replaceAll('&', "&amp;")
    .replaceAll('<', "&lt;")
    .replaceAll('>', "&gt;")
    .replaceAll('"', "&quot;")
    .replaceAll("'", "&#039;");
}

window.slides= {
	config: {},
	slides: [],
	cur_slide: null,
	roles: {},
	sharedState: {},
	
	init: function(config) {
		var self= this
		if (!config)
			config= self.config
		if (!config.websocket_url)
			config.websocket_url= 'slidelink.io'
		if (!config.mode)
			config.mode= 'obs';
		if (config.code_highlight === undefined && window.hljs)
			config.code_highlight= function(el){ window.hljs.highlightElement(el) }
		if (config.mode == 'presenter' && (config.key == null || config.key.length == 0))
			config.key= null;//TODO: getCookieVal('access_key');
		self.config= config
		// Generic button and checkbox handlers
		this._button_dispatch= function(ev) {
			try {
				self[this.dataset.method].call(self, ev);
			} catch (e) {
				console.log('Calling slides.'+this.dataset.method+': ', e);
			}
		};
		this._enter_dispatch= function(ev) {
			if (ev.keyCode == 13) // Enter
				try {
					self[this.dataset.enter_method].call(self, ev);
				} catch (e) {
					console.log('Calling slides.'+this.dataset.enter_method+': ', e);
				}
		};
		this._ckbox_dispatch= function(ev) {
			try {
				self[this.dataset.method].call(self, this.checked, ev);
			} catch(e) {
				console.log('Calling slides.'+this.dataset.method+' : ', e);
			}
		};
		this.slides= this.buildSlidesArray();
		this.resizeSlides();
		window.addEventListener('resize', function(event) { self.resizeSlides() }, true);
		self._build_ui()
		this._show_slide(1,1);
		// The presenter needs a chance to enter the key before connecting
		if (config.mode == 'presenter' && config.key == null) {
			self.togglemenu();
			self.root.find('.status-actions .login').show();

share/public/slides.js  view on Meta::CPAN

		this.root.find('.status-actions .lead input').prop('checked', enable);
		this._update_status();
	},
	enableFollow: function(enable, ev) {
		if (enable) {
			this.following= true;
			this.enableLead(false);
			this.goToLeaderSlide();
		} else {
			this.following= false;
		}
		this.root.find('.status-actions .follow input').prop('checked', enable);
		this._update_status();
	},
	enableNavigate: function(enable, ev) {
		if (enable) {
			this._build_nav_ui();
			this.nav_ui.show();
		} else {
			if (this.nav_ui)
				this.nav_ui.hide();
		}
		this.root.find('.status-actions .navigate input').prop('checked', enable);
	},
	enableNotes: function(enable, ev) {
		if (enable) {
			this._build_presenternotes_ui();
			this.presenternotes_ui.show();
		} else {
			if (this._presenternotes_ui)
				this.presenternotes_ui.hide();
		}
		// re-render current slide
		this.showNotes= !!enable;
		this._show_slide(this.cur_slide, this.getSlide(this.cur_slide).cur_step);
	},
	_set_conn_note: function(content, duration) {
		var self= this;
		if (this._conn_note) {
			var prev= this._conn_note
			delete this._conn_note
			prev.fadeOut(500, function(){ prev.remove() })
		}
		var next= $(content);
		this.root.find('.slides-notify').append(next);
		this._conn_note= next;
		if (duration)
			window.setTimeout(function(){
				if (self._conn_note == next) this._conn_note= null
				next.fadeOut(500, function(){ next.remove() });
			}, duration);
		this._update_status();
	},
	_update_status: function() {
		var status= this.root.find('.status');
		status.empty();
		if (this.ws) {
			var server= ''+this.ws.url;
			server= server.replace(/^wss?:\/\/([^:\/]+).*/, '$1');
			if (this.ws.readyState == 0)
				status.append('<li class="connecting">Connecting to <span class="host">'+escape_html(server)+'</span></li>');
			else if (this.ws.readyState == 1)
				status.append('<li class="connected">Connected to <span class="host">'+escape_html(server)+'</span></li>');
			else
				status.append('<li class="disconnected">Not connected</li>');
		}
		if (this.following)
			status.append('<li class="follow">Following presenter</li>');
		else if (this.leading)
			status.append('<li class="broadcast">Broadcasting</li>');
		if (this.cur_slide && this.slides && this.slides.length)
			status.append('<li class="pos">Slide <b>'+this.cur_slide+'</b> of <b>'+this.slides.length+'</b></li>');
	},
	_handle_connect: function(event, url, mode) {
		this.root.find('.reconnect-btn').hide()
		this._set_conn_note('<p>Connected</p>', 1500)
		if (this.config.mode == 'obs')
			this.enableFollow(true);
	},
	_handle_disconnect: function(event) {
		this.root.find('.reconnect-btn').show()
		this._set_conn_note('<p>Lost connection</p>')
		delete this.ws;
	},
	_handle_ws_event: function(event) {
		//console.log('ws event: ', event);
		if (event.state) {
			this.sharedState= event.state;
			if (this.following)
				this.goToLeaderSlide();
		}
		if (event.roles) {
			this.roles= {};
			for (var i=0; i < event.roles.length; i++)
				this.roles[event.roles[i]]= 1;
			if (this.roles.lead) {
				this.enableFollow(false);
				this.root.find('.status-actions .follow').show();
				this.root.find('.status-actions .lead').show();
				this.root.find('.status-actions .notes').show();
			} else {
				// initial state for non-lead is to follow
				this.enableFollow(true);
			}
			if (this.roles.navigate || this.roles.lead) {
				this.root.find('.status-actions .navigate').show();
			}
		}
		if (event.key_incorrect) {
			// TODO: create a password entry form on the sidebar and a login sequence
			// that happens over the websocket.
			this._set_conn_note('<p>Incorrect Key</p>');
			this.config.key= null;
			this.root.find('.status-actions > .login').show();
			this.root.find('.reconnect-btn').show()
		}
		if (event.page_changed) {
			window.location.reload();
		}
		if (event.slides_changed) {
			console.log('slides_changed', event.slides_changed);
			for (var i=0; i < event.slides_changed.length; i++)
				this.replaceSlide(event.slides_changed[i].idx+1, $(event.slides_changed[i].html)[0]);



( run in 2.044 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )