ethercalc
Version:
Multi-User Spreadsheet Server
1,621 lines (1,183 loc) • 41.8 kB
JavaScript
//
/*
// The module of the SocialCalc package for the optional popup menus in socialcalcspreadsheetcontrol.js
//
// (c) Copyright 2009 Socialtext, Inc.
// All Rights Reserved.
//
// The contents of this file are subject to the Artistic License 2.0; you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at http://socialcalc.org/licenses/al-20/.
//
// Some of the other files in the SocialCalc package are licensed under
// different licenses. Please note the licenses of the modules you use.
//
// Code History:
//
// Initially coded by Dan Bricklin of Software Garden, Inc., for Socialtext, Inc.
//
*/
var SocialCalc; // All values are stored in the master SocialCalc object
if (!SocialCalc) {
SocialCalc = {};
}
// The main Popup data -- there is only one set
SocialCalc.Popup = {};
// Routines and values for each type of control, indexed by type name
// The value for each is an object constructed as follows:
//
// Create = function(type, id, attribs)
// Initialize = function(type, id, data)
// SetValue = function(type, id, value)
// GetValue = function(type, id) returns value
// SetDisabled = function(type, id, t/f)
// Show = function(type, id)
// Hide = function(type, id)
// Cancel = function(type, id)
// Reset = function(type)
//
// data = object to hold type-specific data
//
SocialCalc.Popup.Types = {};
// Definitions for each individual control, indexed by id
// The value for each is an object constructed as follows:
//
// type: type name of the control
// value: current value of the control (usually a string, but can depend on type)
// data: object with type-specific items
//
SocialCalc.Popup.Controls = {};
// System-wide values of currently active control
//
// id: id of current control or null
//
SocialCalc.Popup.Current = {};
// Override this for localization
SocialCalc.Popup.LocalizeString = function(str) {return str;};
// * * * * * * * * * * * * * * * *
//
// GENERAL ROUTINES
//
// * * * * * * * * * * * * * * * *
//
// SocialCalc.Popup.Create(type, id, attribs)
//
// Creates a control of type "type" as the children of document element "id" using "attribs"
//
SocialCalc.Popup.Create = function(type, id, attribs) {
var pt = SocialCalc.Popup.Types[type];
if (pt && pt.Create) {
pt.Create(type, id, attribs);
}
SocialCalc.Popup.imagePrefix = SocialCalc.Constants.defaultImagePrefix; // image prefix
}
//
// SocialCalc.Popup.SetValue(id, value)
//
// Sets the value of control.
//
SocialCalc.Popup.SetValue = function(id, value) {
var sp = SocialCalc.Popup;
var spt = sp.Types;
var spc = sp.Controls;
if (!spc[id]) {alert("Unknown control "+id);return;}
var type = spc[id].type;
var pt = spt[type];
var spcdata = spc[id].data;
if (pt && pt.Create) {
pt.SetValue(type, id, value);
if (spcdata.attribs && spcdata.attribs.changedcallback) {
spcdata.attribs.changedcallback(spcdata.attribs, id, value);
}
}
}
//
// SocialCalc.Popup.SetDisabled(id, disabled)
//
// Sets whether the control is disabled (true) or not (false).
//
SocialCalc.Popup.SetDisabled = function(id, disabled) {
var sp = SocialCalc.Popup;
var spt = sp.Types;
var spc = sp.Controls;
if (!spc[id]) {alert("Unknown control "+id);return;}
var type = spc[id].type;
var pt = spt[type];
if (pt && pt.Create) {
if (sp.Current.id && id == sp.Current.id) {
pt.Hide(type, sp.Current.id);
sp.Current.id = null;
}
pt.SetDisabled(type, id, disabled);
}
}
//
// SocialCalc.Popup.GetValue(id)
//
// Returns the value of control.
//
SocialCalc.Popup.GetValue = function(id) {
var sp = SocialCalc.Popup;
var spt = sp.Types;
var spc = sp.Controls;
if (!spc[id]) {alert("Unknown control "+id);return;}
var type = spc[id].type;
var pt = spt[type];
if (pt && pt.Create) {
return pt.GetValue(type, id);
}
return null;
}
//
// SocialCalc.Popup.Initialize(id, data)
//
// Gives "data" to the appropriate initialization code.
//
SocialCalc.Popup.Initialize = function(id, data) {
var sp = SocialCalc.Popup;
var spt = sp.Types;
var spc = sp.Controls;
if (!spc[id]) {alert("Unknown control "+id);return;}
var type = spc[id].type;
var pt = spt[type];
if (pt && pt.Initialize) {
pt.Initialize(type, id, data);
}
}
//
// SocialCalc.Popup.Reset(type)
//
// Resets Popup, such as when turning to page.
//
SocialCalc.Popup.Reset = function(type) {
var sp = SocialCalc.Popup;
var spt = sp.Types;
var spc = sp.Controls;
if (spt[type].Reset) spt[type].Reset(type);
}
//
// SocialCalc.Popup.CClick(id)
//
// Should be called when the user clicks on a control to do the popup
//
SocialCalc.Popup.CClick = function(id) {
var sp = SocialCalc.Popup;
var spt = sp.Types;
var spc = sp.Controls;
if (!spc[id]) {alert("Unknown control "+id);return;}
if (spc[id].data && spc[id].data.disabled) return;
var type = spc[id].type;
var pt = spt[type];
if (sp.Current.id) {
spt[spc[sp.Current.id].type].Hide(type, sp.Current.id);
if (id == sp.Current.id) { // same one - done
sp.Current.id = null;
return;
}
}
if (pt && pt.Show) {
pt.Show(type, id);
}
sp.Current.id = id;
}
//
// SocialCalc.Popup.Close()
//
// Used to close any open popup.
//
SocialCalc.Popup.Close = function() {
var sp = SocialCalc.Popup;
var spt = sp.Types;
var spc = sp.Controls;
if (!sp.Current.id) return;
sp.CClick(sp.Current.id);
}
//
// SocialCalc.Popup.Cancel()
//
// Closes Popup and restores old value
//
SocialCalc.Popup.Cancel = function() {
var sp = SocialCalc.Popup;
var spt = sp.Types;
var spc = sp.Controls;
if (!sp.Current.id) return;
var type = spc[sp.Current.id].type;
var pt = spt[type];
pt.Cancel(type, sp.Current.id);
sp.Current.id = null;
}
//
// ele = SocialCalc.Popup.CreatePopupDiv(id, attribs)
//
// Utility function to create the main popup div of width attribs.width.
// If attribs.title, create one with that text, and optionally attribs.moveable.
//
SocialCalc.Popup.CreatePopupDiv = function(id, attribs) {
var pos, ele;
var sp = SocialCalc.Popup;
var spc = sp.Controls;
var spcdata = spc[id].data;
var main = document.createElement("div");
main.style.position = "absolute";
pos = SocialCalc.GetElementPosition(spcdata.mainele);
main.style.top = (pos.top+spcdata.mainele.offsetHeight)+"px";
main.style.left = pos.left+"px";
main.style.zIndex = 100;
main.style.backgroundColor = "#FFF";
main.style.border = "1px solid black";
if (attribs.width) {
main.style.width = attribs.width;
}
spcdata.mainele.appendChild(main);
if (attribs.title) {
main.innerHTML = '<table cellspacing="0" cellpadding="0" style="border-bottom:1px solid black;"><tr>'+
'<td style="font-size:10px;cursor:default;width:100%;background-color:#999;color:#FFF;">'+attribs.title+'</td>'+
'<td style="font-size:10px;cursor:default;color:#666;" onclick="SocialCalc.Popup.Cancel();"> X </td></tr></table>';
if (attribs.moveable) {
spcdata.dragregistered = main.firstChild.firstChild.firstChild.firstChild;
SocialCalc.DragRegister(spcdata.dragregistered, true, true,
{MouseDown: SocialCalc.DragFunctionStart,
MouseMove: SocialCalc.DragFunctionPosition,
MouseUp: SocialCalc.DragFunctionPosition,
Disabled: null, positionobj: main},
spcdata.mainele);
}
}
return main;
}
//
// SocialCalc.Popup.EnsurePosition(id, container)
//
// Utility function to make sure popup is positioned completely within container (both element objects)
// and appropriate with respect to the main element controlling the popup.
//
SocialCalc.Popup.EnsurePosition = function(id, container) {
var sp = SocialCalc.Popup;
var spc = sp.Controls;
var spcdata = spc[id].data;
var main = spcdata.mainele.firstChild;
if (!main) {alert("No main popup element firstChild.");return};
var popup = spcdata.popupele;
function GetLayoutValues(ele) {
var r = SocialCalc.GetElementPosition(ele);
r.height = ele.offsetHeight;
r.width = ele.offsetWidth;
r.bottom = r.top+r.height;
r.right = r.left+r.width;
return r;
}
var p = GetLayoutValues(popup);
var c = GetLayoutValues(container);
var m = GetLayoutValues(main);
var t = 0; // type of placement
//addmsg("popup t/r/b/l/h/w= "+p.top+"/"+p.right+"/"+p.bottom+"/"+p.left+"/"+p.height+"/"+p.width);
//addmsg("container t/r/b/l/h/w= "+c.top+"/"+c.right+"/"+c.bottom+"/"+c.left+"/"+c.height+"/"+c.width);
//addmsg("main t/r/b/l/h/w= "+m.top+"/"+m.right+"/"+m.bottom+"/"+m.left+"/"+m.height+"/"+m.width);
// Check various layout cases in priority order
if (m.bottom+p.height < c.bottom && m.left+p.width < c.right) { // normal case: room on bottom and right
popup.style.top = m.bottom + "px";
popup.style.left = m.left + "px";
t = 1;
}
else if (m.top-p.height > c.top && m.left+p.width < c.right) { // room on top and right
popup.style.top = (m.top-p.height) + "px";
popup.style.left = m.left + "px";
t = 2;
}
else if (m.bottom+p.height < c.bottom && m.right-p.width > c.left) { // room on bottom and left
popup.style.top = m.bottom + "px";
popup.style.left = (m.right-p.width) + "px";
t = 3;
}
else if (m.top-p.height > c.top && m.right-p.width > c.left) { // room on top and left
popup.style.top = (m.top-p.height) + "px";
popup.style.left = (m.right-p.width) + "px";
t = 4;
}
else if (m.bottom+p.height < c.bottom && p.width < c.width) { // room on bottom and middle
popup.style.top = m.bottom + "px";
popup.style.left = (c.left+Math.floor((c.width-p.width)/2)) + "px";
t = 5;
}
else if (m.top-p.height > c.top && p.width < c.width) { // room on top and middle
popup.style.top = (m.top-p.height) + "px";
popup.style.left = (c.left+Math.floor((c.width-p.width)/2)) + "px";
t = 6;
}
else if (p.height < c.height && m.right+p.width < c.right) { // room on middle and right
popup.style.top = (c.top+Math.floor((c.height-p.height)/2)) + "px";
popup.style.left = m.right + "px";
t = 7;
}
else if (p.height < c.height && m.left-p.width > c.left) { // room on middle and left
popup.style.top = (c.top+Math.floor((c.height-p.height)/2)) + "px";
popup.style.left = (m.left-p.width) + "px";
t = 8;
}
else { // nothing works, so leave as it is
}
//addmsg("Popup layout "+t);
}
//
// ele = SocialCalc.Popup.DestroyPopupDiv(ele, dragregistered)
//
// Utility function to get rid of the main popup div.
//
SocialCalc.Popup.DestroyPopupDiv = function(ele, dragregistered) {
if (!ele) return;
ele.innerHTML = "";
SocialCalc.DragUnregister(dragregistered); // OK to do this even if not registered
if (ele.parentNode) {
ele.parentNode.removeChild(ele);
}
}
//
// Color Utility Functions
//
SocialCalc.Popup.RGBToHex = function(val) {
var sp = SocialCalc.Popup;
if (val=="") {
return "000000";
}
var rgbvals = val.match(/(\d+)\D+(\d+)\D+(\d+)/);
if (rgbvals) {
return sp.ToHex(rgbvals[1])+sp.ToHex(rgbvals[2])+sp.ToHex(rgbvals[3]);
}
else {
return "000000";
}
}
SocialCalc.Popup.HexDigits="0123456789ABCDEF";
SocialCalc.Popup.ToHex = function(num) {
var sp = SocialCalc.Popup;
var first=Math.floor(num / 16);
var second=num % 16;
return sp.HexDigits.charAt(first)+sp.HexDigits.charAt(second);
}
SocialCalc.Popup.FromHex = function(str) {
var sp = SocialCalc.Popup;
var first = sp.HexDigits.indexOf(str.charAt(0).toUpperCase());
var second = sp.HexDigits.indexOf(str.charAt(1).toUpperCase());
return ((first>=0)?first:0)*16+((second>=0)?second:0);
}
SocialCalc.Popup.HexToRGB = function(val) {
var sp = SocialCalc.Popup;
return "rgb("+sp.FromHex(val.substring(1,3))+","+sp.FromHex(val.substring(3,5))+","+sp.FromHex(val.substring(5,7))+")";
}
SocialCalc.Popup.makeRGB = function(r, g, b) {
return "rgb("+(r>0?r:0)+","+(g>0?g:0)+","+(b>0?b:0)+")";
}
SocialCalc.Popup.splitRGB = function(rgb) {
var parts = rgb.match(/(\d+)\D+(\d+)\D+(\d+)\D/);
if (!parts) {
return {r:0, g:0, b:0};
}
else {
return {r: parts[1]-0, g: parts[2]-0, b: parts[3]-0};
}
}
// * * * * * * * * * * * * * * * *
//
// ROUTINES FOR EACH TYPE
//
// * * * * * * * * * * * * * * * *
//
// List
//
// type: List
// value: value of control,
// display: "value to display",
// custom: true if custom value,
// disabled: t/f,
// attribs: {
// title: "popup title string",
// moveable: t/f,
// width: optional width, e.g., "100px",
// ensureWithin: optional element object to ensure popup fits within if possible
// changedcallback: optional function(attribs, id, newvalue),
// ...
// }
// data: {
// ncols: calculated number of columns
// options: [
// {o: option-name, v: value-to-return,
// a: {option attribs} // optional: {skip: true, custom: true, cancel: true, newcol: true}
// },
// ...]
// }
//
// popupele: gets popup element object when created
// contentele: gets element created with all the content
// listdiv: gets div with list of items
// customele: gets input element with custom value
// dragregistered: gets element, if any, registered as draggable
//
SocialCalc.Popup.Types.List = {};
SocialCalc.Popup.Types.List.Create = function(type, id, attribs) {
var sp = SocialCalc.Popup;
var spt = sp.Types;
var spc = sp.Controls;
var spcid = {type: type, value: "", display: "", data: {}};
//if (spc[id]) {alert("Already created "+id); return;}
spc[id] = spcid;
var spcdata = spcid.data;
spcdata.attribs = attribs || {};
var ele = document.getElementById(id);
if (!ele) {alert("Missing element "+id); return;}
spcdata.mainele = ele;
ele.innerHTML = '<input style="cursor:pointer;width:100px;font-size:smaller;" onfocus="this.blur();" onclick="SocialCalc.Popup.CClick(\''+id+'\');" value="">';
spcdata.options = []; // set to nothing - use Initialize to fill
}
SocialCalc.Popup.Types.List.SetValue = function(type, id, value) {
var i;
var sp = SocialCalc.Popup;
var spt = sp.Types;
var spc = sp.Controls;
var spcdata = spc[id].data;
spcdata.value = value;
spcdata.custom = false;
for (i=0; i<spcdata.options.length; i++) {
o = spcdata.options[i];
if (o.a) {
if (o.a.skip || o.a.custom || o.a.cancel) {
continue;
}
}
if (o.v == spcdata.value) { // matches value
spcdata.display = o.o;
break;
}
}
if (i==spcdata.options.length) { // none found
spcdata.display = "Custom";
spcdata.custom = true;
}
if (spcdata.mainele && spcdata.mainele.firstChild) {
spcdata.mainele.firstChild.value = spcdata.display;
}
}
SocialCalc.Popup.Types.List.SetDisabled = function(type, id, disabled) {
var i;
var sp = SocialCalc.Popup;
var spt = sp.Types;
var spc = sp.Controls;
var spcdata = spc[id].data;
spcdata.disabled = disabled;
if (spcdata.mainele && spcdata.mainele.firstChild) {
spcdata.mainele.firstChild.disabled = disabled;
}
}
SocialCalc.Popup.Types.List.GetValue = function(type, id) {
var sp = SocialCalc.Popup;
var spt = sp.Types;
var spc = sp.Controls;
var spcdata = spc[id].data;
return spcdata.value;
}
// data is: {value: initial value, attribs: {attribs stuff}, options: [{o: option-name, v: value-to-return, a: optional-attribs}, ...]}
SocialCalc.Popup.Types.List.Initialize = function(type, id, data) {
var a;
var sp = SocialCalc.Popup;
var spt = sp.Types;
var spc = sp.Controls;
var spcdata = spc[id].data;
for (a in data.attribs) {
spcdata.attribs[a] = data.attribs[a];
}
spcdata.options = data ? data.options : [];
if (data.value) { // if has a value, set to it
sp.SetValue(id, data.value);
}
}
SocialCalc.Popup.Types.List.Reset = function(type) {
var sp = SocialCalc.Popup;
var spt = sp.Types;
var spc = sp.Controls;
if (sp.Current.id && spc[sp.Current.id].type == type) { // we have a popup
spt[type].Hide(type, sp.Current.id);
sp.Current.id = null;
}
}
SocialCalc.Popup.Types.List.Show = function(type, id) {
var i, ele, o, bg;
var sp = SocialCalc.Popup;
var spt = sp.Types;
var spc = sp.Controls;
var spcdata = spc[id].data
var str = "";
spcdata.popupele = sp.CreatePopupDiv(id, spcdata.attribs);
if (spcdata.custom) {
str = SocialCalc.Popup.Types.List.MakeCustom(type, id);
ele = document.createElement("div");
ele.innerHTML = '<div style="cursor:default;padding:4px;background-color:#CCC;">'+str+'</div>';
spcdata.customele = ele.firstChild.firstChild.childNodes[1];
spcdata.listdiv = null;
spcdata.contentele = ele;
}
else {
str = SocialCalc.Popup.Types.List.MakeList(type, id);
ele = document.createElement("div");
ele.innerHTML = '<div style="cursor:default;padding:4px;">'+str+'</div>';
spcdata.customele = null;
spcdata.listdiv = ele.firstChild;
spcdata.contentele = ele;
}
if (spcdata.mainele && spcdata.mainele.firstChild) {
spcdata.mainele.firstChild.disabled = true;
}
spcdata.popupele.appendChild(ele);
if (spcdata.attribs.ensureWithin) {
SocialCalc.Popup.EnsurePosition(id, spcdata.attribs.ensureWithin);
}
}
SocialCalc.Popup.Types.List.MakeList = function(type, id) {
var i, ele, o, bg;
var sp = SocialCalc.Popup;
var spt = sp.Types;
var spc = sp.Controls;
var spcdata = spc[id].data
var str = '<table cellspacing="0" cellpadding="0"><tr>';
var td = '<td style="vertical-align:top;">';
str += td;
spcdata.ncols = 1;
for (i=0; i<spcdata.options.length; i++) {
o = spcdata.options[i];
if (o.a) {
if ( o.a.newcol) {
str += '</td>'+td+" "+'</td>'+td;
spcdata.ncols += 1;
continue;
}
if (o.a.skip) {
str += '<div style="font-size:x-small;white-space:nowrap;">'+o.o+'</div>';
continue;
}
}
if (o.v == spcdata.value && !(o.a && (o.a.custom || o.a.cancel))) { // matches value
bg = "background-color:#DDF;";
}
else {
bg = "";
}
str += '<div style="font-size:x-small;white-space:nowrap;'+bg+'" onclick="SocialCalc.Popup.Types.List.ItemClicked(\''+id+'\',\''+i+'\');" onmousemove="SocialCalc.Popup.Types.List.MouseMove(\''+id+'\',this);">'+o.o+'</div>';
}
str += "</td></tr></table>";
return str;
}
SocialCalc.Popup.Types.List.MakeCustom = function(type, id) {
var SPLoc = SocialCalc.Popup.LocalizeString;
var i, ele, o, bg;
var sp = SocialCalc.Popup;
var spt = sp.Types;
var spc = sp.Controls;
var spcdata = spc[id].data;
var style = 'style="font-size:smaller;"';
var str = "";
var val = spcdata.value;
val = SocialCalc.special_chars(val);
str = '<div style="white-space:nowrap;"><br>'+
'<input id="customvalue" value="'+val+'"><br><br>'+
'<input '+style+' type="button" value="'+SPLoc("OK")+'" onclick="SocialCalc.Popup.Types.List.CustomOK(\''+id+'\');return false;">'+
'<input '+style+' type="button" value="'+SPLoc("List")+'" onclick="SocialCalc.Popup.Types.List.CustomToList(\''+id+'\');">'+
'<input '+style+' type="button" value="'+SPLoc("Cancel")+'" onclick="SocialCalc.Popup.Close();">'+
'<br></div>';
return str;
}
SocialCalc.Popup.Types.List.ItemClicked = function(id, num) {
var oele, str, nele;
var sp = SocialCalc.Popup;
var spt = sp.Types;
var spc = sp.Controls;
var spcdata = spc[id].data;
var a = spcdata.options[num].a;
if (a && a.custom) {
oele = spcdata.contentele;
str = SocialCalc.Popup.Types.List.MakeCustom("List", id);
nele = document.createElement("div");
nele.innerHTML = '<div style="cursor:default;padding:4px;background-color:#CCC;">'+str+'</div>';
spcdata.customele = nele.firstChild.firstChild.childNodes[1];
spcdata.listdiv = null;
spcdata.contentele = nele;
spcdata.popupele.replaceChild(nele, oele);
if (spcdata.attribs.ensureWithin) {
SocialCalc.Popup.EnsurePosition(id, spcdata.attribs.ensureWithin);
}
return;
}
if (a && a.cancel) {
SocialCalc.Popup.Close();
return;
}
SocialCalc.Popup.SetValue(id, spcdata.options[num].v);
SocialCalc.Popup.Close();
}
SocialCalc.Popup.Types.List.CustomToList = function(id) {
var oele, str, nele;
var sp = SocialCalc.Popup;
var spt = sp.Types;
var spc = sp.Controls;
var spcdata = spc[id].data;
oele = spcdata.contentele;
str = SocialCalc.Popup.Types.List.MakeList("List", id);
nele = document.createElement("div");
nele.innerHTML = '<div style="cursor:default;padding:4px;">'+str+'</div>';
spcdata.customele = null;
spcdata.listdiv = nele.firstChild;
spcdata.contentele = nele;
spcdata.popupele.replaceChild(nele, oele);
if (spcdata.attribs.ensureWithin) {
SocialCalc.Popup.EnsurePosition(id, spcdata.attribs.ensureWithin);
}
}
SocialCalc.Popup.Types.List.CustomOK = function(id) {
var i, c;
var sp = SocialCalc.Popup;
var spt = sp.Types;
var spc = sp.Controls;
var spcdata = spc[id].data;
SocialCalc.Popup.SetValue(id, spcdata.customele.value);
SocialCalc.Popup.Close();
}
SocialCalc.Popup.Types.List.MouseMove = function(id, ele) {
var col, i, c;
var sp = SocialCalc.Popup;
var spt = sp.Types;
var spc = sp.Controls;
var spcdata = spc[id].data;
var list = spcdata.listdiv;
if (!list) return;
var rowele = list.firstChild.firstChild.firstChild; // div.table.tbody.tr
for (col=0; col<spcdata.ncols; col++) {
for (i=0; i<rowele.childNodes[col*2].childNodes.length; i++) {
rowele.childNodes[col*2].childNodes[i].style.backgroundColor = "#FFF";
}
}
ele.style.backgroundColor = "#DDF";
}
SocialCalc.Popup.Types.List.Hide = function(type, id) {
var sp = SocialCalc.Popup;
var spt = sp.Types;
var spc = sp.Controls;
var spcdata = spc[id].data;
sp.DestroyPopupDiv(spcdata.popupele, spcdata.dragregistered);
spcdata.popupele = null;
if (spcdata.mainele && spcdata.mainele.firstChild) {
spcdata.mainele.firstChild.disabled = false;
}
}
SocialCalc.Popup.Types.List.Cancel = function(type, id) {
SocialCalc.Popup.Types.List.Hide(type, id);
}
//
// ColorChooser
//
// type: ColorChooser
// value: value of control as "rgb(r,g,b)" or "" if default,
// oldvalue: starting value to reset to on close,
// display: "value to display" as hex color value,
// custom: true if custom value,
// disabled: t/f,
// attribs: {
// title: "popup title string",
// moveable: t/f,
// width: optional width, e.g., "100px", of popup chooser
// ensureWithin: optional element object to ensure popup fits within if possible
// sampleWidth: optional width, e.g., "20px",
// sampleHeight: optional height, e.g., "20px",
// backgroundImage: optional background image for sample (transparent where want to show current color), e.g., "colorbg.gif"
// backgroundImageDefault: optional background image for sample when default (transparent shows white)
// backgroundImageDisabled: optional background image for sample when disabled (transparent shows gray)
// changedcallback: optional function(attribs, id, newvalue),
// ...
// }
// data: {
// }
//
// popupele: gets popup element object when created
// contentele: gets element created with all the content
// customele: gets input element with custom value
//
SocialCalc.Popup.Types.ColorChooser = {};
SocialCalc.Popup.Types.ColorChooser.Create = function(type, id, attribs) {
var sp = SocialCalc.Popup;
var spt = sp.Types;
var spc = sp.Controls;
var spcid = {type: type, value: "", display: "", data: {}};
//if (spc[id]) {alert("Already created "+id); return;}
spc[id] = spcid;
var spcdata = spcid.data;
spcdata.attribs = attribs || {};
var spca = spcdata.attribs;
spcdata.value = "";
var ele = document.getElementById(id);
if (!ele) {alert("Missing element "+id); return;}
spcdata.mainele = ele;
ele.innerHTML = '<div style="cursor:pointer;border:1px solid black;vertical-align:top;width:'+
(spca.sampleWidth || '15px')+';height:'+(spca.sampleHeight || '15px')+
';" onclick="SocialCalc.Popup.Types.ColorChooser.ControlClicked(\''+id+'\');"> </div>';
}
SocialCalc.Popup.Types.ColorChooser.SetValue = function(type, id, value) {
var i, img, pos;
var sp = SocialCalc.Popup;
var spt = sp.Types;
var spc = sp.Controls;
var spcdata = spc[id].data;
var spca = spcdata.attribs;
spcdata.value = value;
spcdata.custom = false;
if (spcdata.mainele && spcdata.mainele.firstChild) {
if (spcdata.value) {
spcdata.mainele.firstChild.style.backgroundColor = spcdata.value;
if (spca.backgroundImage) {
img = "url("+sp.imagePrefix+spca.backgroundImage+")";
}
else {
img = "";
}
pos = "center center";
}
else {
spcdata.mainele.firstChild.style.backgroundColor = "#FFF";
if (spca.backgroundImageDefault) {
img = "url("+sp.imagePrefix+spca.backgroundImageDefault+")";
pos = "center center";
}
else {
img = "url("+sp.imagePrefix+"defaultcolor.gif)";
pos = "left top";
}
}
spcdata.mainele.firstChild.style.backgroundPosition = pos;
spcdata.mainele.firstChild.style.backgroundImage = img;
}
}
SocialCalc.Popup.Types.ColorChooser.SetDisabled = function(type, id, disabled) {
var i;
var sp = SocialCalc.Popup;
var spt = sp.Types;
var spc = sp.Controls;
var spcdata = spc[id].data;
var spca = spcdata.attribs;
spcdata.disabled = disabled;
if (spcdata.mainele && spcdata.mainele.firstChild) {
if (disabled) {
spcdata.mainele.firstChild.style.backgroundColor = "#DDD";
if (spca.backgroundImageDisabled) {
img = "url("+sp.imagePrefix+spca.backgroundImageDisabled+")";
pos = "center center";
}
else {
img = "url("+sp.imagePrefix+"defaultcolor.gif)";
pos = "left top";
}
spcdata.mainele.firstChild.style.backgroundPosition = pos;
spcdata.mainele.firstChild.style.backgroundImage = img;
}
else {
sp.SetValue(id, spcdata.value);
}
}
}
SocialCalc.Popup.Types.ColorChooser.GetValue = function(type, id) {
var sp = SocialCalc.Popup;
var spt = sp.Types;
var spc = sp.Controls;
var spcdata = spc[id].data;
return spcdata.value;
}
SocialCalc.Popup.Types.ColorChooser.Initialize = function(type, id, data) {
var a;
var sp = SocialCalc.Popup;
var spt = sp.Types;
var spc = sp.Controls;
var spcdata = spc[id].data;
for (a in data.attribs) {
spcdata.attribs[a] = data.attribs[a];
}
if (data.value) { // if has a value, set to it
sp.SetValue(id, data.value);
}
}
SocialCalc.Popup.Types.ColorChooser.Reset = function(type) {
var sp = SocialCalc.Popup;
var spt = sp.Types;
var spc = sp.Controls;
if (sp.Current.id && spc[sp.Current.id].type == type) { // we have a popup
spt[type].Hide(type, sp.Current.id);
sp.Current.id = null;
}
}
SocialCalc.Popup.Types.ColorChooser.Show = function(type, id) {
var i, ele, mainele;
var sp = SocialCalc.Popup;
var spt = sp.Types;
var spc = sp.Controls;
var spcdata = spc[id].data
var str = "";
spcdata.oldvalue = spcdata.value; // remember starting value
spcdata.popupele = sp.CreatePopupDiv(id, spcdata.attribs);
if (spcdata.custom) {
str = SocialCalc.Popup.Types.ColorChooser.MakeCustom(type, id);
ele = document.createElement("div");
ele.innerHTML = '<div style="cursor:default;padding:4px;background-color:#CCC;">'+str+'</div>';
spcdata.customele = ele.firstChild.firstChild.childNodes[2];
spcdata.contentele = ele;
}
else {
mainele = SocialCalc.Popup.Types.ColorChooser.CreateGrid(type, id);
ele = document.createElement("div");
ele.style.padding = "3px";
ele.style.backgroundColor = "#CCC";
ele.appendChild(mainele);
spcdata.customele = null;
spcdata.contentele = ele;
}
spcdata.popupele.appendChild(ele);
if (spcdata.attribs.ensureWithin) {
SocialCalc.Popup.EnsurePosition(id, spcdata.attribs.ensureWithin);
}
}
SocialCalc.Popup.Types.ColorChooser.MakeCustom = function(type, id) {
var i, ele, o, bg;
var sp = SocialCalc.Popup;
var spt = sp.Types;
var spc = sp.Controls;
var spcdata = spc[id].data;
var SPLoc = sp.LocalizeString;
var style = 'style="font-size:smaller;"';
var str = "";
str = '<div style="white-space:nowrap;"><br>'+
'#<input id="customvalue" style="width:75px;" value="'+spcdata.value+'"><br><br>'+
'<input '+style+' type="button" value="'+SPLoc("OK")+'" onclick="SocialCalc.Popup.Types.ColorChooser.CustomOK(\''+id+'\');return false;">'+
'<input '+style+' type="button" value="'+SPLoc("Grid")+'" onclick="SocialCalc.Popup.Types.ColorChooser.CustomToGrid(\''+id+'\');">'+
'<br></div>';
return str;
}
SocialCalc.Popup.Types.ColorChooser.ItemClicked = function(id, num) {
var oele, str, nele;
var sp = SocialCalc.Popup;
var spt = sp.Types;
var spc = sp.Controls;
var spcdata = spc[id].data;
SocialCalc.Popup.Close();
}
SocialCalc.Popup.Types.ColorChooser.CustomToList = function(id) {
var oele, str, nele;
var sp = SocialCalc.Popup;
var spt = sp.Types;
var spc = sp.Controls;
var spcdata = spc[id].data;
}
SocialCalc.Popup.Types.ColorChooser.CustomOK = function(id) {
var i, c;
var sp = SocialCalc.Popup;
var spt = sp.Types;
var spc = sp.Controls;
var spcdata = spc[id].data;
sp.SetValue(id, spcdata.customele.value);
sp.Close();
}
SocialCalc.Popup.Types.ColorChooser.Hide = function(type, id) {
var sp = SocialCalc.Popup;
var spt = sp.Types;
var spc = sp.Controls;
var spcdata = spc[id].data;
sp.DestroyPopupDiv(spcdata.popupele, spcdata.dragregistered);
spcdata.popupele = null;
}
SocialCalc.Popup.Types.ColorChooser.Cancel = function(type, id) {
var sp = SocialCalc.Popup;
var spt = sp.Types;
var spc = sp.Controls;
var spcdata = spc[id].data;
sp.SetValue(id, spcdata.oldvalue); // reset to old value
SocialCalc.Popup.Types.ColorChooser.Hide(type, id);
}
SocialCalc.Popup.Types.ColorChooser.CreateGrid = function (type, id) {
var ele, pos, row, rowele, col, g;
var sp = SocialCalc.Popup;
var spt = sp.Types;
var spc = sp.Controls;
var SPLoc = sp.LocalizeString;
var spcdata = spc[id].data;
spcdata.grid = {};
var grid = spcdata.grid;
var mainele = document.createElement("div");
ele = document.createElement("table");
ele.cellSpacing = 0;
ele.cellPadding = 0;
ele.style.width = "100px";
grid.table = ele;
ele = document.createElement("tbody");
grid.table.appendChild(ele);
grid.tbody = ele;
for (row=0; row<16; row++) {
rowele = document.createElement("tr");
for (col=0; col<5; col++) {
g = {};
grid[row+","+col] = g;
ele = document.createElement("td");
ele.style.fontSize = "1px";
ele.innerHTML = " ";
ele.style.height = "10px";
if (col<=1) {
ele.style.width = "17px";
ele.style.borderRight = "3px solid white";
}
else {
ele.style.width = "20px";
ele.style.backgroundRepeat = "no-repeat";
}
rowele.appendChild(ele);
g.ele = ele;
}
grid.tbody.appendChild(rowele);
}
mainele.appendChild(grid.table);
ele = document.createElement("div");
ele.style.marginTop = "3px";
ele.innerHTML = '<table cellspacing="0" cellpadding="0"><tr>'+
'<td style="width:17px;background-color:#FFF;background-image:url('+sp.imagePrefix+'defaultcolor.gif);height:16px;font-size:10px;cursor:pointer;" title="'+SPLoc("Default")+'"> </td>'+
'<td style="width:23px;height:16px;font-size:10px;text-align:center;cursor:pointer;" title="'+SPLoc("Custom")+'">#</td>'+
'<td style="width:60px;height:16px;font-size:10px;text-align:center;cursor:pointer;">'+SPLoc("OK")+'</td>'+
'</tr></table>';
grid.defaultbox = ele.firstChild.firstChild.firstChild.childNodes[0];
grid.defaultbox.onclick = spt.ColorChooser.DefaultClicked;
grid.custom = ele.firstChild.firstChild.firstChild.childNodes[1];
grid.custom.onclick = spt.ColorChooser.CustomClicked;
grid.msg = ele.firstChild.firstChild.firstChild.childNodes[2];
grid.msg.onclick = spt.ColorChooser.CloseOK;
mainele.appendChild(ele);
grid.table.onmousedown = spt.ColorChooser.GridMouseDown;
spt.ColorChooser.DetermineColors(id);
spt.ColorChooser.SetColors(id);
return mainele;
}
SocialCalc.Popup.Types.ColorChooser.gridToG = function(grid, row, col) {
return grid[row+","+col];
}
SocialCalc.Popup.Types.ColorChooser.DetermineColors = function(id) {
var sp = SocialCalc.Popup;
var spt = sp.Types;
var sptc = spt.ColorChooser;
var spc = sp.Controls;
var spcdata = spc[id].data;
var grid = spcdata.grid;
var col, row;
var rgb = sp.splitRGB(spcdata.value);
var color;
col = 2;
row = 16-Math.floor((rgb.r+16)/16);
grid["selectedrow"+col] = row;
for (row=0; row<16; row++) {
sptc.gridToG(grid,row,col).rgb = sp.makeRGB(17*(15-row),0,0);
}
col = 3;
row = 16-Math.floor((rgb.g+16)/16);
grid["selectedrow"+col] = row;
for (row=0; row<16; row++) {
sptc.gridToG(grid,row,col).rgb = sp.makeRGB(0,17*(15-row),0);
}
col = 4;
row = 16-Math.floor((rgb.b+16)/16);
grid["selectedrow"+col] = row;
for (row=0; row<16; row++) {
sptc.gridToG(grid,row,col).rgb = sp.makeRGB(0,0,17*(15-row));
}
col = 1;
for (row=0; row<16; row++) {
sptc.gridToG(grid,row,col).rgb = sp.makeRGB(17*(15-row),17*(15-row),17*(15-row));
}
col = 0;
var steps = [0, 68, 153, 204, 255];
var commonrgb = ["400", "310", "420", "440", "442", "340", "040", "042", "032", "044", "024", "004", "204", "314", "402", "414"];
var x;
for (row=0; row<16; row++) {
x = commonrgb[row];
sptc.gridToG(grid,row,col).rgb = "rgb("+steps[x.charAt(0)-0]+","+steps[x.charAt(1)-0]+","+steps[x.charAt(2)-0]+")";
}
}
SocialCalc.Popup.Types.ColorChooser.SetColors = function(id) {
var row, col, g, ele, rgb;
var sp = SocialCalc.Popup;
var spt = sp.Types;
var sptc = spt.ColorChooser;
var spc = sp.Controls;
var spcdata = spc[id].data;
var grid = spcdata.grid;
for (row=0; row<16; row++) {
for (col=0; col<5; col++) {
g = sptc.gridToG(grid,row, col);
g.ele.style.backgroundColor = g.rgb;
g.ele.title = sp.RGBToHex(g.rgb);
if (grid["selectedrow"+col]==row) {
g.ele.style.backgroundImage = "url("+sp.imagePrefix+"chooserarrow.gif)";
}
else {
g.ele.style.backgroundImage = "";
}
}
}
sp.SetValue(id, spcdata.value);
grid.msg.style.backgroundColor = spcdata.value;
rgb = sp.splitRGB(spcdata.value || "rgb(255,255,255)");
if (rgb.r+rgb.g+rgb.b < 220) {
grid.msg.style.color = "#FFF";
}
else {
grid.msg.style.color = "#000";
}
if (!spcdata.value) { // default
grid.msg.style.backgroundColor = "#FFF";
grid.msg.style.backgroundImage = "url("+sp.imagePrefix+"defaultcolor.gif)";
grid.msg.title = "Default";
}
else {
grid.msg.style.backgroundImage = "";
grid.msg.title = sp.RGBToHex(spcdata.value);
}
}
SocialCalc.Popup.Types.ColorChooser.GridMouseDown = function(e) {
var event = e || window.event;
var sp = SocialCalc.Popup;
var spt = sp.Types;
var sptc = spt.ColorChooser;
var spc = sp.Controls;
var id = sp.Current.id;
if (!id) return;
var spcdata = spc[id].data;
var grid = spcdata.grid;
switch (event.type) {
case "mousedown":
grid.mousedown = true;
break;
case "mouseup":
grid.mousedown = false;
break;
case "mousemove":
if (!grid.mousedown) {
return;
}
break;
}
var pos = SocialCalc.GetElementPositionWithScroll(spcdata.mainele);
var clientX = event.clientX - pos.left;
var clientY = event.clientY - pos.top;
var gpos = SocialCalc.GetElementPositionWithScroll(grid.table);
gpos.left -= pos.left;
gpos.top -= pos.top
var row = Math.floor((clientY-gpos.top-2)/10); // -2 is to split the diff btw IE & FF
row = row < 0 ? 0 : row;
var col = Math.floor((clientX-gpos.left)/20);
row = row < 0 ? 0 : (row > 15 ? 15 : row);
col = col < 0 ? 0 : (col > 4 ? 4 : col);
var color = sptc.gridToG(grid,row,col).ele.style.backgroundColor;
var newrgb = sp.splitRGB(color);
var oldrgb = sp.splitRGB(spcdata.value);
switch (col) {
case 2:
spcdata.value = sp.makeRGB(newrgb.r, oldrgb.g, oldrgb.b);
break;
case 3:
spcdata.value = sp.makeRGB(oldrgb.r, newrgb.g, oldrgb.b);
break;
case 4:
spcdata.value = sp.makeRGB(oldrgb.r, oldrgb.g, newrgb.b);
break;
case 0:
case 1:
spcdata.value = color;
}
sptc.DetermineColors(id);
sptc.SetColors(id);
}
SocialCalc.Popup.Types.ColorChooser.ControlClicked = function(id) {
var sp = SocialCalc.Popup;
var spt = sp.Types;
var sptc = spt.ColorChooser;
var spc = sp.Controls;
var cid = sp.Current.id;
if (!cid || id != cid) {
sp.CClick(id);
return;
}
sptc.CloseOK();
}
SocialCalc.Popup.Types.ColorChooser.DefaultClicked = function(e) {
var event = e || window.event;
var sp = SocialCalc.Popup;
var spt = sp.Types;
var sptc = spt.ColorChooser;
var spc = sp.Controls;
var id = sp.Current.id;
if (!id) return;
var spcdata = spc[id].data;
spcdata.value = "";
SocialCalc.Popup.SetValue(id, spcdata.value);
SocialCalc.Popup.Close();
}
SocialCalc.Popup.Types.ColorChooser.CustomClicked = function(e) {
var event = e || window.event;
var sp = SocialCalc.Popup;
var spt = sp.Types;
var sptc = spt.ColorChooser;
var spc = sp.Controls;
var id = sp.Current.id;
if (!id) return;
var spcdata = spc[id].data;
var oele, str, nele;
oele = spcdata.contentele;
str = SocialCalc.Popup.Types.ColorChooser.MakeCustom("ColorChooser", id);
nele = document.createElement("div");
nele.innerHTML = '<div style="cursor:default;padding:4px;background-color:#CCC;">'+str+'</div>';
spcdata.customele = nele.firstChild.firstChild.childNodes[2];
spcdata.contentele = nele;
spcdata.popupele.replaceChild(nele, oele);
spcdata.customele.value = sp.RGBToHex(spcdata.value);
if (spcdata.attribs.ensureWithin) {
SocialCalc.Popup.EnsurePosition(id, spcdata.attribs.ensureWithin);
}
}
SocialCalc.Popup.Types.ColorChooser.CustomToGrid = function(id) {
var oele, str, nele;
var sp = SocialCalc.Popup;
var spt = sp.Types;
var spc = sp.Controls;
var spcdata = spc[id].data;
SocialCalc.Popup.SetValue(id, sp.HexToRGB("#"+spcdata.customele.value));
var oele, mainele, nele;
oele = spcdata.contentele;
mainele = SocialCalc.Popup.Types.ColorChooser.CreateGrid("ColorChooser", id);
nele = document.createElement("div");
nele.style.padding = "3px";
nele.style.backgroundColor = "#CCC";
nele.appendChild(mainele);
spcdata.customele = null;
spcdata.contentele = nele;
spcdata.popupele.replaceChild(nele, oele);
if (spcdata.attribs.ensureWithin) {
SocialCalc.Popup.EnsurePosition(id, spcdata.attribs.ensureWithin);
}
}
SocialCalc.Popup.Types.ColorChooser.CustomOK = function(id) {
var i, c;
var sp = SocialCalc.Popup;
var spt = sp.Types;
var spc = sp.Controls;
var spcdata = spc[id].data;
SocialCalc.Popup.SetValue(id, sp.HexToRGB("#"+spcdata.customele.value));
SocialCalc.Popup.Close();
}
SocialCalc.Popup.Types.ColorChooser.CloseOK = function(e) {
var event = e || window.event;
var sp = SocialCalc.Popup;
var spt = sp.Types;
var sptc = spt.ColorChooser;
var spc = sp.Controls;
var id = sp.Current.id;
if (!id) return;
var spcdata = spc[id].data;
SocialCalc.Popup.SetValue(id, spcdata.value);
SocialCalc.Popup.Close();
}