Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Major additions (see Changes.txt for specifics and bug fixes):

drag-repeat, drag handles for fill/move/slide (two new images),
foundation for startup macros and external commands,
added "edit:" to CtrlS for editing OtherSaveParts,
added socialcalcspreadsheetviewer.js for non-editing grid display.

Signed-off-by: DanBricklin <danb@bricklin.com>
  • Loading branch information...
commit 4594429c94d18f295616a9cf2839b5c554ba7d9c 1 parent b294728
@DanBricklin authored
View
36 Changes.txt
@@ -613,6 +613,42 @@ Minor change to SocialCalc.special_chars to clean up regex. Not a bug, but a min
2009-11-03:
Added text format Wikitext to SCFormatTextFormats in socialcalcconstants.js
+2009-12-02:
+Added missing // to socialcalcspreadsheetcontrol.js setting of tabBackground.
+Set minOK to 0 just in case in formatnumber2.js.
+
+2010-01-14:
+Changed socialcalctableeditor.js to do auto-repeat in drag select.
+Made formula editing reset position of InputEcho after pointing in case cell position has changed.
+Added beginning of SocialCalc.CellHandles to socialcalctableeditor.js. Had test code, but now just returns.
+
+2010-02-09:
+Fixed bug where undo stack didn't always set changedrendervalues so moves/pastes/etc of merged cells messed up display
+
+2010-03-23:
+Finished changes to add editor.noEdit to socialcalctableeditor.js, including
+fixing thumb dragging to better handle mouse out of window, handling no socialcalcspreadsheetcontrol.js,
+etc.
+
+2010-03-25:
+Added socialcalcviewer.js.
+Fixed bug in SocialCalc.InitializeSpreadsheetControl that didn't take padding into account when sizing status line.
+
+2010-04-13:
+Added CmdExtensions to socialcalc-3.js, and the startcmdextension command.
+
+2010-05-07:
+Implemented drag handles for fill/move using a single image with a round, segmented palette. Added sc-drag-handles.png.
+
+2010-05-12:
+Added SocialCalc.CtrlSEditor to socialcalctableeditor.js and socialcalcspreadsheetcontrol.js.
+Use "edit:partname" command to edit, "edit:" to list all parts and contents. No text deletes part.
+Added SocialCalc.OtherSaveParts to socialcalcspreadsheetcontrol.js.
+This all gives us a way to set startup macros, etc.
+
+2010-05-13:
+Fixed IE6 and IE7+ compatibility issues with drag palette. Uses .gif for IE6, .png otherwise.
+
TO DO:
View
2  formatnumber2.js
@@ -251,7 +251,7 @@ SocialCalc.FormatNumber.formatNumberWithFormat = function(rawvalue, format_strin
ymd = SocialCalc.FormatNumber.convert_date_julian_to_gregorian(Math.floor(rawvalue+scfn.datevalues.julian_offset));
- minOK; // says "m" can be minutes
+ minOK = 0; // says "m" can be minutes if true
mspos = sectioninfo.sectionstart; // m scan position in ops
for ( ; ; mspos++) { // scan for "m" and "mm" to see if any minutes fields, and am/pm
op = thisformat.operators[mspos];
View
BIN  images/sc-drag-handles.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  images/sc-drag-handles.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
214 socialcalc-3.js
@@ -2,7 +2,7 @@
// The main SocialCalc code module of the SocialCalc package
//
/*
-// (c) Copyright 2008 Socialtext, Inc.
+// (c) Copyright 2010 Socialtext, Inc.
// All Rights Reserved.
//
// The contents of this file are subject to the Artistic License 2.0; you may not
@@ -1588,8 +1588,11 @@ SocialCalc.SheetCommandInfo = { // only one of these
maxtimeslice: 100, // do another slice after this many milliseconds
saveundo: false, // arg for ExecuteSheetCommand
- statuscallback: null, // called during execution
- statuscallbackparams: null
+ CmdExtensionCallbacks: {}, // for startcmdextension, in form: cmdname, {func:function(cmdname, data, sheet, SocialCalc.Parse object, saveundo), data:whatever}
+ cmdextensionbusy: "" // if length>0, command loop waits for SocialCalc.ResumeFromCmdExtension()
+
+// statuscallback: null, // called during execution - obsolete: use sheet obj's
+// statuscallbackparams: null
};
@@ -1634,6 +1637,13 @@ SocialCalc.SheetCommandsTimerRoutine = function() {
sci.parseobj.NextLine();
+ if (sci.cmdextensionbusy.length > 0) { // forced wait
+ if (sci.sheetobj.statuscallback) { // notify others if requested
+ sci.sheetobj.statuscallback(sci, "cmdextension", sci.cmdextensionbusy, sci.sheetobj.statuscallbackparams);
+ }
+ return;
+ }
+
if (((new Date()) - starttime) >= sci.maxtimeslice) { // if taking too long, give up CPU for a while
sci.timerobj = window.setTimeout(SocialCalc.SheetCommandsTimerRoutine, sci.timerdelay);
return;
@@ -1646,6 +1656,15 @@ SocialCalc.SheetCommandsTimerRoutine = function() {
}
+SocialCalc.ResumeFromCmdExtension = function() {
+
+ var sci = SocialCalc.SheetCommandInfo;
+
+ sci.cmdextensionbusy = "";
+
+ SocialCalc.SheetCommandsTimerRoutine();
+
+}
//
// errortext = SocialCalc.ExecuteSheetCommand(sheet, cmd, saveundo)
@@ -1675,12 +1694,15 @@ SocialCalc.SheetCommandsTimerRoutine = function() {
// unmerge C3
// insertcol/insertrow C5
// deletecol/deleterow C5:E7
-// movepaste/moveinsert A1:B5 A8 (if insert, destination must be in same rows or columns or else paste done)
+// movepaste/moveinsert A1:B5 A8 all/formulas/format (if insert, destination must be in same rows or columns or else paste done)
+// sort cr1:cr2 col1 up/down col2 up/down col3 up/down
// name define NAME definition
// name desc NAME description
// name delete NAME
// recalc
// redisplay
+// changedrendervalues
+// startcmdextension extension rest-of-command
//
// If saveundo is true, then undo information is saved in sheet.changes.
//
@@ -1696,6 +1718,7 @@ SocialCalc.ExecuteSheetCommand = function(sheet, cmd, saveundo) {
var cols, dirs, lastsortcol, i, sortlist, sortcells, sortvalues, sorttypes;
var sortfunction, slen, valtype, originalrow, sortedcr;
var name, v1, v2;
+ var cmdextension;
var attribs = sheet.attribs;
var changes = sheet.changes;
@@ -1975,6 +1998,7 @@ SocialCalc.ExecuteSheetCommand = function(sheet, cmd, saveundo) {
rest = cmd.RestOfString();
ParseRange();
+ if (saveundo) changes.AddUndo("changedrendervalues"); // to take care of undone pasted spans
if (cmd1=="cut") { // save copy of whole thing before erasing
if (saveundo) changes.AddUndo("loadclipboard", SocialCalc.encodeForSave(SocialCalc.Clipboard.clipboard));
SocialCalc.Clipboard.clipboard = SocialCalc.CreateSheetSave(sheet, what);
@@ -2020,6 +2044,7 @@ SocialCalc.ExecuteSheetCommand = function(sheet, cmd, saveundo) {
case "filldown":
sheet.renderneeded = true;
sheet.changedrendervalues = true;
+ if (saveundo) changes.AddUndo("changedrendervalues"); // to take care of undone pasted spans
what = cmd.NextToken();
rest = cmd.RestOfString();
ParseRange();
@@ -2101,6 +2126,7 @@ SocialCalc.ExecuteSheetCommand = function(sheet, cmd, saveundo) {
case "paste":
sheet.renderneeded = true;
sheet.changedrendervalues = true;
+ if (saveundo) changes.AddUndo("changedrendervalues"); // to take care of undone pasted spans
what = cmd.NextToken();
rest = cmd.RestOfString();
ParseRange();
@@ -2170,6 +2196,7 @@ SocialCalc.ExecuteSheetCommand = function(sheet, cmd, saveundo) {
case "sort": // sort cr1:cr2 col1 up/down col2 up/down col3 up/down
sheet.renderneeded = true;
sheet.changedrendervalues = true;
+ if (saveundo) changes.AddUndo("changedrendervalues"); // to take care of undone pasted spans
what = cmd.NextToken();
ParseRange();
cols = []; // get columns and sort directions (or "")
@@ -2582,16 +2609,19 @@ SocialCalc.ExecuteSheetCommand = function(sheet, cmd, saveundo) {
case "movepaste":
case "moveinsert":
- var movingcells, destcr, inserthoriz, insertvert, pushamount, movedto;
+ var movingcells, dest, destcr, inserthoriz, insertvert, pushamount, movedto;
sheet.renderneeded = true;
sheet.changedrendervalues = true;
+ if (saveundo) changes.AddUndo("changedrendervalues"); // to take care of undone pasted spans
what = cmd.NextToken();
- rest = cmd.RestOfString();
+ dest = cmd.NextToken();
+ rest = cmd.RestOfString(); // rest is all/formulas/formats
+ if (rest=="") rest = "all";
ParseRange();
- destcr = SocialCalc.coordToCr(rest);
+ destcr = SocialCalc.coordToCr(dest);
coloffset = destcr.col - cr1.col;
rowoffset = destcr.row - cr1.row;
@@ -2607,9 +2637,41 @@ SocialCalc.ExecuteSheetCommand = function(sheet, cmd, saveundo) {
cr = SocialCalc.crToCoord(col, row);
cell=sheet.GetAssuredCell(cr);
if (saveundo) changes.AddUndo("set "+cr+" all", sheet.CellToString(cell));
- if (sheet.cells[cr]) { // if had something
- movingcells[cr] = sheet.cells[cr]; // save it
- delete sheet.cells[cr]; // and delete from sheet
+
+ if (!sheet.cells[cr]) { // if had nothing
+ continue; // don't save anything
+ }
+ movingcells[cr] = new SocialCalc.Cell(cr); // create new cell to copy
+
+ for (attrib in cellProperties) { // go through each property
+ if (typeof cell[attrib] === undefined) { // don't copy undefined things and no need to delete
+ continue;
+ }
+ else {
+ movingcells[cr][attrib] = cell[attrib]; // copy for potential moving
+ }
+ if (rest == "all") {
+ delete cell[attrib];
+ }
+ if (rest == "formulas") {
+ if (cellProperties[attrib] == 1 || cellProperties[attrib] == 3) {
+ delete cell[attrib];
+ }
+ }
+ if (rest == "formats") {
+ if (cellProperties[attrib] == 2) {
+ delete cell[attrib];
+ }
+ }
+ }
+ if (rest == "formulas") { // leave pristene deleted cell
+ cell.datavalue = "";
+ cell.datatype = null;
+ cell.formula = "";
+ cell.valuetype = "b";
+ }
+ if (rest == "all") { // leave nothing for move all
+ delete sheet.cells[cr];
}
}
}
@@ -2656,22 +2718,40 @@ SocialCalc.ExecuteSheetCommand = function(sheet, cmd, saveundo) {
for (row = 0; row < pushamount; row++) {
for (col = cr1.col; col <= cr2.col; col++) {
if (insertvert < 0) {
- cr = SocialCalc.crToCoord(col, destcr.row+pushamount-row-1);
- crbase = SocialCalc.crToCoord(col, cr2.row-row);
+ crbase = SocialCalc.crToCoord(col, destcr.row+pushamount-row-1); // from cell
+ cr = SocialCalc.crToCoord(col, cr2.row-row); // to cell
}
else {
- cr = SocialCalc.crToCoord(col, destcr.row-pushamount+row+1);
- crbase = SocialCalc.crToCoord(col, cr1.row+row);
+ crbase = SocialCalc.crToCoord(col, destcr.row-pushamount+row+1); // from cell
+ cr = SocialCalc.crToCoord(col, cr1.row+row); // to cell
}
- cell=sheet.GetAssuredCell(cr);
- if (saveundo) changes.AddUndo("set "+cr+" all", sheet.CellToString(cell));
- if (sheet.cells[cr]) {
- sheet.cells[crbase] = sheet.cells[cr];
+
+ basecell = sheet.GetAssuredCell(crbase);
+ if (saveundo) changes.AddUndo("set "+crbase+" all", sheet.CellToString(basecell));
+
+ cell = sheet.GetAssuredCell(cr);
+ if (rest == "all" || rest == "formats") {
+ for (attrib in cellProperties) {
+ if (cellProperties[attrib] == 1) continue; // copy only format attributes
+ if (typeof basecell[attrib] === undefined || cellProperties[attrib] == 3) {
+ delete cell[attrib];
+ }
+ else {
+ cell[attrib] = basecell[attrib];
+ }
+ }
}
- else {
- delete sheet.cells[crbase];
+ if (rest == "all" || rest == "formulas") {
+ cell.datavalue = basecell.datavalue;
+ cell.datatype = basecell.datatype;
+ cell.valuetype = basecell.valuetype;
+ cell.formula = basecell.formula;
+ delete cell.parseinfo;
+ cell.errors = basecell.errors;
}
- movedto[cr] = crbase; // old cr is now at crbase
+ delete cell.displaystring;
+
+ movedto[crbase] = cr; // old crbase is now at cr
}
}
}
@@ -2679,22 +2759,40 @@ SocialCalc.ExecuteSheetCommand = function(sheet, cmd, saveundo) {
for (col = 0; col < pushamount; col++) {
for (row = cr1.row; row <= cr2.row; row++) {
if (inserthoriz < 0) {
- cr = SocialCalc.crToCoord(destcr.col+pushamount-col-1, row);
- crbase = SocialCalc.crToCoord(cr2.col-col, row);
+ crbase = SocialCalc.crToCoord(destcr.col+pushamount-col-1, row);
+ cr = SocialCalc.crToCoord(cr2.col-col, row);
}
else {
- cr = SocialCalc.crToCoord(destcr.col-pushamount+col+1, row);
- crbase = SocialCalc.crToCoord(cr1.col+col, row);
+ crbase = SocialCalc.crToCoord(destcr.col-pushamount+col+1, row);
+ cr = SocialCalc.crToCoord(cr1.col+col, row);
}
- cell=sheet.GetAssuredCell(cr);
- if (saveundo) changes.AddUndo("set "+cr+" all", sheet.CellToString(cell));
- if (sheet.cells[cr]) {
- sheet.cells[crbase] = sheet.cells[cr];
+
+ basecell = sheet.GetAssuredCell(crbase);
+ if (saveundo) changes.AddUndo("set "+crbase+" all", sheet.CellToString(basecell));
+
+ cell = sheet.GetAssuredCell(cr);
+ if (rest == "all" || rest == "formats") {
+ for (attrib in cellProperties) {
+ if (cellProperties[attrib] == 1) continue; // copy only format attributes
+ if (typeof basecell[attrib] === undefined || cellProperties[attrib] == 3) {
+ delete cell[attrib];
+ }
+ else {
+ cell[attrib] = basecell[attrib];
+ }
+ }
}
- else {
- delete sheet.cells[crbase];
+ if (rest == "all" || rest == "formulas") {
+ cell.datavalue = basecell.datavalue;
+ cell.datatype = basecell.datatype;
+ cell.valuetype = basecell.valuetype;
+ cell.formula = basecell.formula;
+ delete cell.parseinfo;
+ cell.errors = basecell.errors;
}
- movedto[cr] = crbase; // old cr is now at crbase
+ delete cell.displaystring;
+
+ movedto[crbase] = cr; // old crbase is now at cr
}
}
}
@@ -2709,13 +2807,45 @@ SocialCalc.ExecuteSheetCommand = function(sheet, cmd, saveundo) {
cr = SocialCalc.crToCoord(col+coloffset, row+rowoffset);
cell=sheet.GetAssuredCell(cr);
if (saveundo) changes.AddUndo("set "+cr+" all", sheet.CellToString(cell));
- delete sheet.cells[cr]; // delete what used to be there at destination
crbase = SocialCalc.crToCoord(col, row); // get old cell to move
- if (movingcells[crbase]) { // if has something
- sheet.cells[cr] = movingcells[crbase]; // copy it in
+
+ movedto[crbase] = cr; // old crbase (moved cell) will now be at cr (destination)
+
+ if (rest == "all" && !movingcells[crbase]) { // moving an empty cell
+ delete sheet.cells[cr]; // make the cell empty
+ continue;
}
- movedto[crbase] = cr; // old crbase (moved cell) is now at cr (destination)
+
+ basecell = movingcells[crbase];
+ if (!basecell) basecell = sheet.GetAssuredCell(crbase);
+
+ if (rest == "all" || rest == "formats") {
+ for (attrib in cellProperties) {
+ if (cellProperties[attrib] == 1) continue; // copy only format attributes
+ if (typeof basecell[attrib] === undefined || cellProperties[attrib] == 3) {
+ delete cell[attrib];
+ }
+ else {
+ cell[attrib] = basecell[attrib];
+ }
+ }
+ }
+ if (rest == "all" || rest == "formulas") {
+ cell.datavalue = basecell.datavalue;
+ cell.datatype = basecell.datatype;
+ cell.valuetype = basecell.valuetype;
+ cell.formula = basecell.formula;
+ delete cell.parseinfo;
+ cell.errors = basecell.errors;
+ if (basecell.comment) { // comments are pasted as part of content, though not filled, etc.
+ cell.comment = basecell.comment;
+ }
+ else if (cell.comment) {
+ delete cell.comment;
+ }
+ }
+ delete cell.displaystring;
}
}
@@ -2805,6 +2935,18 @@ SocialCalc.ExecuteSheetCommand = function(sheet, cmd, saveundo) {
sheet.renderneeded = true;
break;
+ case "changedrendervalues": // needed for undo sometimes
+ sheet.changedrendervalues = true;
+ break;
+
+ case "startcmdextension": // startcmdextension extension rest-of-command
+ name = cmd.NextToken();
+ cmdextension = SocialCalc.SheetCommandInfo.CmdExtensionCallbacks[name];
+ if (cmdextension) {
+ cmdextension.func(name, cmdextension.data, sheet, cmd, saveundo);
+ }
+ break;
+
default:
errortext = scc.s_escUnknownCmd+cmdstr;
break;
View
33 socialcalcconstants.js
@@ -3,7 +3,7 @@
// The module of the SocialCalc package with customizable constants, strings, etc.
// This is where most of the common localizations are done.
//
-// (c) Copyright 2008, 2009 Socialtext, Inc.
+// (c) Copyright 2008, 2009, 2010 Socialtext, Inc.
// All Rights Reserved.
//
// The contents of this file are subject to the Artistic License 2.0; you may not
@@ -223,6 +223,20 @@ SocialCalc.Constants = {
ietUnknownFunction: "Unknown function ", // displayed when typing "=unknown("
+ //** SocialCalc.CellHandles
+
+ s_CHfillAllTooltip: "Fill Contents and Formats Down/Right", // tooltip for fill all handle
+ s_CHfillContentsTooltip: "Fill Contents Only Down/Right", // tooltip for fill formulas handle
+ s_CHmovePasteAllTooltip: "Move Contents and Formats", // etc.
+ s_CHmovePasteContentsTooltip: "Move Contents Only",
+ s_CHmoveInsertAllTooltip: "Slide Contents and Formats within Row/Col",
+ s_CHmoveInsertContentsTooltip: "Slide Contents within Row/Col",
+ s_CHindicatorOperationLookup: {"Fill": "Fill", "FillC": "Fill Contents",
+ "Move": "Move", "MoveI": "Slide",
+ "MoveC": "Move Contents", "MoveIC": "Slide Contents"}, // short form of operation to follow drag
+ s_CHindicatorDirectionLookup: {"Down": " Down", "Right": " Right",
+ "Horizontal": " Horizontal", "Vertical": " Vertical"}, // direction that modifies operation during drag
+
//*** SocialCalc.TableControl
defaultTCSliderThickness: 9, // length of pane slider (numeric in pixels)
@@ -241,12 +255,12 @@ SocialCalc.Constants = {
s_panesliderTooltipv: "Drag to lock pane horizontally",
TClessbuttonStyle: "backgroundColor:#AAA;",
TClessbuttonClass: "",
- TClessbuttonRepeatWait: 500, // in milliseconds
- TClessbuttonRepeatInterval: 100, // in milliseconds
+ TClessbuttonRepeatWait: 300, // in milliseconds
+ TClessbuttonRepeatInterval: 20,//100, // in milliseconds
TCmorebuttonStyle: "backgroundColor:#AAA;",
TCmorebuttonClass: "",
- TCmorebuttonRepeatWait: 500, // in milliseconds
- TCmorebuttonRepeatInterval: 100, // in milliseconds
+ TCmorebuttonRepeatWait: 300, // in milliseconds
+ TCmorebuttonRepeatInterval: 20,//100, // in milliseconds
TCscrollareaStyle: "backgroundColor:#DDD;",
TCscrollareaClass: "",
TCscrollareaRepeatWait: 500, // in milliseconds
@@ -511,6 +525,15 @@ SocialCalc.Constants = {
s_loc_Xselect_rangeX: "[select range]",
//
+// SocialCalc Spreadsheet Viewer module, socialcalcviewer.js:
+//
+
+ //*** SocialCalc.SpreadsheetViewer
+
+ SVStatuslineheight: 20, // in pixels
+ SVStatuslineCSS: "font-size:10px;padding:3px 0px;",
+
+//
// SocialCalc Format Number module, formatnumber2.js:
//
View
154 socialcalcserver.pl
@@ -27,6 +27,7 @@
my $titlestr = "SocialCalc Server $versionstr";
my $jsdir = "/sgi/scjs/"; # The subdirectory of the server home page (when run thru CGI)
# where the .js files are, and ./images/ subdirectory.
+ my $imagedir = "/images/sc-";
#
# This whole first section lets this code run either as a CGI script on a server
@@ -36,7 +37,7 @@
#
if ($ENV{REQUEST_METHOD}) { # being run as a CGI on a server
- print "Content-type: text/html\n\n";
+ print "Content-type: text/html\n\n";
my $q = new CGI;
print process_request($q);
exit;
@@ -84,9 +85,9 @@
undef($c);
exit;
}
- if ($uri =~ /\/([a-z\-0-9]+)\.(gif|js|css)$/) { # ok request
+ if ($uri =~ /\/([a-z\-0-9]+)\.(gif|js|css|png)(\?.*)*$/) { # ok request
$uri = "$1.$2";
- $uri = "images/$uri" if $2 eq "gif";
+ $uri = "images/$uri" if ($2 eq "gif" || $2 eq "png");
# if ($2 eq "js") {
# $res->content_type("text/html; charset=UTF-8");
# }
@@ -229,6 +230,20 @@ sub process_request {
"Saved updated '$pagename'.<br>";
}
+ if ($q->param('filecontents')) { # return contents of file
+ my $fileurl = $q->param('filecontents');
+
+ open (PAGEFILEIN, "$fileurl");
+ my $filestr;
+ while (my $line = <PAGEFILEIN>) {
+ $filestr .= $line;
+ }
+ close PAGEFILEIN;
+print $filestr;
+ return $filestr;
+
+ }
+
$response = do_displaypage($q, $pagename, $statusmessage); # Otherwise, display page
return $response;
@@ -327,6 +342,8 @@ sub start_editsheet {
}
$sheetstr = special_chars($sheetstr);
+ close PAGEFILEIN;
+
$response = <<"EOF"; # output page with edit JS code
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
@@ -369,12 +386,15 @@ sub start_editsheet {
// start everything
- SocialCalc.Constants.defaultImagePrefix = "$jsdir/images/sc-";
- SocialCalc.Popup.imagePrefix = "$jsdir/images/sc-";
+ SocialCalc.Constants.defaultImagePrefix = "$jsdir$imagedir";
+ SocialCalc.Popup.imagePrefix = "$jsdir$imagedir";
var spreadsheet = new SocialCalc.SpreadsheetControl();
spreadsheet.InitializeSpreadsheetControl("tableeditor", 0, 0, 0);
+ SocialCalc.SheetCommandInfo.CmdExtensionCallbacks.docmd = {func:docmdext, data:spreadsheet};
+ SocialCalc.SheetCommandInfo.CmdExtensionCallbacks.loadclipboard = {func:doloadclipboardext, data:spreadsheet};
+
var savestr = document.getElementById("sheetdata").value;
var parts = spreadsheet.DecodeSpreadsheetSave(savestr);
if (parts) {
@@ -385,6 +405,9 @@ sub start_editsheet {
if (parts.edit) {
spreadsheet.editor.LoadEditorSettings(savestr.substring(parts.edit.start, parts.edit.end));
}
+ if (parts.startupmacro) {
+ spreadsheet.editor.EditorScheduleSheetCommands(savestr.substring(parts.startupmacro.start, parts.startupmacro.end), false, true);
+ }
}
if (spreadsheet.sheet.attribs.recalc=="off") {
spreadsheet.sheet.attribs.needsrecalc = "yes"; // default turn it on
@@ -394,6 +417,123 @@ sub start_editsheet {
spreadsheet.ExecuteCommand('recalc', '');
}
+function docmdext (name, data, sheet, cmd, saveundo) {
+
+ var cmdstr = cmd.RestOfString();
+ data.editor.EditorScheduleSheetCommands(cmdstr, false, false);
+ SocialCalc.SheetCommandInfo.cmdextensionbusy = "Do Cmd Ext "+cmdstr;
+
+ window.setTimeout(function(){SocialCalc.ResumeFromCmdExtension();}, 100);
+
+ }
+
+function doloadclipboardext (name, data, sheet, cmd, saveundo) {
+
+ var cmdstr = cmd.RestOfString();
+ SocialCalc.SheetCommandInfo.cmdextensionbusy = "Load Clipboard Ext "+cmdstr;
+
+ loaddata(cmdstr);
+
+// window.setTimeout(function(){SocialCalc.ResumeFromCmdExtension();}, 100);
+// SocialCalc.ResumeFromCmdExtension();
+ }
+
+var loaddatatimerobj;
+
+function loaddata(url) {
+
+ var loadscript = document.createElement("script");
+ loadscript.type = "text/javascript";
+ loadscript.src = url+"?"+((new Date()).getTime()+'0');
+ document.body.appendChild(loadscript);
+
+ loaddatatimerobj = window.setTimeout(loaddatatimeout, 4000);
+
+ }
+
+function doloaddataload(val) {
+
+ if (loaddatatimerobj) {
+ window.clearTimeout(loaddatatimerobj);
+ loaddatatimerobj = null;
+ }
+
+ var sview = SocialCalc.GetSpreadsheetControlObject();
+ parts = sview.DecodeSpreadsheetSave(val);
+ if (parts) {
+ if (parts.sheet) {
+ SocialCalc.Clipboard.clipboard = SocialCalc.decodeFromSave(val.substring(parts.sheet.start, parts.sheet.end));
+ }
+ }
+// window.setTimeout(function(){SocialCalc.ResumeFromCmdExtension();}, 100);
+ SocialCalc.ResumeFromCmdExtension();
+ }
+
+function loaddatatimeout() {
+
+ if (loaddatatimerobj) {
+ window.clearTimeout(loaddatatimerobj);
+ loaddatatimerobj = null;
+ }
+
+ window.setTimeout(function(){SocialCalc.ResumeFromCmdExtension();}, 10);
+
+ }
+
+// Remote data lookup demo code
+
+var loadtimerobj;
+
+function loadsheet(sheetname) {
+
+ var matches = sheetname.match(/^\\{scdata\\:\\s+(.+?)\\}\$/); // {scdata: URL w/o http://)
+
+ if (!matches) {
+ return false;
+ }
+
+ var loadscript = document.createElement("script");
+ loadscript.type = "text/javascript";
+ loadscript.src = "http://"+matches[1]+"?"+((new Date()).getTime()+'0');
+ document.body.appendChild(loadscript);
+
+ loadtimerobj = window.setTimeout(loadframetimeout, 4000);
+
+ return true;
+ }
+
+SocialCalc.RecalcInfo.LoadSheet = loadsheet;
+
+function doloadframeload(val) {
+
+ if (loadtimerobj) {
+ window.clearTimeout(loadtimerobj);
+ loadtimerobj = null;
+ }
+
+ var sview = SocialCalc.GetSpreadsheetControlObject();
+ parts = sview.DecodeSpreadsheetSave(val);
+ if (parts) {
+ if (parts.sheet) {
+ SocialCalc.RecalcLoadedSheet(null, val.substring(parts.sheet.start, parts.sheet.end), true); // notify recalc loop
+ }
+ }
+ if (val=="") {
+ SocialCalc.RecalcLoadedSheet(null, "", true); // notify recalc loop that it's not available, but that we tried
+ }
+ }
+
+function loadframetimeout() {
+
+ if (loadtimerobj) {
+ window.clearTimeout(loadtimerobj);
+ loadtimerobj = null;
+ }
+
+ SocialCalc.RecalcLoadedSheet(null, "", true); // notify recalc loop that it's not available, but that we tried
+
+ }
+
</script>
</body>
</html>
@@ -467,8 +607,8 @@ sub start_viewsheet {
var spreadsheet = new SocialCalc.SpreadsheetControl();
- SocialCalc.Constants.defaultImagePrefix = "$jsdir/images/sc-";
- SocialCalc.Popup.imagePrefix = "$jsdir/images/sc-";
+ SocialCalc.Constants.defaultImagePrefix = "$jsdir$imagedir";
+ SocialCalc.Popup.imagePrefix = "$jsdir$imagedir";
var savestr = document.getElementById("sheetdata").value;
var parts = spreadsheet.DecodeSpreadsheetSave(savestr);
View
111 socialcalcspreadsheetcontrol.js
@@ -5,7 +5,7 @@
// The code module of the SocialCalc package that lets you embed a spreadsheet
// control with toolbar, etc., into a web page.
//
-// (c) Copyright 2008, 2009 Socialtext, Inc.
+// (c) Copyright 2008, 2009, 2010 Socialtext, Inc.
// All Rights Reserved.
//
*/
@@ -50,7 +50,7 @@ need not be linked to the Attribution URL but the "tool-tip" is still required.
Attribution Copyright Notice:
- Copyright (C) 2008 Socialtext, Inc.
+ Copyright (C) 2010 Socialtext, Inc.
All Rights Reserved.
Attribution Phrase (not exceeding 10 words): SocialCalc
@@ -183,7 +183,7 @@ SocialCalc.SpreadsheetControl = function() {
this.imagePrefix = scc.defaultImagePrefix; // prefix added to img src
this.toolbarbackground = scc.SCToolbarbackground;
- this.tabbackground = scc.SCTabbackground;"background-color:#CCC;";
+ this.tabbackground = scc.SCTabbackground; // "background-color:#CCC;";
this.tabselectedCSS = scc.SCTabselectedCSS;
this.tabplainCSS = scc.SCTabplainCSS;
this.toolbartext = scc.SCToolbartext;
@@ -216,7 +216,7 @@ SocialCalc.SpreadsheetControl = function() {
var cr;
var spreadsheet = SocialCalc.GetSpreadsheetControlObject();
spreadsheet.context.cursorsuffix = "";
- if (editor.range2.hasrange) {
+ if (editor.range2.hasrange && !editor.cellhandles.noCursorSuffix) {
if (editor.ecell.row==editor.range2.top && (editor.ecell.col<editor.range2.left || editor.ecell.col>editor.range2.right+1)) {
spreadsheet.context.cursorsuffix = "insertleft";
}
@@ -845,7 +845,7 @@ SocialCalc.SpreadsheetControl.prototype.ExecuteCommand =
SocialCalc.SpreadsheetControl.prototype.CreateSheetHTML =
function() {return SocialCalc.SpreadsheetControlCreateSheetHTML(this);};
SocialCalc.SpreadsheetControl.prototype.CreateSpreadsheetSave =
- function() {return SocialCalc.SpreadsheetControlCreateSpreadsheetSave(this);};
+ function(otherparts) {return SocialCalc.SpreadsheetControlCreateSpreadsheetSave(this, otherparts);};
SocialCalc.SpreadsheetControl.prototype.DecodeSpreadsheetSave =
function(str) {return SocialCalc.SpreadsheetControlDecodeSpreadsheetSave(this, str);};
SocialCalc.SpreadsheetControl.prototype.CreateCellHTML =
@@ -1059,7 +1059,10 @@ spreadsheet.Buttons = {
spreadsheet.statuslineDiv = document.createElement("div");
spreadsheet.statuslineDiv.style.cssText = spreadsheet.statuslineCSS;
- spreadsheet.statuslineDiv.style.height = spreadsheet.statuslineheight + "px";
+// spreadsheet.statuslineDiv.style.height = spreadsheet.statuslineheight + "px"; // didn't take padding into account!
+ spreadsheet.statuslineDiv.style.height = spreadsheet.statuslineheight -
+ (spreadsheet.statuslineDiv.style.paddingTop.slice(0,-2)-0) -
+ (spreadsheet.statuslineDiv.style.paddingBottom.slice(0,-2)-0) + "px";
spreadsheet.statuslineDiv.id = spreadsheet.idPrefix+"statusline";
spreadsheet.spreadsheetDiv.appendChild(spreadsheet.statuslineDiv);
@@ -1138,7 +1141,7 @@ SocialCalc.GetSpreadsheetControlObject = function() {
var csco = SocialCalc.CurrentSpreadsheetControlObject;
if (csco) return csco;
- throw ("No current SpreadsheetControl object.");
+// throw ("No current SpreadsheetControl object.");
}
@@ -1877,7 +1880,7 @@ SocialCalc.SpreadsheetControlExecuteCommand = function(obj, combostr, sstr) {
combostr = combostr.replace(/%W/g, str.W);
combostr = combostr.replace(/%P/g, str.P);
- eobj.EditorScheduleSheetCommands(combostr);
+ eobj.EditorScheduleSheetCommands(combostr, true, false);
}
@@ -2568,7 +2571,7 @@ SocialCalc.SpreadsheetControl.DoSum = function() {
}
}
- editor.EditorScheduleSheetCommands(cmd);
+ editor.EditorScheduleSheetCommands(cmd, true, false);
}
@@ -2852,14 +2855,14 @@ SocialCalc.SpreadsheetControlClipboardLoad = function() {
}
s.editor.EditorScheduleSheetCommands("loadclipboard "+
SocialCalc.encodeForSave(
- SocialCalc.ConvertOtherFormatToSave(document.getElementById(s.idPrefix+"clipboardtext").value, savetype)));
+ SocialCalc.ConvertOtherFormatToSave(document.getElementById(s.idPrefix+"clipboardtext").value, savetype)), true, false);
}
SocialCalc.SpreadsheetControlClipboardClear = function() {
var s = SocialCalc.GetSpreadsheetControlObject();
var clipele = document.getElementById(s.idPrefix+"clipboardtext");
clipele.value = "";
- s.editor.EditorScheduleSheetCommands("clearclipboard");
+ s.editor.EditorScheduleSheetCommands("clearclipboard", true, false);
clipele.focus();
}
@@ -2920,7 +2923,7 @@ SocialCalc.SettingsControlSave = function(target) {
else { // Cancel
}
if (cmdstr) {
- s.editor.EditorScheduleSheetCommands(cmdstr);
+ s.editor.EditorScheduleSheetCommands(cmdstr, true, false);
}
}
@@ -2931,7 +2934,7 @@ SocialCalc.SettingsControlSave = function(target) {
///////////////////////
//
-// result = SocialCalc.SpreadsheetControlCreateSpreadsheetSave(spreadsheet)
+// result = SocialCalc.SpreadsheetControlCreateSpreadsheetSave(spreadsheet, otherparts)
//
// Saves the spreadsheet's sheet data, editor settings, and audit trail (redo stack).
// The serialized data strings are concatenated together in multi-part MIME format.
@@ -2943,22 +2946,46 @@ SocialCalc.SettingsControlSave = function(target) {
// part:type2
// ...
//
+// If otherparts is non-null, it is an object with:
+// partname1: "part contents - should end with \n",
+// partname2: "part contents - should end with \n"
+//
+
-SocialCalc.SpreadsheetControlCreateSpreadsheetSave = function(spreadsheet) {
+SocialCalc.SpreadsheetControlCreateSpreadsheetSave = function(spreadsheet, otherparts) {
var result;
+ var otherpartsstr = "";
+ var otherpartsnames = "";
+ var partname, extranl;
+
+ if (otherparts) {
+ for (partname in otherparts) {
+ if (otherparts[partname].charAt(otherparts[partname]-1) != "\n") {
+ extranl = "\n";
+ }
+ else {
+ extranl = "";
+ }
+ otherpartsstr += "--" + spreadsheet.multipartBoundary + "\nContent-type: text/plain; charset=UTF-8\n\n" +
+ otherparts[partname] + extranl;
+ otherpartsnames += "part:"+partname + "\n";
+ }
+ }
+
result = "socialcalc:version:1.0\n" +
"MIME-Version: 1.0\nContent-Type: multipart/mixed; boundary="+
spreadsheet.multipartBoundary + "\n" +
"--" + spreadsheet.multipartBoundary + "\nContent-type: text/plain; charset=UTF-8\n\n" +
- "# SocialCalc Spreadsheet Control Save\nversion:1.0\npart:sheet\npart:edit\npart:audit\n" +
+ "# SocialCalc Spreadsheet Control Save\nversion:1.0\npart:sheet\npart:edit\npart:audit\n" + otherpartsnames +
"--" + spreadsheet.multipartBoundary + "\nContent-type: text/plain; charset=UTF-8\n\n" +
spreadsheet.CreateSheetSave() +
"--" + spreadsheet.multipartBoundary + "\nContent-type: text/plain; charset=UTF-8\n\n" +
spreadsheet.editor.SaveEditorSettings() +
"--" + spreadsheet.multipartBoundary + "\nContent-type: text/plain; charset=UTF-8\n\n" +
spreadsheet.sheet.CreateAuditString() +
+ otherpartsstr +
"--" + spreadsheet.multipartBoundary + "--\n";
return result;
@@ -3502,3 +3529,57 @@ SocialCalc.SettingControlReset = function() {
}
}
+
+/**********************
+*
+* CtrlSEditor implementation for editing SocialCalc.OtherSaveParts
+*
+*/
+
+SocialCalc.OtherSaveParts = {}; // holds other parts to save - must be set when loaded if you want to keep
+
+SocialCalc.CtrlSEditor = function(whichpart) {
+
+ var strtoedit, partname;
+ if (whichpart.length > 0) {
+ strtoedit = SocialCalc.special_chars(SocialCalc.OtherSaveParts[whichpart] || "");
+ }
+ else {
+ strtoedit = "Listing of Parts\n";
+ for (partname in SocialCalc.OtherSaveParts) {
+ strtoedit += SocialCalc.special_chars("\nPart: "+partname+"\n=====\n"+SocialCalc.OtherSaveParts[partname]+"\n");
+ }
+ }
+ var editbox = document.createElement("div");
+ editbox.style.cssText = "position:absolute;z-index:500;width:300px;height:300px;left:100px;top:200px;border:1px solid black;background-color:#EEE;text-align:center;";
+ editbox.id = "socialcalc-editbox";
+ editbox.innerHTML = whichpart+'<br><br><textarea id="socialcalc-editbox-textarea" style="width:250px;height:200px;">'+
+ strtoedit + '</textarea><br><br><input type=button ' +
+ 'onclick="SocialCalc.CtrlSEditorDone (\'socialcalc-editbox\', \''+whichpart+'\');" value="OK">';
+ document.body.appendChild(editbox);
+
+ var ebta = document.getElementById("socialcalc-editbox-textarea");
+ ebta.focus();
+ SocialCalc.CmdGotFocus(ebta);
+
+ }
+
+SocialCalc.CtrlSEditorDone = function(idprefix, whichpart) {
+
+ var edittextarea = document.getElementById(idprefix+"-textarea");
+ var text = edittextarea.value;
+ if (whichpart.length > 0) {
+ if (text.length > 0) {
+ SocialCalc.OtherSaveParts[whichpart] = text;
+ }
+ else {
+ delete SocialCalc.OtherSaveParts[whichpart];
+ }
+ }
+
+ var editbox = document.getElementById(idprefix);
+ SocialCalc.KeyboardFocus();
+ editbox.parentNode.removeChild(editbox);
+
+ }
+
View
1,160 socialcalctableeditor.js
@@ -5,7 +5,7 @@
// The code module of the SocialCalc package that displays a scrolling grid with panes
// and handles keyboard and mouse I/O.
//
-// (c) Copyright 2008 Socialtext, Inc.
+// (c) Copyright 2008, 2009, 2010 Socialtext, Inc.
// All Rights Reserved.
//
*/
@@ -50,7 +50,7 @@ need not be linked to the Attribution URL but the "tool-tip" is still required.
Attribution Copyright Notice:
- Copyright (C) 2008 Socialtext, Inc.
+ Copyright (C) 2010 Socialtext, Inc.
All Rights Reserved.
Attribution Phrase (not exceeding 10 words): SocialCalc
@@ -115,6 +115,8 @@ SocialCalc.TableEditor = function(context) {
this.toplevel = null; // top level HTML element for this table editor
this.fullgrid = null; // rendered editing context
+ this.noEdit = false; // if true, disable all edit UI and make read-only
+
this.width = null;
this.tablewidth = null;
this.height = null;
@@ -127,12 +129,14 @@ SocialCalc.TableEditor = function(context) {
this.logo = null;
+ this.cellhandles = null;
+
// Dynamic properties:
this.timeout = null; // if non-null, timer id for position calculations
this.busy = false; // true when executing command, calculating, etc.
this.ensureecell = false; // if true, ensure ecell is visible after timeout
- this.deferredCommands = []; // commands to execute after busy
+ this.deferredCommands = []; // commands to execute after busy, in form: {cmdstr: "cmds", saveundo: t/f}
this.gridposition = null; // screen coords of full grid
this.headposition = null; // screen coords of upper left of grid within header rows
@@ -204,19 +208,20 @@ SocialCalc.TableEditor = function(context) {
// get what to copy to clipboard
cliptext = SocialCalc.ConvertSaveToOtherFormat(SocialCalc.CreateSheetSave(editor.context.sheetobj, sel), "tab");
- if (charname == "[ctrl-c]") {
+ if (charname == "[ctrl-c]" || editor.noEdit) { // if copy or cut but in no edit
cmd = "copy "+sel+" formulas";
}
else { // [ctrl-x]
cmd = "cut "+sel+" formulas";
}
- editor.EditorScheduleSheetCommands(cmd); // queue up command to put on SocialCalc clipboard
+ editor.EditorScheduleSheetCommands(cmd, true, false); // queue up command to put on SocialCalc clipboard
ta.style.display = "block";
ta.value = cliptext; // must follow "block" setting for Webkit
ta.focus();
ta.select();
window.setTimeout(function() {
+ if (!SocialCalc.GetSpreadsheetControlObject) return; // in case not loaded
var s = SocialCalc.GetSpreadsheetControlObject();
if (!s) return;
var editor = s.editor;
@@ -229,6 +234,7 @@ SocialCalc.TableEditor = function(context) {
return true;
case "[ctrl-v]":
+ if (editor.noEdit) return true; // not if no edit
ta = editor.pasteTextarea;
ta.value = "";
cell=SocialCalc.GetEditorCellElement(editor, editor.ecell.row, editor.ecell.col);
@@ -241,6 +247,7 @@ SocialCalc.TableEditor = function(context) {
ta.value = ""; // must follow "block" setting for Webkit
ta.focus();
window.setTimeout(function() {
+ if (!SocialCalc.GetSpreadsheetControlObject) return;
var s = SocialCalc.GetSpreadsheetControlObject();
if (!s) return;
var editor = s.editor;
@@ -265,19 +272,20 @@ SocialCalc.TableEditor = function(context) {
cr = editor.ecell.coord;
}
cmd += "paste "+cr+" formulas";
- editor.EditorScheduleSheetCommands(cmd);
+ editor.EditorScheduleSheetCommands(cmd, true, false);
SocialCalc.KeyboardFocus();
}, 200);
return true;
case "[ctrl-z]":
- editor.EditorScheduleSheetCommands("undo");
+ editor.EditorScheduleSheetCommands("undo", true, false);
return false;
case "[ctrl-s]": // !!!! temporary hack
if (!SocialCalc.Constants.AllowCtrlS) break;
window.setTimeout(
function() {
+ if (!SocialCalc.GetSpreadsheetControlObject) return;
var s = SocialCalc.GetSpreadsheetControlObject();
if (!s) return;
var editor = s.editor;
@@ -289,6 +297,13 @@ SocialCalc.TableEditor = function(context) {
if (newntvf.match(/^cmd:/)) {
cmd = newntvf.substring(4); // execute as command
}
+ else if (newntvf.match(/^edit:/)) {
+ cmd = newntvf.substring(5); // execute as command
+ if (SocialCalc.CtrlSEditor) {
+ SocialCalc.CtrlSEditor(cmd);
+ }
+ return;
+ }
else {
if (editor.range.hasrange) {
sel = SocialCalc.crToCoord(editor.range.left, editor.range.top)+
@@ -299,7 +314,7 @@ SocialCalc.TableEditor = function(context) {
}
cmd = "set "+sel+" nontextvalueformat "+newntvf;
}
- editor.EditorScheduleSheetCommands(cmd);
+ editor.EditorScheduleSheetCommands(cmd, true, false);
}
},
200);
@@ -377,7 +392,7 @@ SocialCalc.TableEditor.prototype.SaveEditorSettings = function() {return SocialC
SocialCalc.TableEditor.prototype.LoadEditorSettings = function(str, flags) {return SocialCalc.LoadEditorSettings(this, str, flags);};
SocialCalc.TableEditor.prototype.EditorRenderSheet = function() {SocialCalc.EditorRenderSheet(this);};
-SocialCalc.TableEditor.prototype.EditorScheduleSheetCommands = function(cmdstr, ignoreundo) {SocialCalc.EditorScheduleSheetCommands(this, cmdstr, ignoreundo);};
+SocialCalc.TableEditor.prototype.EditorScheduleSheetCommands = function(cmdstr, saveundo, ignorebusy) {SocialCalc.EditorScheduleSheetCommands(this, cmdstr, saveundo, ignorebusy);};
SocialCalc.TableEditor.prototype.ScheduleSheetCommands = function(cmdstr, saveundo) {
this.context.sheetobj.ScheduleSheetCommands(cmdstr, saveundo);
};
@@ -501,8 +516,12 @@ SocialCalc.CreateTableEditor = function(editor, width, height) {
editor.toplevel.appendChild(editor.layouttable);
- editor.inputEcho = new SocialCalc.InputEcho(editor);
- AssignID(editor, editor.inputEcho.main, "inputecho");
+ if (!editor.noEdit) {
+ editor.inputEcho = new SocialCalc.InputEcho(editor);
+ AssignID(editor, editor.inputEcho.main, "inputecho");
+ }
+
+ editor.cellhandles = new SocialCalc.CellHandles(editor);
ta = document.createElement("textarea"); // used for ctrl-c/ctrl-v where an invisible text area is needed
SocialCalc.setStyles(ta, "display:none;position:absolute;height:1px;width:1px;opacity:0;filter:alpha(opacity=0);");
@@ -718,17 +737,17 @@ SocialCalc.EditorRenderSheet = function(editor) {
}
//
-// EditorScheduleSheetCommands(editor, cmdstr, ignorebusy)
+// EditorScheduleSheetCommands(editor, cmdstr, saveundo, ignorebusy)
//
-SocialCalc.EditorScheduleSheetCommands = function(editor, cmdstr, ignorebusy) {
+SocialCalc.EditorScheduleSheetCommands = function(editor, cmdstr, saveundo, ignorebusy) {
if (editor.state!="start" && !ignorebusy) { // ignore commands if editing a cell
return;
}
if (editor.busy && !ignorebusy) { // hold off on commands if doing one
- editor.deferredCommands.push(cmdstr);
+ editor.deferredCommands.push({cmdstr: cmdstr, saveundo: saveundo});
return;
}
@@ -747,7 +766,7 @@ SocialCalc.EditorScheduleSheetCommands = function(editor, cmdstr, ignorebusy) {
break;
default:
- editor.context.sheetobj.ScheduleSheetCommands(cmdstr, true);
+ editor.context.sheetobj.ScheduleSheetCommands(cmdstr, saveundo);
break;
}
}
@@ -761,7 +780,7 @@ SocialCalc.EditorScheduleSheetCommands = function(editor, cmdstr, ignorebusy) {
SocialCalc.EditorSheetStatusCallback = function(recalcdata, status, arg, editor) {
- var f, cell;
+ var f, cell, dcmd;
var sheetobj = editor.context.sheetobj;
var signalstatus = function(s) {
@@ -782,6 +801,9 @@ SocialCalc.EditorSheetStatusCallback = function(recalcdata, status, arg, editor)
sheetobj.celldisplayneeded = "";
break;
+ case "cmdextension":
+ break;
+
case "cmdend":
signalstatus(status);
@@ -798,7 +820,8 @@ SocialCalc.EditorSheetStatusCallback = function(recalcdata, status, arg, editor)
}
if (editor.deferredCommands.length) {
- editor.EditorScheduleSheetCommands(editor.deferredCommands.shift(), true);
+ dcmd = editor.deferredCommands.shift();
+ editor.EditorScheduleSheetCommands(dcmd.cmdstr, dcmd.saveundo, true);
return;
}
@@ -854,7 +877,8 @@ SocialCalc.EditorSheetStatusCallback = function(recalcdata, status, arg, editor)
case "doneposcalc":
if (editor.deferredCommands.length) {
signalstatus(status);
- editor.EditorScheduleSheetCommands(editor.deferredCommands.shift(), true);
+ dcmd = editor.deferredCommands.shift();
+ editor.EditorScheduleSheetCommands(dcmd.cmdstr, dcmd.saveundo, true);
}
else {
editor.busy = false;
@@ -930,6 +954,9 @@ SocialCalc.EditorGetStatuslineString = function(editor, status, arg, params) {
editor.griddiv.style.cursor = "progress";
progress = scc.s_statusline_executing;
break;
+ case "cmdextension":
+ progress = "Command Extension: "+arg;
+ break;
case "cmdend":
params.command = false;
break;
@@ -1080,6 +1107,8 @@ SocialCalc.EditorMouseRegister = function(editor) {
throw "Browser not supported";
}
+ mouseinfo.ignore = false; // just in case
+
return;
}
@@ -1227,6 +1256,7 @@ SocialCalc.EditorMouseRange = function(editor, coord) {
editor.inputBox.Blur();
editor.inputBox.ShowInputBox(false);
editor.state = "start";
+ editor.cellhandles.ShowCellHandles(true);
editor.EditorSaveEdit();
editor.inputBox.DisplayCellContents(null);
}
@@ -1236,6 +1266,7 @@ SocialCalc.EditorMouseRange = function(editor, coord) {
editor.inputBox.Blur();
editor.inputBox.ShowInputBox(false);
editor.state = "start";
+ editor.cellhandles.ShowCellHandles(true);
editor.EditorSaveEdit();
editor.inputBox.DisplayCellContents(null);
break;
@@ -1255,10 +1286,21 @@ SocialCalc.ProcessEditorMouseMove = function(e) {
var mouseinfo = SocialCalc.EditorMouseInfo;
editor = mouseinfo.editor;
if (!editor) return; // not us, ignore
+ if (mouseinfo.ignore) return; // ignore this
element = mouseinfo.element;
result = SocialCalc.GridMousePosition(editor, clientX, clientY); // get cell with move
- if (!result || !result.coord) return;
+
+ if (!result) return;
+
+ if (result && !result.coord) {
+ SocialCalc.SetDragAutoRepeat(editor, result);
+ return;
+ }
+
+ SocialCalc.SetDragAutoRepeat(editor, null); // stop repeating if it was
+
+ if (!result.coord) return;
if (result.coord!=mouseinfo.mouselastcoord) {
if (!e.shiftKey && !editor.range.hasrange) {
@@ -1294,10 +1336,13 @@ SocialCalc.ProcessEditorMouseUp = function(e) {
var mouseinfo = SocialCalc.EditorMouseInfo;
editor = mouseinfo.editor;
if (!editor) return; // not us, ignore
+ if (mouseinfo.ignore) return; // ignore this
element = mouseinfo.element;
result = SocialCalc.GridMousePosition(editor, clientX, clientY); // get cell with up
+ SocialCalc.SetDragAutoRepeat(editor, null); // stop repeating if it was
+
if (!result) return;
if (!result.coord) result.coord = editor.ecell.coord;
@@ -1445,7 +1490,7 @@ SocialCalc.ProcessEditorColsizeMouseUp = function(e) {
var newsize = (editor.context.colwidth[mouseinfo.mouseresizecolnum]-0) + (clientX - mouseinfo.mousedownclientx);
if (newsize < SocialCalc.Constants.defaultMinimumColWidth) newsize = SocialCalc.Constants.defaultMinimumColWidth;
- editor.EditorScheduleSheetCommands("set "+mouseinfo.mouseresizecol+" width "+newsize);
+ editor.EditorScheduleSheetCommands("set "+mouseinfo.mouseresizecol+" width "+newsize, true, false);
if (editor.timeout) window.clearTimeout(editor.timeout);
editor.timeout = window.setTimeout(SocialCalc.FinishColsize, 1); // wait - Firefox 2 has a bug otherwise with next mousedown
@@ -1474,6 +1519,148 @@ SocialCalc.FinishColsize = function() {
}
+//
+// Handle auto-repeat of dragging the cursor into the borders of the sheet
+//
+
+SocialCalc.AutoRepeatInfo = {
+
+ timer: null, // timer object for repeating
+ mouseinfo: null, // result from SocialCalc.GridMousePosition
+ repeatinterval: 1000, // milliseconds to wait between repeats
+ editor: null, // editor object to use when it repeats
+ repeatcallback: null // used instead of default when repeating (e.g., for cellhandles)
+ // called as: repeatcallback(newcoord, direction)
+
+};
+
+// Control auto-repeat. If mouseinfo==null, cancel.
+
+SocialCalc.SetDragAutoRepeat = function(editor, mouseinfo, callback) {
+
+ var repeatinfo = SocialCalc.AutoRepeatInfo;
+ var coord, direction;
+
+ repeatinfo.repeatcallback = callback; // null in regular case
+
+ if (!mouseinfo) { // cancel
+ if (repeatinfo.timer) { // If was repeating, stop
+ window.clearTimeout(repeatinfo.timer); // cancel timer
+ repeatinfo.timer = null;
+ }
+ repeatinfo.mouseinfo = null;
+ return; // done
+ }
+
+ repeatinfo.editor = editor;
+
+ if (repeatinfo.mouseinfo) { // check for change while repeating
+ if (mouseinfo.rowheader || mouseinfo.rowfooter) {
+ if (mouseinfo.row != repeatinfo.mouseinfo.row) { // changed row while dragging sidewards
+ coord = SocialCalc.crToCoord(editor.ecell.col, mouseinfo.row); // change to it
+ if (repeatinfo.repeatcallback) {
+ if (mouseinfo.row < repeatinfo.mouseinfo.row) {
+ direction = "left";
+ }
+ else if (mouseinfo.row > repeatinfo.mouseinfo.row) {
+ direction = "right";
+ }
+ else {
+ direction = "";
+ }
+ repeatinfo.repeatcallback(coord, direction);
+ }
+ else {
+ editor.MoveECell(coord);
+ editor.MoveECell(coord);
+ editor.RangeExtend();
+ editor.EditorMouseRange(coord);
+ }
+ }
+ }
+ else if (mouseinfo.colheader || mouseinfo.colfooter) {
+ if (mouseinfo.col != repeatinfo.mouseinfo.col) { // changed col while dragging vertically
+ coord = SocialCalc.crToCoord(mouseinfo.col, editor.ecell.row); // change to it
+ if (repeatinfo.repeatcallback) {
+ if (mouseinfo.row < repeatinfo.mouseinfo.row) {
+ direction = "left";
+ }
+ else if (mouseinfo.row > repeatinfo.mouseinfo.row) {
+ direction = "right";
+ }
+ else {
+ direction = "";
+ }
+ repeatinfo.repeatcallback(coord, direction);
+ }
+ else {
+ editor.MoveECell(coord);
+ editor.RangeExtend();
+ editor.EditorMouseRange(coord);
+ }
+ }
+ }
+ }
+
+ repeatinfo.mouseinfo = mouseinfo;
+
+ if (mouseinfo.distance < 5) repeatinfo.repeatinterval = 333;
+ else if (mouseinfo.distance < 10) repeatinfo.repeatinterval = 250;
+ else if (mouseinfo.distance < 25) repeatinfo.repeatinterval = 100;
+ else if (mouseinfo.distance < 35) repeatinfo.repeatinterval = 75;
+ else { // too far - stop repeating
+ if (repeatinfo.timer) { // if repeating, cancel it
+ window.clearTimeout(repeatinfo.timer); // cancel timer
+ repeatinfo.timer = null;
+ }
+ return;
+ }
+
+ if (!repeatinfo.timer) { // start if not already running
+ repeatinfo.timer = window.setTimeout(SocialCalc.DragAutoRepeat, repeatinfo.repeatinterval);
+ }
+
+ return;
+
+ }
+
+//
+// DragAutoRepeat()
+//
+
+SocialCalc.DragAutoRepeat = function() {
+
+ var repeatinfo = SocialCalc.AutoRepeatInfo;
+ var mouseinfo = repeatinfo.mouseinfo;
+
+ var direction, coord, cr;
+
+ if (mouseinfo.rowheader) direction = "left";
+ else if (mouseinfo.rowfooter) direction = "right";
+ else if (mouseinfo.colheader) direction = "up";
+ else if (mouseinfo.colfooter) direction = "down";
+
+ if (repeatinfo.repeatcallback) {
+ cr = SocialCalc.coordToCr(repeatinfo.editor.ecell.coord);
+ if (direction == "left" && cr.col > 1) cr.col--;
+ else if (direction == "right") cr.col++;
+ else if (direction == "up" && cr.row > 1) cr.row--;
+ else if (direction == "down") cr.row++;
+ coord = SocialCalc.crToCoord(cr.col, cr.row);
+ repeatinfo.repeatcallback(coord, direction);
+ }
+ else {
+ coord = repeatinfo.editor.MoveECellWithKey("[a"+direction+"]shifted");
+ if (coord) repeatinfo.editor.EditorMouseRange(coord);
+ }
+
+ repeatinfo.timer = window.setTimeout(SocialCalc.DragAutoRepeat, repeatinfo.repeatinterval);
+
+ }
+
+//
+// Handling Clicking
+//
SocialCalc.ProcessEditorDblClick = function(e) {
@@ -1537,7 +1724,7 @@ SocialCalc.EditorOpenCellEdit = function(editor) {
var wval;
if (!editor.ecell) return true; // no ecell
- if (!editor.inputBox) return true; // no input box, so no editing
+ if (!editor.inputBox) return true; // no input box, so no editing (happens on noEdit)
if (editor.inputBox.element.disabled) return true; // multi-line: ignore
editor.inputBox.ShowInputBox(true);
editor.inputBox.Focus();
@@ -1578,7 +1765,9 @@ SocialCalc.EditorProcessKey = function(editor, ch, e) {
return !result;
}
if (ch=="[del]" || ch=="[backspace]") {
- editor.EditorApplySetCommandsToRange("empty", "");
+ if (!editor.noEdit) {
+ editor.EditorApplySetCommandsToRange("empty", "");
+ }
break;
}
if (ch=="[esc]") {
@@ -1593,6 +1782,7 @@ SocialCalc.EditorProcessKey = function(editor, ch, e) {
}
if (ch=="[f2]") {
+ if (editor.noEdit) return true;
SocialCalc.EditorOpenCellEdit(editor);
return false;
}
@@ -1647,6 +1837,7 @@ SocialCalc.EditorProcessKey = function(editor, ch, e) {
editor.inputBox.Blur();
editor.inputBox.ShowInputBox(false);
editor.state = "start";
+ editor.cellhandles.ShowCellHandles(true);
if (ch != "[esc]") {
editor.EditorSaveEdit();
if (editor.ecell.coord != wval.ecoord) {
@@ -1670,6 +1861,7 @@ SocialCalc.EditorProcessKey = function(editor, ch, e) {
wval.partialexpr = "";
editor.RangeRemove();
editor.MoveECell(wval.ecoord);
+ editor.inputBox.ShowInputBox(true); // make sure it's moved back if necessary
return false;
}
if (ch=="[f2]") return false;
@@ -1677,7 +1869,10 @@ SocialCalc.EditorProcessKey = function(editor, ch, e) {
editor.RangeRemove();
}
editor.MoveECell(wval.ecoord);
- wval.partialexpr = ""; // not pointing
+ if (wval.partialexpr) {
+ editor.inputBox.ShowInputBox(true); // make sure it's moved back if necessary
+ wval.partialexpr = ""; // not pointing
+ }
return true;
case "inputboxdirect":
@@ -1686,6 +1881,7 @@ SocialCalc.EditorProcessKey = function(editor, ch, e) {
editor.inputBox.Blur();
editor.inputBox.ShowInputBox(false);
editor.state = "start";
+ editor.cellhandles.ShowCellHandles(true);
if (ch == "[esc]") {
editor.inputBox.DisplayCellContents();
}
@@ -1707,6 +1903,7 @@ SocialCalc.EditorProcessKey = function(editor, ch, e) {
case "skip-and-start":
editor.state = "start";
+ editor.cellhandles.ShowCellHandles(true);
return false;
default:
@@ -1721,6 +1918,8 @@ SocialCalc.EditorAddToInput = function(editor, str, prefix) {
var wval = editor.workingvalues;
+ if (editor.noEdit) return;
+
switch (editor.state) {
case "start":
editor.state = "input";
@@ -1808,7 +2007,7 @@ SocialCalc.EditorSaveEdit = function(editor, text) {
}
cmdline = "set "+wval.ecoord+" "+type+" "+value;
- editor.EditorScheduleSheetCommands(cmdline);
+ editor.EditorScheduleSheetCommands(cmdline, true, false);
return;
@@ -1831,11 +2030,11 @@ SocialCalc.EditorApplySetCommandsToRange = function(editor, cmd) {
if (range.hasrange) {
coord = SocialCalc.crToCoord(range.left, range.top)+":"+SocialCalc.crToCoord(range.right, range.bottom);
line = "set "+coord+" "+cmd;
- errortext = editor.EditorScheduleSheetCommands(line);
+ errortext = editor.EditorScheduleSheetCommands(line, true, false);
}
else {
line = "set "+ecell.coord+" "+cmd;
- errortext = editor.EditorScheduleSheetCommands(line);
+ errortext = editor.EditorScheduleSheetCommands(line, true, false);
}
editor.DisplayCellContents();
@@ -1861,6 +2060,8 @@ SocialCalc.EditorProcessMouseWheel = function(event, delta, mousewheelinfo, wobj
// Returns an object with row and col numbers and coord (spans handled for coords),
// and rowheader/colheader true if in header (where coord will be undefined).
// If in colheader, will return coltoresize if on appropriate place in col header.
+// Also, there is rowfooter (on right) and colfooter (on bottom).
+// In row/col header/footer, returns "distance" as pixels over the edge.
//
SocialCalc.GridMousePosition = function(editor, clientX, clientY) {
@@ -1887,10 +2088,12 @@ SocialCalc.GridMousePosition = function(editor, clientX, clientY) {
if (editor.headposition) {
if (clientX < editor.headposition.left && clientX >= editor.gridposition.left) {
result.rowheader = true;
+ result.distance = editor.headposition.left - clientX;
return result;
}
else if (clientY < editor.headposition.top && clientY > editor.gridposition.top) { // > because of sizing row
result.colheader = true;
+ result.distance = editor.headposition.top - clientY;
result.coltoresize = col-(editor.colpositions[col]+editor.colwidth[col]/2>clientX?1:0) || 1;
for (colpane=0; colpane<editor.context.colpanes.length; colpane++) {
if (result.coltoresize >= editor.context.colpanes[colpane].first &&
@@ -1901,9 +2104,24 @@ SocialCalc.GridMousePosition = function(editor, clientX, clientY) {
delete result.coltoresize;
return result;
}
- else if (clientX >= editor.verticaltablecontrol.controlborder ||
- clientY >= editor.horizontaltablecontrol.controlborder ||
- clientX < editor.gridposition.left || clientY <= editor.gridposition.top) {
+ else if (clientX >= editor.verticaltablecontrol.controlborder) {
+ result.rowfooter = true;
+ result.distance = clientX - editor.verticaltablecontrol.controlborder;
+ return result;
+ }
+ else if (clientY >= editor.horizontaltablecontrol.controlborder) {
+ result.colfooter = true;
+ result.distance = clientY - editor.horizontaltablecontrol.controlborder;
+ return result;
+ }
+ else if (clientX < editor.gridposition.left) {
+ result.rowheader = true;
+ result.distance = editor.headposition.left - clientX;
+ return result;
+ }
+ else if (clientY <= editor.gridposition.top) {
+ result.colheader = true;
+ result.distance = editor.headposition.top - clientY;
return result;
}
else {
@@ -2055,6 +2273,7 @@ SocialCalc.MoveECell = function(editor, newcell) {
}
editor.UpdateCellCSS(cell, editor.ecell.row, editor.ecell.col);
editor.SetECellHeaders(""); // set to regular col/rowname styles
+ editor.cellhandles.ShowCellHandles(false);
}
newcell = editor.context.cellskip[newcell] || newcell;
editor.ecell = SocialCalc.coordToCr(newcell);
@@ -2110,6 +2329,9 @@ SocialCalc.EnsureECellVisible = function(editor) {
if (vamount!=0 || hamount!=0) {
editor.ScrollRelativeBoth(vamount, hamount);
}
+ else {
+ editor.cellhandles.ShowCellHandles(true);
+ }
}
@@ -2617,6 +2839,9 @@ SocialCalc.DoPositionCalculations = function() {
editor.EnsureECellVisible(); // this could cause another redisplay
}
+ editor.cellhandles.ShowCellHandles(true);
+
+
//!!! Need to now check to see if this positioned controls out of the editing area
//!!! (such as when there is a large wrapped cell and it pushes the pane boundary too far down).
@@ -3032,12 +3257,14 @@ SocialCalc.InputBox.prototype.DisplayCellContents = function(coord) {SocialCalc.
SocialCalc.InputBox.prototype.ShowInputBox = function(show) {this.editor.inputEcho.ShowInputEcho(show);};
SocialCalc.InputBox.prototype.GetText = function() {return this.element.value;};
SocialCalc.InputBox.prototype.SetText = function(newtext) {
+ if (!this.element) return;
this.element.value=newtext;
this.editor.inputEcho.SetText(newtext+"_");
};
SocialCalc.InputBox.prototype.Focus = function() {SocialCalc.InputBoxFocus(this);};
SocialCalc.InputBox.prototype.Blur = function() {return this.element.blur();};
SocialCalc.InputBox.prototype.Select = function(t) {
+ if (!this.element) return;
switch (t) {
case "end":
if (this.element.selectionStart!=undefined) {
@@ -3060,6 +3287,7 @@ SocialCalc.InputBoxDisplayCellContents = function(inputbox, coord) {
var scc = SocialCalc.Constants;
+ if (!inputbox) return;
if (!coord) coord = inputbox.editor.ecell.coord;
var text = SocialCalc.GetCellContents(inputbox.editor.context.sheetobj, coord);
if (text.indexOf("\n")!=-1) {
@@ -3082,6 +3310,7 @@ SocialCalc.InputBoxDisplayCellContents = function(inputbox, coord) {
SocialCalc.InputBoxFocus = function(inputbox) {
+ if (!inputbox) return;
inputbox.element.focus();
var editor = inputbox.editor;
editor.state = "input";
@@ -3192,6 +3421,7 @@ SocialCalc.ShowInputEcho = function(inputecho, show) {
if (!editor) return;
if (show) {
+ editor.cellhandles.ShowCellHandles(false);
cell=SocialCalc.GetEditorCellElement(editor, editor.ecell.row, editor.ecell.col);
if (cell) {
position = SocialCalc.GetElementPosition(cell.element);
@@ -3271,6 +3501,863 @@ SocialCalc.InputEchoMouseDown = function(e) {
// *************************************
//
+// CellHandles class:
+//
+// This object creates and controls the elements around the cursor cell for dragging, etc.
+//
+// *************************************
+
+SocialCalc.CellHandles = function(editor) {
+
+ var scc = SocialCalc.Constants;
+ var functions;
+
+ if (editor.noEdit) return; // leave us with nothing
+
+ this.editor = editor; // the TableEditor this belongs to
+
+ this.noCursorSuffix = false;
+
+ this.draghandle = document.createElement("div");
+ SocialCalc.setStyles(this.draghandle, "display:none;position:absolute;zIndex:8;border:1px solid white;width:4px;height:4px;fontSize:1px;backgroundColor:#0E93D8;cursor:default;");
+ this.draghandle.innerHTML = '&nbsp;';
+ editor.toplevel.appendChild(this.draghandle);
+ SocialCalc.AssignID(editor, this.draghandle, "draghandle");
+
+ var imagetype = "png";
+ if (navigator.userAgent.match(/MSIE 6\.0/)) {
+ imagetype = "gif";
+ }
+
+ this.dragpalette = document.createElement("div");
+ SocialCalc.setStyles(this.dragpalette, "display:none;position:absolute;zIndex:8;width:90px;height:90px;fontSize:1px;textAlign:center;cursor:default;"+
+ "backgroundImage:url("+SocialCalc.Constants.defaultImagePrefix+"drag-handles."+imagetype+");");
+ this.dragpalette.innerHTML = '&nbsp;';
+ editor.toplevel.appendChild(this.dragpalette);
+ SocialCalc.AssignID(editor, this.dragpalette, "dragpalette");
+
+ this.dragtooltip = document.createElement("div");
+ SocialCalc.setStyles(this.dragtooltip, "display:none;position:absolute;zIndex:9;border:1px solid black;width:100px;height:auto;fontSize:10px;backgroundColor:#FFFFFF;");
+ this.dragtooltip.innerHTML = '&nbsp;';
+ editor.toplevel.appendChild(this.dragtooltip);
+ SocialCalc.AssignID(editor, this.dragtooltip, "dragtooltip");
+
+ this.fillinghandle = document.createElement("div");
+ SocialCalc.setStyles(this.fillinghandle, "display:none;position:absolute;zIndex:9;border:1px solid black;width:auto;height:14px;fontSize:10px;backgroundColor:#FFFFFF;");
+ this.fillinghandle.innerHTML = '&nbsp;';
+ editor.toplevel.appendChild(this.fillinghandle);
+ SocialCalc.AssignID(editor, this.fillinghandle, "fillinghandle");
+
+ if (this.draghandle.addEventListener) { // DOM Level 2 -- Firefox, et al
+ this.draghandle.addEventListener("mousemove", SocialCalc.CellHandlesMouseMoveOnHandle, false);
+ this.dragpalette.addEventListener("mousedown", SocialCalc.CellHandlesMouseDown, false);
+ this.dragpalette.addEventListener("mousemove", SocialCalc.CellHandlesMouseMoveOnHandle, false);
+ }
+ else if (this.draghandle.attachEvent) { // IE 5+
+ this.draghandle.attachEvent("onmousemove", SocialCalc.CellHandlesMouseMoveOnHandle);
+ this.dragpalette.attachEvent("onmousedown", SocialCalc.CellHandlesMouseDown);
+ this.dragpalette.attachEvent("onmousemove", SocialCalc.CellHandlesMouseMoveOnHandle);
+ }
+ else { // don't handle this
+ throw "Browser not supported";
+ }
+
+ }
+
+// Methods:
+
+SocialCalc.CellHandles.prototype.ShowCellHandles = function(show, moveshow) {return SocialCalc.ShowCellHandles(this, show, moveshow);};
+
+// Functions:
+
+SocialCalc.ShowCellHandles = function(cellhandles, show, moveshow) {
+
+ var cell, cell2, position, position2;
+ var editor = cellhandles.editor;
+ var doshow = false;
+ var row, col, viewport;
+
+ if (!editor) return;
+
+ do { // a block that can you can "break" out of easily
+
+ if (!show) break;
+
+ row = editor.ecell.row;
+ col = editor.ecell.col;
+
+ if (editor.state != "start") break;
+ if (row >= editor.lastvisiblerow) break;
+ if (col >= editor.lastvisiblecol) break;
+ if (row < editor.firstscrollingrow) break;
+ if (col < editor.firstscrollingcol) break;
+
+ if (editor.rowpositions[row+1]+20>editor.horizontaltablecontrol.controlborder) {
+ break;
+ }
+ if (editor.rowpositions[row+1]-10<editor.headposition.top) {
+ break;
+ }
+ if (editor.colpositions[col+1]+20>editor.verticaltablecontrol.controlborder) {
+ break;
+ }
+ if (editor.colpositions[col+1]-30<editor.headposition.left) {
+ break;
+ }
+
+ cellhandles.draghandle.style.left = (editor.colpositions[col+1]-1)+"px";
+ cellhandles.draghandle.style.top = (editor.rowpositions[row+1]-1)+"px";
+ cellhandles.draghandle.style.display = "block";
+
+ if (moveshow) {
+ cellhandles.draghandle.style.display = "none";
+ cellhandles.dragpalette.style.left = (editor.colpositions[col+1]-45)+"px";
+ cellhandles.dragpalette.style.top = (editor.rowpositions[row+1]-45)+"px";
+ cellhandles.dragpalette.style.display = "block";
+ viewport = SocialCalc.GetViewportInfo();
+ cellhandles.dragtooltip.style.right = (viewport.width-(editor.colpositions[col+1]-1))+"px";
+ cellhandles.dragtooltip.style.bottom = (viewport.height-(editor.rowpositions[row+1]-1))+"px";
+ cellhandles.dragtooltip.style.display = "none";
+ }
+
+ doshow = true;
+
+ }
+ while (false); // only do once
+
+ if (!doshow) {
+ cellhandles.draghandle.style.display = "none";
+ }
+ if (!moveshow) {
+ cellhandles.dragpalette.style.display = "none";
+ cellhandles.dragtooltip.style.display = "none";
+ }
+
+ }
+
+SocialCalc.CellHandlesMouseMoveOnHandle = function(e) {
+
+ var scc = SocialCalc.Constants;
+
+ var event = e || window.event;
+ var target = event.target || event.srcElement
+ var viewport = SocialCalc.GetViewportInfo();
+ var clientX = event.clientX + viewport.horizontalScroll;
+ var clientY = event.clientY + viewport.verticalScroll;
+
+ editor = SocialCalc.Keyboard.focusTable; // get TableEditor doing keyboard stuff
+ if (!editor) return true; // we're not handling it -- let browser do default
+ var cellhandles = editor.cellhandles;
+ if (!cellhandles.editor) return true; // no handles
+
+ if (!editor.cellhandles.mouseDown) {
+ editor.cellhandles.ShowCellHandles(true, true); // show move handles, too
+
+ if (target == cellhandles.dragpalette) {
+ var whichhandle = SocialCalc.SegmentDivHit([24.0, 36.0], editor.cellhandles.dragpalette, clientX, clientY);
+ if (whichhandle==0) { // off of active part of palette
+ SocialCalc.CellHandlesHoverTimeout();
+ return;
+ }
+ if (cellhandles.tooltipstimer) {
+ window.clearTimeout(cellhandles.tooltipstimer);
+ cellhandles.tooltipstimer = null;
+ }
+ cellhandles.tooltipswhichhandle = whichhandle;
+ cellhandles.tooltipstimer = window.setTimeout(SocialCalc.CellHandlesTooltipsTimeout, 700);
+ }
+
+ if (cellhandles.timer) {
+ window.clearTimeout(cellhandles.timer);
+ cellhandles.timer = null;
+ }
+ cellhandles.timer = window.setTimeout(SocialCalc.CellHandlesHoverTimeout, 3000);
+ }
+
+ return;
+
+ }
+
+//
+// whichsegment = SocialCalc.SegmentDivHit(segtable, divWithMouseHit, x, y)
+//
+// Takes segtable = [upperleft quadrant, upperright, bottomright, bottomleft]
+// where each quadrant is either:
+// 0 = ignore hits here
+// number = return this value
+// array = a new segtable for this subquadrant
+//
+// Alternatively, segtable can be:
+// [diameter 1, diameter 2] and it returns 0 if no hit,
+// -1, -2, -3, -4 for inner quadrants, and +1...+4 for outer quadrants
+//
+
+SocialCalc.SegmentDivHit = function(segtable, divWithMouseHit, x, y) {
+
+ var width = divWithMouseHit.offsetWidth;
+ var height = divWithMouseHit.offsetHeight;
+ var left = divWithMouseHit.offsetLeft;
+ var top = divWithMouseHit.offsetTop;
+ var v = 0;
+ var table = segtable;
+ var len = Math.sqrt(Math.pow(x-left-(width/2.0-.5), 2)+Math.pow(y-top-(height/2.0-.5), 2));
+
+ if (table.length==2) { // type 2 segtable
+ if (x >= left && x < left+width/2 && y >= top && y < top+height/2) { // upper left
+ if (len <= segtable[0]) v = -1;
+ else if (len <= segtable[1]) v = 1;
+ }
+ if (x >= left+width/2 && x < left+width && y >= top && y < top+height/2) { // upper right
+ if (len <= segtable[0]) v = -2;
+ else if (len <= segtable[1]) v = 2;
+ }
+ if (x >= left+width/2 && x < left+width && y >= top+height/2 && y < top+height) { // bottom right
+ if (len <= segtable[0]) v = -3;
+ else if (len <= segtable[1]) v = 3;
+ }
+ if (x >= left && x < left+width/2 && y >= top+height/2 && y < top+height) { // bottom right
+ if (len <= segtable[0]) v = -4;
+ else if (len <= segtable[1]) v = 4;
+ }
+ return v;
+ }
+
+ while (true) {
+ if (x >= left && x < left+width/2 && y >= top && y < top+height/2) { // upper left
+ quadrant += "1";
+ v = table[0];
+ if (typeof v == "number") {
+ break;
+ }
+ table = v;
+ width = width/2;
+ height = height/2;
+ continue;
+ }
+ if (x >= left+width/2 && x < left+width && y >= top && y < top+height/2) { // upper right
+ quadrant += "2";
+ v = table[1];
+ if (typeof v == "number") {
+ break;
+ }
+ table = v;
+ width = width/2;
+ left = left+width;
+ height = height/2;
+ continue;
+ }
+ if (x >= left+width/2 && x < left+width && y >= top+height/2 && y < top+height) { // bottom right
+ quadrant += "3";
+ v = table[2];
+ if (typeof v == "number") {
+ break;
+ }
+ table = v;
+ width = width/2;
+ left = left + width;
+ height = height/2;
+ top = top + height;
+ continue;
+ }
+ if (x >= left && x < left+width/2 && y >= top+height/2 && y < top+height) { // bottom right
+ quadrant += "4";
+ v = table[3];
+ if (typeof v == "number") {
+ break;
+ }
+ table = v;
+ width = width/2;
+ height = height/2;
+ top = top + height;
+ continue;
+ }
+ return 0; // didn't match
+ }
+
+//addmsg((x-divWithMouseHit.offsetLeft)+","+(y-divWithMouseHit.offsetTop)+"="+quadrant+" "+v);
+ return v;
+
+}
+
+SocialCalc.CellHandlesHoverTimeout = function() {
+
+ editor = SocialCalc.Keyboard.focusTable; // get TableEditor doing keyboard stuff
+ if (!editor) return true; // we're not handling it -- let browser do default
+ var cellhandles = editor.cellhandles;
+ if (cellhandles.timer) {
+ window.clearTimeout(cellhandles.timer);
+ cellhandles.timer = null;
+ }
+ if (cellhandles.tooltipstimer) {
+ window.clearTimeout(cellhandles.tooltipstimer);
+ cellhandles.tooltipstimer = null;
+ }
+ editor.cellhandles.ShowCellHandles(true, false); // hide move handles
+
+}
+
+SocialCalc.CellHandlesTooltipsTimeout = function() {
+
+ editor = SocialCalc.Keyboard.focusTable; // get TableEditor doing keyboard stuff
+ if (!editor) return true; // we're not handling it -- let browser do default
+ var cellhandles = editor.cellhandles;
+ if (cellhandles.tooltipstimer) {
+ window.clearTimeout(cellhandles.tooltipstimer);
+ cellhandles.tooltipstimer = null;
+ }
+
+ var whichhandle = cellhandles.tooltipswhichhandle;
+ if (whichhandle==0) { // off of active part of palette
+ SocialCalc.CellHandlesHoverTimeout();
+ return;
+ }
+ if (whichhandle==-3) {
+ cellhandles.dragtooltip.innerHTML = scc.s_CHfillAllTooltip;
+ }
+ else if (whichhandle==3) {
+ cellhandles.dragtooltip.innerHTML = scc.s_CHfillContentsTooltip;
+ }
+ else if (whichhandle==-2) {
+ cellhandles.dragtooltip.innerHTML = scc.s_CHmovePasteAllTooltip;
+ }
+ else if (whichhandle==-4) {
+ cellhandles.dragtooltip.innerHTML = scc.s_CHmoveInsertAllTooltip;
+ }
+ else if (whichhandle==2) {
+ cellhandles.dragtooltip.innerHTML = scc.s_CHmovePasteContentsTooltip;
+ }
+ else if (whichhandle==4) {
+ cellhandles.dragtooltip.innerHTML = scc.s_CHmoveInsertContentsTooltip;
+ }
+ else {
+ cellhandles.dragtooltip.innerHTML = "&nbsp;";
+ cellhandles.dragtooltip.style.display = "none";
+ return;
+ }
+
+ cellhandles.dragtooltip.style.display = "block";
+
+}
+
+SocialCalc.CellHandlesMouseDown = function(e) {
+
+ var scc = SocialCalc.Constants;
+ var editor, result, coord, textarea, wval, range;
+
+ var event = e || window.event;
+
+ var viewport = SocialCalc.GetViewportInfo();
+ var clientX = event.clientX + viewport.horizontalScroll;
+ var clientY = event.clientY + viewport.verticalScroll;
+
+ var mouseinfo = SocialCalc.EditorMouseInfo;
+
+ editor = SocialCalc.Keyboard.focusTable; // get TableEditor doing keyboard stuff
+ if (!editor) return true; // we're not handling it -- let browser do default
+
+ if (editor.busy) return; // don't do anything when busy (is this correct?)
+
+ var cellhandles = editor.cellhandles;
+
+ if (cellhandles.timer) { // cancel timer
+ window.clearTimeout(cellhandles.timer);
+ cellhandles.timer = null;
+ }
+ if (cellhandles.tooltipstimer) {
+ window.clearTimeout(cellhandles.tooltipstimer);
+ cellhandles.tooltipstimer = null;
+ }
+ cellhandles.dragtooltip.innerHTML = "&nbsp;";
+ cellhandles.dragtooltip.style.display = "none";
+
+ range = editor.range;
+
+ var whichhandle = SocialCalc.SegmentDivHit([24.0, 36.0], editor.cellhandles.dragpalette, clientX, clientY);
+ if (whichhandle==1 || whichhandle==-1 || whichhandle==0) {
+ cellhandles.ShowCellHandles(true, false); // hide move handles
+ return;
+ }
+
+ mouseinfo.ignore = true; // stop other code from looking at the mouse
+
+ if (whichhandle==-3) {
+ cellhandles.dragtype = "Fill";
+ mouseinfo.element = editor.cellhandles.fillhandle;
+ cellhandles.noCursorSuffix = false;
+ }
+ else if (whichhandle==3) {
+ cellhandles.dragtype = "FillC";
+ mouseinfo.element = editor.cellhandles.fillhandle;
+ cellhandles.noCursorSuffix = false;
+ }
+ else if (whichhandle==-2) {
+ cellhandles.dragtype = "Move";
+ mouseinfo.element = editor.cellhandles.movehandle1;
+ cellhandles.noCursorSuffix = true;
+ }
+ else if (whichhandle==-4) {
+ cellhandles.dragtype = "MoveI";
+ mouseinfo.element = editor.cellhandles.movehandle2;
+ cellhandles.noCursorSuffix = false;
+ }
+ else if (whichhandle==2) {
+ cellhandles.dragtype = "MoveC";
+ mouseinfo.element = editor.cellhandles.movehandle1;
+ cellhandles.noCursorSuffix = true;
+ }
+ else if (whichhandle==4) {
+ cellhandles.dragtype = "MoveIC";
+ mouseinfo.element = editor.cellhandles.movehandle2;
+ cellhandles.noCursorSuffix = false;
+ }
+
+ cellhandles.filltype = null;
+
+ switch (cellhandles.dragtype) {
+ case "Fill":
+ case "FillC":
+ if (!range.hasrange) {
+ editor.RangeAnchor();
+ }
+ break;
+
+ case "Move":
+ case "MoveI":
+ case "MoveC":
+ case "MoveIC":
+ if (!range.hasrange) {
+ editor.RangeAnchor();
+ }
+ editor.range2.top = editor.range.top;
+ editor.range2.right = editor.range.right;
+ editor.range2.bottom = editor.range.bottom;
+ editor.range2.left = editor.range.left;
+ editor.range2.hasrange = true;
+ editor.RangeRemove();
+ break;
+
+ default:
+ return; // not for us
+ }
+
+ cellhandles.fillinghandle.style.left = (clientX)+"px";
+ cellhandles.fillinghandle.style.top = (clientY - 17)+"px";
+ cellhandles.fillinghandle.innerHTML = scc.s_CHindicatorOperationLookup[cellhandles.dragtype]+
+ (scc.s_CHindicatorDirectionLookup[editor.cellhandles.filltype] || "");
+ cellhandles.fillinghandle.style.display = "block";
+
+ cellhandles.ShowCellHandles(true, false); // hide move handles
+ cellhandles.mouseDown = true;
+
+ mouseinfo.editor = editor; // remember for later
+
+ coord = editor.ecell.coord; // start with cell with handles
+
+ cellhandles.startingcoord = coord;
+ cellhandles.startingX = clientX;
+ cellhandles.startingY = clientY;
+
+ mouseinfo.mouselastcoord = coord;
+
+ SocialCalc.KeyboardSetFocus(editor);
+
+ if (document.addEventListener) { // DOM Level 2 -- Firefox, et al
+ document.addEventListener("mousemove", SocialCalc.CellHandlesMouseMove, true); // capture everywhere
+ document.addEventListener("mouseup", SocialCalc.CellHandlesMouseUp, true); // capture everywhere
+ }
+ else if (cellhandles.draghandle.attachEvent) { // IE 5+
+ cellhandles.draghandle.setCapture();
+ cellhandles.draghandle.attachEvent("onmousemove", SocialCalc.CellHandlesMouseMove);
+ cellhandles.draghandle.attachEvent("onmouseup", SocialCalc.CellHandlesMouseUp);
+ cellhandles.draghandle.attachEvent("onlosecapture", SocialCalc.CellHandlesMouseUp);
+ }
+ if (event.stopPropagation) event.stopPropagation(); // DOM Level 2
+ else event.cancelBubble = true; // IE 5+
+ if (event.preventDefault) event.preventDefault(); // DOM Level 2
+ else event.returnValue = false; // IE 5+
+
+ return;
+
+ }
+
+SocialCalc.CellHandlesMouseMove = function(e) {
+
+ var scc = SocialCalc.Constants;
+ var editor, element, result, coord, now, textarea, sheetobj, cellobj, wval;
+ var crstart, crend, cr, c, r;
+
+ var event = e || window.event;
+
+ var viewport = SocialCalc.GetViewportInfo();
+ var clientX = event.clientX + viewport.horizontalScroll;
+ var clientY = event.clientY + viewport.verticalScroll;
+
+ var mouseinfo = SocialCalc.EditorMouseInfo;
+ editor = mouseinfo.editor;
+ if (!editor) return; // not us, ignore
+ var cellhandles = editor.cellhandles;
+
+ element = mouseinfo.element;
+
+ result = SocialCalc.GridMousePosition(editor, clientX, clientY); // get cell with move
+
+ if (!result) return;
+
+ if (result && !result.coord) {
+ SocialCalc.SetDragAutoRepeat(editor, result, SocialCalc.CellHandlesDragAutoRepeat);
+ return;
+ }
+
+ SocialCalc.SetDragAutoRepeat(editor, null); // stop repeating if it was
+
+ if (!result.coord) return;
+
+ crstart = SocialCalc.coordToCr(editor.cellhandles.startingcoord);
+ crend = SocialCalc.coordToCr(result.coord);
+
+ switch (cellhandles.dragtype) {
+ case "Fill":
+ case "FillC":
+
+ if (result.coord == cellhandles.startingcoord) { // reset when come back
+ cellhandles.filltype = null;
+ cellhandles.startingX = clientX;
+ cellhandles.startingY = clientY;
+ }
+ else {
+ if (cellhandles.filltype) { // moving and have already determined filltype
+ if (cellhandles.filltype=="Down") { // coerse to that
+ crend.col = crstart.col;
+ if (crend.row < crstart.row) crend.row = crstart.row;
+ }
+ else {
+ crend.row = crstart.row;
+ if (crend.col < crstart.col) crend.col = crstart.col;
+ }
+ }
+ else {
+ if (Math.abs(clientY - cellhandles.startingY) > 10) {
+ cellhandles.filltype = "Down";
+ }
+ else if (Math.abs(clientX - cellhandles.startingX) > 10) {