1# 2# WKC.pl -- Main package wikiCalc 3# 4# (c) Copyright 2005, 2006, 2007 Software Garden, Inc. 5# All Rights Reserved. 6# Subject to Software License at the end of this file 7# 8 9# 10 11# 12# Define Package 13# 14 15 package WKC; 16 17# 18# Do uses 19# 20 21 use strict; 22 use CGI qw(:standard); 23 use utf8; 24 use LWP::UserAgent; 25 26 use WKCStrings; 27 use WKCSheet; 28 use WKCSheetFunctions; 29 use WKCPageCommands; 30 use WKCDataFiles; 31 use WKCFormatCommands; 32 use WKCToolsCommands; 33 34# 35# Export symbols 36# 37 38 require Exporter; 39 our @ISA = qw(Exporter); 40 our @EXPORT = qw(process_request update_hiddenfields site_not_allowed find_in_sheet_cache 41 %config_values $programname); 42 our $VERSION = '1.0.0'; 43 44# 45# Define some variables 46# 47 48 # 49 # Public ones: 50 # 51 52 our %config_values = (socket => 6556); 53 54 # 55 # Here are the program name strings for display when executing. See the Note below. 56 # 57 58 our $programversion = "1.0"; # The version information string 59 our $programmark = "wikiCalc"; # This is the main trademark for the product. Change if required by trademark law. 60 our $programmarksymbol = qq!<span style="font-weight:normal;vertical-align:super;">®</span>!; # The HTML for the trademark symbol for $programmark 61 our $programname = "$programmark $programversion"; # Change name if required by trademark usage. This is where the version is indicated. 62 our $trademark1 = qq!, a Software Garden<span style="font-weight:normal;vertical-align:super;">®</span> product!; # Remove if required by trademark usage (also: \xC2\xAE as UTF-8) 63 our $SGIfootertext = <<"EOF"; 64wikiCalc Program (c) Copyright 2007 Software Garden, Inc. 65<br>All Rights Reserved. 66<br>Garden, Software Garden, and wikiCalc are registered trademarks or trademarks 67<br>of Software Garden, Inc., in the United States and in other countries. 68<br>The original version of this program is from <a href="http://www.softwaregarden.com">Software Garden</a>. 69EOF 70 71 # *** Note: *** 72 # 73 # In order to carry a prominent notice stating that you changed the files when distributing 74 # works based on this program, you may use the $WKCStrings values "programextratop" and "footerextratext". 75 # 76 # An example of a "programextratop" value would be "Modified" which would result in 77 # a displayed banner of "Modified wikiCalc..." indicating that this is 78 # a modification to the original version to which the trademark applied. 79 # Another example would be "Foobar 1.5 modification of " which would 80 # result in a displayed banner of "Foobar 1.5 modification of wikiCalc...". 81 # (Use of "Foobar 1.5 " without the words "modification of" is a trademark violation.) 82 # If you make any modifications to the product you should set programextratop appropriately 83 # since it is no longer the Software Garden product alone. 84 # 85 # An example of a "footerextratext" value would be "<br><br>Modification to original:<br>Localisation to UK English (c) 2007 ABC Localizers Ltd." 86 # 87 # In both cases, you would also put comments in any source files that were modified indicating 88 # the author, date, and nature of the changes. 89 90 # 91 # Private ones: 92 # 93 94 my $securitycode = "not set!"; # Requests may need a parameter that matches this 95 96 my %initial_datavalues = ( # Used to initialize %datavalues 97 ); 98 99 my $defaultcookieexpire = "+6M"; # how long do cookies (remembering page being edited and maybe login info) last by default? 100 101 my $template_headertop = <<"EOF"; 102<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> 103<html> 104<head> 105<META http-equiv="Content-Type" content="text/html; charset=UTF-8"> 106<title>$programname</title> 107EOF 108 109 my $template_styletop = <<"EOF"; 110<style type="text/css"> 111body, td, input, textarea {font-family:verdana,helvetica,sans-serif;font-size:small;} 112.smaller {font-size: smaller;} 113form { 114 margin:0px; 115 padding:0px; 116} 117dd { 118 padding: 1pt 0px 2pt 0px; 119} 120dt { 121 font-weight: bold; 122 padding: 1pt 0px 1pt 0px; 123} 124.programtop { 125 margin-bottom: 10px; 126 } 127.programtopdark { 128 color: #006600; 129 font-size: smaller; 130 font-weight: bold; 131} 132.programtoplight { 133 color: #999999; 134 font-size: smaller; 135} 136.programtoplogout, .programtoplogout a { 137 color: #999999; 138 font-weight: bold; 139 font-size: smaller; 140 text-decoration: none; 141} 142.programtoplogout a:hover { 143 text-decoration: underline; 144} 145.programtopname { 146 color: #006600; 147 font-weight: bold; 148 font-size: smaller; 149 border: 1px solid #006600; 150 padding: 4px; 151} 152.programtoprevert { 153 color: #CC0000; 154 font-size: smaller; 155 font-weight: bold; 156} 157.tab { 158 border-bottom: 1px solid black; 159 padding-bottom: 4px; 160 } 161.tab input { 162 background-color:#CCCC99; 163 color:black; 164} 165.tabselected { 166 border-left: 1px solid black; 167 border-right: 1px solid black; 168 border-top: 1px solid black; 169 background-color:#DDFFDD; 170 color:black; 171 padding: 1px 14px 0px 14px; 172 text-align: center; 173 font-weight: bold; 174 } 175.tab1 { 176 border-bottom: 1px solid black; 177 } 178.tab2 { 179 background-color:#DDFFDD; 180 } 181.tab2left { 182 border-left: 1px solid black; 183 background-color:#DDFFDD; 184 padding-left:20px; 185 } 186.tab2right { 187 border-right: 1px solid black; 188 background-color:#DDFFDD; 189 } 190.ttbody { 191 background-color:#DDFFDD; 192 border-right: 1px solid black; 193 border-left: 1px solid black; 194 border-bottom: 1px solid black; 195 padding: 0px 10px 4px 10px; 196} 197EOF 198 199 my $template_stylemiddle_verbose = <<"EOF"; 200.sectionoutlined { 201 border: 1px solid #99CC99; 202 padding: 8px; 203} 204.sectionoutlineddark { 205 border-left: 20px solid #99CC99; 206 padding: 8px 8px 0px 8px; 207 margin-bottom: 8px; /* IE bug work-around with padding-bottom and border-left (?!!) */ 208} 209.sectionplain { 210 padding: 10px; 211} 212.sectionerror { 213 padding: 10px; 214 color: red; 215 font-weight: bold; 216} 217.title { 218 color: #006600; 219 font-weight:bold; 220 margin: 0em 0px 2pt 0px; 221 padding: 0px 0px 0px 0px; 222} 223.title2 { 224 border-top: 1px solid #006600; 225 color: #006600; 226 font-weight:bold; 227 margin: .5em 0px 0px 0px; 228 padding: 0px 0px 0px 0px; 229} 230.pagetitle { 231 color: #006600; 232 font-weight:bold; 233 margin: 0em 0px 0px 0px; 234 padding: 0px 0px 0px 0px; 235} 236.pagebreadcrumbs { 237 color: #006600; 238 font-weight:bold; 239 font-size:smaller; 240 margin: 0em 0px 6pt 0px; 241 padding: 0px 0px 0px 0px; 242} 243.pagefilename { 244 color: #006600; 245 font-size: smaller; 246 font-weight: bold; 247 margin: 1pt 0px 2pt 0px; 248 padding: 0px 0px 0px 0px; 249} 250.pagetitledesc { 251 color: black; 252 font-size: smaller; 253 margin: 1pt 0px 2pt 0px; 254 padding: 0px 0px 0px 0px; 255} 256.desc { 257 font-size:smaller; 258 padding: 0px 0px .75em 0px; 259} 260.warning { 261 font-size:smaller; 262 font-weight:bold; 263 color:red; 264} 265.footer { 266 border: 1px dashed #006600; 267 padding: 6px; 268 color: #006600; 269 font-size: smaller; 270 margin: 1em 0px .5em 0px; 271} 272EOF 273 274 my $template_stylemiddle_concise = <<"EOF"; 275.sectionoutlined { 276 padding: 0px 8px 6px 8px; 277} 278.sectionoutlineddark { 279 border-left: 20px solid #99CC99; 280 padding: 8px; 281 margin-bottom: 8px; 282 margin-left: 10px; 283} 284.sectionplain { 285 padding: 10px; 286} 287.sectionerror { 288 padding: 10px; 289 color: red; 290 font-weight: bold; 291} 292.title { 293 color: #006600; 294 font-weight:bold; 295 margin: 0em 0px 2pt 0px; 296 padding: 0px 0px 0px 0px; 297} 298.title2 { 299 border-top: 1px solid #006600; 300 color: #006600; 301 font-weight:bold; 302 margin: .5em 0px 0px 0px; 303 padding: 0px 0px 0px 0px; 304} 305.pagebreadcrumbs { 306 color: #006600; 307 font-weight:bold; 308 font-size:smaller; 309 margin: 0em 0px 2pt 0px; 310 padding: 0px 0px 0px 0px; 311} 312.pagetitle { 313 color: #006600; 314 font-weight:bold; 315 margin: 0em 0px 0px 0px; 316 padding: 0px 0px 0px 0px; 317} 318.pagefilename { 319 color: #006600; 320 font-size: smaller; 321 font-weight: bold; 322 margin: 1pt 0px 2pt 0px; 323 padding: 0px 0px 0px 0px; 324} 325.pagetitledesc { 326 visibility:hidden; 327 height:0px; 328} 329.desc { 330 visibility:hidden; 331 height:0px; 332} 333.warning { 334 font-size:smaller; 335 font-weight:bold; 336 color:red; 337} 338.footer { 339 visibility:hidden; 340 height:0px; 341} 342EOF 343 344 my $template_stylebottom = <<"EOF"; 345.browsepageavailable { 346 font-size: smaller; 347 font-weight: bold; 348 background-color: white; 349 padding-left: 4pt; 350 padding-right: 4pt; 351 padding-bottom: 1pt; 352 vertical-align: top; 353} 354.browsepageavailable1 { 355 background-color: white; 356 padding-bottom: 1pt; 357 vertical-align: top; 358} 359.browsepageavailable2 { 360 font-size: smaller; 361 background-color: white; 362 padding-left: 4pt; 363 padding-right: 4pt; 364 padding-bottom: 1pt; 365 vertical-align: top; 366} 367.browsepageavailable3 { 368 font-size: smaller; 369 font-weight: bold; 370 color: #999999; 371 background-color: white; 372 padding-left: 4pt; 373 padding-right: 0px; 374 vertical-align: top; 375 text-align: right; 376} 377.browsepageediting { 378 font-size: smaller; 379 color: white; 380 font-weight: bold; 381 background-color: #339933; 382 padding-left: 4pt; 383 padding-right: 4pt; 384 padding-bottom: 1pt; 385 vertical-align: top; 386} 387.browsepageediting2 { 388 font-size: smaller; 389 color: white; 390 background-color: #339933; 391 padding-left: 4pt; 392 padding-right: 4pt; 393 padding-bottom: 1pt; 394 vertical-align: top; 395} 396.browsepageediting3 { 397 font-size: smaller; 398 font-weight: bold; 399 color: white; 400 background-color: #339933; 401 padding-left: 4pt; 402 padding-right: 4pt; 403 padding-bottom: 1pt; 404 vertical-align: top; 405} 406.browsepagemedium { 407 font-size: smaller; 408 font-weight: bold; 409 padding-left: 4pt; 410 vertical-align: top; 411 color: black; 412} 413.browsepagedim { 414 font-size: smaller; 415 padding-left: 4pt; 416 vertical-align: top; 417 color: #999999; 418} 419.browsepagename { 420 font-size: smaller; 421 padding-left: 4pt; 422 padding-right: 4pt; 423 vertical-align: top; 424 color: black; 425} 426.browseusername { 427 font-weight: bold; 428 padding-left: 4pt; 429 padding-right: 4pt; 430 vertical-align: top; 431 color: black; 432} 433.browseusersite { 434 text-align:center; 435} 436.browseuseradd { 437 font-size: smaller; 438 font-style: italic; 439 padding-left: 4pt; 440 text-align: center; 441 color: #999999; 442} 443.browsebuttons { 444 padding-left: 4pt; 445 vertical-align: top; 446} 447.browsenormal { 448 font-size: smaller; 449 padding-left: 4pt; 450 vertical-align: top; 451} 452.browsetablehead { 453 background-color: #339933; 454 color: white; 455 font-size: smaller; 456 font-weight: bold; 457 padding: 4pt 0 4pt 4pt; 458 text-align: center; 459} 460.browsegrouphead { 461 background-color: #99CC99; 462 color: black; 463 font-size: smaller; 464 font-weight: bold; 465 padding: 4pt 0 4pt 4pt; 466 text-align: center; 467} 468.browsecolumnhead { 469 background-color: #99CC99; 470 color: white; 471 font-size: smaller; 472 font-weight: bold; 473 padding: 4pt 0 4pt 4pt; 474} 475.browsebuttoncell { 476 vertical-align: top; 477 white-space: nowrap; 478} 479.browsebuttoncellediting { 480 text-align: left; 481 white-space: nowrap; 482 background-color: #339933; 483} 484.browseselectedtext { 485 font-size: smaller; 486 font-weight: bold; 487 color: black; 488 background-color: white; 489 margin: 0px 4px 4px 4px; 490 padding: 0px 3px 2px 0px; 491} 492.browsereconcile { 493 background-color: white; 494 padding: 6pt; 495 vertical-align: top; 496 text-align: center; 497} 498.colsample1 { 499 border-top:2px solid black; 500 border-left:1px solid black; 501 padding:10px 0px 0px 8px; 502 font-size:1pt; 503} 504.colsample2 { 505 border-left:1px solid black; 506 font-size:x-small; 507 padding-left:1pt; 508} 509.cellnormal { 510 } 511.cellcursor { 512 margin:1px; 513 padding:1px; 514 border:3px solid #666633; 515 } 516.cellcorner { 517 margin:1px; 518 padding:1px; 519 border:1px solid #99CC99; 520 } 521.colorbox { 522 border:1px solid black; 523 padding:5px; 524 height:1px; 525 width:1px; 526} 527.defaultbox { 528 border:1px solid black; 529 padding:0px; 530 background-color:white; 531 background-image:url('?getfile=hatchbg'); 532 height:16px; 533 width:16px; 534} 535.previewlisttitle { 536 font-size:smaller; 537 font-weight:bold; 538 text-align:right; 539} 540</style> 541EOF 542 543 my $template_headerscripts = <<"EOF"; # start with do nothing for setf and remove end of URL for setf0 544<script> 545<!-- 546var setf = function() {1;} 547function setactions() { 548if (document.f0) document.f0.action=location.protocol+"//"+location.host+location.pathname; 549if (document.ftabs) document.ftabs.action=location.protocol+"//"+location.host+location.pathname; 550} 551// --> 552</script> 553EOF 554 555# 556# * * * * * 557# 558# PRE-LOAD special strings (WKCStrings overrides) 559# 560# * * * * * 561# 562 563 load_special_strings(); # loaded at first parse... (in WKCSheet.pm) 564 565 my @tablist = ($WKCStrings{"Page"}, $WKCStrings{"Edit"}, 566 $WKCStrings{"Format"}, $WKCStrings{"Preview"}, 567 $WKCStrings{"Tools"}, $WKCStrings{"Quit"},); 568 569 570# 571# * * * * * 572# 573# process_request($querystring, $cookievalue, \%responsedata, $security, $noquittab) 574# 575# Process the HTTP request 576# 577# Responds to browser request and does all the work 578# Returns data in %responsedata: 579# $responsedata{content} - a string with the HTML response 580# $responsedata{contenttype} - the HTTP response header content MIME type or null for default text/html UTF-8 581# $responsedata{contentexpires} - expire string or null for default (-1d) 582# $responsedata{cookie} - a string with the cookie value to set, if any 583# $responsedata{cookieexpires} - expire value for cookie (e.g., "+1yr" or "" for session only) 584# 585# The $querystring is the raw query from the browser. 586# $cookievalue is the value of any cookie. 587# If $security is present and true, a "security" 588# parameter is used in each request to guard against 589# URLs on web sites that guess we are running locally. 590# $noquittab suppresses the Quit tab if true (for CGI and other cases where you always have a running system) 591# 592 593sub process_request { 594 595 my ($querystring, $cookievalue, $responsedata, $security, $noquittab) = @_; 596 my ($response, $rhead, $rbody1, $rbodytabs, $rbodytabs2, $inlinescripts); 597 598 my %sheetdata; 599 my @sheetlines; 600 my %headerdata; 601 my @headerlines; 602 603 # Initialize timers 604 605 my $start_clock_time = scalar localtime; 606 my $start_cpu_time = times(); 607 608 # Get CGI object to get parameters: 609 610 $querystring ||= ""; # make sure has something 611 my $q = new CGI($querystring); 612 my %params = $q->Vars; 613 614 # Parse cookie 615 616 my %cookievalues; 617 618 foreach my $cookie (split /;/, $cookievalue) { 619 if ($cookie) { 620 my ($n, $v) = split /:/, $cookie; 621 $cookievalues{$n} = $v; 622 } 623 } 624 625 # If Quit tab is chosen, then return nothing: 626 627 if ($params{newtab} eq $WKCStrings{"Quit"}) { 628 return unless $noquittab; 629 } 630 631 # 632 # Check security code 633 # 634 # If not the same as ours, set it and wipe out parameters. 635 # This is to prevent malicious web sites from linking 636 # to a "known" local address and affect this app. 637 # 638 639 $securitycode = "" if !$security; # Don't use if running through a web server 640 641 if ($params{securitycode} ne $securitycode) { 642 %params = (); 643 $querystring = ""; 644 $securitycode = sprintf("%.14f", rand); # assign a random security code 645 } 646 647 my %datavalues = %initial_datavalues; # start with default values 648 # before reading in 649 my $dvchanged; # if true, then need to write out 650 651 # 652 # *** Declarations 653 # 654 655 my ($editmode, $editcoords); 656 my $published = 0; 657 my $ok; 658 my $responsecookie; 659 660 # 661 # *** Retrieve initial values from params 662 # 663 664 $params{localwkcpath} = $WKCdirectory; 665 666 $editmode = $params{editmode}; 667 $editcoords = $params{editcoords}; 668 669 my $hostinfo = get_hostinfo(\%params); # input hostinfo data 670 671 # 672 # *** Check if login is necessary 673 # 674 675 $params{loggedinusername} ||= $cookievalues{loggedinusername}; # get from cookie if not in params 676 $params{loggedinuserpassword} ||= $cookievalues{loggedinuserpassword}; 677 678 if ($params{dologin}) { 679 $params{loggedinusername} = $params{editusername}; 680 } 681 elsif ($params{dologout}) { 682 %params = (); # forget everything 683 %cookievalues = (); 684 } 685 686 my %userinfo; # information about current user to be filled in when checking password 687 $userinfo{HOSTrequirelogin} = $hostinfo->{requirelogin}; # remember whether this host requires login here, too 688 689 my $loggedinuser = $params{loggedinusername}; 690 my $needlogin; # if true, need to login a user 691 my $loginerrtext; 692 $params{loggedinadmin} = "yes"; # if true, have wikiCalc admin privileges 693 if ($hostinfo->{requirelogin} eq "yes") { # global setting 694 my $password = $params{loggedinuserpassword}; 695 $needlogin = 1; # assume need to login 696 $params{loggedinadmin} = ""; # assume not admin 697#print "logged in user: $loggedinuser/$password (cookies:$cookievalues{loggedinusername}/$cookievalues{loggedinuserpassword})\n"; 698 if ($loggedinuser || $params{dologin}) { # is someone already logged in or logging in? 699 my $errtext = get_userinfofileinfo(\%params, \%userinfo, $loggedinuser); 700 if (!$errtext) { 701 if ($params{dologin}) { 702 $params{loggedinuserpassword} = substr(crypt($params{edituserpassword}, $userinfo{$params{editusername}}->{password}), 2); 703 $password = $params{loggedinuserpassword}; 704 } 705 if ($password eq substr($userinfo{$loggedinuser}->{password}, 2)) { # password is OK (salt is not passed back to browser) 706 if ($userinfo{$loggedinuser}->{admin} eq "yes") { 707 $params{loggedinadmin} = "yes"; # turn on 708 } 709 $needlogin = 0; # don't need to login 710 if ($params{dologin}) { 711 if ($params{editusercookies}) { # if the user says to save login info in cookie 712 $responsecookie .= "loggedinusername:$params{loggedinusername};loggedinuserpassword:$params{loggedinuserpassword};"; 713 $cookievalues{expires} = $params{editusercookies}; 714 } 715 } 716 elsif ($cookievalues{loggedinusername} && $params{loggedinusername}) { # if have been saving login info, continue to 717 $responsecookie .= "loggedinusername:$params{loggedinusername};loggedinuserpassword:$params{loggedinuserpassword};"; 718 } 719 } 720 else { 721 sleep 4; # if bad password, wait a bit so can't power through many easily 722 $loginerrtext = $WKCStrings{"loginerror"}; 723 } 724 } 725 else { 726 sleep 4; # if bad password, wait a bit so can't power through many easily 727 $loginerrtext = $WKCStrings{"loginerror"}; 728 } 729 } 730 } 731 732 # 733 # *** Look for special calls 734 # 735 736 # 737 # ?getfile=type for downloading special files, such as 1x1.gif 738 # 739 740 if ($params{getfile}) { 741 if ($params{getfile} eq "1x1" || $params{getfile} eq "hatchbg" || $params{getfile} eq "colsizehandle" || $params{getfile} eq "colsizescale") { 742 open IMAGEFILE, "$WKCdirectory/$params{getfile}.gif"; 743 binmode IMAGEFILE; 744 my @imagelines = <IMAGEFILE>; 745 close IMAGEFILE; 746 $response = join "", @imagelines; 747 $responsedata->{content} = $response; 748 $responsedata->{contenttype} = "image/gif"; 749 $responsedata->{contentexpires} = "+1h"; 750 return; 751 } 752 } 753 754 # 755 # ?ajaxsetcell=sitename:pagename:coord:newvalue for new cell value 756 # 757 # Returns XML with <root>new cell data in a CDATA</root>. 758 # 759 # The cell data is in the form of one or more text lines, each one of the following: 760 # coord:type:displayvalue:editvalue:align:colspan:rowspan:skip:csss\n 761 # error:Error message to display 762 # needsrecalc:yes/no 763 # footer:New runtime message for page footer 764 # Where: 765 # coord - A1, B7, etc. 766 # newvalue - what was typed in, including "=", etc., if present 767 # type - t is explicit text, tw is wikitext, n is number, 768 # f is formula without "=", and "e" is empty 769 # displayvalue - rendered HTML 770 # align - left/right/center 771 # colspan/rowspan - 1 or more 772 # skip - blank if normal cell, else coord of cell to move cursor to if it lands here 773 # csss - optional explicit style 774 # 775 776 if ($params{ajaxsetcell}) { 777 my ($psite, $pname, $coord, $value) = split(/:/, $params{ajaxsetcell}, 4); 778 $value = decode_from_ajax($value); 779 780 ($params{sitename}, $params{datafilename}) = ("", ""); # not used, but do this just in case 781 782 if ($needlogin || site_not_allowed(\%userinfo, $loggedinuser, $psite)) { # Not logged in or not allowed 783 my $msg = $needlogin ? $WKCStrings{"ajxnotloggedin"} : $WKCStrings{"ajaxnotfound"}; 784 my $xmlresponse = <<"EOF"; 785<?xml version="1.0" ?> 786<root><![CDATA[ 787error:$msg 788]]></root> 789EOF 790 $responsedata->{content} = $xmlresponse; 791 $responsedata->{contenttype} = "text/xml"; 792 return; 793 } 794 795 my ($type, $v1, $aep, @aheaderlines, @asheetlines, %aheaderdata, %asheetdata, %asheetdata, $aerrtext); 796 797 $aep = get_page_edit_path(\%params, $hostinfo, $psite, $pname); 798 $ok = load_page($aep, \@aheaderlines, \@asheetlines); 799 800 $ok = parse_header_save(\@aheaderlines, \%aheaderdata); 801 $ok = parse_sheet_save(\@asheetlines, \%asheetdata); 802 init_sheet_cache(\%asheetdata, \%params, $hostinfo, $psite); # remember in case have references to other worksheets 803 804 my %celldatabefore; 805 my $linkstyle = "?view=$psite/[[pagename]]"; 806 render_values_only(\%asheetdata, \%celldatabefore, $linkstyle); 807 808 # Determine value type and do appropriate command to set it 809 810 $type = "text tw"; 811 my $fch = substr($value, 0, 1); 812 if ($fch eq "=" && $value !~ m/\n/) { 813 $type = "formula"; 814 $value = substr($value, 1); 815 } 816 elsif ($fch eq "'") { 817 $type = "text tw"; 818 $value = substr($value, 1); 819 } 820 elsif (length $value == 0) { 821 $type = "empty"; 822 } 823 else { 824 $v1 = determine_value_type($value, \$type); 825 if ($type eq 'n' && $v1 == $value) { # check that we don't need "constant" 826 $type = "value n"; 827 } 828 elsif ($type eq 't') { 829 $type = "text tw"; 830 } 831 else { # handle all the special types 832 $type = "constant $type $v1"; 833 } 834 } 835 836 my $cmdline = "set $coord $type $value"; # create and execute command to set the cell 837 $ok = execute_sheet_command_and_log(\%asheetdata, $cmdline, \%aheaderdata); 838 if ($ok) { 839 if ($asheetdata{sheetattribs}->{recalc} ne "off") { 840 $aerrtext = recalc_sheet(\%asheetdata); 841 } 842 else { 843 $asheetdata{sheetattribs}->{needsrecalc} = "yes"; 844 } 845 } 846 else { 847 $aerrtext = "Failed: $ok"; # should not get here, so use English... 848 } 849 my %celldataafter; 850 render_values_only(\%asheetdata, \%celldataafter, $linkstyle); 851 852 my $asheetcontents = create_sheet_save(\%asheetdata); 853 854 $aheaderdata{lastmodified} = $start_clock_time; # remember it in header 855 856 my $sitedata = $hostinfo->{sites}->{$psite}; 857 my $thisauthor = $sitedata->{authoronhost}; # Get author name 858 if ($sitedata->{authorfromlogin} eq "yes" && $params{loggedinusername}) { 859 $thisauthor = $params{loggedinusername}; 860 $thisauthor =~ s/[^a-z0-9\-]//g; 861 } 862 $aheaderdata{lastauthor} = $thisauthor; 863 864 my $aheadercontents = create_header_save(\%aheaderdata); 865 866 $ok = save_page($aep, $aheadercontents, $asheetcontents); 867 868 foreach my $cr (sort keys %celldataafter) { # construct output 869 my $cdbefore = $celldatabefore{$cr}; 870 my $cdafter = $celldataafter{$cr}; 871 next 872 if $cdbefore->{type} eq $cdafter->{type} 873 && $cdbefore->{display} eq $cdafter->{display} 874 && $cdbefore->{align} eq $cdafter->{align} 875 && $cr ne $coord; # only stuff that has changed unknown to client (but send at least one -- the one with "loading") 876 877 my $displayvalue = encode_for_ajax($cdafter->{display}); 878 $displayvalue = "" if $displayvalue eq " "; # this is the default 879 my $csssvalue = encode_for_save($asheetdata{cellattribs}->{$cr}->{csss}); # need this to scroll back 880 my $editvalue; 881 if ($asheetdata{datatypes}->{$cr} eq 'f' || $asheetdata{datatypes}->{$cr} eq 'c') { # formula or constant 882 $editvalue = encode_for_ajax($asheetdata{formulas}->{$cr}); 883 } 884 else { 885 $editvalue = encode_for_ajax($asheetdata{datavalues}->{$cr}); 886 } 887 $response .= "$cr:$cdafter->{type}:$displayvalue:$editvalue:$cdafter->{align}:$cdafter->{colspan}:$cdafter->{rowspan}:$cdafter->{skip}:$csssvalue\n"; 888 } 889 if ($asheetdata{sheetattribs}->{circularreferencecell}) { # include some error information 890 my ($from, $to) = split(/\|/, $asheetdata{sheetattribs}->{circularreferencecell}); 891 my $str = "$WKCStrings{editcircular1}$from$WKCStrings{editcircular2}$to"; 892 $response .= "error:$str\n"; 893 } 894 $response .= "needsrecalc:$asheetdata{sheetattribs}->{needsrecalc}\n"; 895 $response .= sprintf ("footer:$WKCStrings{wkcfooterruntime} %.2f $WKCStrings{wkcfootersecondsat} $start_clock_time\n", 896 times() - $start_cpu_time); 897 898 my $xmlresponse = <<"EOF"; 899<?xml version="1.0" ?> 900<root><![CDATA[ 901$response 902]]></root> 903EOF 904 $responsedata->{content} = $xmlresponse; 905 $responsedata->{contenttype} = "text/xml"; 906 return; 907 } 908 909 # 910 # ?ajaxgetpagelist=sitename 911 # 912 # Returns XML with <root>page data in a CDATA</root> 913 # 914 # The page data is in one of the following forms: 915 # pages:pagename1:longname1:type1:pagename2:longname2:type2... 916 # or: 917 # error:Error message to display 918 # Where: 919 # pagename - the name, without the .html 920 # longname - longname, with \ and : converted to \b and \c 921 # type - e (editing locally), r (editing remotely), or p (published) 922 # 923 924 if ($params{ajaxgetpagelist}) { 925 my $currentsite = $params{sitename}; # temporarily switch to other site 926 $params{sitename} = $params{ajaxgetpagelist}; 927 928 if ($needlogin || site_not_allowed(\%userinfo, $loggedinuser, $params{sitename})) { # Not logged in or not allowed 929 my $msg = $needlogin ? $WKCStrings{"ajaxnotloggedin"} : $WKCStrings{"ajaxnotfound"}; 930 my $xmlresponse = <<"EOF"; 931<?xml version="1.0" ?> 932<root><![CDATA[error:$msg]]></root> 933EOF 934 $responsedata->{content} = $xmlresponse; 935 $responsedata->{contenttype} = "text/xml"; 936 return; 937 } 938 939 my $siteinfo = get_siteinfo(\%params); # get site information 940 my $ok = update_siteinfo(\%params, $hostinfo, $siteinfo); # update it 941 if ($siteinfo->{updates}) { 942 $ok = save_siteinfo(\%params, $siteinfo); 943 } 944 my $currentauthor = $hostinfo->{sites}->{$params{sitename}}->{authoronhost}; 945 if ($hostinfo->{sites}->{$params{sitename}}->{authorfromlogin} eq "yes" && $params{loggedinusername}) { 946 $currentauthor = $params{loggedinusername}; 947 } 948 $params{sitename} = $currentsite; 949 950 $response = "pages"; 951 952 foreach my $name (sort keys %{$siteinfo->{files}}) { # List each file, depending on edit/pub status 953 my $fileinfo = $siteinfo->{files}->{$name}; 954 my $longname = encode_for_ajax($fileinfo->{fullnamepublished}); 955 my $editstatus = $fileinfo->{authors}->{$currentauthor}->{editstatus}; # is current author editing? 956 my $pubstatus = $fileinfo->{pubstatus}; # has it been published? 957 if ($pubstatus) { 958 $response .= ":$name:$longname:p"; 959 } 960 if ($editstatus) { 961 if ($editstatus eq "remote") { 962 $response .= ":$name:$longname:r"; 963 } 964 else { 965 $response .= ":$name:$longname:e"; 966 } 967 } 968 } 969 970 my $xmlresponse = <<"EOF"; 971<?xml version="1.0" ?> 972<root><![CDATA[$response]]></root> 973EOF 974 $responsedata->{content} = $xmlresponse; 975 $responsedata->{contenttype} = "text/xml"; 976 return; 977 } 978 979 # 980 # ?ajaxgetnamedtext=textname 981 # 982 # Returns XML with <root>text data in a CDATA</root> 983 # The text data is in WKCtextdata.txt. That file is in the following format: 984 # *** WKCtexdataname: textname1 *** 985 # Lines of text to be returned... 986 # *** WKCtexdataname: textname2 *** 987 # Lines of text to be returned... 988 # textname is alphanumerics plus - 989 990 if ($params{ajaxgetnamedtext}) { 991 my $textname = $params{ajaxgetnamedtext}; 992 $textname =~ s/[^A-Za-z0-9\-]//g; 993 my ($returnstr, $line); 994 995 open(TEXTFILEIN, "$WKCdirectory/WKCtextdata.txt"); 996 997 while ($line = <TEXTFILEIN>) { # find start of desired text 998 last if $line =~ m/^\*\*\* WKCtextdataname\: $textname \*\*\*/; 999 } 1000 1001 while ($line = <TEXTFILEIN>) { # copy lines 1002 last if $line =~ m/^\*\*\* WKCtextdataname\: [A-Za-z0-9\-]+ \*\*\*/; 1003 $returnstr .= $line; 1004 } 1005 1006 close TEXTFILEIN; 1007 1008 my $xmlresponse = <<"EOF"; 1009<?xml version="1.0" ?> 1010<root><![CDATA[$returnstr]]></root> 1011EOF 1012 $responsedata->{content} = $xmlresponse; 1013 $responsedata->{contenttype} = "text/xml"; 1014 return; 1015 } 1016 1017 # 1018 # *** Process CGI-access to view pages 1019 # 1020 # Use with: 1021 # ?view=sitename/pagename (assumes type=page) 1022 # ?view=sitename/pagename&type=outputtype (page, html, js, cdata, and source are the allowed types) 1023 # optional: &recalc=no (anything else or no &recalc means "yes, do a recalc first" 1024 # The saved page is not modified by viewing it, even if a recalc is done 1025 # ?view=logout (logs user out) 1026 # ?view=sitename/pagename&cell:coord:type=value (type is n, t, or e:na) 1027 # 1028 1029 if ($params{view}) { # "wikicalc.pl?view=sitename/pagename" invocation 1030 if ($params{view} eq "logout") { # logout user 1031 $responsedata->{content} = <<"EOF"; 1032<html> 1033<head> 1034</head> 1035<body style="background-color:gray;"> 1036<table cellspacing="0" cellpadding="0" border="0" align="center"> 1037<tr><td style="border:1px solid black;background-color:white;padding:1em;"> 1038$WKCStrings{"viewlogoutcompleted"} 1039</td></tr></table> 1040</body> 1041</html> 1042EOF 1043 $responsedata->{contenttype} = "text/html"; 1044 $responsedata->{cookie} = "datafilename:;sitename:"; 1045 $responsedata->{cookieexpires} = ""; 1046 return; 1047 } 1048 1049 my ($vsitename, $vpagename) = split(/\//, lc $params{view}, 2); 1050 $vsitename =~ s/[^a-z0-9\-]//g; 1051 my $viewerrstr; 1052 $vpagename =~ s/[^a-z0-9\-]//g; 1053 $responsedata->{contenttype} = "text/plain"; # default 1054 1055 $params{sitename} = $vsitename; 1056 $params{datafilename} = $vpagename; 1057 1058 my (@vheaderlines, %vheaderdata, @vsheetlines, %vsheetdata); 1059 1060 my $vstr; 1061 my $linkstyle; 1062 1063 # Load page (even if this user doesn't have permission) and then parse header 1064 1065 my $vpath = get_page_published_datafile_path(\%params, $hostinfo, $vsitename, $vpagename); 1066 1067 my $loaderr = load_page($vpath, \@vheaderlines, \@vsheetlines); 1068 1069 my $pareseok = parse_header_save(\@vheaderlines, \%vheaderdata); # Get data from header 1070 1071 # Determine access 1072 1073 if ($vheaderdata{viewwithoutlogin} ne "yes" && $needlogin) { 1074 my $temp1 = $params{view}; 1075 my $temp2 = $params{type}; 1076 my $temp3 = $params{etpurl}; 1077 %params = (); # need login -- wipe out all parameters (for now...) 1078 $params{view} = $temp1 if $temp1; 1079 $params{type} = $temp2 if $temp2; 1080 $params{etpurl} = $temp3 if $temp3; 1081 $loggedinuser = ""; 1082 } 1083 1084 if ($vheaderdata{viewwithoutlogin} ne "yes" && readsite_not_allowed(\%userinfo, $loggedinuser, $vsitename)) { 1085 if (!$params{type} || lc($params{type}) eq "page") { 1086 if ($loginerrtext) { # error logging in 1087 $loginerrtext = qq!<span style="color:red;">$loginerrtext</span><br><br>!; 1088 } 1089 elsif ($params{viewlogin}) { # probably site not allowed 1090 $loginerrtext = <<"EOF"; 1091$WKCStrings{"viewliveviewloggedinasuser"} "$loggedinuser" (<a href="$hostinfo->{sites}->{$vsitename}->{editurl}?view=logout">$WKCStrings{"viewliveviewsologout"}</a>)<br><br> 1092<span style="color:red;">$WKCStrings{"viewliveviewnoreadaccess"} "$vsitename" $WKCStrings{"viewliveviewforuser"} "$loggedinuser"</span><br><br> 1093EOF 1094 } 1095 $responsedata->{content} = <<"EOF"; # need POST to keep password out of URL 1096<html> 1097<head> 1098</head> 1099<body style="background-color:gray;" onload="setf();"> 1100<form name="f0" method="POST"> 1101<table cellspacing="0" cellpadding="0" border="0" align="center"> 1102<tr><td style="border:1px solid black;background-color:white;padding:1em;"> 1103$loginerrtext 1104$WKCStrings{"viewlogin1"} '$vsitename/$vpagename' 1105<br><br> 1106$WKCStrings{"loginname"} <input type="text" name="editusername" size="15" value=""> 1107 $WKCStrings{"loginpassword"} <input type="password" name="edituserpassword" size="10" value=""> 1108 <input type="submit" name="dologin" value="$WKCStrings{"loginlogin"}"> 1109<br><br> 1110<input type="radio" name="editusercookies" value="session" CHECKED>$WKCStrings{"loginsessioncookie"} 1111<input type="radio" name="editusercookies" value="$defaultcookieexpire">$WKCStrings{"loginlongcookie"} 1112<input type="hidden" name="view" value="$params{view}"> 1113<input type="hidden" name="type" value="$params{type}"> 1114<input type="hidden" name="viewlogin" value="1"> 1115</td></tr></table> 1116</form> 1117<script> 1118var setf = function() {document.f0.editusername.focus();} 1119</script> 1120</body> 1121</html> 1122EOF 1123 $responsedata->{contenttype} = "text/html"; 1124 } 1125 1126 elsif (lc($params{type}) eq "js") { 1127 $responsedata->{content} = "document.write('$WKCStrings{viewnotloggedin} \\'$params{view}\\'');"; 1128 $responsedata->{contenttype} = "text/javascript"; 1129 } 1130 elsif (lc($params{type}) eq "cdata") { 1131 $responsedata->{content} = <<"EOF"; 1132<?xml version="1.0" ?> 1133<root><![CDATA[$WKCStrings{"viewnotloggedin"} '$params{view}']]></root> 1134EOF 1135 $responsedata->{contenttype} = "text/xml"; 1136 } 1137 else { 1138 $responsedata->{content} = "$WKCStrings{viewnotloggedin} '$params{view}'"; 1139 } 1140 return; 1141 } 1142 1143 if ($params{viewlogin}) { # successful login 1144 # This makes sure the page is accessed with a GET and works with or without Javascript 1145 $responsedata->{content} = <<"EOF"; 1146<html> 1147<head> 1148</head> 1149<body style="background-color:gray;" onload="setf();"> 1150<form name="f0" method="GET"> 1151<table cellspacing="0" cellpadding="0" border="0" align="center"> 1152<tr><td style="border:1px solid black;background-color:white;padding:1em;"> 1153$WKCStrings{"viewloggedin"} "$loggedinuser"<br> 1154<br>$WKCStrings{"viewclicktoview"} "$vsitename/$vpagename":<br><br> 1155<input type="submit" name="view" value="$params{view}" onclick="location.href=location.href;return false;"> 1156</td></tr></table> 1157</form> 1158<script> 1159var setf = function() {document.f0.view.focus();} 1160</script> 1161</body> 1162</html> 1163EOF 1164 $responsedata->{contenttype} = "text/html"; 1165 $responsecookie .= "datafilename:;sitename:;expires:$cookievalues{expires}"; 1166 $responsedata->{cookie} = $responsecookie; 1167 $responsedata->{cookieexpires} = $cookievalues{expires} eq "session" ? "" : ($cookievalues{expires} || $defaultcookieexpire); 1168 return; 1169 } 1170 1171 if (lc($params{type}) eq "source") { 1172 if ($loaderr) { 1173 $responsedata->{content} = "$WKCStrings{viewunabletoload} '$params{view}'"; 1174 return; 1175 } 1176 if ($vheaderdata{publishsource} ne "yes") { # not allowed 1177 $responsedata->{content} = "$WKCStrings{viewnosource} '$params{view}'."; 1178 return; 1179 } 1180 my $ok = open (DATAFILEIN, $vpath); 1181 if (!$ok) { 1182 $responsedata->{content} = "$WKCStrings{notfound1} '$vpath' $WKCStrings{notfound2}"; 1183 return; 1184 } 1185 my $line; 1186 while ($line = <DATAFILEIN>) { 1187 $vstr .= $line; 1188 } 1189 close DATAFILEIN; 1190 $responsedata->{content} = $vstr; 1191 return; 1192 } 1193 1194 $pareseok = parse_sheet_save(\@vsheetlines, \%vsheetdata); # Get data from sheet 1195 1196 $loaderr = $WKCStrings{"viewunabletoload"} if $loaderr; 1197 1198 if (lc($params{recalc}) ne "no") { # do a recalc 1199 foreach my $param (keys %params) { # see if any cell value overrides 1200 next unless $param =~ /^cell\:([a-z]{1,2}\d+)\:(n|t|e\:na)$/i; 1201 if ($vsheetdata{cellattribs}->{uc $1}->{mod} ne "y") { 1202 $loaderr = "$WKCStrings{viewnomodify1} $1 $WKCStrings{viewnomodify2}"; 1203 last; 1204 } 1205 if (lc($2) eq "n") { # numeric value 1206 $vsheetdata{datavalues}->{uc($1)} = $params{$param}; 1207 $vsheetdata{datatypes}->{uc($1)} = "v"; 1208 $vsheetdata{valuetypes}->{uc($1)} = "n"; 1209 } 1210 elsif (lc($2) eq "t") { # text value 1211 $vsheetdata{datavalues}->{uc($1)} = $params{$param}; 1212 $vsheetdata{datatypes}->{uc($1)} = "t"; 1213 $vsheetdata{valuetypes}->{uc($1)} = "t"; 1214 } 1215 if (lc($2) eq "e:na") { # error value 1216 $vsheetdata{datavalues}->{uc($1)} = $params{$param}; 1217 $vsheetdata{datatypes}->{uc($1)} = "v"; 1218 $vsheetdata{valuetypes}->{uc($1)} = "e#N/A"; 1219 $vsheetdata{cellerrors}->{uc($1)} = "#N/A"; 1220 } 1221 } 1222 init_sheet_cache(\%vsheetdata, \%params, $hostinfo, $vsitename); # remember in case have references to other worksheets 1223 my $aerrtext = recalc_sheet(\%vsheetdata); # do the recalc 1224 } 1225 1226 my $vstr; 1227 1228 if (!$params{type} || lc($params{type}) eq "page") { 1229 if ($loaderr) { 1230 $responsedata->{content} = "$loaderr '$params{view}'"; 1231 return; 1232 } 1233 my $sitedata = $hostinfo->{sites}->{$vsitename}; 1234 my $hostdata = $hostinfo->{hosts}->{$sitedata->{host}}; 1235 1236 $linkstyle = "$sitedata->{editurl}?view=$vsitename/[[pagename]]"; 1237 my ($stylestr, $sheetstr) = render_sheet(\%vsheetdata, 'class="wkcsheet"', "", "s", "a", "publish", "", "", $linkstyle); 1238 1239 my $author = $vheaderdata{lastauthor} || $sitedata->{authoronhost}; # Get author name 1240 1241 $vstr = $vheaderdata{templatetext} 1242 || get_template(\%params, "htmltemplate", $vheaderdata{templatefile}) 1243 || get_template(\%params, "htmltemplate", "site:default") 1244 || get_template(\%params, "htmltemplate", "shared:default") 1245 || get_template(\%params, "htmltemplate", "system:default") 1246 || $WKCStrings{"publishtemplate"}; 1247 1248 $vstr = fill_in_HTML_template($vstr, $sitedata, \%vheaderdata, $vsitename, $vpagename, $start_clock_time, $author, $loggedinuser, $stylestr, $sheetstr, 1); 1249 $responsedata->{content} = $vstr; 1250 $responsedata->{contenttype} = "text/html; charset=UTF-8"; 1251 } 1252 1253 elsif (lc($params{type}) eq "js") { 1254 if ($loaderr) { 1255 $responsedata->{content} = "document.write('$loaderr \\'$params{view}\\'');"; 1256 $responsedata->{contenttype} = "text/javascript"; 1257 return; 1258 } 1259 my ($stylestr, $sheetstr) = render_sheet(\%vsheetdata, 'class="wkcsheet"', "", "s", "a", "embed", "", "", $linkstyle); 1260 $vstr = create_embeddable_JS_sheet($stylestr, $sheetstr); 1261 $responsedata->{content} = $vstr; 1262 $responsedata->{contenttype} = "text/javascript; charset=UTF-8"; 1263 } 1264 1265 elsif (lc($params{type}) eq "html") { 1266 if ($loaderr) { 1267 $responsedata->{content} = "$loaderr '$params{view}'"; 1268 $responsedata->{contenttype} = "text/plain"; 1269 return; 1270 } 1271 my ($stylestr, $sheetstr) = render_sheet(\%vsheetdata, 'class="wkcsheet"', "", "s", "a", "inline", "", "", $linkstyle); 1272 $responsedata->{content} = $sheetstr; 1273 $responsedata->{contenttype} = "text/plain; charset=UTF-8"; 1274 } 1275 1276 elsif (lc($params{type}) eq "cdata") { 1277 if ($loaderr) { 1278 $responsedata->{content} = <<"EOF"; 1279<?xml version="1.0" ?> 1280<root><![CDATA[Error: $loaderr '$params{view}']]></root> 1281EOF 1282 $responsedata->{contenttype} = "text/xml"; 1283 return; 1284 } 1285 my ($stylestr, $sheetstr) = render_sheet(\%vsheetdata, 'class="wkcsheet"', "", "s", "a", "inline", "", "", $linkstyle); 1286 my $xmlresponse = <<"EOF"; 1287<?xml version="1.0" ?> 1288<root><![CDATA[$sheetstr]]></root> 1289EOF 1290 $responsedata->{content} = $xmlresponse; 1291 $responsedata->{contenttype} = "text/xml"; 1292 return; 1293 } 1294 1295 else { 1296 $responsedata->{content} = "$WKCStrings{viewunknowntype} '$params{type}'."; 1297 } 1298 1299 $responsedata->{contenttype} = "text/html; charset=UTF-8"; 1300 1301 # (leave cookies as they were) 1302 1303 return; 1304 } 1305 1306 # 1307 # *** Protect from not being logged in 1308 # 1309 1310 if ($needlogin) { 1311 my $temp1 = $params{editthispage}; 1312 my $temp2 = $params{etpurl}; 1313 %params = (); # need login -- wipe out all parameters (for now...) 1314 $params{logineditthispage} = $temp1 if $temp1; 1315 $params{etpurl} = $temp2 if $temp2; 1316 } 1317 1318 # 1319 # *** Process Edit This Page call (do a POST with editthispage=sitename/pagename) 1320 # 1321 1322 my $checkmultiedit; # if non-blank, list of others editing already 1323 1324 if ($params{editthispage}) { # "Edit this page" invocation 1325 my ($etpsavesitename, $etpsavedatafilename) = ($params{sitename}, $params{datafilename}); 1326 ($params{sitename}, $params{datafilename}) = split(/\//, $params{editthispage}, 2); 1327 $params{sitename} =~ s/[^a-z0-9\-]//g; # get new sitename and pagename 1328 my $etperrstr; 1329 if (site_not_allowed(\%userinfo, $loggedinuser, $params{sitename})) { 1330 $params{sitename} = ""; 1331 $params{datafilename} = ""; 1332 $params{etpurl} = ""; # if wipe out name, wipe out back to where we started when editing 1333 $etperrstr = $WKCStrings{"etpnotfound"}; 1334 } 1335 if ($params{cancelmultieditthispage}) { # someone else editing and decided not to override 1336 $etperrstr = qq!$WKCStrings{"etpeditstartof"} "$params{datafilename}" $WKCStrings{"etpcancelled"}!; 1337 $params{datafilename} = ""; 1338 $params{etpurl} = ""; 1339 $params{newtab} = $WKCStrings{"Page"}; 1340 } 1341 $params{datafilename} =~ s/[^a-z0-9\-]//g; 1342 $editcoords = ""; 1343 delete $params{scrollrow}; 1344 1345 # See if anybody else is editing this 1346 1347 if (!$params{editthispageokmulti} && !$etperrstr) { 1348 my $siteinfo = get_siteinfo(\%params); 1349 1350 my $currentauthor = $hostinfo->{sites}->{$params{sitename}}->{authoronhost}; 1351 if ($hostinfo->{sites}->{$params{sitename}}->{authorfromlogin} eq "yes" && $params{loggedinusername}) { 1352 $currentauthor = $params{loggedinusername}; 1353 } 1354 1355 my $ok = update_siteinfo(\%params, $hostinfo, $siteinfo); 1356 1357 if ($siteinfo->{updates}) { 1358 $ok = save_siteinfo(\%params, $siteinfo); 1359 } 1360 my $fileinfo = $siteinfo->{files}->{$params{datafilename}}; 1361 my $editstatus = $fileinfo->{authors}->{$currentauthor}->{editstatus}; 1362 1363 foreach my $author (sort keys %{$fileinfo->{authors}}) { 1364 if ($author ne $currentauthor) { # not us 1365 $checkmultiedit .= "$author, "; 1366 } 1367 } 1368 } 1369 1370 if ($checkmultiedit) { # others editing - check if that's OK first 1371 $checkmultiedit =~ s/, $//; # make readable 1372 ($params{sitename}, $params{datafilename}) = ($etpsavesitename, $etpsavedatafilename); # restore 1373 $params{checkmultiediteditthispage} = $params{editthispage}; 1374 } 1375 1376 elsif (!$etperrstr) { # all ready for us 1377 delete $params{scrollrow}; 1378 $etperrstr = edit_published_page(\%params, $hostinfo, $params{sitename}, $params{datafilename}) unless $etperrstr; 1379 if ($etperrstr && !$needlogin) { 1380 $params{newtab} = $WKCStrings{"Page"}; 1381 $params{etpurl} = ""; 1382 $params{debugmessage} = $etperrstr; 1383 } 1384 else { 1385 $params{newtab} = $WKCStrings{"Edit"}; 1386 } 1387 } 1388 } 1389 1390 # 1391 # *** If nothing set, see if anything remembered in cookie 1392 # 1393 1394 if (!$params{datafilename} && !$params{sitename}) { 1395 if ($cookievalues{datafilename}) { 1396 $params{datafilename} = $cookievalues{datafilename}; 1397 delete $params{scrollrow}; 1398 } 1399 if ($cookievalues{sitename}) { 1400 $params{sitename} = $cookievalues{sitename}; 1401 } 1402 } 1403 1404 # 1405 # *** Check OK to edit this site 1406 # 1407 1408 if (site_not_allowed(\%userinfo, $loggedinuser, $params{sitename})) { 1409 $params{sitename} = ""; 1410 $params{datafilename} = ""; 1411 $params{etpurl} = "" unless $params{logineditthispage}; 1412 } 1413 1414 # 1415 # *** Process buttons 1416 # 1417 1418 foreach my $p (keys %params) { # go through all the parameters 1419 1420 # 1421 # Change which page we are editing 1422 # 1423 1424 if ($p =~ /^choosepage(local|pub|backup):(.*)/) { 1425 my $newname = $2; 1426 my $editerrstr; 1427 if ($1 eq "pub") { # if editing from published page, copy the contents to an edit file 1428 $editerrstr = edit_published_page(\%params, $hostinfo, $params{sitename}, $2); 1429 } 1430 elsif ($1 eq "backup") { 1431 my $basefile = $2; 1432 $basefile =~ m/([a-z0-9\-]+?)\.\w+?\.[0-9\-]+?\.txt$/; 1433 $newname = $1; 1434 $editerrstr = edit_backup_page(\%params, $hostinfo, $params{sitename}, $basefile); 1435 } 1436 elsif ($1 ne "local") { 1437 $editerrstr = qq!Got command "$p"!; # debugging, shouldn't get here 1438 $params{"oktools:backup"} = 1; 1439 } 1440 if ($editerrstr) { 1441 $params{pagemessage} = qq!$WKCStrings{"choosecondition1"} "$2" $WKCStrings{"choosecondition2"}<br>$editerrstr!; 1442 } 1443 else { 1444 $params{datafilename} = $newname; 1445 $params{etpurl} = ""; # don't go back to last one from Edit This Page invocation 1446 $editcoords = ""; 1447 delete $params{scrollrow}; 1448 $params{newtab} = $WKCStrings{"Edit"}; 1449 } 1450 } 1451 1452 # 1453 # Publish page 1454 # 1455 1456 elsif ($p =~ /^publish(preview):(.*)/) { 1457 $params{pagemessage} = qq!Old code: $p!; # debugging 1458 } 1459 1460 elsif ($p =~ /^publish(continue|page|frompage):(.*)/) { 1461 my $continuepage = $1; # which invocation 1462 my $name = $2; 1463 1464 my (@pubheaderlines, %pubheaderdata, @pubsheetlines, %pubsheetdata); 1465 1466 my $pubpath = get_page_edit_path(\%params, $hostinfo, $params{sitename}, $name); 1467 my $loaderr = load_page($pubpath, \@pubheaderlines, \@pubsheetlines); 1468 1469 my $pareseok = parse_header_save(\@pubheaderlines, \%pubheaderdata); # Get data from header 1470 $pareseok = parse_sheet_save(\@pubsheetlines, \%pubsheetdata); # Get data from sheet 1471 1472 my ($stylestr, $sheetstr) = render_sheet(\%pubsheetdata, 'class="wkcsheet"', "", "s", "a", "publish", "", ""); 1473 1474 my $sitedata = $hostinfo->{sites}->{$params{sitename}}; 1475 my $hostdata = $hostinfo->{hosts}->{$sitedata->{host}}; 1476 1477 my $thisauthor = $sitedata->{authoronhost}; # Get author name 1478 if ($sitedata->{authorfromlogin} eq "yes" && $params{loggedinusername}) { 1479 $thisauthor = $params{loggedinusername}; 1480 $thisauthor =~ s/[^a-z0-9\-]//g; 1481 } 1482 1483 my $pubstr; 1484 if ($continuepage ne "frompage") { # invoked from view tab -- check updates to what to publish 1485 $pubheaderdata{publishhtml} = $params{editpublishhtml} ? "yes" : "no"; 1486 $pubheaderdata{publishsource} = $params{editpublishsource} ? "yes" : ""; 1487 $pubheaderdata{publishjs} = $params{editpublishjs} ? "yes" : ""; 1488 $pubheaderdata{viewwithoutlogin} = $params{editviewwithoutlogin} ? "yes" : ""; 1489 } 1490 $pubstr = $pubheaderdata{templatetext} 1491 || get_template(\%params, "htmltemplate", $pubheaderdata{templatefile}) 1492 || get_template(\%params, "htmltemplate", "site:default") 1493 || get_template(\%params, "htmltemplate", "shared:default") 1494 || get_template(\%params, "htmltemplate", "system:default") 1495 || $WKCStrings{"publishtemplate"}; 1496 1497 if ($params{editcomments}) { # New comment content to go with this publish - saved when published 1498 $pubheaderdata{editcomments} = $params{editcomments}; # do here so available to HTML 1499 } 1500 1501 add_to_editlog(\%pubheaderdata, "# $WKCStrings{logpublishedby} $thisauthor") if $thisauthor ne $pubheaderdata{lastauthor}; # if unmodified may have last author 1502 1503 $pubstr = fill_in_HTML_template($pubstr, $sitedata, \%pubheaderdata, $params{sitename}, $name, $start_clock_time, $thisauthor, $loggedinuser, $stylestr, $sheetstr, 0); 1504 1505 my $continueediting = $continuepage eq "continue" ? 1 : 0; # Continue editing if requested 1506 1507 my $jsstr; 1508 if ($pubheaderdata{publishjs} eq "yes") { 1509 ($stylestr, $sheetstr) = render_sheet(\%pubsheetdata, 'class="wkcsheet"', "", "s", "a", "embed", "", ""); 1510 $jsstr = create_embeddable_JS_sheet($stylestr, $sheetstr); 1511 } 1512 1513 my $puberrstr = publish_page(\%params, $hostinfo, $params{sitename}, $name, $pubstr, $jsstr, \%pubheaderdata, \%pubsheetdata, $continueediting); 1514 if ($puberrstr) { 1515 $params{pagemessage} = qq!$WKCStrings{"publisherror"} "$name":<br>$puberrstr!; 1516 } 1517 1518 if (!$continueediting && $name eq $params{datafilename}) { # reset if were editing page just published 1519 $params{datafilename} = ""; 1520 delete $params{scrollrow}; 1521 $params{etpurl} = "" if $continuepage eq "frompage"; 1522 } 1523 1524 $published = $name; 1525 } 1526 1527 # 1528 # Delete page 1529 # 1530 1531 elsif ($p =~ /^choosepagedel:(.*)/) { 1532 my $deletepage = $1; 1533 my $errstr = delete_page(\%params, $hostinfo, $params{sitename}, $deletepage); 1534 if ($errstr) { 1535 $params{pagemessage} = qq!$WKCStrings{"choosedelerror"} "$deletepage":<br>$errstr!; 1536 } 1537 else { 1538 $params{pagemessage} = qq!$WKCStrings{"choosedeldeleted"} "$deletepage"!; 1539 } 1540 if ($deletepage eq $params{datafilename}) { 1541 delete $params{datafilename}; # if deleted current page, make it not the current page 1542 delete $params{scrollrow}; 1543 $params{etpurl} = ""; 1544 } 1545 delete $params{pagebuttons}; # go back to normal editing state 1546 } 1547 1548 # 1549 # Abandon editing page 1550 # 1551 1552 elsif ($p =~ /^choosepageabandon:(.*)/) { # Abandon editing page 1553 my $abandonpage = $1; 1554 my $errstr = abandon_page_edit(\%params, $hostinfo, $params{sitename}, $abandonpage); 1555 if ($errstr) { 1556 $params{pagemessage} = qq!$WKCStrings{"chooseabandonerror"} "$abandonpage":<br>$errstr!; 1557 } 1558 else { 1559 $params{pagemessage} = qq!$WKCStrings{"chooseabandondeleted1"} "$abandonpage" $WKCStrings{"chooseabandondeleted2"}!; 1560 } 1561 if ($abandonpage eq $params{datafilename}) { 1562 delete $params{datafilename}; # if abandoned current page, make it not the current page 1563 delete $params{scrollrow}; 1564 $params{etpurl} = ""; 1565 } 1566 delete $params{pagebuttons}; # go back to normal editing state 1567 } 1568 1569 # 1570 # Set a new range 1571 # 1572 1573 elsif ($p =~ /^okeditrange:(.+)/) { # Range edit command 1574 $params{okeditrange} = $1; # Remember which particular command 1575 } 1576 1577 # 1578 # Backup subcommand 1579 # 1580 1581 elsif ($p =~ /^backup:(details|archive|delete|download|preferences|savepreferences|all|list):(.+)/) { # Backup sub-command 1582 $params{backupsubcommand} = $1; # Remember which particular command 1583 $params{backupfilename} = $2; # Remember which file and/or other information 1584 if ($1 eq "list" || $1 eq "all") { # List and All may have paging info 1585 ($params{backupfilename}, $params{startitem}) = split(/:/, $params{backupfilename}); 1586 } 1587 $params{"oktools:backup"} = 1; # Invoke backup command to process 1588 } 1589 1590 } 1591 1592 if ($params{okeditpreview}) { 1593 $params{newtab} = $WKCStrings{"Preview"}; 1594 } 1595 1596 if (!$params{datafilename}) { # If no page chosen, go to Page tab in most cases 1597 if ($params{newtab}) { 1598 if ($params{newtab} ne $WKCStrings{"showlicense"} && $params{newtab} ne $WKCStrings{"Tools"}) { 1599 $params{newtab} = $WKCStrings{"Page"}; 1600 } 1601 } 1602 elsif ($params{currenttab} ne $WKCStrings{"Tools"}) { 1603 $params{newtab} = $WKCStrings{"Page"}; 1604 } 1605 } 1606 1607 if ($params{newtab}) { 1608 if ($params{newtab} eq $WKCStrings{"Page"}) { 1609 $params{currenttab} = $params{newtab}; 1610 $editmode = ""; 1611 } 1612 elsif ($params{newtab} eq $WKCStrings{"Preview"}) { 1613 $params{currenttab} = $params{newtab}; 1614 $editmode = ""; 1615 } 1616 elsif ($params{newtab} eq $WKCStrings{"Edit"}) { 1617 $params{currenttab} = $params{newtab}; 1618 $editmode = $WKCStrings{"editsub-general"}; 1619 $editcoords =~ s/:.*$//; # start with only upper left 1620 $editcoords ||= "A1"; 1621 $params{editcoords} = $editcoords; 1622 } 1623 elsif ($params{newtab} eq $WKCStrings{"Format"}) { 1624 $params{currenttab} = $params{newtab}; 1625 $editmode = $WKCStrings{"formatsub-range"}; 1626 $editcoords ||= "A1"; 1627 $params{editcoords} = $editcoords; 1628 } 1629 elsif ($params{newtab} eq $WKCStrings{"Tools"}) { 1630 $params{currenttab} = $params{newtab}; 1631 $editcoords ||= "A1"; 1632 $params{editcoords} = $editcoords; 1633 } 1634 elsif ($params{newtab} eq $WKCStrings{"showlicense"}) { 1635 $params{currenttab} = $params{newtab}; 1636 $editmode = ""; 1637 } 1638 } 1639 1640 if ($params{editsub}) { 1641 $editmode = $params{editsub}; 1642 } 1643 1644 # 1645 # Get current tab and switch if necessary 1646 # 1647 1648 my $currenttab = $params{currenttab} || $WKCStrings{"Page"}; 1649 my $lineheight; 1650 if ($currenttab eq $WKCStrings{"Edit"} || $currenttab eq $WKCStrings{"Format"}) { 1651 $lineheight = qq! style="font-size:1pt;"!; 1652 } 1653 1654 # 1655 # Display tabs and other top stuff 1656 # 1657 1658 $rbodytabs = <<"EOF"; 1659<form name="ftabs" action="" method="POST"> 1660<table cellpadding="0" cellspacing="0"> 1661<tr> 1662EOF 1663 1664 foreach my $tab (@tablist) { 1665 next if ($tab eq $WKCStrings{"Quit"} && $noquittab); # CGI version doesn't show Quit tab 1666 if ($currenttab eq $tab && !$needlogin) { 1667 $rbodytabs .= <<"EOF"; 1668<td class="tab1"> </td> 1669<td class="tabselected">$tab</td> 1670EOF 1671 } 1672 else { 1673 $rbodytabs .= <<"EOF"; 1674<td class="tab1"> </td> 1675<td class="tab"><input type="submit" name="newtab" value="$tab"></td> 1676EOF 1677 } 1678 } 1679 1680 $rbodytabs .= <<"EOF"; 1681<td class="tab1" width="100%"> </td> 1682</tr> 1683<tr> 1684<td class="tab2left" width="1"$lineheight> </td> 1685EOF 1686 1687 my $ncols = @tablist - ($noquittab ? 1 : 0); 1688 $ncols = $ncols * 2 + 1; 1689 for (my $i=0; $i<$ncols-2; $i++) { 1690 $rbodytabs .= <<"EOF"; 1691<td class="tab2"$lineheight> </td> 1692EOF 1693 } 1694 1695 $rbodytabs .= <<"EOF"; 1696<td class="tab2right"$lineheight> </td> 1697</tr> 1698</table> 1699EOF 1700 1701 # # # # # # # # # # 1702 # 1703 # *** Read in data and do things 1704 # 1705 # # # # # # # # # # 1706 1707 1708 my $sheetmodified; 1709 1710 my $editpath; 1711 1712 if ($params{datafilename} && $params{sitename}) { 1713 $editpath = get_page_edit_path(\%params, $hostinfo, $params{sitename}, $params{datafilename}); 1714 my $loaderr = load_page($editpath, \@headerlines, \@sheetlines); 1715 1716 if ($loaderr) { # deselect if can't load -- don't let us edit an inappropriate blank page 1717 $params{datafilename} = ""; 1718 } 1719 1720 $ok = parse_header_save(\@headerlines, \%headerdata); 1721 $ok = parse_sheet_save(\@sheetlines, \%sheetdata); 1722 $sheetmodified = 0; 1723 } 1724 else { # No file -- use null sheet 1725 $sheetlines[0] = ""; 1726 $ok = parse_sheet_save(\@sheetlines, \%sheetdata); 1727 $sheetmodified = 0; 1728 } 1729 init_sheet_cache(\%sheetdata, \%params, $hostinfo, $params{sitename}); # remember in case have references to other worksheets 1730 1731 # 1732 # *** See if there are edits to do 1733 # 1734 1735 if ($params{okeditcoord}) { 1736 $editcoords = $params{editeditcoords}; 1737 } 1738 1739 elsif ($params{editaddrow} || $params{editaddcol}) { # extend sheet by a row or column 1740 my $newsize; 1741 if ($params{editaddrow}) { 1742 $newsize = $sheetdata{sheetattribs}->{lastrow} + 1; 1743 $ok = execute_sheet_command_and_log(\%sheetdata, "set sheet lastrow $newsize", \%headerdata); 1744 } 1745 elsif ($params{editaddcol}) { 1746 $newsize = $sheetdata{sheetattribs}->{lastcol} + 1; 1747 $ok = execute_sheet_command_and_log(\%sheetdata, "set sheet lastcol $newsize", \%headerdata); 1748 } 1749 $sheetmodified += 1; 1750 } 1751 1752 elsif ($params{okcolumns}) { 1753 my $value = $params{colwidthvalue}; 1754 $value = "" if $params{colwidthtype} eq "default"; 1755 $value = "auto" if $params{colwidthtype} eq "auto"; 1756 if ($params{colwidthpercent}) { 1757 $value = $value > 100 ? 100 : ($value < 1 ? 1 : $value); 1758 $value .= "%"; 1759 } 1760 my $ok; 1761 if ($params{columnsedefault}) { 1762 my $cmdline = "set sheet defaultcolwidth $value"; 1763 $ok = execute_sheet_command_and_log(\%sheetdata, $cmdline, \%headerdata); 1764 } 1765 else { 1766 my $colname = $editcoords; 1767 $colname =~ s/\d//g; 1768 my $cmdline = "set $colname width $value"; 1769 $ok = execute_sheet_command_and_log(\%sheetdata, $cmdline, \%headerdata); 1770 $value = $params{colhidevalue} ? "yes" : ""; # set hide value to yes or blank 1771 $cmdline = "set $colname hide $value"; 1772 $ok = execute_sheet_command_and_log(\%sheetdata, $cmdline, \%headerdata); 1773 } 1774 if ($ok) { 1775 $sheetmodified += 1; 1776 } 1777 else { 1778 $params{debugmessage} = "Failed: $ok\n"; 1779 } 1780 } 1781 1782 elsif ($params{okrows}) { 1783 my $rowname = $editcoords; 1784 $rowname =~ s/[A-Za-z]//g; 1785 my $value = $params{rowhidevalue} ? "yes" : ""; # set hide value to yes or blank 1786 my $cmdline = "set $rowname hide $value"; 1787 $ok = execute_sheet_command_and_log(\%sheetdata, $cmdline, \%headerdata); 1788 if ($ok) { 1789 $sheetmodified += 1; 1790 } 1791 else { 1792 $params{debugmessage} = "Failed: $ok\n"; 1793 } 1794 } 1795 1796 elsif ($params{okborders}) { 1797 my ($crd, $ok); 1798 $ok = 1; 1799 if ($params{borderoutline}) { 1800 my ($coord1, $coord2) = split(/:/, $editcoords); 1801 my ($c1, $r1) = coord_to_cr($coord1); 1802 my $c2 = $c1; 1803 my $r2 = $r1; 1804 ($c2, $r2) = coord_to_cr($coord2) if $coord2; 1805 for (my $c = $c1; $c <= $c2; $c++) { 1806 $crd = cr_to_coord($c, $r1); 1807 $ok &&= execute_sheet_command_and_log(\%sheetdata, "set $crd bt $params{editborder1}", \%headerdata); 1808 $crd = cr_to_coord($c, $r2); 1809 $ok &&= execute_sheet_command_and_log(\%sheetdata, "set $crd bb $params{editborder3}", \%headerdata); 1810 } 1811 for (my $r = $r1; $r <= $r2; $r++) { 1812 $crd = cr_to_coord($c1, $r); 1813 $ok &&= execute_sheet_command_and_log(\%sheetdata, "set $crd bl $params{editborder4}", \%headerdata); 1814 $crd = cr_to_coord($c2, $r); 1815 $ok &&= execute_sheet_command_and_log(\%sheetdata, "set $crd br $params{editborder2}", \%headerdata); 1816 } 1817 } 1818 else { 1819 $ok &&= execute_sheet_command_and_log(\%sheetdata, "set $editcoords bt $params{editborder1}", \%headerdata); 1820 $ok &&= execute_sheet_command_and_log(\%sheetdata, "set $editcoords br $params{editborder2}", \%headerdata); 1821 $ok &&= execute_sheet_command_and_log(\%sheetdata, "set $editcoords bb $params{editborder3}", \%headerdata); 1822 $ok &&= execute_sheet_command_and_log(\%sheetdata, "set $editcoords bl $params{editborder4}", \%headerdata); 1823 } 1824 if ($ok) { 1825 $sheetmodified += 1; 1826 } 1827 else { 1828 $params{debugmessage} = "Failed: $ok\n"; 1829 } 1830 } 1831 1832 elsif ($params{oklayout}) { 1833 my $ok; 1834 my $layoutstr; # default to blank, which is "use default" 1835 if ($params{explicitlayout} eq "yes") { # set explicitly 1836 # 1837 # layout format is: padding:top right bottom left;vertical-align:style 1838 # 1839 $layoutstr = "padding:$params{layoutpaddingtop} $params{layoutpaddingright} $params{layoutpaddingbottom} $params{layoutpaddingleft};"; 1840 $layoutstr .= "vertical-align:$params{verticalalign};"; 1841 } 1842 if ($params{layoutdefault}) { 1843 $ok = execute_sheet_command_and_log(\%sheetdata, "set sheet defaultlayout $layoutstr", \%headerdata); 1844 } 1845 else { 1846 $ok = execute_sheet_command_and_log(\%sheetdata, "set $editcoords layout $layoutstr", \%headerdata); 1847 } 1848 if ($ok) { 1849 $sheetmodified += 1; 1850 } 1851 else { 1852 $params{debugmessage} = "Failed: $ok\n"; 1853 } 1854 } 1855 1856 elsif ($params{okcolors}) { 1857 my $ok; 1858 if ($params{colorsedefault}) { 1859 $ok = execute_sheet_command_and_log(\%sheetdata, "set sheet defaultcolor $params{edittextcolor}", \%headerdata); 1860 $ok &&= execute_sheet_command_and_log(\%sheetdata, "set sheet defaultbgcolor $params{editbackgroundcolor}", \%headerdata); 1861 } 1862 else { 1863 $ok = execute_sheet_command_and_log(\%sheetdata, "set $editcoords color $params{edittextcolor}", \%headerdata); 1864 $ok &&= execute_sheet_command_and_log(\%sheetdata, "set $editcoords bgcolor $params{editbackgroundcolor}", \%headerdata); 1865 } 1866 if ($ok) { 1867 $sheetmodified += 1; 1868 } 1869 else { 1870 $params{debugmessage} = "Failed: $ok\n"; 1871 } 1872 } 1873 1874 elsif ($params{okfonts}) { 1875 my $ok; 1876 my $fontstyleweight; 1877 if ($params{fontdefault}) { 1878 $fontstyleweight = "*"; 1879 } 1880 else { 1881 $fontstyleweight = $params{fontitalic} ? "italic " : "normal "; 1882 $fontstyleweight .= $params{fontbold} ? "bold" : "normal"; 1883 } 1884 $params{fontsize} = "*" if $params{fontsize} eq "default"; 1885 $params{fontfamily} = "*" if $params{fontfamily} eq "default"; 1886 if ($params{fontedefault}) { 1887 $ok = execute_sheet_command_and_log(\%sheetdata, "set sheet defaultfont $fontstyleweight $params{fontsize} $params{fontfamily}", \%headerdata); 1888 } 1889 else { 1890 $ok = execute_sheet_command_and_log(\%sheetdata, "set $editcoords font $fontstyleweight $params{fontsize} $params{fontfamily}", \%headerdata); 1891 } 1892 if ($ok) { 1893 $sheetmodified += 1; 1894 } 1895 else { 1896 $params{debugmessage} = "Failed: $ok\n"; 1897 } 1898 } 1899 1900 elsif ($params{oktext}) { 1901 my $ok; 1902 $params{textalign} = "" if $params{textalign} eq "default"; 1903 $params{textvalueformat} = "" if $params{textvalueformat} eq "default"; 1904 if ($params{textedefault}) { 1905 $ok = execute_sheet_command_and_log(\%sheetdata, "set sheet defaulttextformat $params{textalign}", \%headerdata); 1906 $ok = execute_sheet_command_and_log(\%sheetdata, "set sheet defaulttextvalueformat $params{textvalueformat}", \%headerdata); 1907 } 1908 else { 1909 $ok = execute_sheet_command_and_log(\%sheetdata, "set $editcoords cellformat $params{textalign}", \%headerdata); 1910 $ok = execute_sheet_command_and_log(\%sheetdata, "set $editcoords textvalueformat $params{textvalueformat}", \%headerdata) if $ok; 1911 } 1912 if ($ok) { 1913 $sheetmodified += 1; 1914 } 1915 else { 1916 $params{debugmessage} = "Failed: $ok\n"; 1917 } 1918 } 1919 1920 elsif ($params{okmisc}) { 1921 my $ok; 1922 $ok = execute_sheet_command_and_log(\%sheetdata, "set $editcoords cssc $params{miscclassvalue}", \%headerdata); 1923 $ok = execute_sheet_command_and_log(\%sheetdata, "set $editcoords csss $params{miscstylevalue}", \%headerdata) if $ok; 1924 $ok = execute_sheet_command_and_log(\%sheetdata, "set $editcoords mod $params{miscmodvalue}", \%headerdata) if $ok; 1925 if ($ok) { 1926 $sheetmodified += 1; 1927 } 1928 else { 1929 $params{debugmessage} = "Failed: $ok\n"; 1930 } 1931 } 1932 1933 elsif ($params{oknumeric}) { 1934 my $ok; 1935 $params{numbersalign} = "" if $params{numbersalign} eq "default"; 1936 $params{numbersvalueformat} = "" if $params{numbersvalueformat} eq "default"; 1937 if ($params{numbersedefault}) { 1938 $ok = execute_sheet_command_and_log(\%sheetdata, "set sheet defaultnontextformat $params{numbersalign}", \%headerdata); 1939 $ok = execute_sheet_command_and_log(\%sheetdata, "set sheet defaultnontextvalueformat $params{numbersvalueformat}", \%headerdata) if $ok; 1940 } 1941 else { 1942 $ok = execute_sheet_command_and_log(\%sheetdata, "set $editcoords cellformat $params{numbersalign}", \%headerdata); 1943 $ok = execute_sheet_command_and_log(\%sheetdata, "set $editcoords nontextvalueformat $params{numbersvalueformat}", \%headerdata) if $ok; 1944 } 1945 if ($ok) { 1946 $sheetmodified += 1; 1947 } 1948 else { 1949 $params{debugmessage} = "Failed: $ok\n"; 1950 } 1951 } 1952 1953 elsif ($params{okeditrange}) { 1954 my $errtxt = execute_edit_command(\%params, \%sheetdata, $editcoords, \%headerdata); 1955 if ($errtxt) { 1956 $params{debugmessage} = "Failed: $errtxt\n"; 1957 } 1958 else { 1959 if ($params{recalc} ne "off" && $params{okeditrange}!~/merge|copy/) { 1960 my $errtext = recalc_sheet(\%sheetdata); 1961 } 1962 else { 1963 if ($params{okeditrange}!~/merge|copy|recalc/) { 1964 $sheetdata{sheetattribs}->{needsrecalc} = "yes" if $params{okeditrange}!~/merge|copy/; 1965 } 1966 } 1967 $editcoords = $params{editcoords}; 1968 $sheetmodified += 1; 1969 } 1970 } 1971 1972 elsif ($params{dorecalc}) { 1973 my $errtext = recalc_sheet(\%sheetdata); 1974 $sheetmodified += 1; 1975 } 1976 1977 elsif ($params{oktoolspageproperties}) { 1978 $headerdata{fullname} = $params{editlongname}; 1979 if ($params{edittemplatetype} eq "default") { 1980 $headerdata{templatefile} = ""; 1981 $headerdata{templatetext} = ""; 1982 } 1983 if ($params{edittemplatetype} eq "shared") { 1984 $headerdata{templatefile} = $params{edittemplatelist}; 1985 $headerdata{templatetext} = ""; 1986 } 1987 if ($params{edittemplatetype} eq "explicit") { 1988 $headerdata{templatefile} = ""; 1989 $headerdata{templatetext} = $params{edittemplatetext}; 1990 } 1991 $headerdata{publishhtml} = $params{editpublishhtml} ? "yes" : "no"; 1992 $headerdata{publishsource} = $params{editpublishsource}; 1993 $headerdata{publishjs} = $params{editpublishjs}; 1994 $headerdata{viewwithoutlogin} = $params{editviewwithoutlogin}; 1995 add_to_editlog(\%headerdata, "# $WKCStrings{logeditedpageproperties}"); 1996 $sheetmodified += 1; 1997 } 1998 1999 elsif ($params{okeditcomments}) { 2000 $headerdata{editcomments} = $params{editcomments}; # no need to log -- this is different for each backup 2001 $sheetmodified += 1; 2002 } 2003 2004 elsif ($params{oktoolsloadfromtext} || $params{oktoolsloadfromsheet}) { 2005 my $errtxt = execute_tools_command(\%params, \%sheetdata, $editcoords, \%headerdata); 2006 if ($errtxt) { 2007 $params{debugmessage} = "Failed: $errtxt\n"; 2008 } 2009 else { 2010 if ($params{recalc} ne "off") { 2011 my $errtext = recalc_sheet(\%sheetdata); 2012 } 2013 else { 2014 $sheetdata{sheetattribs}->{needsrecalc} = "yes"; 2015 } 2016 $editcoords = $params{editcoords}; 2017 $sheetmodified += 1; 2018 } 2019 } 2020 2021 elsif ($params{oktoolsuseradmin}) { 2022 if ($params{loggedinadmin} eq "yes") { # must be admin 2023 my $errtxt = execute_tools_useradmincommand(\%params); 2024 } 2025 } 2026 2027 # 2028 # *** Save sheet if modifications 2029 # 2030 2031 if ($sheetmodified && $params{sitename}) { 2032 my $sheetcontents = create_sheet_save(\%sheetdata); 2033 2034 $headerdata{lastmodified} = $start_clock_time; # remember it in header 2035 2036 my $sitedata = $hostinfo->{sites}->{$params{sitename}}; 2037 my $thisauthor = $sitedata->{authoronhost}; # Get author name 2038 if ($sitedata->{authorfromlogin} eq "yes" && $params{loggedinusername}) { 2039 $thisauthor = $params{loggedinusername}; 2040 $thisauthor =~ s/[^a-z0-9\-]//g; 2041 } 2042 $headerdata{lastauthor} = $thisauthor; 2043 my $headercontents = create_header_save(\%headerdata); 2044 2045 $ok = save_page($editpath, $headercontents, $sheetcontents); 2046 2047 } 2048 2049 # 2050 # *** See if need to rename page 2051 # 2052 2053 if ($params{oktoolspageproperties} && $params{editpagename} ne $params{datafilename} && $params{sitename}) { 2054 my $newname = $params{editpagename}; 2055 $newname =~ s/[^a-z0-9\-]//g; 2056 $params{toolsmessage} = rename_existing_page(\%params, $hostinfo, $params{sitename}, $params{datafilename}, $newname); 2057 $params{etpurl} = ""; 2058 } 2059 2060 # # # # # # # # # # 2061 # 2062 # Output command section (if necessary) and data depending upon mode 2063 # 2064 # # # # # # # # # # 2065 2066 my $template_stylemiddle = $template_stylemiddle_verbose; 2067 $params{promptlevelspacing} = "<br>"; 2068 2069 2070 my $fullname = special_chars($headerdata{fullname}); # used in some places 2071 my $fullsitename = special_chars($hostinfo->{sites}->{$params{sitename}}->{longname}); 2072 2073 my $programnametop = $WKCStrings{programextratop} ? "$WKCStrings{programextratop} " : ""; 2074 $programnametop .= "$programmark $programversion"; 2075 2076 # 2077 # Top line of screen with page name and login/logout stuff 2078 # 2079 2080 $rbody1 = <<"EOF"; # Top line of screen 2081</head> 2082<body onload="setactions();setf()"> 2083<div class="programtop"> 2084<form name="flo" method="POST"> 2085<table cellspacing="0" cellpadding="0"><tr><td width="100%" valign="top"> 2086EOF 2087 $rbody1 .= <<"EOF" if $params{datafilename} && $currenttab ne $WKCStrings{"Page"}; 2088<span class="programtopdark">$fullname</span> 2089<span class="programtoplight">($params{datafilename}.html $WKCStrings{"topon"} $fullsitename)</span> 2090EOF 2091 $rbody1 .= <<"EOF" if $params{loggedinusername}; # stay with POST 2092<span class="programtoplight">$WKCStrings{"topuser"}: $params{loggedinusername}</span> 2093<span class="programtoplogout">[<a href="" onClick="document.flo.submit();return false;">$WKCStrings{"toplogout"}</a>]</span> 2094<input name="dologout" type="hidden" value="1"> 2095EOF 2096 if ($headerdata{reverted} && $currenttab ne $WKCStrings{"Page"}) { 2097 $headerdata{reverted} =~ m/^.+?\.\w+?\.([0-9\-]+)\.txt/; 2098 $rbody1 .= <<"EOF" 2099<br> 2100<span class="programtoprevert">$WKCStrings{"toprevert"} $1</span> 2101EOF 2102 } 2103 $rbody1 .= <<"EOF"; 2104</td><td valign="top"><div class="programtopname">$programnametop</div></td></tr></table></form> 2105</div> 2106EOF 2107 2108 my $etpurlencoded = url_encode_plain($params{etpurl}); 2109 my $hiddenfields = <<"EOF"; 2110<input type="hidden" name="editcoords" value="$editcoords"> 2111<input type="hidden" name="editmode" value="$editmode"> 2112<input type="hidden" name="scrollrow" value="$params{scrollrow}"> 2113<input type="hidden" name="formatmode" value="$params{formatmode}"> 2114<input type="hidden" name="securitycode" value="$securitycode"> 2115<input type="hidden" name="currenttab" value="$currenttab"> 2116<input type="hidden" name="datafilename" value="$params{datafilename}"> 2117<input type="hidden" name="sitename" value="$params{sitename}"> 2118<input type="hidden" name="loggedinusername" value="$params{loggedinusername}"> 2119<input type="hidden" name="loggedinuserpassword" value="$params{loggedinuserpassword}"> 2120<input type="hidden" name="etpurl" value="$etpurlencoded"> 2121EOF 2122 2123 $rbodytabs2 .= <<"EOF"; 2124</form> 2125EOF 2126 2127 # # # # # # # # # # 2128 # 2129 # Do login 2130 # 2131 # # # # # # # # # # 2132 2133 if ($needlogin) { 2134 $response .= $template_headertop . $template_styletop . $template_stylemiddle . $template_stylebottom . 2135 $template_headerscripts . $rbody1 . $rbodytabs . $hiddenfields . $rbodytabs2; 2136 2137 my $descstring = $loginerrtext; 2138 2139 my $etpstr; 2140 $etpstr = <<"EOF" if $params{logineditthispage}; 2141<input name="editthispage" type="hidden" value="$params{logineditthispage}"> 2142EOF 2143 2144 $response .= <<"EOF"; 2145<table cellpadding="0" cellspacing="0" width="100%"> 2146<tr> 2147<td class="ttbody" width="100%"> 2148<div class="sectionoutlined"> 2149<div class="pagetitle">$WKCStrings{"logintitle"}</div> 2150<div class="pagetitledesc">$descstring</div> 2151</div> 2152<form name="f0" method="POST"> 2153<div class="sectionplain"> 2154<table cellpadding="0" cellspacing="0"> 2155<tr> 2156<td><div class="title">$WKCStrings{"loginname"} </div></td> 2157<td><div style="margin-bottom:2pt;"><input type="text" name="editusername" size="15" value=""></div></td> 2158<td><div class="title"> $WKCStrings{"loginpassword"} </div></td> 2159<td><div style="margin-bottom:2pt;"><input type="password" name="edituserpassword" size="10" value=""></div></td> 2160<td> <input type="submit" name="dologin" value="$WKCStrings{"loginlogin"}"></td> 2161</tr> 2162</table> 2163<input type="radio" name="editusercookies" value="session" CHECKED><span class="smaller">$WKCStrings{"loginsessioncookie"}</span> 2164<input type="radio" name="editusercookies" value="$defaultcookieexpire"><span class="smaller">$WKCStrings{"loginlongcookie"}</span> 2165<br> 2166</div> 2167$etpstr 2168$hiddenfields 2169</form> 2170</td></tr> 2171</table> 2172<script> 2173var setf = function() {document.f0.editusername.focus();} 2174</script> 2175EOF 2176 } 2177 2178 # # # # # # # # # # 2179 # 2180 # Do you want to edit this page when others are already editing it? 2181 # 2182 # # # # # # # # # # 2183 2184 elsif ($checkmultiedit) { 2185 $response .= $template_headertop . $template_styletop . $template_stylemiddle . $template_stylebottom . 2186 $template_headerscripts . $rbody1 . $rbodytabs . $hiddenfields . $rbodytabs2; 2187 2188 my $descstring = $loginerrtext; 2189 2190 $response .= <<"EOF"; 2191<table cellpadding="0" cellspacing="0" width="100%"> 2192<tr> 2193<td class="ttbody" width="100%"> 2194<div class="sectionoutlined"> 2195<div class="pagetitle">$WKCStrings{"multiedittitle"}</div> 2196<div class="pagetitledesc">$WKCStrings{"multieditdoyou"} "$params{datafilename}" $WKCStrings{""} 2197$WKCStrings{"multiediteventhough2"} 2198</div> 2199</div> 2200<form name="f0" method="POST"> 2201<div class="sectionplain"> 2202$WKCStrings{"multieditpage"} "$params{datafilename}" $WKCStrings{"multieditonsite"} "$params{sitename}" $WKCStrings{"multieditisopen"}: $checkmultiedit<br><br> 2203<input type="submit" name="okmultieditthispage" value="$WKCStrings{"multiedityes"}"> 2204<input type="submit" name="cancelmultieditthispage" value="$WKCStrings{"multieditno"}"> 2205</div> 2206<input name="editthispage" type="hidden" value="$params{checkmultiediteditthispage}"> 2207<input name="editthispageokmulti" type="hidden" value="1"> 2208$hiddenfields 2209</form> 2210</td></tr> 2211</table> 2212EOF 2213 } 2214 2215 # # # # # # # # # # 2216 # 2217 # Just published 2218 # 2219 # # # # # # # # # # 2220 2221 elsif ($published) { 2222 $response .= $template_headertop . $template_styletop . $template_stylemiddle . $template_stylebottom . 2223 $template_headerscripts . $rbody1 . $rbodytabs . $hiddenfields . $rbodytabs2; 2224 2225 my $descstring = $params{datafilename} ? $WKCStrings{"publisheddescopen"} : $WKCStrings{"publisheddescclosed"}; 2226 2227 my $pagemessage; 2228 if ($params{pagemessage}) { # Publish info 2229 $pagemessage = <<"EOF"; 2230<div class="sectionerror"> 2231$params{pagemessage} 2232</div> 2233EOF 2234 } 2235 2236 $response .= <<"EOF"; 2237<table cellpadding="0" cellspacing="0" width="100%"> 2238<tr> 2239<td class="ttbody" width="100%"> 2240<div class="sectionoutlined"> 2241<div class="pagetitle">$WKCStrings{"publishedtitle"}$published</div> 2242<div class="pagetitledesc">$descstring</div> 2243</div> 2244$pagemessage 2245<form name="f0" method="POST"> 2246<div class="sectionplain"> 2247EOF 2248 if ($params{datafilename}) { # continue 2249 $response .= <<"EOF"; 2250<input type="submit" name="publishcontinue" value="$WKCStrings{"publishcontinueediting"}"> 2251EOF 2252 } 2253 else { 2254 $response .= <<"EOF"; 2255<input type="submit" name="publishcontinue" value="$WKCStrings{"publishviewpagelist"}"> 2256EOF 2257 } 2258 2259 if ($params{editpublishhtml} eq "yes" && $hostinfo->{sites}->{$params{sitename}}->{htmlurl}) { # HTML accessible 2260 $response .= <<"EOF"; 2261<input type="submit" value="$WKCStrings{"publishviewhtmlpage"}" onclick="location.href='$hostinfo->{sites}->{$params{sitename}}->{htmlurl}/$published.html';return false;"> 2262EOF 2263 } 2264 my $editurl = $hostinfo->{sites}->{$params{sitename}}->{editurl}; 2265 if ($editurl) { 2266 $response .= <<"EOF"; 2267<input type="submit" value="$WKCStrings{"publishviewlivepage"}" onclick="location.href='$editurl?view=$params{sitename}/$published';return false;"> 2268EOF 2269 } 2270 $response .= <<"EOF"; 2271</div> 2272EOF 2273 if ($params{etpurl}) { 2274 my $etpurlencode = url_encode_plain($params{etpurl}); 2275 $response .= <<"EOF"; 2276<br> 2277<div class="sectionoutlined"> 2278<div style="padding-bottom:4pt;"><input type="submit" value="$WKCStrings{"publishresume"}" onclick="location.href='$etpurlencode';return false;"></div> 2279<div class="pagetitledesc">$WKCStrings{"publishresumedesc"}<br> 2280$params{etpurl} 2281</div> 2282</div> 2283<br> 2284EOF 2285 } 2286 $response .= <<"EOF"; 2287$hiddenfields 2288</form> 2289</td></tr> 2290</table> 2291EOF 2292 } 2293 2294 # # # # # # # # # # 2295 # 2296 # Page mode 2297 # 2298 # # # # # # # # # # 2299 2300 elsif ($currenttab eq $WKCStrings{"Page"}) { 2301 my $pcstr = do_page_command(\%params, $loggedinuser, \%userinfo, $hiddenfields); 2302 2303 $hiddenfields = update_hiddenfields(\%params, $hiddenfields); 2304 2305 $response .= $template_headertop . $template_styletop . $template_stylemiddle . $template_stylebottom . 2306 $template_headerscripts . $rbody1 . $rbodytabs . $hiddenfields . $rbodytabs2 . $pcstr; 2307 2308 } 2309 2310 # # # # # # # # # # 2311 # 2312 # Preview mode (Publish tab) 2313 # 2314 # # # # # # # # # # 2315 2316 elsif ($currenttab eq $WKCStrings{"Preview"}) { 2317 2318 my $editcommentsnl = special_chars_nl($headerdata{editcomments}); 2319 2320 # Load scripts from a file 2321 2322 $inlinescripts .= $WKCStrings{"jsdefinestrings"}; 2323 open JSFILE, "$WKCdirectory/WKCjs.txt"; 2324 while (my $line = <JSFILE>) { 2325 $inlinescripts .= $line; 2326 } 2327 close JSFILE; 2328 2329 open JSFILE, "$WKCdirectory/WKCpreviewjs.txt"; 2330 while (my $line = <JSFILE>) { 2331 $inlinescripts .= $line; 2332 } 2333 close JSFILE; 2334 2335 my $onclickstr = q! onclick="rcc('$coord');"!; 2336 my $linkstyle = "?view=$params{sitename}/[[pagename]]"; 2337 my ($stylestr, $outstr) = render_sheet(\%sheetdata, 'class="wkcsheet"', "", "s", "a", $editmode, $editcoords, $onclickstr, $linkstyle); 2338 2339 $response .= $template_headertop . $template_styletop . $template_stylemiddle . $stylestr . $template_stylebottom . 2340 $template_headerscripts . $rbody1 . $rbodytabs . $hiddenfields . $rbodytabs2; 2341 2342 my ($publishhtmlchecked, $publishsourcechecked, $publishjschecked, $viewwithoutloginchecked); 2343 $publishhtmlchecked = " CHECKED" if $headerdata{publishhtml} ne "no"; 2344 $publishsourcechecked = " CHECKED" if $headerdata{publishsource} eq "yes"; 2345 $publishjschecked = " CHECKED" if $headerdata{publishjs} eq "yes"; 2346 $viewwithoutloginchecked = " CHECKED" if $headerdata{viewwithoutlogin} eq "yes"; 2347 2348 $response .= <<"EOF"; 2349<table cellpadding="0" cellspacing="0" width="100%"> 2350<tr><td class="ttbody" width="100%"><form name="f0" method="POST"> 2351<div style="margin:4px 0px 4px 0px;"> 2352 <table class="buttonbar" cellspacing="0" cellpadding="0"><tr> 2353 <td id="publishbutton"><input class="smaller" type="submit" name="bpublish" value="$WKCStrings{"previewpublish"}" onclick="this.blur();return switchto('publish');"> 2354 </td><td id="viewbutton"><input class="smaller" type="submit" name="bview" value="$WKCStrings{"previewviewonweb"}" onclick="this.blur();return switchto('view');"> 2355 </td><td id="helpbutton"><input class="smaller" type="submit" name="bhelp" value="$WKCStrings{"previewhelp"}" onclick="toggle_help('previewhelptext');this.blur();return false;"> 2356 </td> 2357 </tr></table> 2358</div> 2359 2360<div id="c1publish" style="display:none;"> 2361<span class="smaller"> 2362<b>$WKCStrings{"previewpublishtoserver"}:</b> $hostinfo->{sites}->{$params{sitename}}->{htmlurl}/$params{datafilename}.html 2363</span> 2364<br> 2365<span class="smaller"><b>Options:</b></span> 2366<input type="checkbox" name="editpublishhtml" value="yes"$publishhtmlchecked><span class="smaller">$WKCStrings{"previewpublishhtml"}</span> 2367<input type="checkbox" name="editpublishsource" value="yes"$publishsourcechecked><span class="smaller">$WKCStrings{"previewpublishsource"}</span> 2368<input type="checkbox" name="editpublishjs" value="yes"$publishjschecked><span class="smaller">$WKCStrings{"previewpublishjs"}</span> 2369<input type="checkbox" name="editviewwithoutlogin" value="yes"$viewwithoutloginchecked><span class="smaller">$WKCStrings{"previewpublishnologin"}</span> 2370<br> 2371<span class="smaller">$WKCStrings{"previewcomments"}</span> 2372<br> 2373<textarea cols="60" rows="3" name="editcomments"> 2374$editcommentsnl</textarea> 2375<br> 2376<div class="smaller" style="margin:6px 0px;"> 2377$WKCStrings{"previewcomments2"} 2378</div> 2379<input type="submit" class="smaller" name="okeditcomments" value="$WKCStrings{"previewsavecomments"}"> 2380<input type="submit" class="smaller" name="publishcontinue:$params{datafilename}" value="$WKCStrings{"previewpublishcontinue"}"> 2381<input type="submit" class="smaller" name="publishpage:$params{datafilename}" value="$WKCStrings{"previewpublishclose"}"> 2382</div> 2383 2384<div id="c1view" style="display:none;"> 2385<div class="smaller" style="margin-bottom:6px;"> 2386$WKCStrings{"previewview1"} 2387</div> 2388<table cellspacing="0" cellpadding="0"> 2389EOF 2390 2391 my $editurl = $hostinfo->{sites}->{$params{sitename}}->{editurl}; 2392 if ($editurl) { 2393 $response .= <<"EOF"; 2394<tr> 2395<td align="center" style="padding:0px 2pt 2pt 0px;"><input type="submit" class="smaller" value="$WKCStrings{"previewlivethis"}" onclick="location.href='$editurl?view=$params{sitename}/$params{datafilename}';return false;"></td> 2396<td align="center" style="padding:0px 2pt 2pt 0px;"><input type="submit" class="smaller" value="$WKCStrings{"previewlivepopup"}" onclick="window.open('$editurl?view=$params{sitename}/$params{datafilename}');return false;"></td> 2397</tr> 2398EOF 2399 } 2400 else { 2401 $response .= <<"EOF"; 2402<tr> 2403<td colspan="2"><span class="warning"> 2404$WKCStrings{"previewnolive"} 2405</span> 2406</td> 2407</tr> 2408EOF 2409 } 2410 2411 if ($hostinfo->{sites}->{$params{sitename}}->{htmlurl}) { 2412 $response .= <<"EOF"; 2413<tr> 2414<td align="center" style="padding:0px 2pt 2pt 0px;"><input type="submit" class="smaller" value="$WKCStrings{"previewplainthis"}" onclick="location.href='$hostinfo->{sites}->{$params{sitename}}->{htmlurl}/$params{datafilename}.html';return false;"></td> 2415<td align="center" style="padding:0px 2pt 2pt 0px;"><input type="submit" class="smaller" value="$WKCStrings{"previewplainpopup"}" onclick="window.open('$hostinfo->{sites}->{$params{sitename}}->{htmlurl}/$params{datafilename}.html');return false;"></td> 2416</tr> 2417EOF 2418 } 2419 else { 2420 $response .= <<"EOF"; 2421<tr> 2422<td colspan="2"><span class="warning"> 2423$WKCStrings{"previewnohtml"} 2424</span> 2425</td> 2426</tr> 2427EOF 2428 } 2429 2430 $response .= <<"EOF"; 2431</table> 2432</div> 2433 2434<div id="helptext" style="width:500px;padding:10px 0px 10px 0px;display:none;"> 2435 <div style="border-top:1px solid black;border-left:1px solid black;border-right:1px solid black;color:white;background-color:#66CC66;"> 2436 <table cellspacing="0" cellpadding="0"><tr><td align="center" width="100%" class="smaller"><b>$WKCStrings{"helphelp"}</b></td> 2437 </td><td align="right"><input class="smaller" type="submit" name="hidehelp" value="$WKCStrings{"helphide"}" onClick="toggle_help('');this.blur();return false;"></td> 2438 </tr></table></div> 2439 <div id="helpbody" class="smaller" style="height:200px;overflow:auto;background-color:white;padding:4px;border:1px solid black;"> 2440 $WKCStrings{"helpnotloaded"} 2441 </div> 2442</div> 2443 2444<br> 2445$hiddenfields 2446$inlinescripts 2447</form> 2448</td></tr></table> 2449<br> 2450<script> 2451<!-- 2452function rcc(c) {document.ftabs.editcoords.value=c;document.ftabs.newtab[1].click();1;} 2453var setf = function() {switchto("publish");} 2454// --> 2455</script> 2456EOF 2457 2458 $response .= <<"EOF"; 2459$outstr 2460<br> 2461EOF 2462 2463 } 2464 2465 # # # # # # # # # # 2466 # 2467 # Edit mode 2468 # 2469 # # # # # # # # # # 2470 2471 elsif ($currenttab eq $WKCStrings{"Edit"}) { 2472 2473 # Load scripts from a file 2474 2475 $inlinescripts .= $WKCStrings{"jsdefinestrings"}; 2476 open JSFILE, "$WKCdirectory/WKCjs.txt"; 2477 while (my $line = <JSFILE>) { 2478 $inlinescripts .= $line; 2479 } 2480 close JSFILE; 2481 2482 $inlinescripts .= $WKCStrings{"editjsdefinestrings"}; 2483 open JSFILE, "$WKCdirectory/WKCeditjs.txt"; 2484 while (my $line = <JSFILE>) { 2485 $inlinescripts .= $line; 2486 } 2487 close JSFILE; 2488 2489 my $coord = $editcoords; 2490 $coord =~ s/:.*$//; # only first cell 2491 my $cellcontents; 2492 if ($sheetdata{datatypes}->{$coord} eq "f" || $sheetdata{datatypes}->{$coord} eq "c") { 2493 $cellcontents = $sheetdata{formulas}->{$coord} if $sheetdata{datatypes}->{$coord} eq "f"; 2494 } 2495 else { 2496 $cellcontents = $sheetdata{datavalues}->{$coord}; 2497 } 2498 my $cellcontentsnl = special_chars_nl($cellcontents); 2499 2500 my $onclickstr = q! onclick="rc0('$coord');"!; 2501 2502 my $linkstyle = "?view=$params{sitename}/[[pagename]]"; 2503 my ($stylestr, $outstr) = render_sheet(\%sheetdata, 'id="sheet0" class="wkcsheet"', "", "s", "a", "ajax", $coord, q! onclick="rc0('$coord');"!, , $linkstyle); 2504 2505 $rbody1 =~ s/<body /<body onKeydown="return ev1(event);" onKeypress="return ev2(event);" onLoad="save_initial_sheet_data();move_cursor(ecell,ecell,true);" /; 2506 2507 $response .= $template_headertop . $template_styletop . $template_stylemiddle . $stylestr . $template_stylebottom . 2508 $template_headerscripts . $rbody1; 2509 2510 $response .= <<"EOF"; 2511$rbodytabs 2512$hiddenfields 2513$rbodytabs2 2514<table cellspacing="0" cellpadding="0" width="100%"> 2515<tr><td class="ttbody" width="100%"> 2516<form name="f0" method="POST"> 2517<table cellpadding="0" cellspacing="0"> 2518EOF 2519 2520 my %afterentercheck; 2521 if ($params{afterenter}) { 2522 $afterentercheck{$params{afterenter}} = " CHECKED"; 2523 } 2524 else { 2525 $afterentercheck{same} = " CHECKED"; 2526 } 2527 2528 my %celldata; 2529 my ($lcol, $lrow) = render_values_only(\%sheetdata, \%celldata, $linkstyle); 2530 my $jsdata = qq!var isheet="";\nisheet="!; 2531 2532 foreach my $cr (sort keys %celldata) { # construct output 2533 my $cellspecifics = $celldata{$cr}; 2534 my $displayvalue = encode_for_save($cellspecifics->{display}); 2535 $displayvalue = "" if $displayvalue eq " "; # this is the default 2536 my $csssvalue = encode_for_save($sheetdata{cellattribs}->{$cr}->{csss}); # need this to scroll back 2537 my $editvalue; 2538 if ($sheetdata{datatypes}->{$cr} eq 'f' || $sheetdata{datatypes}->{$cr} eq 'c') { # formula or constant 2539 $editvalue = encode_for_save($sheetdata{formulas}->{$cr}); 2540 } 2541 else { 2542 $editvalue = encode_for_save($sheetdata{datavalues}->{$cr}); 2543 } 2544 my $str = "$cr:$cellspecifics->{type}:$displayvalue:$editvalue:$cellspecifics->{align}:$cellspecifics->{colspan}:$cellspecifics->{rowspan}:$cellspecifics->{skip}:$csssvalue"; 2545 $str =~ s/\\/\\\\/g; 2546 $str =~ s/"/\\x22/g; 2547 $str =~ s/</\\x3C/g; 2548 $jsdata .= "$str\\n"; 2549 } 2550 $jsdata .= qq!"\n!; 2551 2552 if ($sheetdata{sheetattribs}->{circularreferencecell}) { 2553 my ($from, $to) = split(/\|/, $sheetdata{sheetattribs}->{circularreferencecell}); 2554 my $str = "$WKCStrings{editcircular1}$from$WKCStrings{editcircular2}$to"; 2555 $jsdata .= qq!isheet=isheet+"error:$str\\n";\n!; 2556 } 2557 2558 $response .= <<"EOF"; 2559<tr> 2560 <td class="smaller"> </td> 2561 <td valign="bottom"> 2562 <div id="mode1"><span class="smaller" id="valuetype">$WKCStrings{"editloading"}</span> <span id="warning" class="warning"> </span> 2563 <span id="recalcmsg" class="smaller" style="font-style:italic;display:none"> $WKCStrings{"editrecalcneeded"}</span></div> 2564 <div id="mode4" style="display:none;"><span class="smaller">$WKCStrings{"editrange"}</span> 2565 <span class="smaller" style="font-style:italic;color:gray;">$WKCStrings{"editextendrange"}</span></div> 2566 <div id="mode5" class="smaller" style="display:none;">$WKCStrings{"editmoreedit"} 2567 <span style="font-style:italic;color:gray;">$WKCStrings{"editesctoreturn"}</span></div> 2568 <div id="mode6" class="smaller" style="display:none;">$WKCStrings{"editdatatable"} 2569 <span style="font-style:italic;color:gray;">$WKCStrings{"editesctoreturn"}</span></div> 2570 </td> 2571</tr> 2572<tr> 2573 <td valign="top" width="1"> 2574 <span id="coordtext">$editcoords</span> 2575 </td> 2576 <td valign="bottom" width="100%" nowrap><span id="config1a"> 2577 <input class="smaller" type="text" size="80" name="valueedit" value="" autocomplete="off" onFocus="ve_focus()"> 2578 <input class="smaller" type="submit" name="okedit" id="okeditve" value="$WKCStrings{"editok"}" onClick="this.blur();return process_OK();"> 2579 </span><span id="config2a" style="display:none;"> 2580 <input class="smaller" style="font-style:italic;" type="text" size="80" value="$WKCStrings{"editmultilinereq"}" disabled> 2581 </span><span id="config45a" style="display:none;"><span id="rangeend"></span><span id="kbdprompt" class="smaller"></span></span><span id="config3a" style="display:none;"> 2582 <textarea cols="80" rows="10" name="valueedittext" onFocus="vet_focus()"> 2583$cellcontentsnl</textarea> 2584 </span> 2585 </td> 2586</tr> 2587<tr> 2588 <td></td> 2589 <td valign="top"><div id="config1c"> 2590 <input class="smaller" type="submit" name="switcheditvet" id="switcheditvet" value='$WKCStrings{"editmultilineedit"}' onClick="set_editconfig(3);document.f0.valueedittext.focus();return false;"> 2591 <input class="smaller" type="submit" name="range" value="$WKCStrings{"editrange"}" onClick="this.blur();range_button();return false;"> 2592 <input class="smaller" type="submit" name="range" value="$WKCStrings{"editmore"}" onClick="this.blur();more_button();return false;"> 2593 <input class="smaller" type="submit" name="canceledit" value="$WKCStrings{"editcancel"}" onClick="this.blur();process_typed_char('[esc]');return false;"> 2594 <input class="smaller" type="submit" name="help" value="$WKCStrings{"edithelp"}" onClick="toggle_help('edithelptext');this.blur();return false;"> 2595 <input id="dorecalcbutton" class="smaller" type="submit" name="dorecalcbutton" value="$WKCStrings{"editrecalconce"}" style="display:none;" onClick="document.f0.dorecalc.value=1;"> 2596 </div><div id="config3c" style="display:none;"> 2597 <input class="smaller" type="submit" name="okeditvet" value="$WKCStrings{"editok"}" onClick="this.blur();return process_OK();"> 2598 <input class="smaller" type="submit" name="blankvet" value="$WKCStrings{"editblank"}" onClick="document.f0.valueedittext.value='';val='';document.f0.valueedittext.focus();return false;"> 2599 <input class="smaller" type="submit" name="pagelink" value="$WKCStrings{"editlinktopage"}" onClick="this.blur();update_page_list();return false;"> 2600 <input class="smaller" type="submit" name="canceleditvet" value="$WKCStrings{"editcancel"}" onClick="this.blur();process_typed_char('[esc]');return false;"> 2601 <input class="smaller" type="submit" name="helpvet" value="$WKCStrings{"edithelp"}" onClick="toggle_help('edithelptext');this.blur();return false;"> 2602 </div> 2603 </td> 2604</tr> 2605<tr> 2606 <td></td> 2607 <td> 2608 <div id="config4d" style="display:none;"> 2609 <input id="mergebutton" class="smaller" type="submit" name="okeditrange:merge" value="$WKCStrings{"editmergecells"}" onClick="set_range('all');document.f0.okeditrange.value='merge';"> 2610 <input id="unmergebutton" class="smaller" type="submit" name="okeditrange:unmerge" value="$WKCStrings{"editunmerge"}" onClick="set_more('all');document.f0.okeditrange.value='unmerge';"> 2611 <input class="smaller" type="submit" name="okeditrange:copy" value="$WKCStrings{"editcopy"}" onClick="set_range('all');"> 2612 <input class="smaller" type="submit" name="okeditrange:cut" value="$WKCStrings{"editcut"}"> 2613 <input class="smaller" type="submit" name="okeditrange:erase" value="$WKCStrings{"editerase"}"> 2614 <input class="smaller" type="submit" name="okeditrange:fillright" value="$WKCStrings{"editfillright"}" onClick="set_range('all');"> 2615 <input class="smaller" type="submit" name="okeditrange:filldown" value="$WKCStrings{"editfilldown"}" onClick="set_range('all');"> 2616 <input class="smaller" type="submit" name="tables" value="$WKCStrings{"edittable"}" onClick="this.blur();table_button();return false;"> 2617 <input class="smaller" type="submit" name="cancelrange" value="$WKCStrings{"editcancel"}" onClick="this.blur();cancel_range();return false;"> 2618 <input class="smaller" type="submit" name="rangehelp" value="$WKCStrings{"edithelp"}" onClick="toggle_help('rangehelptext');this.blur();return false;"> 2619 <span class="smaller"> 2620 <input type="radio" name="editparts" value="all" CHECKED>$WKCStrings{"editall"} 2621 <input type="radio" name="editparts" value="formulas">$WKCStrings{"editcontents"} 2622 <input type="radio" name="editparts" value="formats">$WKCStrings{"editformats"} 2623 </span> 2624 </div><div id="config5d" style="display:none;"> 2625 <div style="margin:6px 0px 6px 0px;"> 2626 <input class="smaller" type="submit" name="range" value="$WKCStrings{"editrange"}" onClick="this.blur();range_button();return false;"> 2627 <input class="smaller" type="submit" name="okeditrange:paste" value="$WKCStrings{"editpasteall"}" onClick="set_more('all');"> 2628 <input class="smaller" type="submit" name="okeditrange:paste" value="$WKCStrings{"editpastecontents"}" onClick="set_more('formulas');"> 2629 <input class="smaller" type="submit" name="okeditrange:paste" value="$WKCStrings{"editpasteformats"}" onClick="set_more('formats');"> 2630 <input id="recalcmanualbutton" class="smaller" type="submit" name="okeditrange:recalcmanual" value="$WKCStrings{"editrecalcmanual"}"> 2631 <input id="recalcautobutton" class="smaller" type="submit" name="okeditrange:recalcauto" value="$WKCStrings{"editrecalcauto"}" style="display:none;"> 2632 </div> 2633 <input class="smaller" type="submit" name="okeditrange:insertrow" value="$WKCStrings{"editinsertrow"}" onClick="set_more('all');"> 2634 <input class="smaller" type="submit" name="okeditrange:insertcol" value="$WKCStrings{"editinsertcol"}" onClick="set_more('all');"> 2635 <input class="smaller" type="submit" name="okeditrange:deleterow" value="$WKCStrings{"editdeleterow"}" onClick="set_more('all');"> 2636 <input class="smaller" type="submit" name="okeditrange:deletecol" value="$WKCStrings{"editdeletecol"}" onClick="set_more('all');"> 2637 <input class="smaller" type="submit" name="cancelrange2" value="$WKCStrings{"editcancel"}" onClick="this.blur();cancel_more();return false;"> 2638 <input class="smaller" type="submit" name="rangehelp2" value="$WKCStrings{"edithelp"}" onClick="toggle_help('editmorehelptext');this.blur();return false;"> 2639 </div><div id="config6d" style="display:none;"><div id="config6d1"> 2640 <input class="smaller" type="submit" name="tablesort" value="$WKCStrings{"editsort"}" onClick="this.blur();set_kbdprompt('/RTS');return false;"> 2641 <input class="smaller" type="submit" name="canceltable" value="$WKCStrings{"editcancel"}" onClick="this.blur();cancel_table();return false;"> 2642 <input class="smaller" type="submit" name="canceltable" value="$WKCStrings{"edithelp"}" onClick="toggle_help('edittablehelptext');this.blur();return false;"> 2643 </div><div id="config6d2"> 2644 <table cellspacing="0" cellpadding="0" style="border:1px solid black;background-color:white;margin:6px 0px 4px 0px;"> 2645 <tr><td colspan="13" style="background-color:gray;color:white;font-weight:bold;text-align:center;">$WKCStrings{"editsorttitle"}</td></tr><tr> 2646 <td> </td> 2647 <td style="font-size:smaller;font-weight:bold;color:black">$WKCStrings{"editmajorsort"}</td><td> </td><td> </td><td> </td> 2648 <td style="font-size:smaller;font-weight:bold;color:black">$WKCStrings{"editminorsort"}</td><td> </td><td> </td><td> </td> 2649 <td style="font-size:smaller;font-weight:bold;color:black">$WKCStrings{"editlastsort"}</td><td> </td><td> </td><td> </td> 2650 </tr><tr> 2651 <td> </td> 2652 <td valign="top"><select name="sort1" size="1"><option value="" selected><option value="B">Column B<option value="C">Column C</select></td><td> </td> 2653 <td> 2654 <input name="sortorder1" type="radio" value="up" checked><span class="smaller">$WKCStrings{"editascending"}</span><br> 2655 <input name="sortorder1" type="radio" value="down"><span class="smaller">$WKCStrings{"editdescending"}</span><br> 2656 </td><td> </td> 2657 <td valign="top"><select name="sort2" size="1"><option value="" selected><option value="B">Column B<option value="C">Column C</select></td><td> </td> 2658 <td> 2659 <input name="sortorder2" type="radio" value="up" checked><span class="smaller">$WKCStrings{"editascending"}</span><br> 2660 <input name="sortorder2" type="radio" value="down"><span class="smaller">$WKCStrings{"editdescending"}</span><br> 2661 </td><td> </td> 2662 <td valign="top"><select name="sort3" size="1"><option value="" selected><option value="B">Column B<option value="C">Column C</select></td><td> </td> 2663 <td> 2664 <input name="sortorder3" type="radio" value="up" checked><span class="smaller">$WKCStrings{"editascending"}</span><br> 2665 <input name="sortorder3" type="radio" value="down"><span class="smaller">$WKCStrings{"editdescending"}</span><br></td><td> </td> 2666 </tr><tr><td> </td><td colspan="12" style="padding:6px 0px 6px 0px;"> 2667 <input class="smaller" type="submit" name="okeditrange:sort" value="$WKCStrings{"editok"}"> 2668 <input class="smaller" type="submit" name="cancelsort" value="$WKCStrings{"editcancel"}" onClick="this.blur();set_kbdprompt('/RT');return false;"> 2669 <input class="smaller" type="submit" name="sorthelp" value="$WKCStrings{"edithelp"}" onClick="toggle_help('edittablesorthelptext');this.blur();return false;"> 2670 </td> 2671 </tr> 2672 </table> 2673 </div> 2674 </div><div id="linkpagelist" style="padding-top:10px;display:none;"> 2675 <span class="smaller">$WKCStrings{"editpagetolinkto"}</span><br> 2676 <select name="pagelist" size="10"> 2677 <option value="">$WKCStrings{"editempty"} 2678 </select><br> 2679 <input class="smaller" type="submit" value="$WKCStrings{"editchoose"}" onClick="choose_pagelink(true);return false;"> 2680 <input class="smaller" type="submit" value="$WKCStrings{"editcancel"}" onClick="choose_pagelink(false);return false;"> 2681 </div><div id="helptext" style="width:500px;padding:10px 0px 10px 0px;display:none;"> 2682 <div style="border-top:1px solid black;border-left:1px solid black;border-right:1px solid black;color:white;background-color:#66CC66;"> 2683 <table cellspacing="0" cellpadding="0"><tr><td align="center" width="100%" class="smaller"><b>$WKCStrings{"helphelp"}</b></td> 2684 </td><td align="right"><input class="smaller" type="submit" name="hidehelp" value="$WKCStrings{"helphide"}" onClick="toggle_help('');this.blur();return false;"></td> 2685 </tr></table></div> 2686 <div id="helpbody" class="smaller" style="height:200px;overflow:auto;background-color:white;padding:4px;border:1px solid black;"> 2687 $WKCStrings{"helpnotloaded"} 2688 </div> 2689 </div> 2690 </td> 2691</tr> 2692EOF 2693 $inlinescripts .= <<"EOF"; 2694<script> 2695 2696$jsdata 2697 2698sheetlastcol=$lcol; 2699sheetlastrow=$lrow; 2700parse_sheet(isheet); 2701ecell="$coord"; 2702cliprange="$sheetdata{clipboard}->{range}"; 2703needsrecalc="$sheetdata{sheetattribs}->{needsrecalc}"; 2704check_error(); 2705</script> 2706EOF 2707 2708 $response .= <<"EOF"; 2709</table> 2710$inlinescripts 2711$hiddenfields 2712<input type="hidden" name="okeditrange" value=""> 2713<input type="hidden" name="newtab" value=""> 2714<input type="hidden" name="recalc" value="$sheetdata{sheetattribs}->{recalc}"> 2715<input type="hidden" name="dorecalc" value=""> 2716<input type="hidden" name="mergetype" value=""> 2717</form> 2718</td></tr></table> 2719<br> 2720EOF 2721 2722 $response .= <<"EOF"; 2723<table cellspacing="0" cellpadding="0"><tr> 2724<td valign="top"> 2725$outstr 2726</td> 2727<td valign="top"> 2728<div style="border:4px solid #CCCC99;background-color: #CCCC99;" unselectable="on"> 2729<div class="smaller" style="text-align:center;color:#666633;" id="statusthing" unselectable="on" onmousedown="scroll_to_home();"> </div> 2730<div id="draghandle" style="margin:0 auto 0 auto;width:14px;height:6px;border:1px solid #666633;background-color:#DDFFDD;position:relative;top:17px;left:0;z-index:1" onmousedown="begindrag(event);" unselectable="on"><img src="?getfile=1x1" width="1" height="1" unselectable="on"></div> 2731<div id="scrollup" style="margin:0 auto 0 auto;width:12px;height:8px;border:1px solid #666633;background-color:white;" onmousedown="begin_scroll(-1,this);" unselectable="on"><img src="?getfile=1x1" width="1" height="1" unselectable="on"></div> 2732<div id="slider" style="margin:0 auto 0 auto;width:20px;position:relative;top:0px;left:0;" onmousedown="slider_page(event);" unselectable="on"><div style="margin:0 auto 0 auto;width:4px;height:150px;background-color:white;border-left:1px solid #666633;border-right:1px solid #666633;"></div></div> 2733<div id="scrolldown" style="margin:0 auto 0 auto;width:12px;height:8px;border:1px solid #666633;background-color:white;" onmousedown="begin_scroll(1,this);" unselectable="on"><img src="?getfile=1x1" width="1" height="1" unselectable="on"></div> 2734<img src="?getfile=1x1" width="24" height="10" unselectable="on"> 2735</div> 2736</td> 2737</tr> 2738</table> 2739<div style="margin:6px 0px 6px 0px;"> 2740<form name="f1" method="POST"> 2741<input name="editaddrow" type="submit" value="$WKCStrings{"editaddrow"}" class="smaller" onclick="document.f1.editcoords.value=ecell;"> 2742<input name="editaddcol" type="submit" value="$WKCStrings{"editaddcolumn"}" class="smaller" onclick="document.f1.editcoords.value=ecell;"> 2743<span class="smaller" style="color:#999999;">$WKCStrings{"editcurrentsheetextent"} $sheetdata{sheetattribs}->{lastcol} $WKCStrings{"editcolsby"} $sheetdata{sheetattribs}->{lastrow} $WKCStrings{"editrows"}</span> 2744$hiddenfields 2745</form> 2746</div> 2747EOF 2748 } 2749 2750 # # # # # # # # # # 2751 # 2752 # Format mode 2753 # 2754 # # # # # # # # # # 2755 2756 elsif ($currenttab eq $WKCStrings{"Format"}) { 2757 2758 my ($fcstylestr, $fcbodystr) = do_format_command(\%params, \%sheetdata, \%headerdata, $hiddenfields, $editcoords, $editmode); 2759 2760 $hiddenfields = update_hiddenfields(\%params, $hiddenfields); 2761 2762 $rbody1 =~ s/<body /<body onKeydown="return ev1(event);" onKeypress="return ev2(event);" /; 2763 2764 $response .= $template_headertop . $template_styletop . $template_stylemiddle . $fcstylestr . $template_stylebottom . 2765 $template_headerscripts . $rbody1 . $rbodytabs . $hiddenfields . $rbodytabs2 . $fcbodystr; 2766 2767 } 2768 2769 # # # # # # # # # # 2770 # 2771 # Tools mode 2772 # 2773 # # # # # # # # # # 2774 2775 elsif ($currenttab eq $WKCStrings{"Tools"}) { 2776 2777 my ($tcstylestr, $tcbodystr) = do_tools_command(\%params, \%sheetdata, \%headerdata, $hiddenfields, $editcoords, $hostinfo, $loggedinuser, \%userinfo); 2778 2779 $hiddenfields = update_hiddenfields(\%params, $hiddenfields); 2780 2781 $response .= $template_headertop . $template_styletop . $template_stylemiddle . $tcstylestr . $template_stylebottom . 2782 $template_headerscripts . $rbody1 . $rbodytabs . $hiddenfields . $rbodytabs2 . $tcbodystr; 2783 2784 } 2785 2786 # # # # # # # # # # 2787 # 2788 # Show License mode 2789 # 2790 # # # # # # # # # # 2791 2792 elsif ($currenttab eq $WKCStrings{"showlicense"}) { 2793 2794 use WKCLicense; 2795 2796 $response .= $template_headertop . $template_styletop . $template_stylemiddle . $template_stylebottom . 2797 $template_headerscripts . $rbody1; 2798 2799 $response .= <<"EOF"; 2800$rbodytabs 2801$hiddenfields 2802$rbodytabs2 2803<table cellpadding="0" cellspacing="0" width="100%"> 2804<tr><td class="ttbody" width="100%"> 2805<div class="sectiondark"> 2806$sgilicensetext 2807</div> 2808<br> 2809<div class="sectiondark"> 2810$gpllicensetext 2811</div> 2812</td></tr> 2813</table> 2814EOF 2815 } 2816 2817 # # # # # # # # # # 2818 # 2819 # ? mode 2820 # 2821 # # # # # # # # # # 2822 2823 else { 2824 $response .= <<"EOF"; 2825UNKNOWN MODE<br> 2826EOF 2827 } 2828 2829 # # # # # # # # # # 2830 # 2831 # Output footer 2832 # 2833 # # # # # # # # # # 2834 2835 my $end_time = times(); 2836 my $time_string = sprintf ("$WKCStrings{wkcfooterruntime} %.2f $WKCStrings{wkcfootersecondsat} $start_clock_time", 2837 $end_time - $start_cpu_time); 2838 2839 if ($params{debugmessage}) { # Message to display -- would print, but that would mess up CGI-based version 2840 $response .= <<"EOF"; 2841<div class="sectionerror"> 2842$WKCStrings{"editdebuggingmsg"}: $params{debugmessage}<br><br> 2843</div> 2844EOF 2845 } 2846 2847 my $programnamebottom; 2848 if ($WKCStrings{programextratop}) { # if extra program name material, don't add SGI stuff 2849 $programnamebottom = "$WKCStrings{programextratop} $programmark$programmarksymbol $programversion"; 2850 } 2851 else { 2852 $programnamebottom .= "$programmark$programmarksymbol $programversion$trademark1"; 2853 } 2854 2855 $response .= <<"EOF"; 2856<div class="footer"> 2857$programnamebottom<br><br> 2858<div id="footertimemsg">$time_string</div> 2859<br> 2860$SGIfootertext 2861$WKCStrings{"footerextratext"} 2862EOF 2863 2864 $response .= <<"EOF"; 2865<br><br> 2866<form name="fsl" action="" method="POST"> 2867$hiddenfields 2868<input style="font-size:xx-small;" type="submit" name="newtab" value="$WKCStrings{"showlicense"}"> 2869</form> 2870</div> 2871</body> 2872</html> 2873EOF 2874 2875 $responsecookie .= "datafilename:$params{datafilename};sitename:$params{sitename};expires:$cookievalues{expires}"; 2876 2877 $responsedata->{content} = $response; 2878 $responsedata->{contenttype} = "text/html; charset=UTF-8"; 2879 $responsedata->{cookie} = $responsecookie; 2880 $responsedata->{cookieexpires} = $cookievalues{expires} eq "session" ? "" : ($cookievalues{expires} || $defaultcookieexpire); 2881 return; 2882} 2883 2884 2885 # # # # # # # # # # 2886 # 2887 # $hiddenfields = update_hiddenfields(\$params, $hiddenfields) 2888 # 2889 # Updates the values for editmode, datafilename, sitename, etc., from params 2890 # 2891 2892sub update_hiddenfields { 2893 2894 my ($params, $hiddenfields) = @_; 2895 2896 $hiddenfields =~ s/(name="editmode" value=").*?"/$1$params->{editmode}"/; 2897 $hiddenfields =~ s/(name="datafilename" value=").*?"/$1$params->{datafilename}"/; 2898 $hiddenfields =~ s/(name="sitename" value=").*?"/$1$params->{sitename}"/; 2899 $hiddenfields =~ s/(name="editcoords" value=").*?"/$1$params->{editcoords}"/; 2900 $hiddenfields =~ s/(name="etpurl" value=").*?"/$1$params->{etpurl}"/; 2901 $hiddenfields =~ s/(name="scrollrow" value=").*?"/$1$params->{scrollrow}"/; 2902 2903 return $hiddenfields; 2904 2905} 2906 2907 2908# # # # # # # # # # 2909# 2910# $notok = site_not_allowed(\%userinfo, $user, $sitename) 2911# 2912# Checks to see if $user is allowed to edit $sitename, returning 0 (yes) or 1 (no) 2913# 2914# # # # # # # # # # 2915 2916sub site_not_allowed { 2917 2918 my ($userinfo, $user, $sitename) = @_; 2919 2920 return 0 if $userinfo->{HOSTrequirelogin} ne "yes"; 2921 2922 return 0 if $userinfo->{$user}->{allsites} eq "yes"; 2923 2924 my $sitestr = ",$userinfo->{$user}->{sites},"; # comma separated list of allowed sites 2925 2926 return 0 if ($sitestr =~ m/,$sitename,/ && $userinfo->{$user}->{sites}); 2927 2928 return 1; 2929 2930} 2931 2932 2933# # # # # # # # # # 2934# 2935# $notok = readsite_not_allowed(\%userinfo, $user, $sitename) 2936# 2937# Checks to see if $user is allowed to read $sitename, returning 0 (yes) or 1 (no) 2938# 2939# # # # # # # # # # 2940 2941sub readsite_not_allowed { 2942 2943 my ($userinfo, $user, $sitename) = @_; 2944 2945 return 0 if $userinfo->{HOSTrequirelogin} ne "yes"; 2946 2947 return 0 if ($userinfo->{$user}->{allsites} eq "yes" || $userinfo->{$user}->{allreadsites} eq "yes"); 2948 2949 my $sitestr = ",$userinfo->{$user}->{sites},"; # comma separated list of allowed read/write sites 2950 return 0 if ($sitestr =~ m/,$sitename,/ && $userinfo->{$user}->{sites}); 2951 2952 my $readsitestr = ",$userinfo->{$user}->{readsites},"; # comma separated list of allowed read sites 2953 return 0 if ($readsitestr =~ m/,$sitename,/ && $userinfo->{$user}->{readsites}); 2954 2955 return 1; 2956 2957} 2958 2959 2960# # # # # # # # 2961# 2962# $tstr = fill_in_HTML_template($inputstr, $sitedata, \%headerdata, $sitename, $pagename, $clock_time, $author, $loggedinusername, $stylestr, $sheetstr, $renderingliveview) 2963# 2964# Fill in the HTML template variables 2965# 2966# # # # # # # # 2967 2968sub fill_in_HTML_template { 2969 2970 my ($inputstr, $sitedata, $headerdata, $sitename, $pagename, $clock_time, $author, $loggedinusername, $stylestr, $sheetstr, $renderingliveview) = @_; 2971 2972 my $tstr = $inputstr; 2973 2974 # Remove description line if it's there 2975 2976 $tstr =~ s/^{{templatedescriptionline}}.*?(\n|\r\n)//; 2977 2978 # Process directives 2979 2980 while ($tstr =~ m/{{line-if-editurl}}/) { 2981 if ($sitedata->{editurl}) { # if a URL for editing is provided leave rest of line 2982 $tstr =~ s/{{line-if-editurl}}(.*?)(\n|\r\n)/$1$2/; 2983 } 2984 else { # no URL so remove line 2985 $tstr =~ s/{{line-if-editurl}}.*?(\n|\r\n)/$1/; 2986 } 2987 } 2988 2989 while ($tstr =~ m/{{line-if-htmlurl}}/) { 2990 if ($sitedata->{htmlurl}) { # if a URL for the directory with HTML is provided leave rest of line 2991 $tstr =~ s/{{line-if-htmlurl}}(.*?)(\n|\r\n)/$1$2/; 2992 } 2993 else { # no URL so remove line 2994 $tstr =~ s/{{line-if-htmlurl}}.*?(\n|\r\n)/$1/; 2995 } 2996 } 2997 2998 while ($tstr =~ m/{{line-if-loggedin}}/) { 2999 if ($loggedinusername) { # have the name of logged in user leave rest of line 3000 $tstr =~ s/{{line-if-loggedin}}(.*?)(\n|\r\n)/$1$2/; 3001 } 3002 else { # no URL so remove line 3003 $tstr =~ s/{{line-if-loggedin}}.*?(\n|\r\n)/$1/; 3004 } 3005 } 3006 3007 while ($tstr =~ m/{{line-if-liveview}}/) { 3008 if ($renderingliveview) { # if doing live view rendering leave rest of line 3009 $tstr =~ s/{{line-if-liveview}}(.*?)(\n|\r\n)/$1$2/; 3010 } 3011 else { # no URL so remove line 3012 $tstr =~ s/{{line-if-liveview}}.*?(\n|\r\n)/$1/; 3013 } 3014 } 3015 3016 # Do all the substitutions 3017 3018 $tstr =~ s/{{editthispagehtml}}/$sitedata->{editurl}?$WKCStrings{"editthispagehtml"}:""/ge; # must preceed others 3019 $tstr =~ s/{{pagetitle}}/$headerdata->{fullname}/ge; 3020 $tstr =~ s/{{pagename}}/$pagename/ge; 3021 $tstr =~ s/{{sitename}}/$sitename/ge; 3022 $tstr =~ s/{{pubdatetime}}/$clock_time/ge; 3023 $tstr =~ s/{{author}}/$author/ge; 3024 $tstr =~ s/{{loggedinuser}}/$loggedinusername/ge; 3025 $tstr =~ s/{{editurl}}/$sitedata->{editurl}/ge; 3026 $tstr =~ s/{{htmlurl}}/$sitedata->{htmlurl}/ge; 3027 3028 $tstr =~ s/{{sheetstyles}}/$stylestr/e; 3029 $tstr =~ s/{{sheet0}}/$sheetstr/e; 3030 3031 return $tstr; 3032 3033 } 3034 3035 3036# # # # # # # # 3037# 3038# $jsstr = create_embeddable_JS_sheet($stylestr, $sheetstr) 3039# 3040# Turn the output of rendering into embeddable Javascript 3041# Uses WKCembeddablejs.txt, replacing {{stylestr}} and {{sheetstr}} 3042# 3043# # # # # # # # 3044 3045sub create_embeddable_JS_sheet { 3046 3047 my ($stylestr, $sheetstr) = @_; 3048 3049 my $jsstr; 3050 $sheetstr =~ s/^(.*?)$/ str+=pl('$1',styles);/gm; 3051 $stylestr =~ s/^/ /gm; 3052 3053 open JSFILE, "$WKCdirectory/WKCembeddablejs.txt"; 3054 while (my $line = <JSFILE>) { 3055 $jsstr .= $line; 3056 } 3057 close JSFILE; 3058 3059 $jsstr =~ s/{{stylestr}}/$stylestr/e; 3060 $jsstr =~ s/{{sheetstr}}/$sheetstr/e; 3061 3062 return $jsstr; 3063 3064 } 3065 3066 3067# # # # # # # # 3068# 3069# $errortext = execute_edit_command(\%params, \%sheetdata, $editcoords, \%headerdata) 3070# 3071# Modify the sheet in response to an edit command 3072# 3073# # # # # # # # 3074 3075sub execute_edit_command { 3076 3077 my ($params, $sheetdata, $editcoords, $headerdata) = @_; 3078 3079 my ($ok, $errortext); 3080 3081 if ($params->{okeditrange} eq "erase") { 3082 $ok = execute_sheet_command_and_log($sheetdata, "erase $editcoords $params->{editparts}", $headerdata); 3083 } 3084 3085 elsif ($params->{okeditrange} eq "copy" || $params->{okeditrange} eq "cut") { 3086 $ok = execute_sheet_command_and_log($sheetdata, "$params->{okeditrange} $editcoords $params->{editparts}", $headerdata); 3087 } 3088 3089 elsif ($params->{okeditrange} eq "clearclipboard") { 3090 $ok = execute_sheet_command_and_log($sheetdata, "clearclipboard", $headerdata); 3091 } 3092 3093 elsif ($params->{okeditrange} eq "paste") { 3094 $ok = execute_sheet_command_and_log($sheetdata, "paste $editcoords $params->{editparts}", $headerdata); 3095 delete $params->{doingrangesetting}; 3096 } 3097 3098 elsif ($params->{okeditrange} eq "fillright" || $params->{okeditrange} eq "filldown") { 3099 $ok = execute_sheet_command_and_log($sheetdata, "$params->{okeditrange} $editcoords $params->{editparts}", $headerdata); 3100 } 3101 3102 elsif ($params->{okeditrange} eq "insertrow" || $params->{okeditrange} eq "insertcol") { 3103 $ok = execute_sheet_command_and_log($sheetdata, "$params->{okeditrange} $editcoords", $headerdata); 3104 delete $params->{doingrangesetting}; 3105 } 3106 3107 elsif ($params->{okeditrange} eq "deleterow" || $params->{okeditrange} eq "deletecol") { 3108 $ok = execute_sheet_command_and_log($sheetdata, "$params->{okeditrange} $editcoords", $headerdata); 3109 $editcoords =~ s/:(.+)//; # switch to just one cell 3110 my ($c, $r) = coord_to_cr($editcoords); 3111 if ($c > $sheetdata->{sheetattribs}->{lastcol}) { 3112 $c = $sheetdata->{sheetattribs}->{lastcol}; 3113 } 3114 if ($r > $sheetdata->{sheetattribs}->{lastrow}) { 3115 $r = $sheetdata->{sheetattribs}->{lastrow}; 3116 } 3117 $params->{editcoords} = cr_to_coord($c, $r); 3118 } 3119 3120 elsif ($params->{okeditrange} eq "merge" || $params->{okeditrange} eq "unmerge") { 3121 $ok = execute_sheet_command_and_log($sheetdata, "$params->{okeditrange} $editcoords", $headerdata); 3122 $editcoords =~ s/:(.+)//; # switch to just one cell 3123 $params->{editcoords} = $editcoords; 3124 } 3125 3126 elsif ($params->{okeditrange} eq "recalcauto" || $params->{okeditrange} eq "recalcmanual") { 3127 $sheetdata->{sheetattribs}->{recalc} = $params->{okeditrange} eq "recalcauto" ? "on" : "off"; 3128 $params->{recalc} = $sheetdata->{sheetattribs}->{recalc}; 3129 add_to_editlog($headerdata, "# $WKCStrings{logautorecalset}: $params->{recalc}"); 3130 } 3131 3132 elsif ($params->{okeditrange} eq "sort") { 3133 my $cstr = "sort $editcoords"; 3134 $cstr .= " $params->{sort1} $params->{sortorder1}" if $params->{sort1} ne "none"; 3135 $cstr .= " $params->{sort2} $params->{sortorder2}" if $params->{sort2} ne "none"; 3136 $cstr .= " $params->{sort3} $params->{sortorder3}" if $params->{sort3} ne "none"; 3137 $ok = execute_sheet_command_and_log($sheetdata, $cstr, $headerdata); 3138 } 3139 3140 return $errortext; 3141} 3142 3143 3144# # # # # # # # # # 3145# 3146# decode_from_ajax($string) 3147# 3148# Returns a string with \n, \b, \c, and \e escaped to \n, \, :, and ]]> 3149# 3150 3151sub decode_from_ajax { 3152 my $string = shift @_; 3153 3154 $string =~ s/\\n/\n/g; 3155 $string =~ s/\\c/:/g; 3156 $string =~ s/\\b/\\/g; 3157 3158 return $string; 3159} 3160 3161 3162# # # # # # # # # # 3163# 3164# encode_for_ajax($string) 3165# 3166# Returns a string with \n, \, :, and ]]> escaped to \n, \b, \c, and \e 3167# 3168 3169sub encode_for_ajax { 3170 my $string = shift @_; 3171 3172 $string =~ s/\\/\\b/g; 3173 $string =~ s/\n/\\n/g; 3174 $string =~ s/\r//g; 3175 $string =~ s/:/\\c/g; 3176 $string =~ s/]]>/\\e/g; 3177 3178 return $string; 3179} 3180 3181 3182# # # # # # # # # # 3183# 3184# $ok = execute_sheet_command_and_log($sheetdata, $command, \%headerdata) 3185# 3186# Passes the first two arguments to execute_sheet_command and then logs the command if ok 3187# 3188 3189sub execute_sheet_command_and_log { 3190 3191 my ($sheetdata, $command, $headerdata) = @_; 3192 3193 my $ok = execute_sheet_command($sheetdata, $command); 3194 3195 if ($ok) { 3196 add_to_editlog($headerdata, $command) 3197 } 3198 3199 return $ok; 3200 3201} 3202 3203 3204# # # # # # # # # # 3205# 3206# init_sheet_cache(\%sheetdata, \%params, \%hostinfo, $sitename) 3207# 3208# Stores enough information in the sheetdata to load additional sheets' information for worksheet references 3209# 3210 3211sub init_sheet_cache { 3212 3213 my ($sheetdata, $params, $hostinfo, $sitename) = @_; 3214 3215 $sheetdata->{sheetcache} = {}; 3216 $sheetdata->{sheetcache}->{params} = $params; 3217 $sheetdata->{sheetcache}->{hostinfo} = $hostinfo; 3218 $sheetdata->{sheetcache}->{sitename} = $sitename; 3219 $sheetdata->{sheetcache}->{sheets} = {}; # see find_in_sheet_cache 3220 3221 return; 3222 3223} 3224 3225 3226# # # # # # # # # # 3227# 3228# $othersheet_sheetdata = find_in_sheet_cache(\%sheetdata, $datafilename) 3229# 3230# Load additional sheet's information for worksheet references as a sheetdata structure 3231# stored in $sheetdata->{sheetcache}->{sheets}->{$datafilename} if necessary. 3232# Return that structure as \%othersheet_sheetdata 3233# 3234# If $datafilename starts with "http:" it is assumed to be a URL and an HTTP GET is done to retrieve 3235# the file. Otherwise it is assumed to be a pagename and the file is loaded from the current site. 3236# 3237 3238sub find_in_sheet_cache { 3239 3240 my ($sheetdata, $datafilename) = @_; 3241 3242 my $sdsc = $sheetdata->{sheetcache}; 3243 3244 if ($datafilename !~ m/^http:/i) { # not URL 3245 $datafilename = lc $datafilename; # lower case for consistency 3246 } 3247 3248 if ($sdsc->{sheets}->{$datafilename}) { # already in cache 3249 return $sdsc->{sheets}->{$datafilename}; 3250 } 3251 3252 my (@headerlines, @sheetlines, $loaderror); 3253 3254 if ($datafilename =~ m/^http:/i) { # URL - use HTTP GET 3255 my $ua = LWP::UserAgent->new; 3256 $ua->agent($programname); 3257 $ua->timeout(30); 3258 my $req = HTTP::Request->new("GET", $datafilename); 3259 $req->header('Accept' => '*/*'); 3260 my $res = $ua->request($req); 3261 if ($res->is_success) { 3262 $loaderror = load_page_from_array($res->content, \@headerlines, \@sheetlines); 3263 } 3264 else { 3265 $loaderror = "$WKCStrings{findsheetincacheunabletoload} '$datafilename'"; 3266 } 3267 } 3268 else { # assume local pagename 3269 my $editpath = get_page_published_datafile_path($sdsc->{params}, $sdsc->{hostinfo}, $sdsc->{sitename}, $datafilename); 3270 $loaderror = load_page($editpath, \@headerlines, \@sheetlines); 3271 } 3272 3273 $sdsc->{sheets}->{$datafilename} = {}; # start fresh 3274 my $ok = parse_sheet_save(\@sheetlines, $sdsc->{sheets}->{$datafilename}); 3275 3276 $sdsc->{sheets}->{$datafilename}->{loaderror} = $loaderror if $loaderror; 3277 3278 return $sdsc->{sheets}->{$datafilename}; 3279 3280} 3281 3282 32831; 3284 3285=begin license 3286 3287SOFTWARE LICENSE 3288 3289This software and documentation is 3290Copyright (c) 2007 Software Garden, Inc. 3291All rights reserved. 3292 32931. The source code of this program is made available as free software; 3294you can redistribute it and/or modify it under the terms of the GNU 3295General Public License, version 2, as published by the Free Software 3296Foundation. 3297 32982. This program is distributed in the hope that it will be useful, but 3299WITHOUT ANY WARRANTY; without even the implied warranty of 3300MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 3301General Public License for more details. You should have received a 3302copy of the GNU General Public License along with this program; if not, 3303write to the Free Software Foundation, Inc., 51 Franklin Street, 3304Fifth Floor, Boston, MA 02110-1301, USA. 3305 33063. If the GNU General Public License is restrictive in a way that does 3307not meet your needs, contact the copyright holder (Software Garden, 3308Inc.) to inquire about the availability of other licenses, such as 3309traditional commercial licenses. 3310 33114. The right to distribute this software or to use it for any purpose 3312does not give you the right to use Servicemarks or Trademarks of 3313Software Garden, Inc., including Garden, Software Garden, ListGarden, 3314and wikiCalc. 3315 33165. An appropriate copyright notice will include the Software Garden, 3317Inc., copyright, and a prominent change notice will include a 3318reference to Software Garden, Inc., as the originator of the code 3319to which the changes were made. 3320 3321Exception for Executable Bundle 3322 3323In some cases this program is distributed together with programs and 3324libraries of ActiveState Corporation as a single executable file (an 3325"Executable Bundle") produced using ActiveState Corporation's "Perl Dev 3326Kit" PerlTray program ("PDK PerlTray"). This free software license does 3327not apply to those programs and libraries of ActiveState Corporation 3328that are part of the Executable Bundle. You only have a license to use 3329those programs and libraries of ActiveState Corporation for runtime 3330purposes in order to execute this software of Software Garden, Inc. In 3331order to create and distribute similar executable files from modified 3332source files, you will need to license your own copy of PDK PerlTray. 3333 3334As a specific exception for this product to the terms and conditions of 3335the GNU General Public License version 2, you are free to distribute 3336this software (modified or unmodified) in an Executable Bundle created 3337with PDK PerlTray as long as you adhere to the GNU General Public 3338License in all respects for all software components except for those of 3339PDK PerlTray added by that program when used to create the Executable 3340Bundle. 3341 3342Disclaimer 3343 3344THIS SOFTWARE IS PROVIDED BY SOFTWARE GARDEN, INC., "AS IS" AND ANY 3345EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 3346WARRANTIES OF INFRINGEMENT AND THE IMPLIED WARRANTIES OF 3347MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 3348IN NO EVENT SHALL SOFTWARE GARDEN, INC. NOR ITS EMPLOYEES AND OFFICERS 3349BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 3350CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 3351SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 3352BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 3353WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 3354OTHERWISE) ARISING IN ANY WAY OUT OF THE DISTRIBUTION OR USE OF THIS 3355SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3356 3357Software Garden, Inc. 3358PO Box 610369 3359Newton Highlands, MA 02461 USA 3360www.softwaregarden.com 3361 3362License version: 1.4/2007-01-02 3363 3364=end 3365 3366=cut 3367