fish-shell/share/tools/web_config/index.html

603 lines
18 KiB
HTML
Raw Normal View History

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html ng-app="webconfig">
2012-03-15 10:43:45 +00:00
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
<title>fish shell configuration</title>
<link rel="stylesheet" type="text/css" href="webconfig.css"/>
2012-03-15 10:43:45 +00:00
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="angular.js"></script>
<script type="text/javascript" src="webconfig.js"></script>
2012-03-15 10:43:45 +00:00
<script type="text/javascript">
function show_error(msg) {
$('#global_error').text(msg)
}
2012-03-22 17:23:07 +00:00
function request_failed(jqXHR, textStatus, errorThrown) {
msg = ''
if (textStatus == "timeout") {
msg = 'The request timed out. Perhaps the server has shut down or is hung.'
2012-03-22 17:23:07 +00:00
} else if (textStatus == "error") {
msg = 'The request received an error.'
if (jqXHR.status == 0)
msg = msg + ' Perhaps the server has shut down.'
2012-03-22 17:23:07 +00:00
} else if (msg == 'abort') {
msg = 'The request aborted.'
} else if (msg == 'parsererror') {
msg = 'The request experienced a parser error.'
} else {
msg = 'The request had an unknown error "' + textStatus + '."'
}
if (errorThrown.length > 0) {
msg = msg + ' The HTTP reply returned ' + errorThrown
}
show_error(msg)
2012-03-16 10:03:43 +00:00
}
2012-03-17 00:21:37 +00:00
/* Runs a GET request, parses the JSON, and invokes the handler for each element in it. The JSON result is assumed to be an array. */
function run_get_request_with_bulk_handler(url, handler) {
2012-03-17 00:21:37 +00:00
$.ajax({
type: "GET",
url: url,
2013-01-16 22:50:08 +00:00
dataType: "text",
2012-03-17 00:21:37 +00:00
success: function(data){
2012-03-22 17:23:07 +00:00
$('#global_error').text('')
handler($.parseJSON(data))
2012-03-17 00:21:37 +00:00
},
2012-03-22 17:23:07 +00:00
error: request_failed
2012-03-17 00:21:37 +00:00
})
}
function run_get_request(url, handler) {
run_get_request_with_bulk_handler(url, function(json_contents){
$.each(json_contents, function(idx, contents){
handler(contents)
})
})
}
/* As above but with POST request. */
function run_post_request(url, data_map, handler) {
$.ajax({
type: "POST",
url: url,
2013-01-16 22:50:08 +00:00
dataType: "text",
data: data_map,
success: function(data){
$('#global_error').text('')
$.each($.parseJSON(data), function(idx, contents) {
handler(contents)
})
},
error: request_failed
})
}
function rgb_to_hsl(r, g, b){
r /= 255, g /= 255, b /= 255;
var max = Math.max(r, g, b), min = Math.min(r, g, b);
var h, s, l = (max + min) / 2;
if(max == min){
h = s = 0; // achromatic
}else{
var d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch(max){
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
}
h /= 6;
}
return [h, s, l];
}
function hsl_to_rgb(h, s, l){
var r, g, b;
if(s == 0){
r = g = b = l; // achromatic
}else{
function hue2rgb(p, q, t){
if(t < 0) t += 1;
if(t > 1) t -= 1;
if(t < 1/6) return p + (q - p) * 6 * t;
if(t < 1/2) return q;
if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
return p;
}
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
var p = 2 * l - q;
r = hue2rgb(p, q, h + 1.0/3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1.0/3);
}
return [r * 255, g * 255, b * 255]
}
/* Given an RGB color as a hex string, like FF0033, convert to HSL, apply the function to adjust its lightness, then return the new color as an RGB string */
function adjust_lightness(color_str, func) {
/* Hack to handle for example F00 */
if (color_str.length == 3) {
color_str = color_str[0] + color_str[0] + color_str[1] + color_str[1] + color_str[2] + color_str[2]
}
rgb = parseInt(color_str, 16)
r = (rgb >> 16) & 0xFF
g = (rgb >> 8) & 0xFF
b = (rgb >> 0) & 0xFF
hsl = rgb_to_hsl(r, g, b)
new_lightness = func(hsl[2])
function to_int_str(val) {
str = Math.round(val).toString(16)
while (str.length < 2)
str = '0' + str
return str
}
new_rgb = hsl_to_rgb(hsl[0], hsl[1], new_lightness)
return to_int_str(new_rgb[0]) + to_int_str(new_rgb[1]) + to_int_str(new_rgb[2])
}
/* Given a color, compute the master text color for it, by giving it a minimum brightness */
function master_color_for_color(color_str) {
return adjust_lightness(color_str, function(lightness){
if (lightness < .33) {
lightness = .33
}
return lightness
})
}
/* Update prompt_demo_text with the given text, adjusting the font */
function set_prompt_demo_text(txt, font_size) {
/* Set the font size and the text */
var prompt_demo_text = $('.prompt_demo_text')
prompt_demo_text.css('font-size', font_size)
prompt_demo_text.html(txt)
}
function current_master_element_name() {
/* Get the name of the current color variable, like 'autosuggestion' */
var elems = $('.selected_master_elem')
if (elems.length == 0) {
return ''
}
elem = elems[0]
if (elem.id.indexOf('master_') != 0) {
show_error('Unknown master variable')
return ''
}
return elem.id.substring(7)
}
function is_foreground() {
/* Returns true if the selected tab is foreground, false if it's background */
who = $('.colorpicker_target_selected')
if (who.length == 0) {
show_error('Not sure if we are in foreground or background')
return false
}
return who[0].id == 'foreground'
}
function current_style() {
/* Returns the style object corresponding to the current color variable */
return style_map[current_master_element_name()]
}
function reflect_style() {
/* Unselect everything */
$('.colorpicker_cell_selected').removeClass('colorpicker_cell_selected')
$('.modifier_cell_selected').removeClass('modifier_cell_selected')
$('.master_element_no_border').removeClass('master_element_no_border')
/* Now update the color picker with the current style (if we have one) */
style = current_style()
if (style) {
/* Use this function to make a color that contrasts well with the given color */
var adjust = .5
function compute_constrast(lightness){
var new_lightness = lightness + adjust
if (new_lightness > 1.0 || new_lightness < 0.0) {
new_lightness -= 2 * adjust
}
return new_lightness
}
color = is_foreground() ? style.color : style.background_color
var color_cell = $('#color_' + color)
color_cell.addClass('colorpicker_cell_selected')
color_cell.css('border-color', adjust_lightness(is_foreground() ? style.color : style.background_color, compute_constrast))
if (style.underline) {
$('#modifier_underline').addClass('modifier_cell_selected')
}
/* In the master list, ensure the color is visible against the dark background. If we're deselecting, use COLOR_NORMAL */
master_color = style.color ? master_color_for_color(style.color) : COLOR_NORMAL
//$('.selected_master_elem').children('.master_element_text').css({'color': master_color, 'border-bottom-color': master_color})
var selected_elem = $('.selected_master_elem');
var desc_elems = selected_elem.children('.master_element_description')
selected_elem.css({'color': master_color})
selected_elem.children().css({'border-bottom-color': master_color})
if (desc_elems.length) {
/* We have a description element, so hide the bottom border of the master element */
selected_elem.children('.master_element_text').addClass('master_element_no_border')
}
}
}
function cleanup_fish_function(contents) {
/* Replace leading tabs and groups of four spaces at the beginning of a line with two spaces. */
lines = contents.split('\n')
rx = /^[\t ]+/
for (var i=0; i < lines.length; i++) {
line = lines[i]
/* Get leading tabs and spaces */
whitespace_arr = rx.exec(line)
if (whitespace_arr) {
/* Replace four spaces with two spaces, and tabs with two spaces */
var whitespace = whitespace_arr[0]
new_whitespace = whitespace.replace(/( )|(\t)/g, ' ')
lines[i] = new_whitespace + line.slice(whitespace.length)
}
}
return lines.join('\n')
}
2012-03-22 17:23:07 +00:00
function select_master_element(elem) {
$('.selected_master_elem').removeClass('selected_master_elem')
$(elem).addClass('selected_master_elem')
}
2012-03-22 17:23:07 +00:00
function select_color_master_element(elem) {
select_master_element(elem)
/* This changed the current style; reflect that */
reflect_style()
2012-03-22 17:23:07 +00:00
}
function select_function_master_element(elem) {
select_master_element(elem)
run_post_request('/get_function/', {
what: current_master_element_name()
}, function(contents){
2012-03-25 22:56:43 +00:00
/* Replace leading tabs and groups of four spaces at the beginning of a line with two spaces. */
munged_contents = cleanup_fish_function(contents)
2012-03-25 22:56:43 +00:00
$('#detail_function').text(munged_contents)
});
}
var sample_prompts = new Array();
function select_sample_prompt_master_element(elem) {
$('.prompt_save_button').show()
select_master_element(elem)
var name = current_master_element_name()
sample_prompt = sample_prompts[name]
run_post_request('/get_sample_prompt/', {
what: sample_prompt['function']
}, function(keys_and_values){
var prompt_func = keys_and_values['function']
var prompt_demo = keys_and_values['demo']
var prompt_font_size = keys_and_values['font_size']
set_prompt_demo_text(prompt_demo, prompt_font_size)
//$('.prompt_demo_text').html(prompt_demo)
$('.prompt_function_text').text(cleanup_fish_function(prompt_func))
})
}
function select_current_prompt_master_element(elem) {
$('.prompt_save_button').hide()
select_master_element(elem)
run_get_request_with_bulk_handler('/current_prompt/', function(keys_and_values){
var prompt_func = keys_and_values['function']
var prompt_demo = keys_and_values['demo']
var prompt_font_size = keys_and_values['font_size']
set_prompt_demo_text(prompt_demo, prompt_font_size)
$('.prompt_function_text').text(cleanup_fish_function(prompt_func))
})
}
/* Applies the current prompt */
function save_current_prompt() {
var name = current_master_element_name()
var sample_prompt = sample_prompts[name]
run_post_request('/set_prompt/', {
what: sample_prompt['function']
}, function(contents){
if (contents == "OK") {
select_current_prompt_master_element($('#master_Current'))
} else {
show_error(contents)
}
})
}
function post_style_to_server() {
style = current_style()
if (! style)
return
run_post_request('/set_color/', {
what: current_master_element_name(),
color: style.color,
background_color: style.background_color,
bold: style.bold,
underline: style.underline
}, function(contents){
})
}
function picked_color_cell(cell) {
/* Get the color to set */
if (cell.id.indexOf('color_') != 0) {
show_error('Unknown cell')
return
}
color = cell.id.substring(6)
/* Determine whether we are going to select or unselect this cell */
var deselect = $(cell).hasClass('colorpicker_cell_selected')
/* Get the current style */
style = current_style()
if (! style)
return
/* Change the color */
if (is_foreground()) {
style.color = deselect ? '' : color
} else {
style.background_color = deselect ? '' : color
}
/* Show our changes */
reflect_style()
/* Tell the server */
post_style_to_server()
}
2012-03-20 10:01:00 +00:00
function picked_modifier(cell) {
style = current_style()
if (! style)
return
if (cell.id == 'modifier_underline') {
style.underline = ! style.underline
} else if (cell.id == 'modifier_bold') {
style.bold = ! style.bold
} else {
show_error('Unknown cell')
}
reflect_style()
post_style_to_server()
}
function picked_colorpicker_target(tab) {
/* The function that gets called when a tab is selected */
$('.colorpicker_target_selected').removeClass('colorpicker_target_selected')
$(tab).addClass('colorpicker_target_selected')
reflect_style()
}
/* Given a color name, like 'normal' or 'red' or 'FF00F0', return an RGB color string (or empty string) */
function interpret_color(str) {
str = str.toLowerCase()
if (str == 'black') return '000000'
if (str == 'red') return 'FF0000'
if (str == 'green') return '00FF00'
if (str == 'brown') return '725000'
if (str == 'yellow') return 'FFFF00'
if (str == 'blue') return '0000FF'
if (str == 'magenta') return 'FF00FF'
if (str == 'purple') return 'FF00FF'
if (str == 'cyan') return '00FFFF'
if (str == 'white') return 'FFFFFF'
if (str == 'normal') return ''
return str
}
/* Class representing a color style */
function Style(stuff) {
this.color = interpret_color(stuff[0])
this.background_color = interpret_color(stuff[1])
this.bold = stuff[2]
this.underline = stuff[3]
}
var style_map = new Array();
//var items_per_row = 15
2012-03-20 18:33:24 +00:00
var show_labels = 0
2012-03-17 00:21:37 +00:00
var COLOR_NORMAL = 'CCC'
2012-03-15 10:43:45 +00:00
/* Adds a new element to master */
function create_master_element(contents, description_or_false, color, font_size, click_handler) {
/* In the master list, ensure the color is visible against the dark background */
var master_color = color ? master_color_for_color(color) : COLOR_NORMAL
var master_style = 'color: #' + master_color
var master_children_style = 'border-bottom-color: #' + master_color
var text_style = ''
2012-03-25 22:56:43 +00:00
if (font_size.length > 0) {
text_style += 'font-size: ' + font_size + ';'
2012-03-25 22:56:43 +00:00
}
if (contents.length >= 20) {
text_style += 'letter-spacing:-2px;'
2012-03-25 22:56:43 +00:00
}
elem = $('<div/>', {
2012-03-15 10:43:45 +00:00
class: 'master_element',
id: 'master_' + contents,
style: master_style,
2012-03-15 10:43:45 +00:00
click: function(){
click_handler(this)
2012-03-15 10:43:45 +00:00
}
}).append(
$("<span/>", {
class: 'master_element_text',
style: text_style,
2012-03-22 17:23:07 +00:00
text: contents,
2012-03-15 10:43:45 +00:00
})
)
/* Append description if we have one */
if (description_or_false) {
/* Newline between label and description */
elem.append($('<br/>'))
elem.append(
$('<span/>', {
class: 'master_element_description',
text: description_or_false
})
)
}
/* Update border color of the master element's children */
elem.children().css(master_children_style)
elem.appendTo('#master')
return elem
2012-03-15 10:43:45 +00:00
}
/* Toggle the no_overflow class */
function toggle_overflow(who) {
$(who).toggleClass('no_overflow')
}
function escape_HTML(foo) {
return foo.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
}
/* Given the image, walk up to the table */
function tell_fish_to_delete_element(idx) {
var row_elem = $('#data_table_row_' + idx)
var txt = history_element_map[idx]
run_post_request('/delete_history_item/', {
what: txt
}, function(contents){
if (contents == "OK") {
row_elem.remove();
} else {
show_error(contents)
}
});
}
2012-03-17 00:21:37 +00:00
/* Creates a new row in the data table */
var last_global_element_identifier = 0
var history_element_map = new Array();
function create_data_table_element_text(contents_list, show_delete_button) {
var element_identifier = (++last_global_element_identifier).toString()
lines = new Array()
var result_str = '<tr class="data_table_row" id="data_table_row_' + element_identifier + '">'
2012-03-17 00:21:37 +00:00
for (idx = 0; idx < contents_list.length; idx++) {
/* If we have more than one, then align the first one right, subsequent ones left */
if (idx == 0 && contents_list.length > 1) {
result_str += '<td class="data_table_cell no_overflow" style="text-align: right; padding-right: 30px;">'
2012-03-17 00:21:37 +00:00
} else {
result_str += '<td class="data_table_cell no_overflow" style="text-align: left; padding-right: 30px;" onClick:"toggle_overflow(this)">'
2012-03-17 00:21:37 +00:00
}
text_list = contents_list[idx].split("\n")
for (j=0; j < text_list.length; j++) {
if (j > 0) result_str += '<br>'
result_str += escape_HTML(text_list[j]);
}
result_str += '</td>'
2012-03-17 00:21:37 +00:00
}
if (show_delete_button) {
result_str += '<td class="data_table_cell" style="text-align: right; width: 25px"><a onClick="tell_fish_to_delete_element(' + element_identifier + ')"><img class="delete_icon" src="delete.png"></a></td>'
}
result_str += '</tr>'
return result_str
2012-03-17 00:21:37 +00:00
}
/* Update the filter text box */
function update_table_filter_text_box(allow_transient_message) {
var box = $('#table_filter_text_box')
var has_transient = box.hasClass('text_box_transient')
if (! allow_transient_message && has_transient) {
box.val('')
box.removeClass('text_box_transient')
has_transient = false
} else if (allow_transient_message && ! has_transient && ! box.val().length) {
box.val('Filter')
box.addClass('text_box_transient')
has_transient = true
}
var search_text = box.val()
if (has_transient || search_text.length == 0) {
/* Unfilter all */
$('.data_table_row_filtered').removeClass('data_table_row_filtered')
} else {
/* Helper function to return whether a node (or its descendants) matches the given text */
function match_text(node) {
if (node.nodeType == 3) {
return node.nodeValue.indexOf(search_text) != -1
} else {
for (var i = 0, len = node.childNodes.length; i < len; ++i) {
if (match_text(node.childNodes[i])) {
return true;
}
}
}
return false
}
$('.data_table_row').each(function(idx) {
var row = $(this)
var is_hidden = row.hasClass('data_table_row_filtered')
var should_be_hidden = ! match_text(this)
if (is_hidden && ! should_be_hidden) {
row.removeClass('data_table_row_filtered')
} else if (! is_hidden && should_be_hidden) {
row.addClass('data_table_row_filtered')
}
})
}
return true
}
2012-03-17 00:21:37 +00:00
</script>
2012-03-15 10:43:45 +00:00
</head>
<body>
<div id="ancestor">
2012-03-22 17:23:07 +00:00
<span style="font-size: 30pt">fish</span><p id="global_error" class="error_msg"></p>
2012-03-15 10:43:45 +00:00
<div id="parent">
<div id="tab_parent" ng-controller="main">
<div ng-class="tabCssClass('colors')" id="tab_colors" ng-click="changeView('colors')">colors</div>
<div ng-class="tabCssClass('prompt')" id="tab_prompt" ng-click="changeView('prompt')">prompt</div>
<div ng-class="tabCssClass('functions')" id="tab_functions" ng-click="changeView('functions')">functions</div>
<div ng-class="tabCssClass('variables')" id="tab_variables" ng-click="changeView('variables')">variables</div>
<div ng-class="tabCssClass('history')" id="tab_history" ng-click="changeView('history')">history</div>
2012-03-15 10:43:45 +00:00
</div>
<div id="tab_contents">
<ng-view></ng-view>
</div>
2012-03-15 10:43:45 +00:00
</div>
</div>
</body></html>