<commit_before>function load_draft_list(page_num,page_size,callback){
	$.getJSON(config['web_root']+"Home/Draft/list_drafts",
		{page_num:page_num,page_size:page_size},function(data){
		var $table = $("#west table")
		// do some clean jobs
		$table.html('')
		$("#go_previous,#go_next").addClass("disabled")
		// create new elements
		for(var i=0;i<data.drafts.length;i++){
			var $del = $("").addClass("btn btn-danger btn-xs pull-right remove_draft")
			.append($("").addClass("glyphicon glyphicon-remove"))
			.attr("data-id",data.drafts[i]['id'])
			var $td = $("")
			var $tr = $("
").attr("data-id",data.drafts[i]['id'])
			$td.text(data.drafts[i]['title'])
			$td.append($del)
			$tr.append($td)
			$table.append($tr)
		}
		draft_list_events_binding($table,data)
		var total_page = Math.ceil(data['total']/page_size)
		$("#current_page").text(data['current'])
		$("#total_page").text(total_page)
		if(data['current']>1){
			$("#go_previous").removeClass("disabled").attr("data-page",data['current']-1)
		}
		if(data['current']<total_page){
			$("#go_next").removeClass("disabled").attr("data-page",data['current']+1)
		}
		if(callback){
			callback(data)
		}
	})
}
function draft_list_events_binding($table,data){
	$table.find("a.remove_draft").click(function(){
		var c = confirm("Are you sure to delete?")
		if(!c){
			return false;
		}
		var id = $(this).attr("data-id")
		$.getJSON(config['web_root']+"Home/Draft/delete_draft",
			{id:id},function(data){
			if(data.result==="ok"){
				$table.find("tr[data-id="+id+"]").remove()
				if(id===$("#update_title").attr("data-id")){
					clear_draft();
				}
			}else{
				alert(data.info)
			}
		})
		return false;
	})
	$table.find("tr").click(function(){
		var id = $(this).attr("data-id")
		load_draft(id)
	})
}
function load_draft(id,callback){
	$.getJSON(config['web_root']+"Home/Draft/load_draft",
	{id:id},function(data){
		$("#title").val(data['title'])
		$("#create_time").text(data['create_time'])
		$("#last_save_time").text(data['last_save_time'])
		$("#update_title").attr("data-id",id)
		editor.setValue(data['content'])
		var result = parse(data['content'])
		$("#ptitle").text(result['title'])
		re_load_thumb(get_thumb_name(data.title)+'.jpg')
		load_images(id)
		load_attachments(id)
		if(callback){
			callback(data)
		}
	})
	function get_thumb_name(title){
		var first_word = title.split("-")[3]
		var begin_idx = title.indexOf(first_word)
		return title.substring(begin_idx)
	}
}
function re_load_thumb(title){
	$("#thumb").attr("src",config['thumb_dir']+title)
}
function parse(content){
	var head = content.split("---")[1]
	var lines = head.split("\n")
	var result = {}
	for(var i=0;i<lines.length;i++){
		var titleIdx = lines[i].indexOf("title:")
		if(titleIdx>=0){
			result['title'] = lines[i].substring(titleIdx+6).trim().split('"')[1]
			continue
		}
		titleIdx = lines[i].indexOf("date:")
		if(titleIdx>=0){
			result['date'] = new Date(
				Date.parse(
					lines[i].substring(titleIdx+5).trim()
					)
				).toDateString()
			continue
		}
		titleIdx = lines[i].indexOf("categories:")
		if(titleIdx>=0){
			result['tags'] = lines[i].substring(titleIdx+11).trim().split(' ')
			continue
		}
	}
	return result
}
function load_images(id,callback){
	$.getJSON(config['web_root']+"Home/Image/list_images",{id:id},
		function(data){
			var $table = $("#east-center table")
			// do some clean jobs
			$table.html('').attr("data-id",id)
			// create new elements
			for(var i=0;i<data.length;i++){
				var $del = $("").addClass("btn btn-danger btn-xs pull-right remove_image")
				.append($("").addClass("glyphicon glyphicon-remove"))
				.attr("data-filename",data[i]['filename'])
				var $td = $("")
				var $tr = $("
").attr("data-filename",data[i]['filename'])
				$td.append(
					$("").text(data[i]['filename'])
					.attr("href",config['inset_dir']+data[i]['filename'])
					.attr("target","_blank")
					)
				$td.append($del)
				$tr.append($td)
				$table.append($tr)
			}
			image_list_events_binding($table,data)
		})
}
function image_list_events_binding($table,data){
	$table.find("a.remove_image").click(function(){
		var c = confirm("Are you sure to delete?")
		if(!c){
			return;
		}
		var filename = $(this).attr("data-filename")
		$.getJSON(config['web_root']+"Home/Image/delete_image",
			{filename:filename},function(data){
			if(data.result==="ok"){
				$table.find("tr[data-filename='"+filename+"']").remove()
			}else{
				alert(data.info)
			}
		})
	})
}
function load_attachments(id,callback){
	$.getJSON(config['web_root']+"Home/Attachment/list_attachments",{id:id},
		function(data){
			var $table = $("#east-south table")
			// do some clean jobs
			$table.html('').attr("data-id",id)
			// create new elements
			for(var i=0;i<data.length;i++){
				var $del = $("").addClass("btn btn-danger btn-xs pull-right remove_attachment")
				.append($("").addClass("glyphicon glyphicon-remove"))
				.attr("data-filename",data[i]['filename'])
				var $td = $("")
				var $tr = $("
").attr("data-filename",data[i]['filename'])
				$td.append(
					$("").text(data[i]['filename'])
					.attr("href",config['attachment_dir']+data[i]['filename'])
					.attr("target","_blank")
					)
				$td.append($del)
				$tr.append($td)
				$table.append($tr)
			}
			attachment_list_events_binding($table,data)
		})
}
function attachment_list_events_binding($table,data){
	$table.find("a.remove_attachment").click(function(){
		var c = confirm("Are you sure to delete?")
		if(!c){
			return;
		}
		var filename = $(this).attr("data-filename")
		$.getJSON(config['web_root']+"Home/Attachment/delete_attachment",
			{filename:filename},function(data){
			if(data.result==="ok"){
				$table.find("tr[data-filename='"+filename+"']").remove()
			}else{
				alert(data.info)
			}
		})
	})
}
function clear_draft(){
	$("#east-center table,#east-south table,#update_title").removeAttr("data-id")
	$("#east-center table,#east-south table").html('')
	$("#thumb").attr("src",'')
	$("#title").val('')
	$("#create_time,#last_save_time,#ptitle").text('')
	editor.setValue('')
}

function bind_file_upload_event($file_input,callback){
	var $progress_bar = $file_input.parent().siblings(".progress").find(".progress-bar")
	up = new uploader($file_input.get(0), {
		url:$file_input.attr("data-url"),
		autoUpload:true,
		before:function(){
			$progress_bar.css("width",'0')
			if(!$("#update_title").attr("data-id")){
				alert("Please select a draft.")
				return false
			}
			$progress_bar.text($file_input.val().split(/(\\|\/)/g).pop())
			return true;
		},
		get_data:function(){
			return {id:$("#update_title").attr("data-id")}
		},
		progress:function(ev){
			$progress_bar.css("width",Math.floor((ev.loaded/ev.total)*100)+'%')
		},
		error:function(ev){ alert(ev); },
		success:function(data){
			if(data['result']==='ok'){
				alert('Upload successfully!')
				if(callback){
					callback(data)
				}
			}else{
				alert("Upload error:"+data['info'])
			}
		}
	});
}
function compile(mixed_content){
	var splited = mixed_content.split("---")
	var head = splited[1]
	var content = splited[2]
	var content_lines = content.split('\n')
	for(var i=0;i<content_lines.length;i++){
		var line = content_lines[i]
		if(line.indexOf('{%')!=-1&&line.indexOf('%}')!=-1&&line.indexOf('endhighlight')!=-1){
			content_lines[i] = "

"
			continue;
		}
		if(line.indexOf('{%')!=-1&&line.indexOf('%}')!=-1&&line.indexOf('highlight')!=-1){
			var lang = line.split('highlight')[1].split('%}')[0].trim()
			content_lines[i] = "

"
			continue;
		}
	}
	var parsed_content = content_lines.join('\n').replace(/{{ site.images }}\//g,config['inset_dir'])
	var result = parse(mixed_content)
	return {parsed_content:parsed_content,title:result['title'],date:result['date'],tags:result['tags']}
}
$(function(){
	$("#go_previous,#go_next").click(function(){
		if($(this).hasClass("disabled")){
			return;
		}
		load_draft_list($(this).attr("data-page"),config['page_size'])
		return false;
	})
	$("#thumb").error(function(){
		$(this).attr("src",$(this).attr("data-holder"))
	})
	load_draft_list(1,10)
	editor = CodeMirror.fromTextArea(document.getElementById("content"), {
	    mode: 'markdown',
	    lineNumbers: true,
	    theme: "default",
	    lineWrapping: true,
	    extraKeys: {"Enter": "newlineAndIndentContinueMarkdownList"}
	  });
	$("#update_title").click(function(){
		var id = $(this).attr("data-id")
		if(!id){
			return
		}
		$.getJSON(config["web_root"]+"Home/Draft/rename_draft",
			{id:id,new_title:$("#title").val()},
			function(data){
				if(data['result'] === 'ok'){
					alert("Rename draft ok")
					load_draft_list($("#current_page").text(),config['page_size'])
				}else{
					alert(data.info)
				}
			})
	})
	//test
	bind_file_upload_event($("#thumb_upload"),function(data){
		re_load_thumb(data.filename)
	})
	bind_file_upload_event($("#inset_upload"),function(data){
		load_images($("#update_title").attr("data-id"))
	})
	bind_file_upload_event($("#attachment_upload"),function(data){
		load_attachments($("#update_title").attr("data-id"))
	})
	$("#save-btn").click(function(){
		var id=$("#update_title").attr('data-id')
		if(!id){
			alert("Please select a draft")
			return false
		}
		$.post(config['web_root']+"Home/Draft/update_draft",{id:id,content:editor.getValue()},function(data){
			if(data['aff']===1){
				alert("Save draft ok.")
			}else{
				alert(data['error'])
			}
		},'json')
		return false
	})
	var now = new Date()
	$("#new-title-input").val(
		now.getFullYear()+"-"+(now.getMonth()+1)+"-"+now.getDate()
		+"-new-draft-title-here")
	$("#create_draft_btn").click(function(){
		$.getJSON(config['web_root']+"Home/Draft/create_draft",
			{title:$("#new-title-input").val()},
			function(data){
				if(data['aff']){
					clear_draft()
					load_draft_list(1,config['page_size'])
				}
			})
		return false;
	})
	$("#preview-btn").click(function(){
		var id=$("#update_title").attr('data-id')
		if(!id){
			alert("Please select a draft")
			return false
		}
		var mixed_content = editor.getValue();
		var converter = new Markdown.Converter();
		try{
			var result = compile(mixed_content)
			var html = converter.makeHtml(result['parsed_content']);
			var $div = $("
").html(html)
			var $codes = $div.find(".highlight pre code")
			for(var i=0;i<$codes.length;i++){
				var $code = $($codes[i])
				var first = $code.text().substr(0,1)
				if(first === '\n'){
					$code.text($code.text().substr(1))
				}
			}
			result['html'] = $div.html()
			console.log(html);
			console.log(result['date'])
			console.log(result['title'])
			console.log(JSON.stringify(result['tags']))
			window.parent.postMessage(result, '*');
		}catch(error){
			alert(JSON.stringify(error))
		}
		return false;
	})
})<commit_msg>escape html < > in  blocks<commit_after>function load_draft_list(page_num,page_size,callback){
	$.getJSON(config['web_root']+"Home/Draft/list_drafts",
		{page_num:page_num,page_size:page_size},function(data){
		var $table = $("#west table")
		// do some clean jobs
		$table.html('')
		$("#go_previous,#go_next").addClass("disabled")
		// create new elements
		for(var i=0;i<data.drafts.length;i++){
			var $del = $("").addClass("btn btn-danger btn-xs pull-right remove_draft")
			.append($("").addClass("glyphicon glyphicon-remove"))
			.attr("data-id",data.drafts[i]['id'])
			var $td = $("")
			var $tr = $("
").attr("data-id",data.drafts[i]['id'])
			$td.text(data.drafts[i]['title'])
			$td.append($del)
			$tr.append($td)
			$table.append($tr)
		}
		draft_list_events_binding($table,data)
		var total_page = Math.ceil(data['total']/page_size)
		$("#current_page").text(data['current'])
		$("#total_page").text(total_page)
		if(data['current']>1){
			$("#go_previous").removeClass("disabled").attr("data-page",data['current']-1)
		}
		if(data['current']<total_page){
			$("#go_next").removeClass("disabled").attr("data-page",data['current']+1)
		}
		if(callback){
			callback(data)
		}
	})
}
function draft_list_events_binding($table,data){
	$table.find("a.remove_draft").click(function(){
		var c = confirm("Are you sure to delete?")
		if(!c){
			return false;
		}
		var id = $(this).attr("data-id")
		$.getJSON(config['web_root']+"Home/Draft/delete_draft",
			{id:id},function(data){
			if(data.result==="ok"){
				$table.find("tr[data-id="+id+"]").remove()
				if(id===$("#update_title").attr("data-id")){
					clear_draft();
				}
			}else{
				alert(data.info)
			}
		})
		return false;
	})
	$table.find("tr").click(function(){
		var id = $(this).attr("data-id")
		load_draft(id)
	})
}
function load_draft(id,callback){
	$.getJSON(config['web_root']+"Home/Draft/load_draft",
	{id:id},function(data){
		$("#title").val(data['title'])
		$("#create_time").text(data['create_time'])
		$("#last_save_time").text(data['last_save_time'])
		$("#update_title").attr("data-id",id)
		editor.setValue(data['content'])
		var result = parse(data['content'])
		$("#ptitle").text(result['title'])
		re_load_thumb(get_thumb_name(data.title)+'.jpg')
		load_images(id)
		load_attachments(id)
		if(callback){
			callback(data)
		}
	})
	function get_thumb_name(title){
		var first_word = title.split("-")[3]
		var begin_idx = title.indexOf(first_word)
		return title.substring(begin_idx)
	}
}
function re_load_thumb(title){
	$("#thumb").attr("src",config['thumb_dir']+title)
}
function parse(content){
	var head = content.split("---")[1]
	var lines = head.split("\n")
	var result = {}
	for(var i=0;i<lines.length;i++){
		var titleIdx = lines[i].indexOf("title:")
		if(titleIdx>=0){
			result['title'] = lines[i].substring(titleIdx+6).trim().split('"')[1]
			continue
		}
		titleIdx = lines[i].indexOf("date:")
		if(titleIdx>=0){
			result['date'] = new Date(
				Date.parse(
					lines[i].substring(titleIdx+5).trim()
					)
				).toDateString()
			continue
		}
		titleIdx = lines[i].indexOf("categories:")
		if(titleIdx>=0){
			result['tags'] = lines[i].substring(titleIdx+11).trim().split(' ')
			continue
		}
	}
	return result
}
function load_images(id,callback){
	$.getJSON(config['web_root']+"Home/Image/list_images",{id:id},
		function(data){
			var $table = $("#east-center table")
			// do some clean jobs
			$table.html('').attr("data-id",id)
			// create new elements
			for(var i=0;i<data.length;i++){
				var $del = $("").addClass("btn btn-danger btn-xs pull-right remove_image")
				.append($("").addClass("glyphicon glyphicon-remove"))
				.attr("data-filename",data[i]['filename'])
				var $td = $("")
				var $tr = $("
").attr("data-filename",data[i]['filename'])
				$td.append(
					$("").text(data[i]['filename'])
					.attr("href",config['inset_dir']+data[i]['filename'])
					.attr("target","_blank")
					)
				$td.append($del)
				$tr.append($td)
				$table.append($tr)
			}
			image_list_events_binding($table,data)
		})
}
function image_list_events_binding($table,data){
	$table.find("a.remove_image").click(function(){
		var c = confirm("Are you sure to delete?")
		if(!c){
			return;
		}
		var filename = $(this).attr("data-filename")
		$.getJSON(config['web_root']+"Home/Image/delete_image",
			{filename:filename},function(data){
			if(data.result==="ok"){
				$table.find("tr[data-filename='"+filename+"']").remove()
			}else{
				alert(data.info)
			}
		})
	})
}
function load_attachments(id,callback){
	$.getJSON(config['web_root']+"Home/Attachment/list_attachments",{id:id},
		function(data){
			var $table = $("#east-south table")
			// do some clean jobs
			$table.html('').attr("data-id",id)
			// create new elements
			for(var i=0;i<data.length;i++){
				var $del = $("").addClass("btn btn-danger btn-xs pull-right remove_attachment")
				.append($("").addClass("glyphicon glyphicon-remove"))
				.attr("data-filename",data[i]['filename'])
				var $td = $("")
				var $tr = $("
").attr("data-filename",data[i]['filename'])
				$td.append(
					$("").text(data[i]['filename'])
					.attr("href",config['attachment_dir']+data[i]['filename'])
					.attr("target","_blank")
					)
				$td.append($del)
				$tr.append($td)
				$table.append($tr)
			}
			attachment_list_events_binding($table,data)
		})
}
function attachment_list_events_binding($table,data){
	$table.find("a.remove_attachment").click(function(){
		var c = confirm("Are you sure to delete?")
		if(!c){
			return;
		}
		var filename = $(this).attr("data-filename")
		$.getJSON(config['web_root']+"Home/Attachment/delete_attachment",
			{filename:filename},function(data){
			if(data.result==="ok"){
				$table.find("tr[data-filename='"+filename+"']").remove()
			}else{
				alert(data.info)
			}
		})
	})
}
function clear_draft(){
	$("#east-center table,#east-south table,#update_title").removeAttr("data-id")
	$("#east-center table,#east-south table").html('')
	$("#thumb").attr("src",'')
	$("#title").val('')
	$("#create_time,#last_save_time,#ptitle").text('')
	editor.setValue('')
}

function bind_file_upload_event($file_input,callback){
	var $progress_bar = $file_input.parent().siblings(".progress").find(".progress-bar")
	up = new uploader($file_input.get(0), {
		url:$file_input.attr("data-url"),
		autoUpload:true,
		before:function(){
			$progress_bar.css("width",'0')
			if(!$("#update_title").attr("data-id")){
				alert("Please select a draft.")
				return false
			}
			$progress_bar.text($file_input.val().split(/(\\|\/)/g).pop())
			return true;
		},
		get_data:function(){
			return {id:$("#update_title").attr("data-id")}
		},
		progress:function(ev){
			$progress_bar.css("width",Math.floor((ev.loaded/ev.total)*100)+'%')
		},
		error:function(ev){ alert(ev); },
		success:function(data){
			if(data['result']==='ok'){
				alert('Upload successfully!')
				if(callback){
					callback(data)
				}
			}else{
				alert("Upload error:"+data['info'])
			}
		}
	});
}
function compile(mixed_content){
	var splited = mixed_content.split("---")
	var head = splited[1]
	var content = splited[2]
	var content_lines = content.split('\n')
	var is_code_line=false
	for(var i=0;i<content_lines.length;i++){
		var line = content_lines[i]
		if(line.indexOf('{%')!=-1&&line.indexOf('%}')!=-1&&line.indexOf('endhighlight')!=-1){
			content_lines[i] = "

"
			is_code_line=false
			continue;
		}
		if(line.indexOf('{%')!=-1&&line.indexOf('%}')!=-1&&line.indexOf('highlight')!=-1){
			var lang = line.split('highlight')[1].split('%}')[0].trim()
			content_lines[i] = "

"
			is_code_line=true
			continue;
		}
		if(is_code_line){
			content_lines[i] = content_lines[i].replace(/</g,"<").replace(/>/g,">")
		}
	}
	var parsed_content = content_lines.join('\n').replace(/{{ site.images }}\//g,config['inset_dir'])
	var result = parse(mixed_content)
	return {parsed_content:parsed_content,title:result['title'],date:result['date'],tags:result['tags']}
}
$(function(){
	$("#go_previous,#go_next").click(function(){
		if($(this).hasClass("disabled")){
			return;
		}
		load_draft_list($(this).attr("data-page"),config['page_size'])
		return false;
	})
	$("#thumb").error(function(){
		$(this).attr("src",$(this).attr("data-holder"))
	})
	load_draft_list(1,10)
	editor = CodeMirror.fromTextArea(document.getElementById("content"), {
	    mode: 'markdown',
	    lineNumbers: true,
	    theme: "default",
	    lineWrapping: true,
	    extraKeys: {"Enter": "newlineAndIndentContinueMarkdownList"}
	  });
	$("#update_title").click(function(){
		var id = $(this).attr("data-id")
		if(!id){
			return
		}
		$.getJSON(config["web_root"]+"Home/Draft/rename_draft",
			{id:id,new_title:$("#title").val()},
			function(data){
				if(data['result'] === 'ok'){
					alert("Rename draft ok")
					load_draft_list($("#current_page").text(),config['page_size'])
				}else{
					alert(data.info)
				}
			})
	})
	//test
	bind_file_upload_event($("#thumb_upload"),function(data){
		re_load_thumb(data.filename)
	})
	bind_file_upload_event($("#inset_upload"),function(data){
		load_images($("#update_title").attr("data-id"))
	})
	bind_file_upload_event($("#attachment_upload"),function(data){
		load_attachments($("#update_title").attr("data-id"))
	})
	$("#save-btn").click(function(){
		var id=$("#update_title").attr('data-id')
		if(!id){
			alert("Please select a draft")
			return false
		}
		$.post(config['web_root']+"Home/Draft/update_draft",{id:id,content:editor.getValue()},function(data){
			if(data['aff']===1){
				alert("Save draft ok.")
			}else{
				alert(data['error'])
			}
		},'json')
		return false
	})
	var now = new Date()
	$("#new-title-input").val(
		now.getFullYear()+"-"+(now.getMonth()+1)+"-"+now.getDate()
		+"-new-draft-title-here")
	$("#create_draft_btn").click(function(){
		$.getJSON(config['web_root']+"Home/Draft/create_draft",
			{title:$("#new-title-input").val()},
			function(data){
				if(data['aff']){
					clear_draft()
					load_draft_list(1,config['page_size'])
				}
			})
		return false;
	})
	$("#preview-btn").click(function(){
		var id=$("#update_title").attr('data-id')
		if(!id){
			alert("Please select a draft")
			return false
		}
		var mixed_content = editor.getValue();
		var converter = new Markdown.Converter();
		try{
			var result = compile(mixed_content)
			var html = converter.makeHtml(result['parsed_content']);
			//html.replace(/unformatedcode>\n/g,'>')
			result['html'] = html.replace(/unformatedcode>\n/g,'>')
			console.log(html);
			console.log(result['date'])
			console.log(result['title'])
			console.log(JSON.stringify(result['tags']))
			window.parent.postMessage(result, '*');
		}catch(error){
			alert(JSON.stringify(error))
		}
		return false;
	})
})<|endoftext|>


<commit_before>const router = require('express').Router()

const contactController = require('./controllers/details')
const contactEditController = require('./controllers/edit')
const contactArchiveController = require('./controllers/archive')
const contactInteractionController = require('./controllers/interactions')

router.get('/:contactId', contactController.getCommon, contactController.getDetails)

router
  .route('/create')
  .get(contactEditController.editDetails)
  .post(contactEditController.postDetails)

router
  .route('/:contactId/edit')
  .get(contactController.getCommon, contactEditController.editDetails)
  .post(contactEditController.postDetails)

router.post('/:id/archive', contactArchiveController.archiveContact)
router.get('/:id/unarchive', contactArchiveController.unarchiveContact)

router.get('/:contactId/interactions', contactController.getCommon, contactInteractionController.getInteractions)

module.exports = router
<commit_msg>Allow the router to process create/ before attemtpting :contactId<commit_after>const router = require('express').Router()

const contactController = require('./controllers/details')
const contactEditController = require('./controllers/edit')
const contactArchiveController = require('./controllers/archive')
const contactInteractionController = require('./controllers/interactions')

router
  .route('/create')
  .get(contactEditController.editDetails)
  .post(contactEditController.postDetails)

router.get('/:contactId', contactController.getCommon, contactController.getDetails)

router
  .route('/:contactId/edit')
  .get(contactController.getCommon, contactEditController.editDetails)
  .post(contactEditController.postDetails)

router.post('/:id/archive', contactArchiveController.archiveContact)
router.get('/:id/unarchive', contactArchiveController.unarchiveContact)

router.get('/:contactId/interactions', contactController.getCommon, contactInteractionController.getInteractions)

module.exports = router
<|endoftext|>


<commit_before>angular.module('mrlapp.service.WebGuiGui', []).controller('WebGuiGuiCtrl', ['$scope', '$log', 'mrl', function($scope, $log, mrl) {
    $log.info('WebGuiGuiCtrl')
    var _self = this
    var msg = this.msg
    $scope.mrl = mrl
    $scope.panel = mrl.getPanel('runtime')

    $scope.activePanel = 'settings'

     // $scope.displayImages =  mrl.getDisplayImages()

    // GOOD TEMPLATE TO FOLLOW
    this.updateState = function(service) {
        $scope.service = service
        $scope.port = service.port
    }

    $scope.setActive = function(val) {
        var index = array.indexOf(5);
        if (index > -1) {
            array.splice(index, 1);
        }
    }

    //$scope.saveP
    this.onMsg = function(inMsg) {
        let data = inMsg.data[0]
        switch (inMsg.method) {
        case 'display':
            console.info('display - ' + data)
            mrl.display(data)
            $scope.$apply()
            break
        case 'onState':
            _self.updateState(data)
            $scope.$apply()
            break
        case 'onShowAll':
            // panelSvc.showAll(inMsg.data[0]) TODO - fix
            break
        case 'onShow':
            // panelSvc.show(inMsg.data[0]) TODO - fix
            break
        case 'onHide':
            // panelSvc.hide(inMsg.data[0]) TODO - fix
            break
        case 'onPanel':
            // panelSvc.setPanel(inMsg.data[0]) TODO - fix
            break
        default:
            $log.error("ERROR - unhandled method " + $scope.name + " " + inMsg.method)
            break
        }
    }

    //mrl.subscribe($scope.service.name, 'pulse')
    msg.subscribe('publishShowAll')
    // msg.subscribe('publishHideAll') FIXME ? not symmetric
    msg.subscribe('publishHide')
    msg.subscribe('publishShow')
    msg.subscribe('publishSet')
    msg.subscribe('publishPanel')
    msg.send("publishPanels")
    // msg.subscribe('loadPanels')
    msg.subscribe(this)
}
])
<commit_msg>removed all homepage stuff<commit_after>angular.module('mrlapp.service.WebGuiGui', []).controller('WebGuiGuiCtrl', ['$scope', '$log', 'mrl', function($scope, $log, mrl) {
    $log.info('WebGuiGuiCtrl')
    var _self = this
    var msg = this.msg
    $scope.mrl = mrl

     // $scope.displayImages =  mrl.getDisplayImages()

    // GOOD TEMPLATE TO FOLLOW
    this.updateState = function(service) {
        $scope.service = service
        $scope.port = service.port
    }

    // init scope variables
    $scope.pulseData = ''
    //$scope.saveP
    this.onMsg = function(inMsg) {
        let data = inMsg.data[0]
        switch (inMsg.method) {
        case 'display':
            console.info('display - ' + data)
            mrl.display(data)
            $scope.$apply()
            break
        case 'onState':
            _self.updateState(data)
            $scope.$apply()
            break
        case 'onShowAll':
            // panelSvc.showAll(inMsg.data[0]) TODO - fix
            break
        case 'onShow':
            // panelSvc.show(inMsg.data[0]) TODO - fix
            break
        case 'onHide':
            // panelSvc.hide(inMsg.data[0]) TODO - fix
            break
        case 'onPanel':
            // panelSvc.setPanel(inMsg.data[0]) TODO - fix
            break
        default:
            $log.error("ERROR - unhandled method " + $scope.name + " " + inMsg.method)
            break
        }
    }

    // $scope.panel = mrl.getPanel($scope.service.name)
	$scope.panel = mrl.getPanel('runtime')

    //mrl.subscribe($scope.service.name, 'pulse')
    msg.subscribe('publishShowAll')
    // msg.subscribe('publishHideAll') FIXME ? not symmetric
    msg.subscribe('publishHide')
    msg.subscribe('publishShow')
    msg.subscribe('publishSet')
    msg.subscribe('publishPanel')
    msg.send("publishPanels")
    // msg.subscribe('loadPanels')
    msg.subscribe(this)
}
])

<|endoftext|>


<commit_before>/*//===
	API
*///===

var fs = require("fs"),
	express = require("express"),
	qs = require("querystring"),
	mysql = require("mysql")

var inArray = function(n, h){
	var f = false;
	for(var x in h)
		if(h[x] == n)
			f = true;
	return f;
}

var md5 = function($str){
	var cpto = require('crypto').createHash('md5')
	cpto.update($str);
	return cpto.digest('hex');
}

app.post("/API*", function(req, res) {
	var $data = req.url.split("/").splice(2, 10),
	    $method = $data.shift().toLowerCase(),
	    $postdata = "",
	    $session = req.session

    req.on('data', function(bit){
    	$postdata += bit;
    });

    req.on('end', function(){
    	try{
    		var $post = JSON.parse($postdata);
		    switch($method){
		    	default:
		    		throw new Error("No Method Selected.");
		    	break;

		    	case "connect":
		    		if(!('db' in $post) || typeof $post.db != 'object')
		    			throw new Error("Bad db Object");

		    		if($post.name == "")
		    			throw new Error("Bad Connection Name");

		    		var $con = mysql.createConnection($post.db)

		    		$con.connect(function(err){
		    			if(err){
		    				res.json({
		    					status : false,
		    					reason : err.code
		    				})
		    				return;
		    			}
		    			$session.connections.push($post.db)

		    			res.json({
		    				status : true
		    			})

		    			$con.destroy();
		    		})

		    	break;

		    	case "query":
		    		var $connection = parseInt($post.connection);

		    		if(isNaN($connection) || !($connection in $session.connections))
		    			throw new Error("Bad Connection ID");

		    		if($post.sql == "")
		    			throw new Error("Bad SQL");

		    		var $con = mysql.createConnection($session.connections[$connection]);

		    		$con.connect(function(err){
		    			if(err){
		    				res.json({
		    					status : false,
		    					reason : err.code
		    				})
		    				return;
		    			}

		    			var queries = $post.sql.split(';');

		    			for(var x in queries)
		    				if(queries[x] != '')
		    					var $query = $con.query(queries[x]);

		    			$query.on('result', function(row){
		    				res.write(JSON.stringify(row) + "\r\n");
		    				if(config.slow){
			    				$con.pause();
			    				setTimeout(function(){
			    					$con.resume();
			    				}, 500)
		    				}
		    			})

		    			$query.on('error', function(err){
		    				res.json(err);
		    			})

		    			$query.on('end', function(){
		    				res.end();
		    				$con.destroy();
		    			})

		    		})

		    	break;

		    	case "update":
		    		if('selected' in $post)
		    			$session.selected = $post.selected;

		    		if('database' in $post)
		    			$session.database = $post.database;

		    		if('tab' in $post)
		    			$session.tab = $post.tab;

		    		if('tabs' in $post)
		    			$session.tabs = $post.tabs;

		    		var o = {
		    			status : true,
		    			connections : $session.connections
		    		};

		    		if('selected' in $session)
		    			o.selected = $session.selected

		    		if('database' in $session)
		    			o.database = $session.database

		    		if('tab' in $session)
		    			o.tab = $session.tab

		    		if('tabs' in $session)
		    			o.tabs = $session.tabs

		    		res.json(o)
		    	break;

		    	case "terminate":
		    		req.endSession();
		    		res.json({
		    			status : true
		    		})
		    	break;
		    }
    	} catch($e){
    		res.json({
		    	status : false,
		    	reason : $e.message
		    })
    	}
    })

});<commit_msg>Adds Token login<commit_after>/*//===
	API
*///===

var fs = require("fs"),
	express = require("express"),
	qs = require("querystring"),
	mysql = require("mysql"),
	tokens = {}

var inArray = function(n, h){
	var f = false;
	for(var x in h)
		if(h[x] == n)
			f = true;
	return f;
}

var md5 = function($str){
	var cpto = require('crypto').createHash('md5')
	cpto.update($str);
	return cpto.digest('hex');
}

app.get("/Login/*", function(req, res, next){
	var $token = req.url.split('/').pop();
	if(!($token in tokens)){
		next();
		return;
	}
	tokens[$token].name = 'Local Database';
	req.session.connections.push(tokens[$token]);
	res.redirect('/');
});

app.post("/API*", function(req, res) {
	var $data = req.url.split("/").splice(2, 10),
	    $method = $data.shift().toLowerCase(),
	    $postdata = "",
	    $session = req.session

    req.on('data', function(bit){
    	$postdata += bit;
    });

    req.on('end', function(){
    	try{
    		var $post = JSON.parse($postdata);
		    switch($method){
		    	default:
		    		throw new Error("No Method Selected.");
		    	break;

		    	case "createtoken":
		    		try{
		    			if(!('db' in $post))
		    				throw new Error("DB not found in post");

		    			if(typeof $post.db != 'object')
		    				throw new Error("DB Not Object");

			    		do var $token = md5(Math.random() * Math.random() + 'nodeDBMTokenFGT');
			    		while($token in tokens)

			    		tokens[$token] = $post.db;

			    		res.json({
			    			status : true,
			    			token : $token
			    		})
		    		} catch($e){
		    			res.json({
		    				status : false,
		    				reason : $e.message
		    			})
		    		}
		    	break;

		    	case "connect":
		    		if(!('db' in $post) || typeof $post.db != 'object')
		    			throw new Error("Bad db Object");

		    		if($post.name == "")
		    			throw new Error("Bad Connection Name");

		    		var $con = mysql.createConnection($post.db)

		    		$con.connect(function(err){
		    			if(err){
		    				res.json({
		    					status : false,
		    					reason : err.code
		    				})
		    				return;
		    			}
		    			$session.connections.push($post.db)

		    			res.json({
		    				status : true
		    			})

		    			$con.destroy();
		    		})

		    	break;

		    	case "query":
		    		var $connection = parseInt($post.connection);

		    		if(isNaN($connection) || !($connection in $session.connections))
		    			throw new Error("Bad Connection ID");

		    		if($post.sql == "")
		    			throw new Error("Bad SQL");

		    		var $con = mysql.createConnection($session.connections[$connection]);

		    		$con.connect(function(err){
		    			if(err){
		    				res.json({
		    					status : false,
		    					reason : err.code
		    				})
		    				return;
		    			}

		    			var queries = $post.sql.split(';');

		    			for(var x in queries)
		    				if(queries[x] != '')
		    					var $query = $con.query(queries[x]);

		    			$query.on('result', function(row){
		    				res.write(JSON.stringify(row) + "\r\n");
		    				if(config.slow){
			    				$con.pause();
			    				setTimeout(function(){
			    					$con.resume();
			    				}, 500)
		    				}
		    			})

		    			$query.on('error', function(err){
		    				res.json(err);
		    			})

		    			$query.on('end', function(){
		    				res.end();
		    				$con.destroy();
		    			})

		    		})

		    	break;

		    	case "update":
		    		if('selected' in $post)
		    			$session.selected = $post.selected;

		    		if('database' in $post)
		    			$session.database = $post.database;

		    		if('tab' in $post)
		    			$session.tab = $post.tab;

		    		if('tabs' in $post)
		    			$session.tabs = $post.tabs;

		    		var o = {
		    			status : true,
		    			connections : $session.connections
		    		};

		    		if('selected' in $session)
		    			o.selected = $session.selected

		    		if('database' in $session)
		    			o.database = $session.database

		    		if('tab' in $session)
		    			o.tab = $session.tab

		    		if('tabs' in $session)
		    			o.tabs = $session.tabs

		    		res.json(o)
		    	break;

		    	case "terminate":
		    		req.endSession();
		    		res.json({
		    			status : true
		    		})
		    	break;
		    }
    	} catch($e){
    		res.json({
		    	status : false,
		    	reason : $e.message
		    })
    	}
    })

});<|endoftext|>


<commit_before>// A generalisation of the search-and-sort functionality that underlies searching-and-sorting modules

import _ from 'lodash';
import React from 'react';
import PropTypes from 'prop-types';
import Route from 'react-router-dom/Route';
import { withRouter } from 'react-router';
// eslint-disable-next-line import/no-unresolved
import { stripesShape } from '@folio/stripes-core/src/Stripes';
import queryString from 'query-string';
import FilterGroups, { initialFilterState, onChangeFilter as commonChangeFilter } from '@folio/stripes-components/lib/FilterGroups';
import FilterPaneSearch from '@folio/stripes-components/lib/FilterPaneSearch';
import Pane from '@folio/stripes-components/lib/Pane';
import Paneset from '@folio/stripes-components/lib/Paneset';
import PaneMenu from '@folio/stripes-components/lib/PaneMenu';
import Layer from '@folio/stripes-components/lib/Layer';
import Button from '@folio/stripes-components/lib/Button';
import MultiColumnList from '@folio/stripes-components/lib/MultiColumnList';
import SRStatus from '@folio/stripes-components/lib/SRStatus';
import IfPermission from '@folio/stripes-components/lib/IfPermission';
import Notes from '@folio/stripes-smart-components/lib/Notes';

class SearchAndSort extends React.Component {
  static contextTypes = {
    stripes: stripesShape.isRequired,
  };

  static propTypes = {
    // parameter properties provided by caller
    moduleName: PropTypes.string.isRequired, // machine-readable, for HTML ids and translation keys
    moduleTitle: PropTypes.string.isRequired, // human-readable
    objectName: PropTypes.string.isRequired, // machine-readable
    initialPath: PropTypes.string.isRequired,
    filterConfig: PropTypes.arrayOf(
      PropTypes.shape({
        label: PropTypes.string.isRequired,
        name: PropTypes.string.isRequired,
        cql: PropTypes.string.isRequired,
        values: PropTypes.arrayOf(
          PropTypes.oneOfType([
            PropTypes.string,
            PropTypes.shape({
              name: PropTypes.string.isRequired,
              cql: PropTypes.string.isRequired,
            }),
          ]),
        ).isRequired,
      }),
    ).isRequired,
    initialResultCount: PropTypes.number.isRequired,
    resultCountIncrement: PropTypes.number.isRequired,
    viewRecordComponent: PropTypes.func.isRequired,
    editRecordComponent: PropTypes.func.isRequired, // eslint-disable-line react/no-unused-prop-types
    newRecordInitialValues: PropTypes.object.isRequired,
    visibleColumns: PropTypes.arrayOf(
      PropTypes.string,
    ),
    columnMapping: PropTypes.object,
    resultsFormatter: PropTypes.shape({}),
    onSelectRow: PropTypes.func,
    massageNewRecord: PropTypes.func,
    onCreate: PropTypes.func.isRequired,
    finishedResourceName: PropTypes.string,
    viewRecordPerms: PropTypes.string.isRequired,
    newRecordPerms: PropTypes.string.isRequired,
    disableRecordCreation: PropTypes.bool,
    parentResources: PropTypes.shape({
      query: PropTypes.shape({
        filters: PropTypes.string.isRequired,
      }),
      resultCount: PropTypes.number,
      records: PropTypes.shape({
        hasLoaded: PropTypes.bool.isRequired,
        other: PropTypes.shape({
          totalRecords: PropTypes.number.isRequired,
        }),
        isPending: PropTypes.bool.isPending,
        successfulMutations: PropTypes.arrayOf(
          PropTypes.shape({
            record: PropTypes.shape({
              id: PropTypes.string.isRequired,
            }).isRequired,
          }),
        ),
      }),
    }).isRequired,
    parentMutator: PropTypes.shape({
      resultCount: PropTypes.shape({
        replace: PropTypes.func.isRequired,
      }).isRequired,
      query: PropTypes.shape({
        update: PropTypes.func.isRequired,
        replace: PropTypes.func.isRequired,
      }),
    }).isRequired,

    // react-route properties provided by withRouter
    location: PropTypes.shape({
      pathname: PropTypes.string.isRequired,
      search: PropTypes.string.isRequired,
    }).isRequired,
    history: PropTypes.shape({
      push: PropTypes.func.isRequired,
    }).isRequired,
    match: PropTypes.shape({
      path: PropTypes.string.isRequired,
    }).isRequired,
  };

  static manifest = Object.freeze({
    notes: {
      type: 'okapi',
      path: 'notes',
      records: 'notes',
      clear: false,
      GET: {
        params: {
          query: 'link=:{id}',
        },
      },
    },
  });

  constructor(props, context) {
    super(props, context);

    const queryResource = props.parentResources.query || {};

    let initiallySelected = {};
    const match = this.props.location.pathname.match('/[^/]*/view/');
    if (match && match.index === 0) {
      const id = /view\/(.*)$/.exec(this.props.location.pathname)[1];
      initiallySelected = { id };
    }

    this.state = {
      filters: { uninitialized: true },
      selectedItem: initiallySelected,
      searchTerm: queryResource.query || '',
      sortOrder: queryResource.sort || '',
      showNotesPane: false,
    };

    this.transitionToParams = values => this.props.parentMutator.query.update(values);
    this.commonChangeFilter = commonChangeFilter.bind(this);
    this.toggleNotes = this.toggleNotes.bind(this);
    this.anchoredRowFormatter = this.anchoredRowFormatter.bind(this);

    this.connectedViewRecord = context.stripes.connect(props.viewRecordComponent);
    this.connectedNotes = context.stripes.connect(Notes);
    this.SRStatus = null;

    const logger = context.stripes.logger;
    this.log = logger.log.bind(logger);
  }

  componentWillReceiveProps(nextProps) {
    const finishedResourceName = this.props.finishedResourceName || 'records';
    const recordResource = this.props.parentResources.records;
    const finishedResource = this.props.parentResources[finishedResourceName];

    // If the nominated mutation has finished, select the newly created record
    if (finishedResource) {
      const finishedResourceNextSM = nextProps.parentResources[finishedResourceName].successfulMutations;
      const sm = nextProps.parentResources.records.successfulMutations;
      if (finishedResourceNextSM.length > finishedResource.successfulMutations.length)
        this.onSelectRow(undefined, { id: sm[0].record.id });
    }

    // If a search that was pending is now complete, notify the screen-reader
    if (recordResource && recordResource.isPending && !nextProps.parentResources.records.isPending) {
      this.log('event', 'new search-result');
      const resultAmount = nextProps.parentResources.records.other.totalRecords;
      this.SRStatus.sendMessage(`Search returned ${resultAmount} result${resultAmount !== 1 ? 's' : ''}`);
    }

    if (this.state.filters.uninitialized && this.props.parentResources.query) {
      this.setState({
        filters: initialFilterState(this.props.filterConfig, this.props.parentResources.query.filters),
      });
    }
  }

  onChangeSearch = (e) => {
    const query = e.target.value;
    this.props.parentMutator.resultCount.replace(this.props.initialResultCount);
    this.setState({ searchTerm: query });
    this.performSearch(query);
  }

  // eslint-disable-next-line react/sort-comp
  performSearch = _.debounce((query) => {
    this.log('action', `searched for '${query}'`);
    this.transitionToParams({ search: query });
  }, 350);

  onClearSearch = () => {
    this.log('action', 'cleared search');
    // Should we need to set state? Shouldn't the state get set from the new URL?
    this.setState({
      searchTerm: '',
      sortOrder: 'Name',
      filters: { 'active.Active': true },
    });
    this.transitionToParams({
      search: '',
      sort: 'Name',
      filters: 'active.Active',
    });
  }

  onSort = (e, meta) => {
    const newOrder = meta.alias;
    const oldOrder = this.state.sortOrder || '';

    const orders = oldOrder ? oldOrder.split(',') : [];
    if (orders[0] && newOrder === orders[0].replace(/^-/, '')) {
      orders[0] = `-${orders[0]}`.replace(/^--/, '');
    } else {
      orders.unshift(newOrder);
    }

    const sortOrder = orders.slice(0, 2).join(',');
    this.log('action', `sorted by ${sortOrder}`);
    this.setState({ sortOrder });
    this.transitionToParams({ sort: sortOrder });
  }

  onChangeFilter = (e) => {
    this.props.parentMutator.resultCount.replace(this.props.initialResultCount);
    this.commonChangeFilter(e);
  }

  onNeedMore = () => {
    this.props.parentMutator.resultCount.replace(this.props.parentResources.resultCount + this.props.resultCountIncrement);
  }

  onSelectRow = this.props.onSelectRow ? this.props.onSelectRow : (e, meta) => {
    this.log('action', `clicked ${meta.id}, selected record =`, meta);
    this.setState({ selectedItem: meta });
    this.props.history.push(this.getRowURL(meta.id));
  }

  addNewRecord = (e) => {
    if (e) e.preventDefault();
    this.log('action', 'clicked "add new record"');
    this.transitionToParams({ layer: 'create' });
  }

  closeNewRecord = (e) => {
    if (e) e.preventDefault();
    this.log('action', 'clicked "close new record"');

    const p = this.props;
    const parsed = queryString.parse(p.location.search || '');
    _.unset(parsed, 'layer');
    p.history.push(`${p.location.pathname}?${queryString.stringify(parsed)}`);
  }

  toggleNotes() {
    this.setState((curState) => {
      const show = !curState.showNotesPane;
      return {
        showNotesPane: show,
      };
    });
  }

  collapseDetails = () => {
    this.setState({
      selectedItem: {},
    });
    this.props.history.push(`${this.props.match.path}${this.props.location.search}`);
  }

  updateFilters = (filters) => { // provided for onChangeFilter
    this.transitionToParams({ filters: Object.keys(filters).filter(key => filters[key]).join(',') });
  }

  getRowURL(id) {
    const first = this.props.location.pathname.split('/')[1];
    return `/${first}/view/${id}${this.props.location.search}`;
  }

  // custom row formatter to wrap rows in anchor tags.
  anchoredRowFormatter(
    { rowIndex,
      rowClass,
      rowData,
      cells,
      rowProps,
      labelStrings,
    },
  ) {
    return (
      <a
        href={this.getRowURL(rowData.id)} key={`row-${rowIndex}`}
        aria-label={labelStrings && labelStrings.join('...')}
        role="listitem"
        className={rowClass}
        {...rowProps}
      >
        {cells}

    );
  }

  createRecord(record) {
    if (this.props.massageNewRecord) this.props.massageNewRecord(record);
    this.props.onCreate(record);
  }

  render() {
    const { parentResources, filterConfig, moduleName, newRecordPerms, viewRecordPerms, objectName } = this.props;
    const urlQuery = queryString.parse(this.props.location.search || '');
    const stripes = this.context.stripes;
    const objectNameUC = _.upperFirst(objectName);
    const records = (parentResources.records || {}).records || [];
    const resource = parentResources.records;

    /* searchHeader is a 'custom pane header' */
    const searchHeader = (<FilterPaneSearch
      searchFieldId={`input-${objectName}-search`}
      onChange={this.onChangeSearch}
      onClear={this.onClearSearch}
      resultsList={this.resultsList}
      value={this.state.searchTerm}
      placeholder={stripes.intl.formatMessage({ id: `ui-${moduleName}.search` })}
    />);

    const newRecordButton = (
      <IfPermission perm={newRecordPerms}>
        <PaneMenu>
          <Button id={`clickable-new${objectName}`} title={`Add New ${objectNameUC}`} onClick={this.addNewRecord} buttonStyle="primary paneHeaderNewButton">+ New</Button>
        </PaneMenu>
      </IfPermission>
    );

    const detailsPane = (
      stripes.hasPerm(viewRecordPerms) ?
        (<Route
          path={`${this.props.match.path}/view/:id`}
          render={props => <this.connectedViewRecord
            stripes={stripes}
            paneWidth="44%"
            parentResources={this.props.parentResources}
            parentMutator={this.props.parentMutator}
            onClose={this.collapseDetails}
            notesToggle={this.toggleNotes}
            {...props}
          />}
        />) :
        (

Permission Error

Sorry - your permissions do not allow access to this page.

));

    const maybeTerm = this.state.searchTerm ? ` for "${this.state.searchTerm}"` : '';
    const maybeSpelling = this.state.searchTerm ? 'spelling and ' : '';
    const count = resource && resource.hasLoaded ? resource.other.totalRecords : '';
    return (
      <Paneset>
        <SRStatus ref={(ref) => { this.SRStatus = ref; }} />
        {/* Filter Pane */}
        <Pane id="pane-filter" defaultWidth="16%" header={searchHeader}>
          <FilterGroups config={filterConfig} filters={this.state.filters} onChangeFilter={this.onChangeFilter} />
        </Pane>
        {/* Results Pane */}
        <Pane
          id="pane-results"
          defaultWidth="fill"
          paneTitle={

              {this.props.moduleTitle}

                {stripes.intl.formatMessage({ id: `ui-${moduleName}.resultCount` }, { count })}

          }
          lastMenu={!this.props.disableRecordCreation ? newRecordButton : null}
          noOverflow
        >
          <MultiColumnList
            id={`list-${this.props.moduleName}`}
            contentData={records}
            selectedRow={this.state.selectedItem}
            formatter={this.props.resultsFormatter}
            onRowClick={this.onSelectRow}
            onHeaderClick={this.onSort}
            onNeedMoreData={this.onNeedMore}
            visibleColumns={this.props.visibleColumns}
            sortOrder={this.state.sortOrder.replace(/^-/, '').replace(/,.*/, '')}
            sortDirection={this.state.sortOrder.startsWith('-') ? 'descending' : 'ascending'}
            isEmptyMessage={`No results found${maybeTerm}. Please check your ${maybeSpelling}filters.`}
            columnMapping={this.props.columnMapping}
            loading={resource ? resource.isPending : false}
            autosize
            virtualize
            ariaLabel={`${objectNameUC} search results`}
            rowFormatter={this.anchoredRowFormatter}
            containerRef={(ref) => { this.resultsList = ref; }}
          />
        </Pane>

        {detailsPane}
        <Layer isOpen={urlQuery.layer ? urlQuery.layer === 'create' : false} label={`Add New ${objectNameUC} Dialog`}>
          <this.props.editRecordComponent
            id={`${objectName}form-add${objectName}`}
            initialValues={this.props.newRecordInitialValues}
            onSubmit={record => this.createRecord(record)}
            onCancel={this.closeNewRecord}
            parentResources={this.props.parentResources}
            parentMutator={this.props.parentMutator}
          />
        </Layer>
        {
          this.state.showNotesPane &&
          <Route
            path={`${this.props.match.path}/view/:id`}
            render={props => <this.connectedNotes
              stripes={stripes}
              onToggle={this.toggleNotes}
              link={`${this.props.moduleName}/${props.match.params.id}`}
              {...props}
            />}
          />
          }
      </Paneset>
    );
  }
}

export default withRouter(SearchAndSort);
<commit_msg>Use this.transitionToParams({ _path }) for full-record view<commit_after>// A generalisation of the search-and-sort functionality that underlies searching-and-sorting modules

import _ from 'lodash';
import React from 'react';
import PropTypes from 'prop-types';
import Route from 'react-router-dom/Route';
import { withRouter } from 'react-router';
// eslint-disable-next-line import/no-unresolved
import { stripesShape } from '@folio/stripes-core/src/Stripes';
import queryString from 'query-string';
import FilterGroups, { initialFilterState, onChangeFilter as commonChangeFilter } from '@folio/stripes-components/lib/FilterGroups';
import FilterPaneSearch from '@folio/stripes-components/lib/FilterPaneSearch';
import Pane from '@folio/stripes-components/lib/Pane';
import Paneset from '@folio/stripes-components/lib/Paneset';
import PaneMenu from '@folio/stripes-components/lib/PaneMenu';
import Layer from '@folio/stripes-components/lib/Layer';
import Button from '@folio/stripes-components/lib/Button';
import MultiColumnList from '@folio/stripes-components/lib/MultiColumnList';
import SRStatus from '@folio/stripes-components/lib/SRStatus';
import IfPermission from '@folio/stripes-components/lib/IfPermission';
import Notes from '@folio/stripes-smart-components/lib/Notes';

class SearchAndSort extends React.Component {
  static contextTypes = {
    stripes: stripesShape.isRequired,
  };

  static propTypes = {
    // parameter properties provided by caller
    moduleName: PropTypes.string.isRequired, // machine-readable, for HTML ids and translation keys
    moduleTitle: PropTypes.string.isRequired, // human-readable
    objectName: PropTypes.string.isRequired, // machine-readable
    initialPath: PropTypes.string.isRequired,
    filterConfig: PropTypes.arrayOf(
      PropTypes.shape({
        label: PropTypes.string.isRequired,
        name: PropTypes.string.isRequired,
        cql: PropTypes.string.isRequired,
        values: PropTypes.arrayOf(
          PropTypes.oneOfType([
            PropTypes.string,
            PropTypes.shape({
              name: PropTypes.string.isRequired,
              cql: PropTypes.string.isRequired,
            }),
          ]),
        ).isRequired,
      }),
    ).isRequired,
    initialResultCount: PropTypes.number.isRequired,
    resultCountIncrement: PropTypes.number.isRequired,
    viewRecordComponent: PropTypes.func.isRequired,
    editRecordComponent: PropTypes.func.isRequired, // eslint-disable-line react/no-unused-prop-types
    newRecordInitialValues: PropTypes.object.isRequired,
    visibleColumns: PropTypes.arrayOf(
      PropTypes.string,
    ),
    columnMapping: PropTypes.object,
    resultsFormatter: PropTypes.shape({}),
    onSelectRow: PropTypes.func,
    massageNewRecord: PropTypes.func,
    onCreate: PropTypes.func.isRequired,
    finishedResourceName: PropTypes.string,
    viewRecordPerms: PropTypes.string.isRequired,
    newRecordPerms: PropTypes.string.isRequired,
    disableRecordCreation: PropTypes.bool,
    parentResources: PropTypes.shape({
      query: PropTypes.shape({
        filters: PropTypes.string.isRequired,
      }),
      resultCount: PropTypes.number,
      records: PropTypes.shape({
        hasLoaded: PropTypes.bool.isRequired,
        other: PropTypes.shape({
          totalRecords: PropTypes.number.isRequired,
        }),
        isPending: PropTypes.bool.isPending,
        successfulMutations: PropTypes.arrayOf(
          PropTypes.shape({
            record: PropTypes.shape({
              id: PropTypes.string.isRequired,
            }).isRequired,
          }),
        ),
      }),
    }).isRequired,
    parentMutator: PropTypes.shape({
      resultCount: PropTypes.shape({
        replace: PropTypes.func.isRequired,
      }).isRequired,
      query: PropTypes.shape({
        update: PropTypes.func.isRequired,
        replace: PropTypes.func.isRequired,
      }),
    }).isRequired,

    // react-route properties provided by withRouter
    location: PropTypes.shape({
      pathname: PropTypes.string.isRequired,
      search: PropTypes.string.isRequired,
    }).isRequired,
    history: PropTypes.shape({
      push: PropTypes.func.isRequired,
    }).isRequired,
    match: PropTypes.shape({
      path: PropTypes.string.isRequired,
    }).isRequired,
  };

  static manifest = Object.freeze({
    notes: {
      type: 'okapi',
      path: 'notes',
      records: 'notes',
      clear: false,
      GET: {
        params: {
          query: 'link=:{id}',
        },
      },
    },
  });

  constructor(props, context) {
    super(props, context);

    const queryResource = props.parentResources.query || {};

    let initiallySelected = {};
    const match = this.props.location.pathname.match('/[^/]*/view/');
    if (match && match.index === 0) {
      const id = /view\/(.*)$/.exec(this.props.location.pathname)[1];
      initiallySelected = { id };
    }

    this.state = {
      filters: { uninitialized: true },
      selectedItem: initiallySelected,
      searchTerm: queryResource.query || '',
      sortOrder: queryResource.sort || '',
      showNotesPane: false,
    };

    this.transitionToParams = values => this.props.parentMutator.query.update(values);
    this.commonChangeFilter = commonChangeFilter.bind(this);
    this.toggleNotes = this.toggleNotes.bind(this);
    this.anchoredRowFormatter = this.anchoredRowFormatter.bind(this);

    this.connectedViewRecord = context.stripes.connect(props.viewRecordComponent);
    this.connectedNotes = context.stripes.connect(Notes);
    this.SRStatus = null;

    const logger = context.stripes.logger;
    this.log = logger.log.bind(logger);
  }

  componentWillReceiveProps(nextProps) {
    const finishedResourceName = this.props.finishedResourceName || 'records';
    const recordResource = this.props.parentResources.records;
    const finishedResource = this.props.parentResources[finishedResourceName];

    // If the nominated mutation has finished, select the newly created record
    if (finishedResource) {
      const finishedResourceNextSM = nextProps.parentResources[finishedResourceName].successfulMutations;
      const sm = nextProps.parentResources.records.successfulMutations;
      if (finishedResourceNextSM.length > finishedResource.successfulMutations.length)
        this.onSelectRow(undefined, { id: sm[0].record.id });
    }

    // If a search that was pending is now complete, notify the screen-reader
    if (recordResource && recordResource.isPending && !nextProps.parentResources.records.isPending) {
      this.log('event', 'new search-result');
      const resultAmount = nextProps.parentResources.records.other.totalRecords;
      this.SRStatus.sendMessage(`Search returned ${resultAmount} result${resultAmount !== 1 ? 's' : ''}`);
    }

    if (this.state.filters.uninitialized && this.props.parentResources.query) {
      this.setState({
        filters: initialFilterState(this.props.filterConfig, this.props.parentResources.query.filters),
      });
    }
  }

  onChangeSearch = (e) => {
    const query = e.target.value;
    this.props.parentMutator.resultCount.replace(this.props.initialResultCount);
    this.setState({ searchTerm: query });
    this.performSearch(query);
  }

  // eslint-disable-next-line react/sort-comp
  performSearch = _.debounce((query) => {
    this.log('action', `searched for '${query}'`);
    this.transitionToParams({ search: query });
  }, 350);

  onClearSearch = () => {
    this.log('action', 'cleared search');
    // Should we need to set state? Shouldn't the state get set from the new URL?
    this.setState({
      searchTerm: '',
      sortOrder: 'Name',
      filters: { 'active.Active': true },
    });
    this.transitionToParams({
      search: '',
      sort: 'Name',
      filters: 'active.Active',
    });
  }

  onSort = (e, meta) => {
    const newOrder = meta.alias;
    const oldOrder = this.state.sortOrder || '';

    const orders = oldOrder ? oldOrder.split(',') : [];
    if (orders[0] && newOrder === orders[0].replace(/^-/, '')) {
      orders[0] = `-${orders[0]}`.replace(/^--/, '');
    } else {
      orders.unshift(newOrder);
    }

    const sortOrder = orders.slice(0, 2).join(',');
    this.log('action', `sorted by ${sortOrder}`);
    this.setState({ sortOrder });
    this.transitionToParams({ sort: sortOrder });
  }

  onChangeFilter = (e) => {
    this.props.parentMutator.resultCount.replace(this.props.initialResultCount);
    this.commonChangeFilter(e);
  }

  onNeedMore = () => {
    this.props.parentMutator.resultCount.replace(this.props.parentResources.resultCount + this.props.resultCountIncrement);
  }

  onSelectRow = this.props.onSelectRow ? this.props.onSelectRow : (e, meta) => {
    this.log('action', `clicked ${meta.id}, selected record =`, meta);
    this.setState({ selectedItem: meta });
    this.transitionToParams({ _path: `/users/view/${meta.id}` });
  }

  addNewRecord = (e) => {
    if (e) e.preventDefault();
    this.log('action', 'clicked "add new record"');
    this.transitionToParams({ layer: 'create' });
  }

  closeNewRecord = (e) => {
    if (e) e.preventDefault();
    this.log('action', 'clicked "close new record"');

    const p = this.props;
    const parsed = queryString.parse(p.location.search || '');
    _.unset(parsed, 'layer');
    p.history.push(`${p.location.pathname}?${queryString.stringify(parsed)}`);
  }

  toggleNotes() {
    this.setState((curState) => {
      const show = !curState.showNotesPane;
      return {
        showNotesPane: show,
      };
    });
  }

  collapseDetails = () => {
    this.setState({
      selectedItem: {},
    });
    this.props.history.push(`${this.props.match.path}${this.props.location.search}`);
  }

  updateFilters = (filters) => { // provided for onChangeFilter
    this.transitionToParams({ filters: Object.keys(filters).filter(key => filters[key]).join(',') });
  }

  getRowURL(id) {
    const first = this.props.location.pathname.split('/')[1];
    return `/${first}/view/${id}${this.props.location.search}`;
  }

  // custom row formatter to wrap rows in anchor tags.
  anchoredRowFormatter(
    { rowIndex,
      rowClass,
      rowData,
      cells,
      rowProps,
      labelStrings,
    },
  ) {
    return (
      <a
        href={this.getRowURL(rowData.id)} key={`row-${rowIndex}`}
        aria-label={labelStrings && labelStrings.join('...')}
        role="listitem"
        className={rowClass}
        {...rowProps}
      >
        {cells}

    );
  }

  createRecord(record) {
    if (this.props.massageNewRecord) this.props.massageNewRecord(record);
    this.props.onCreate(record);
  }

  render() {
    const { parentResources, filterConfig, moduleName, newRecordPerms, viewRecordPerms, objectName } = this.props;
    const urlQuery = queryString.parse(this.props.location.search || '');
    const stripes = this.context.stripes;
    const objectNameUC = _.upperFirst(objectName);
    const records = (parentResources.records || {}).records || [];
    const resource = parentResources.records;

    /* searchHeader is a 'custom pane header' */
    const searchHeader = (<FilterPaneSearch
      searchFieldId={`input-${objectName}-search`}
      onChange={this.onChangeSearch}
      onClear={this.onClearSearch}
      resultsList={this.resultsList}
      value={this.state.searchTerm}
      placeholder={stripes.intl.formatMessage({ id: `ui-${moduleName}.search` })}
    />);

    const newRecordButton = (
      <IfPermission perm={newRecordPerms}>
        <PaneMenu>
          <Button id={`clickable-new${objectName}`} title={`Add New ${objectNameUC}`} onClick={this.addNewRecord} buttonStyle="primary paneHeaderNewButton">+ New</Button>
        </PaneMenu>
      </IfPermission>
    );

    const detailsPane = (
      stripes.hasPerm(viewRecordPerms) ?
        (<Route
          path={`${this.props.match.path}/view/:id`}
          render={props => <this.connectedViewRecord
            stripes={stripes}
            paneWidth="44%"
            parentResources={this.props.parentResources}
            parentMutator={this.props.parentMutator}
            onClose={this.collapseDetails}
            notesToggle={this.toggleNotes}
            {...props}
          />}
        />) :
        (

Permission Error

Sorry - your permissions do not allow access to this page.

));

    const maybeTerm = this.state.searchTerm ? ` for "${this.state.searchTerm}"` : '';
    const maybeSpelling = this.state.searchTerm ? 'spelling and ' : '';
    const count = resource && resource.hasLoaded ? resource.other.totalRecords : '';
    return (
      <Paneset>
        <SRStatus ref={(ref) => { this.SRStatus = ref; }} />
        {/* Filter Pane */}
        <Pane id="pane-filter" defaultWidth="16%" header={searchHeader}>
          <FilterGroups config={filterConfig} filters={this.state.filters} onChangeFilter={this.onChangeFilter} />
        </Pane>
        {/* Results Pane */}
        <Pane
          id="pane-results"
          defaultWidth="fill"
          paneTitle={

              {this.props.moduleTitle}

                {stripes.intl.formatMessage({ id: `ui-${moduleName}.resultCount` }, { count })}

          }
          lastMenu={!this.props.disableRecordCreation ? newRecordButton : null}
          noOverflow
        >
          <MultiColumnList
            id={`list-${this.props.moduleName}`}
            contentData={records}
            selectedRow={this.state.selectedItem}
            formatter={this.props.resultsFormatter}
            onRowClick={this.onSelectRow}
            onHeaderClick={this.onSort}
            onNeedMoreData={this.onNeedMore}
            visibleColumns={this.props.visibleColumns}
            sortOrder={this.state.sortOrder.replace(/^-/, '').replace(/,.*/, '')}
            sortDirection={this.state.sortOrder.startsWith('-') ? 'descending' : 'ascending'}
            isEmptyMessage={`No results found${maybeTerm}. Please check your ${maybeSpelling}filters.`}
            columnMapping={this.props.columnMapping}
            loading={resource ? resource.isPending : false}
            autosize
            virtualize
            ariaLabel={`${objectNameUC} search results`}
            rowFormatter={this.anchoredRowFormatter}
            containerRef={(ref) => { this.resultsList = ref; }}
          />
        </Pane>

        {detailsPane}
        <Layer isOpen={urlQuery.layer ? urlQuery.layer === 'create' : false} label={`Add New ${objectNameUC} Dialog`}>
          <this.props.editRecordComponent
            id={`${objectName}form-add${objectName}`}
            initialValues={this.props.newRecordInitialValues}
            onSubmit={record => this.createRecord(record)}
            onCancel={this.closeNewRecord}
            parentResources={this.props.parentResources}
            parentMutator={this.props.parentMutator}
          />
        </Layer>
        {
          this.state.showNotesPane &&
          <Route
            path={`${this.props.match.path}/view/:id`}
            render={props => <this.connectedNotes
              stripes={stripes}
              onToggle={this.toggleNotes}
              link={`${this.props.moduleName}/${props.match.params.id}`}
              {...props}
            />}
          />
          }
      </Paneset>
    );
  }
}

export default withRouter(SearchAndSort);
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014, Tidepool Project
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice, this
 * list of conditions and the following disclaimer in the documentation and/or other
 * materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

var config = require('./lib/common/config.js');
var except = require('./lib/common/except.js');

module.exports = (function(){
  var env = {};

  // The port to attach an HTTP listener, if null, no HTTP listener will be attached
  env.httpPort = config.fromEnvironment('HTTP_PORT', null);

  // The port to attach an HTTPS listener, if null, no HTTPS listener will be attached
  env.httpsPort = config.fromEnvironment('HTTPS_PORT', null);

  // The https config to pass along to https.createServer.
  var theConfig = config.fromEnvironment('HTTPS_CONFIG', null);
  env.httpsConfig = null;
  if (theConfig != null) {
    env.httpsConfig = JSON.parse(theConfig);
  }
  if (env.httpsPort != null && env.httpsConfig == null) {
    throw except.ISE('No https config provided, please set HTTPS_CONFIG with at least the certificate to use.');
  }

  // A JSON object of domain -> JSON Array of rules.  Domains ignore case and must be exact.
  // The domain "*" is a catchall for everything that didn't match a specific domain.
  //
  // The rules are applied by first taking the value of the Host: header, looking up the correct
  // set of rules for the specific host and then running through the rules until it finds a rule
  // that covers the request.  The request is then completely delegated to that rule.
  env.rules = JSON.parse(config.fromEnvironment('RULES'));

  return env;
})();<commit_msg>Load up key/cert files automatically if defined as files.<commit_after>/*
 * Copyright (c) 2014, Tidepool Project
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice, this
 * list of conditions and the following disclaimer in the documentation and/or other
 * materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

var fs = require('fs');

var config = require('./lib/common/config.js');
var except = require('./lib/common/except.js');

function maybeReplaceWithContentsOfFile(obj, field)
{
  var potentialFile = obj[field];
  if (potentialFile != null && fs.existsSync(potentialFile)) {
    obj[field] = fs.readFileSync(potentialFile).toString();
  }
}

module.exports = (function(){
  var env = {};

  // The port to attach an HTTP listener, if null, no HTTP listener will be attached
  env.httpPort = config.fromEnvironment('HTTP_PORT', null);

  // The port to attach an HTTPS listener, if null, no HTTPS listener will be attached
  env.httpsPort = config.fromEnvironment('HTTPS_PORT', null);

  // The https config to pass along to https.createServer.
  var theConfig = config.fromEnvironment('HTTPS_CONFIG', null);
  env.httpsConfig = null;
  if (theConfig != null) {
    env.httpsConfig = JSON.parse(theConfig);
    maybeReplaceWithContentsOfFile(env.httpsConfig, 'key');
    maybeReplaceWithContentsOfFile(env.httpsConfig, 'cert');
    maybeReplaceWithContentsOfFile(env.httpsConfig, 'pfx');
  }
  if (env.httpsPort != null && env.httpsConfig == null) {
    throw except.ISE('No https config provided, please set HTTPS_CONFIG with at least the certificate to use.');
  }

  // A JSON object of domain -> JSON Array of rules.  Domains ignore case and must be exact.
  // The domain "*" is a catchall for everything that didn't match a specific domain.
  //
  // The rules are applied by first taking the value of the Host: header, looking up the correct
  // set of rules for the specific host and then running through the rules until it finds a rule
  // that covers the request.  The request is then completely delegated to that rule.
  env.rules = JSON.parse(config.fromEnvironment('RULES'));

  return env;
})();<|endoftext|>


<commit_before>import PropTypes from 'prop-types'
import React from 'react'
import FormField from 'part:@sanity/components/formfields/default'
import Fieldset from 'part:@sanity/components/fieldsets/default'
import DefaultSelect from 'part:@sanity/components/selects/default'
import PatchEvent, {set, unset, setIfMissing} from '@sanity/form-builder/PatchEvent'
import AceEditor from 'react-ace'
import {get, has, xor} from 'lodash'
import fieldsetStyles from './Fieldset.css'
import styles from './Styles.css'

import 'brace/mode/text'
import 'brace/mode/javascript'
import 'brace/mode/json'
import 'brace/mode/jsx'
import 'brace/mode/markdown'
import 'brace/mode/css'
import 'brace/mode/html'

import 'brace/theme/tomorrow'

function compareNumbers(a, b) { // eslint-disable-line id-length
  return a - b
}

const SUPPORTED_LANGUAGES = [
  {title: 'JSX', value: 'jsx'},
  {title: 'JavaScript', value: 'javascript'},
  {title: 'JSON', value: 'json'},
  {title: 'Markdown', value: 'markdown'},
  {title: 'CSS', value: 'css'},
  {title: 'HTML', value: 'html'},
  {title: 'text', value: 'text'}
]

const ACE_SET_OPTIONS = {
  useSoftTabs: true,
  navigateWithinSoftTabs: true /* note only supported by ace v1.2.7 or higher */
}
const ACE_EDITOR_PROPS = {$blockScrolling: true}

export default class CodeInput extends React.Component {

  static propTypes = {
    type: PropTypes.object,
    level: PropTypes.number.isRequired,
    value: PropTypes.shape({
      _type: PropTypes.string,
      code: PropTypes.string,
      language: PropTypes.string,
      highlightedLines: PropTypes.array
    }),
    onChange: PropTypes.func
  }

  static defaultProps = {
    value: '',
    onChange() {}
  }

  state = {
    hasFocus: false
  }

  componentWillUnmount() {
    this.editor.removeListener('guttermousedown', this.handleGutterMouseDown)
  }

  handleCodeChange = code => {
    const {type, onChange} = this.props
    const path = ['code']

    const fixedLanguage = get(type, 'options.language')

    onChange(PatchEvent.from([
      setIfMissing({_type: type.name, language: fixedLanguage}),
      code ? set(code, path) : unset(path)
    ]))
  }

  handleToggleSelectLine = lineNumber => {
    const {type, onChange} = this.props
    const path = ['highlightedLines']
    const {highlightedLines} = this.props.value

    const highlightedLinesCleaned = xor(highlightedLines, [lineNumber]).sort(compareNumbers)

    onChange(PatchEvent.from([
      setIfMissing({_type: type.name, highlightedLines: []}),
      lineNumber ? set(highlightedLinesCleaned, path) : unset(path)
    ]))
  }

  handleGutterMouseDown = event => {
    const target = event.domEvent.target
    if (target.classList.contains('ace_gutter-cell')) {
      const row = event.getDocumentPosition().row
      this.handleToggleSelectLine(`${row}`)
    }
  }

  handleEditorLoad = editor => {
    this.editor = editor
    this.editor.focus()
    this.editor.on('guttermousedown', this.handleGutterMouseDown)
  }

  handleLanguageChange = item => {
    const {type, onChange} = this.props
    const path = ['language']
    onChange(PatchEvent.from([
      setIfMissing({_type: type.name}),
      item ? set(item.value, path) : unset(path)
    ]))
  }

  createMarkers = rows => {
    return rows.map(row => {
      return {
        startRow: Number(row),
        startCol: 0,
        endRow: Number(row),
        endCol: 500,
        className: styles.highlight,
        type: 'background',
        inFront: true
      }
    })
  }

  renderEditor = () => {
    const {value, type} = this.props
    const fixedLanguage = get(type, 'options.language')
    return (
      <AceEditor
        mode={value.language || fixedLanguage || 'text'}
        theme="tomorrow"
        width="100%"
        onChange={this.handleCodeChange}
        name={`${this._inputId}__aceEditor`}
        value={value.code || ''}
        markers={value.highlightedLines ? this.createMarkers(value.highlightedLines) : null}
        onLoad={this.handleEditorLoad}
        tabSize={2}
        setOptions={ACE_SET_OPTIONS}
        editorProps={ACE_EDITOR_PROPS}
      />

    )
  }

  render() {
    const {value, type, level} = this.props

    if (has(type, 'options.language')) {
      return (
        <Fieldset styles={fieldsetStyles} legend={type.title} description={type.description}>
          {
            this.renderEditor()
          }
        </Fieldset>
      )
    }

    const currentLanguage = (value && value.language) ? SUPPORTED_LANGUAGES.find(item => item.value === value.language) : null

    const languageField = type.fields.find(field => field.name === 'language')
    const languages = currentLanguage ? SUPPORTED_LANGUAGES : [{title: 'Select language'}].concat(SUPPORTED_LANGUAGES)

    return (
      <Fieldset legend={type.title} description={type.description}>
        <DefaultSelect
          label={languageField.type.title}
          onChange={this.handleLanguageChange}
          value={currentLanguage}
          items={languages}
          level={level + 1}
        />
        <FormField label={type.title} level={level + 1}>
          {
            this.renderEditor()
          }
        </FormField>
      </Fieldset>
    )
  }
}
<commit_msg>[code-input] Make code-input a pure component<commit_after>import React, {PureComponent} from 'react'
import PropTypes from 'prop-types'
import FormField from 'part:@sanity/components/formfields/default'
import Fieldset from 'part:@sanity/components/fieldsets/default'
import DefaultSelect from 'part:@sanity/components/selects/default'
import PatchEvent, {set, unset, setIfMissing} from '@sanity/form-builder/PatchEvent'
import AceEditor from 'react-ace'
import {get, has, xor} from 'lodash'
import fieldsetStyles from './Fieldset.css'
import styles from './Styles.css'

import 'brace/mode/text'
import 'brace/mode/javascript'
import 'brace/mode/json'
import 'brace/mode/jsx'
import 'brace/mode/markdown'
import 'brace/mode/css'
import 'brace/mode/html'

import 'brace/theme/tomorrow'

function compareNumbers(a, b) { // eslint-disable-line id-length
  return a - b
}

const SUPPORTED_LANGUAGES = [
  {title: 'JSX', value: 'jsx'},
  {title: 'JavaScript', value: 'javascript'},
  {title: 'JSON', value: 'json'},
  {title: 'Markdown', value: 'markdown'},
  {title: 'CSS', value: 'css'},
  {title: 'HTML', value: 'html'},
  {title: 'text', value: 'text'}
]

const ACE_SET_OPTIONS = {
  useSoftTabs: true,
  navigateWithinSoftTabs: true /* note only supported by ace v1.2.7 or higher */
}
const ACE_EDITOR_PROPS = {$blockScrolling: true}

export default class CodeInput extends PureComponent {

  static propTypes = {
    type: PropTypes.object,
    level: PropTypes.number.isRequired,
    value: PropTypes.shape({
      _type: PropTypes.string,
      code: PropTypes.string,
      language: PropTypes.string,
      highlightedLines: PropTypes.array
    }),
    onChange: PropTypes.func
  }

  static defaultProps = {
    value: '',
    onChange() {}
  }

  state = {
    hasFocus: false
  }

  componentWillUnmount() {
    this.editor.removeListener('guttermousedown', this.handleGutterMouseDown)
  }

  handleCodeChange = code => {
    const {type, onChange} = this.props
    const path = ['code']

    const fixedLanguage = get(type, 'options.language')

    onChange(PatchEvent.from([
      setIfMissing({_type: type.name, language: fixedLanguage}),
      code ? set(code, path) : unset(path)
    ]))
  }

  handleToggleSelectLine = lineNumber => {
    const {type, onChange} = this.props
    const path = ['highlightedLines']
    const {highlightedLines} = this.props.value

    const highlightedLinesCleaned = xor(highlightedLines, [lineNumber]).sort(compareNumbers)

    onChange(PatchEvent.from([
      setIfMissing({_type: type.name, highlightedLines: []}),
      lineNumber ? set(highlightedLinesCleaned, path) : unset(path)
    ]))
  }

  handleGutterMouseDown = event => {
    const target = event.domEvent.target
    if (target.classList.contains('ace_gutter-cell')) {
      const row = event.getDocumentPosition().row
      this.handleToggleSelectLine(`${row}`)
    }
  }

  handleEditorLoad = editor => {
    this.editor = editor
    this.editor.focus()
    this.editor.on('guttermousedown', this.handleGutterMouseDown)
  }

  handleLanguageChange = item => {
    const {type, onChange} = this.props
    const path = ['language']
    onChange(PatchEvent.from([
      setIfMissing({_type: type.name}),
      item ? set(item.value, path) : unset(path)
    ]))
  }

  createMarkers = rows => {
    return rows.map(row => {
      return {
        startRow: Number(row),
        startCol: 0,
        endRow: Number(row),
        endCol: 500,
        className: styles.highlight,
        type: 'background',
        inFront: true
      }
    })
  }

  renderEditor = () => {
    const {value, type} = this.props
    const fixedLanguage = get(type, 'options.language')
    return (
      <AceEditor
        mode={value.language || fixedLanguage || 'text'}
        theme="tomorrow"
        width="100%"
        onChange={this.handleCodeChange}
        name={`${this._inputId}__aceEditor`}
        value={value.code || ''}
        markers={value.highlightedLines ? this.createMarkers(value.highlightedLines) : null}
        onLoad={this.handleEditorLoad}
        tabSize={2}
        setOptions={ACE_SET_OPTIONS}
        editorProps={ACE_EDITOR_PROPS}
      />

    )
  }

  render() {
    const {value, type, level} = this.props

    if (has(type, 'options.language')) {
      return (
        <Fieldset styles={fieldsetStyles} legend={type.title} description={type.description}>
          {
            this.renderEditor()
          }
        </Fieldset>
      )
    }

    const currentLanguage = (value && value.language) ? SUPPORTED_LANGUAGES.find(item => item.value === value.language) : null

    const languageField = type.fields.find(field => field.name === 'language')
    const languages = currentLanguage ? SUPPORTED_LANGUAGES : [{title: 'Select language'}].concat(SUPPORTED_LANGUAGES)

    return (
      <Fieldset legend={type.title} description={type.description}>
        <DefaultSelect
          label={languageField.type.title}
          onChange={this.handleLanguageChange}
          value={currentLanguage}
          items={languages}
          level={level + 1}
        />
        <FormField label={type.title} level={level + 1}>
          {
            this.renderEditor()
          }
        </FormField>
      </Fieldset>
    )
  }
}
<|endoftext|>


<commit_before>export default class Binding {
  constructor({ identifier, scope, path, kind }) {
    this.constantViolations = [];
    this.constant           = true;

    this.identifier = identifier;
    this.references = 0;
    this.referenced = false;

    this.scope = scope;
    this.path  = path;
    this.kind  = kind;

    this.clearValue();
  }

  /**
   * Description
   */

  deoptValue() {
    this.clearValue();
    this.deoptValue = true;
  }

  /**
   * Description
   */

  setValue(value) {
    if (this.deoptValue) return;
    this.hasValue = true;
    this.value    = value;
  }

  /**
   * Description
   */

  clearValue() {
    this.deoptValue = false;
    this.hasValue   = false;
    this.value      = null;
  }

  /**
   * Description
   */

  reassign(path) {
    this.constant = false;
    this.constantViolations.push(path);
  }

  /**
   * Description
   */

  reference() {
    this.referenced = true;
    this.references++;
  }

  /**
   * Description
   */

  dereference() {
    this.references--;
    this.referenced = !!this.references;
  }

  /**
   * Description
   */

  isCompatibleWithType(): boolean {
    return false;
  }
}
<commit_msg>fix deoptValue binding boolean - fixes #1687<commit_after>export default class Binding {
  constructor({ identifier, scope, path, kind }) {
    this.constantViolations = [];
    this.constant           = true;

    this.identifier = identifier;
    this.references = 0;
    this.referenced = false;

    this.scope = scope;
    this.path  = path;
    this.kind  = kind;

    this.clearValue();
  }

  /**
   * Description
   */

  deoptValue() {
    this.clearValue();
    this.hasDeoptedValue = true;
  }

  /**
   * Description
   */

  setValue(value) {
    if (this.hasDeoptedValue) return;
    this.hasValue = true;
    this.value    = value;
  }

  /**
   * Description
   */

  clearValue() {
    this.hasDeoptedValue = false;
    this.hasValue        = false;
    this.value           = null;
  }

  /**
   * Description
   */

  reassign(path) {
    this.constant = false;
    this.constantViolations.push(path);
  }

  /**
   * Description
   */

  reference() {
    this.referenced = true;
    this.references++;
  }

  /**
   * Description
   */

  dereference() {
    this.references--;
    this.referenced = !!this.references;
  }

  /**
   * Description
   */

  isCompatibleWithType(): boolean {
    return false;
  }
}
<|endoftext|>


<commit_before>import controllers from '../controllers';

export default ({
    app,
    datalayer
}) => {
    app.use('/content', new controllers.ContentController({
        app,
        datalayer
    }).router);
    app.use('/util', new controllers.UtilityController({
        app,
        datalayer
    }).router);
};
<commit_msg>removed utility for now<commit_after>import controllers from '../controllers';

export default ({
    app,
    datalayer
}) => {
    app.use('/content', new controllers.ContentController({
        app,
        datalayer
    }).router);
    // app.use('/util', new controllers.UtilityController({
    //     app,
    //     datalayer
    // }).router);
};
<|endoftext|>


<commit_before>var List = require('./list.js');
var assert = require('assert');

function add(lst1, lst2) {
  var p = lst1.head;
  var q = lst2.head;
  var lst = new List();
  m = lst.head;

  var carry = 0;

  while (p.next) {
    p = p.next;
    q = q.next;

    var result = p.value + q.value;
    remain = result % 10;

    m.next = { next: null, value: remain + carry };
    m = m.next;

    carry = result > 9 ? 1 : 0;
  }

  if (carry) {
    m.next = { next: null, value: carry };
  }

  return lst;
}

// tests

var lst1 = new List();
lst1.insert(6);
lst1.insert(1);
lst1.insert(7);

var lst2 = new List();
lst2.insert(8);
lst2.insert(9);
lst2.insert(5);

var result = add(lst1, lst2);

assert.deepEqual(result.toArray(), [2, 1, 5, 1], 'should return result as a linked list');
<commit_msg>new version<commit_after>var List = require('./list.js');
var assert = require('assert');

/**
 * GIVEN: two numbers represented by a list of digits, in reverse order
 * RETURNS: the sum of the given numbers represented by a list of digits, in reverse order
 * EXAMPLES: see tests
 */
function add(lst1, lst2) {
  var v1, v2;
  var p = lst1.head.next;
  var q = lst2.head.next;
  var lst = new List();
  m = lst.head;

  var carry = 0;

  while (p || q) {
    var v1 = p ? p.value : 0;
    var v2 = q ? q.value : 0;
    var result = v1 + v2;

    remain = result % 10;

    m.next = { next: null, value: remain + carry };
    m = m.next;

    carry = result > 9 ? 1 : 0;

    p && (p = p.next);
    q && (q = q.next);
  }

  if (carry) {
    m.next = { next: null, value: carry };
  }

  return lst;
}

// tests

var lst1 = new List();
lst1.insert(6);
lst1.insert(1);
lst1.insert(7);

var lst2 = new List();
lst2.insert(1);
lst2.insert(8);
lst2.insert(9);
lst2.insert(5);

var result = add(lst1, lst2);

assert.deepEqual(result.toArray(), [2, 1, 5, 2], 'should return result as a linked list');
<|endoftext|>


<commit_before>import {Container, inject} from 'aurelia-dependency-injection';
import {ViewSlot, ViewLocator, customElement, noView, BehaviorInstruction, bindable, CompositionTransaction} from 'aurelia-templating';
import {Router} from 'aurelia-router';
import {Origin} from 'aurelia-metadata';
import {DOM} from 'aurelia-pal';

class SwapStrategies {
  // animate the next view in before removing the current view;
  before(viewSlot, previousView, callback) {
    let promise = Promise.resolve(callback());

    if (previousView !== undefined) {
      return promise.then(() => viewSlot.remove(previousView, true));
    }

    return promise;
  }

  // animate the next view at the same time the current view is removed
  with(viewSlot, previousView, callback) {
    let promise = Promise.resolve(callback());

    if (previousView !== undefined) {
      return Promise.all([viewSlot.remove(previousView, true), promise]);
    }

    return promise;
  }

  // animate the next view in after the current view has been removed
  after(viewSlot, previousView, callback) {
    return Promise.resolve(viewSlot.removeAll(true)).then(callback);
  }
}

const swapStrategies = new SwapStrategies();

@customElement('router-view')
@noView
@inject(DOM.Element, Container, ViewSlot, Router, ViewLocator, CompositionTransaction)
export class RouterView {
  @bindable swapOrder;

  constructor(element, container, viewSlot, router, viewLocator, compositionTransaction) {
    this.element = element;
    this.container = container;
    this.viewSlot = viewSlot;
    this.router = router;
    this.viewLocator = viewLocator;
    this.compositionTransaction = compositionTransaction;
    this.router.registerViewPort(this, this.element.getAttribute('name'));

    if (!('initialComposition' in compositionTransaction)) {
      compositionTransaction.initialComposition = true;
      this.compositionTransactionNotifier = compositionTransaction.enlist();
    }
  }

  created(owningView) {
    this.owningView = owningView;
  }

  bind(bindingContext, overrideContext) {
    this.container.viewModel = bindingContext;
    this.overrideContext = overrideContext;
  }

  process(viewPortInstruction, waitToSwap) {
    let component = viewPortInstruction.component;
    let childContainer = component.childContainer;
    let viewModel = component.viewModel;
    let viewModelResource = component.viewModelResource;
    let metadata = viewModelResource.metadata;

    let viewStrategy = this.viewLocator.getViewStrategy(component.view || viewModel);
    if (viewStrategy) {
      viewStrategy.makeRelativeTo(Origin.get(component.router.container.viewModel.constructor).moduleId);
    }

    return metadata.load(childContainer, viewModelResource.value, null, viewStrategy, true).then(viewFactory => {
      if (!this.compositionTransactionNotifier && !this.compositionTransaction.hasOwner) {
        this.compositionTransactionOwnershipToken = this.compositionTransaction.tryCapture();
      }

      viewPortInstruction.controller = metadata.create(childContainer,
        BehaviorInstruction.dynamic(
          this.element,
          viewModel,
          viewFactory
        )
      );

      if (waitToSwap) {
        return;
      }

      this.swap(viewPortInstruction);
    });
  }

  swap(viewPortInstruction) {
    let work = () => {
      let previousView = this.view;
      let viewSlot = this.viewSlot;
      let swapStrategy;

      swapStrategy = this.swapOrder in swapStrategies
                  ? swapStrategies[this.swapOrder]
                  : swapStrategies.after;

      swapStrategy(viewSlot, previousView, () => {
        return Promise.resolve(viewSlot.add(viewPortInstruction.controller.view)).then(() => {
          if (this.compositionTransactionNotifier) {
            this.compositionTransactionNotifier.done();
            this.compositionTransactionNotifier = null;
          }
        });
      });

      this.view = viewPortInstruction.controller.view;
    };

    viewPortInstruction.controller.automate(this.overrideContext, this.owningView);

    if (this.compositionTransactionOwnershipToken) {
      return this.compositionTransactionOwnershipToken.waitForCompositionComplete().then(() => {
        this.compositionTransactionOwnershipToken = null;
        work();
      });
    } else {
      work();
    }
  }
}
<commit_msg>fix(router-view): simplify composition transaction use<commit_after>import {Container, inject} from 'aurelia-dependency-injection';
import {ViewSlot, ViewLocator, customElement, noView, BehaviorInstruction, bindable, CompositionTransaction} from 'aurelia-templating';
import {Router} from 'aurelia-router';
import {Origin} from 'aurelia-metadata';
import {DOM} from 'aurelia-pal';

class SwapStrategies {
  // animate the next view in before removing the current view;
  before(viewSlot, previousView, callback) {
    let promise = Promise.resolve(callback());

    if (previousView !== undefined) {
      return promise.then(() => viewSlot.remove(previousView, true));
    }

    return promise;
  }

  // animate the next view at the same time the current view is removed
  with(viewSlot, previousView, callback) {
    let promise = Promise.resolve(callback());

    if (previousView !== undefined) {
      return Promise.all([viewSlot.remove(previousView, true), promise]);
    }

    return promise;
  }

  // animate the next view in after the current view has been removed
  after(viewSlot, previousView, callback) {
    return Promise.resolve(viewSlot.removeAll(true)).then(callback);
  }
}

const swapStrategies = new SwapStrategies();

@customElement('router-view')
@noView
@inject(DOM.Element, Container, ViewSlot, Router, ViewLocator, CompositionTransaction)
export class RouterView {
  @bindable swapOrder;

  constructor(element, container, viewSlot, router, viewLocator, compositionTransaction) {
    this.element = element;
    this.container = container;
    this.viewSlot = viewSlot;
    this.router = router;
    this.viewLocator = viewLocator;
    this.compositionTransaction = compositionTransaction;
    this.router.registerViewPort(this, this.element.getAttribute('name'));

    if (!('initialComposition' in compositionTransaction)) {
      compositionTransaction.initialComposition = true;
      this.compositionTransactionNotifier = compositionTransaction.enlist();
    }
  }

  created(owningView) {
    this.owningView = owningView;
  }

  bind(bindingContext, overrideContext) {
    this.container.viewModel = bindingContext;
    this.overrideContext = overrideContext;
  }

  process(viewPortInstruction, waitToSwap) {
    let component = viewPortInstruction.component;
    let childContainer = component.childContainer;
    let viewModel = component.viewModel;
    let viewModelResource = component.viewModelResource;
    let metadata = viewModelResource.metadata;

    let viewStrategy = this.viewLocator.getViewStrategy(component.view || viewModel);
    if (viewStrategy) {
      viewStrategy.makeRelativeTo(Origin.get(component.router.container.viewModel.constructor).moduleId);
    }

    return metadata.load(childContainer, viewModelResource.value, null, viewStrategy, true).then(viewFactory => {
      if (!this.compositionTransactionNotifier) {
        this.compositionTransactionOwnershipToken = this.compositionTransaction.tryCapture();
      }

      viewPortInstruction.controller = metadata.create(childContainer,
        BehaviorInstruction.dynamic(
          this.element,
          viewModel,
          viewFactory
        )
      );

      if (waitToSwap) {
        return;
      }

      this.swap(viewPortInstruction);
    });
  }

  swap(viewPortInstruction) {
    let work = () => {
      let previousView = this.view;
      let viewSlot = this.viewSlot;
      let swapStrategy;

      swapStrategy = this.swapOrder in swapStrategies
                  ? swapStrategies[this.swapOrder]
                  : swapStrategies.after;

      swapStrategy(viewSlot, previousView, () => {
        return Promise.resolve(viewSlot.add(viewPortInstruction.controller.view)).then(() => {
          if (this.compositionTransactionNotifier) {
            this.compositionTransactionNotifier.done();
            this.compositionTransactionNotifier = null;
          }
        });
      });

      this.view = viewPortInstruction.controller.view;
    };

    viewPortInstruction.controller.automate(this.overrideContext, this.owningView);

    if (this.compositionTransactionOwnershipToken) {
      return this.compositionTransactionOwnershipToken.waitForCompositionComplete().then(() => {
        this.compositionTransactionOwnershipToken = null;
        work();
      });
    } else {
      work();
    }
  }
}
<|endoftext|>