From: ivan Date: Thu, 27 Jan 2005 10:21:18 +0000 (+0000) Subject: DHTML progress bar for glacial rate adding and editing, closes: Bug#1100 X-Git-Tag: BEFORE_FINAL_MASONIZE~728 X-Git-Url: http://git.freeside.biz/gitweb/?p=freeside.git;a=commitdiff_plain;h=6cf964d0dc008621fb30fd2da28e2c44f29c6364 DHTML progress bar for glacial rate adding and editing, closes: Bug#1100 --- diff --git a/CREDITS b/CREDITS index 59edea610..02dd9a80c 100644 --- a/CREDITS +++ b/CREDITS @@ -113,7 +113,7 @@ Infostreet export. Richard Siddall sent in Mason fixes and other things I'm probably forgetting. -Contains "JS Calendar" v0.9.3 +Contains "JS Calendar" by Mihai Bazon licensed under the terms of the GNU LGPL. Latex invoice template based on a template from eBills @@ -137,5 +137,13 @@ released with 1.4.2beta1 and 1.5.0pre6. Troy Hammonds sent in RADIUS session history viewing code and other things I'm probably forgetting. +Contains the "Javascript Remote Scripting (JSRS)" client library + by Brent Ashley +licensed under the "No Nonsense Copyright and License" (see the included +JSRS-LICENSE file). + +Contains the QLIB JavaScript library by +Quazzle.com, Serge Dolgov, licensed under the terms of the GNU GPL. + Everything else is my (Ivan Kohler ) fault. diff --git a/FS/FS/UID.pm b/FS/FS/UID.pm index 3d893ee2f..c0c9f7af4 100644 --- a/FS/FS/UID.pm +++ b/FS/FS/UID.pm @@ -98,7 +98,7 @@ sub forksuidsetup { } sub myconnect { - $dbh = DBI->connect( getsecrets, {'AutoCommit' => 0, 'ChopBlanks' => 1, } ) + DBI->connect( getsecrets, {'AutoCommit' => 0, 'ChopBlanks' => 1, } ) or die "DBI->connect error: $DBI::errstr\n"; } diff --git a/FS/FS/queue.pm b/FS/FS/queue.pm index dcac3c62b..f42d99837 100644 --- a/FS/FS/queue.pm +++ b/FS/FS/queue.pm @@ -3,7 +3,7 @@ package FS::queue; use strict; use vars qw( @ISA @EXPORT_OK $DEBUG $conf $jobnums); use Exporter; -use FS::UID; +use FS::UID qw(myconnect); use FS::Conf; use FS::Record qw( qsearch qsearchs dbh ); #use FS::queue; @@ -15,7 +15,6 @@ use FS::cust_svc; @EXPORT_OK = qw( joblisting ); $DEBUG = 0; -#$DEBUG = 1; $FS::UID::callback{'FS::queue'} = sub { $conf = new FS::Conf; @@ -307,6 +306,38 @@ sub depended_delete { } } +=item update_statustext VALUE + +Updates the statustext value of this job to supplied value, in the database. +If there is an error, returns the error, otherwise returns false. + +=cut + +use vars qw($_update_statustext_dbh); +sub update_statustext { + my( $self, $statustext ) = @_; + return '' if $statustext eq $self->statustext; + warn "updating statustext for $self to $statustext" if $DEBUG; + + $_update_statustext_dbh ||= myconnect; + + my $sth = $_update_statustext_dbh->prepare( + 'UPDATE queue set statustext = ? WHERE jobnum = ?' + ) or return $_update_statustext_dbh->errstr; + + $sth->execute($statustext, $self->jobnum) or return $sth->errstr; + $_update_statustext_dbh->commit or die $_update_statustext_dbh->errstr; + $self->statustext($statustext); + ''; + + #my $new = new FS::queue { $self->hash }; + #$new->statustext($statustext); + #my $error = $new->replace($self); + #return $error if $error; + #$self->statustext($statustext); + #''; +} + =back =head1 SUBROUTINES diff --git a/FS/FS/rate.pm b/FS/FS/rate.pm index b8a694041..7f625a6b1 100644 --- a/FS/FS/rate.pm +++ b/FS/FS/rate.pm @@ -1,12 +1,14 @@ package FS::rate; use strict; -use vars qw( @ISA ); -use FS::Record qw( qsearch qsearchs dbh ); +use vars qw( @ISA $DEBUG ); +use FS::Record qw( qsearch qsearchs dbh fields ); use FS::rate_detail; @ISA = qw(FS::Record); +$DEBUG = 1; + =head1 NAME FS::rate - Object methods for rate records @@ -94,13 +96,32 @@ sub insert { } if ( $options{'rate_detail'} ) { + + my( $num, $last, $min_sec ) = (0, time, 5); #progressbar foo + foreach my $rate_detail ( @{$options{'rate_detail'}} ) { + $rate_detail->ratenum($self->ratenum); $error = $rate_detail->insert; if ( $error ) { $dbh->rollback if $oldAutoCommit; return $error; } + + if ( $options{'job'} ) { + $num++; + if ( time - $min_sec > $last ) { + my $error = $options{'job'}->update_statustext( + int( 100 * $num / scalar( @{$options{'rate_detail'}} ) ) + ); + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + $last = time; + } + } + } } @@ -148,8 +169,8 @@ sub replace { local $FS::UID::AutoCommit = 0; my $dbh = dbh; - my @old_rate_detail = (); - @old_rate_detail = $old->rate_detail if $options{'rate_detail'}; +# my @old_rate_detail = (); +# @old_rate_detail = $old->rate_detail if $options{'rate_detail'}; my $error = $new->SUPER::replace($old); if ($error) { @@ -157,21 +178,67 @@ sub replace { return $error; } - foreach my $old_rate_detail ( @old_rate_detail ) { - my $error = $old_rate_detail->delete; - if ($error) { +# foreach my $old_rate_detail ( @old_rate_detail ) { +# +# my $error = $old_rate_detail->delete; +# if ($error) { +# $dbh->rollback if $oldAutoCommit; +# return $error; +# } +# +# if ( $options{'job'} ) { +# $num++; +# if ( time - $min_sec > $last ) { +# my $error = $options{'job'}->update_statustext( +# int( 50 * $num / scalar( @old_rate_detail ) ) +# ); +# if ( $error ) { +# $dbh->rollback if $oldAutoCommit; +# return $error; +# } +# $last = time; +# } +# } +# +# } + if ( $options{'rate_detail'} ) { + my $sth = $dbh->prepare('DELETE FROM rate_detail WHERE ratenum = ?') or do { $dbh->rollback if $oldAutoCommit; - return $error; - } - } - - foreach my $rate_detail ( @{$options{'rate_detail'}} ) { - $rate_detail->ratenum($new->ratenum); - $error = $rate_detail->insert; - if ( $error ) { + return $dbh->errstr; + }; + + $sth->execute($old->ratenum) or do { $dbh->rollback if $oldAutoCommit; - return $error; + return $sth->errstr; + }; + + my( $num, $last, $min_sec ) = (0, time, 5); #progresbar foo +# $num = 0; + foreach my $rate_detail ( @{$options{'rate_detail'}} ) { + + $rate_detail->ratenum($new->ratenum); + $error = $rate_detail->insert; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + + if ( $options{'job'} ) { + $num++; + if ( time - $min_sec > $last ) { + my $error = $options{'job'}->update_statustext( + int( 100 * $num / scalar( @{$options{'rate_detail'}} ) ) + ); + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + $last = time; + } + } + } + } $dbh->commit or die $dbh->errstr if $oldAutoCommit; @@ -230,6 +297,120 @@ sub rate_detail { =back +=head1 SUBROUTINES + +=over 4 + +=item process + +Experimental job-queue processor for web interface adds/edits + +=cut + +sub process { + my $job = shift; + + #my %param = @_; + + my $param = shift; + my %param = split(/[;=]/, $param); + + my $old = qsearchs('rate', { 'ratenum' => $param{'ratenum'} } ) + if $param{'ratenum'}; + + my @rate_detail = map { + + my $regionnum = $_->regionnum; + if ( $param{"sec_granularity$regionnum"} ) { + + new FS::rate_detail { + 'dest_regionnum' => $regionnum, + map { $_ => $param{"$_$regionnum"} } + qw( min_included min_charge sec_granularity ) + }; + + } else { + + new FS::rate_detail { + 'dest_regionnum' => $regionnum, + 'min_included' => 0, + 'min_charge' => 0, + 'sec_granularity' => '60' + }; + + } + + } qsearch('rate_region', {} ); + + my $rate = new FS::rate { + map { $_ => $param{$_} } + fields('rate') + }; + + my $error = ''; + if ( $param{'ratenum'} ) { + warn "$rate replacing $old ($param{'ratenum'})\n" if $DEBUG; + $error = $rate->replace( $old, + 'rate_detail' => \@rate_detail, + 'job' => $job, + ); + } else { + warn "inserting $rate\n" if $DEBUG; + $error = $rate->insert( 'rate_detail' => \@rate_detail, + 'job' => $job, + ); + #$ratenum = $rate->getfield('ratenum'); + } + + die $error if $error; + +} + +# begin JSRPC code... + +package FS::rate::JSRPC; +use vars qw(@ISA $DEBUG); +use JavaScript::RPC::Server::CGI; +use FS::UID; +@ISA = qw( JavaScript::RPC::Server::CGI ); +$DEBUG = 1; + +sub process_rate { + my $self = shift; + + my %param = @_; + warn "FS::rate::JSRPC::process_rate\n". + join('', map " $_ => $param{$_}\n", keys %param ) + if $DEBUG; + + #progressbar prototype code... should be generalized + + #first get the CGI params shipped off to a job ASAP so an id can be returned + #to the caller + + my $job = new FS::queue { 'job' => 'FS::rate::process' }; + + #too slow to insert all the cgi params as individual args..,? + #my $error = $queue->insert('_JOB', $cgi->Vars); + + #my $bigstring = join(';', map { "$_=". scalar($cgi->param($_)) } $cgi->param ); + my $bigstring = join(';', map { "$_=". $param{$_} } keys %param ); + my $error = $job->insert('_JOB', $bigstring); + + if ( $error ) { + $error; + } else { + $job->jobnum; + } + +} + +sub get_new_query { + FS::UID::cgi(); +} + +# end JSRPC code... + =head1 BUGS =head1 SEE ALSO diff --git a/FS/bin/freeside-queued b/FS/bin/freeside-queued index e14ddad8e..a3fb7e562 100644 --- a/FS/bin/freeside-queued +++ b/FS/bin/freeside-queued @@ -87,7 +87,7 @@ while (1) { unless ( dbh && dbh->ping ) { warn "WARNING: connection to database lost, reconnecting...\n"; - eval { myconnect; }; + eval { $FS::UID::dbh = myconnect; }; unless ( !$@ && dbh && dbh->ping ) { warn "WARNING: still no connection to database, sleeping for retry...\n"; @@ -162,6 +162,7 @@ while (1) { #} my @args = $ljob->args; + splice @args, 0, 1, $ljob if $args[0] eq '_JOB'; defined( my $pid = fork ) or do { warn "WARNING: can't fork: $!\n"; @@ -184,8 +185,12 @@ while (1) { forksuidsetup($user); - #auto-use export classes... - if ( $ljob->job =~ /(FS::part_export::\w+)::/ ) { + #auto-use classes... + #if ( $ljob->job =~ /(FS::part_export::\w+)::/ ) { + if ( $ljob->job =~ /(FS::part_export::\w+)::/ + || $ljob->job =~ /(FS::\w+)::/ + ) + { my $class = $1; eval "use $class;"; if ( $@ ) { diff --git a/JSRS-LICENSE b/JSRS-LICENSE new file mode 100644 index 000000000..fd14984a9 --- /dev/null +++ b/JSRS-LICENSE @@ -0,0 +1,29 @@ + +No Nonsense Copyright and License for JSRS JavaScript Remote Scripting +====================================================================== + +Copyright: + +This JSRS stuff was written by me. I find it useful. Others find it useful. +You are welcome to use it, modify it to suit your needs, distribute it as you +see fit. I'm happy if you use it for personal stuff or for commercial gain. + +The only thing you can't do is to restrict anyone else from using it however +they see fit. You may not copyright it yourself or change the rules I have +set on how it can be used. + +JSRS Javascript Remote Scripting Copyright (C) 2001 by Brent Ashley + +License: + +You can use this however you like. I make no guarantees whatsoever that it +will suit your purpose. You take full responsibility for getting it working +properly and for any implications of its failure or inability to satisfy your +every need. + +====================================================================== + +email inquiries: jsrs@megahuge.com + + + diff --git a/httemplate/docs/install.html b/httemplate/docs/install.html index 86e2a6b8c..898eb9ef8 100644 --- a/httemplate/docs/install.html +++ b/httemplate/docs/install.html @@ -58,6 +58,7 @@ Before installing, you need:
  • NetAddr-IP
  • Chart
  • Crypt::PasswdMD5 +
  • JavaScript::RPC (JavaScript::RPC::Server::CGI)
  • Apache::DBI (optional but recommended for better webinterface performance) diff --git a/httemplate/edit/process/rate.cgi b/httemplate/edit/process/rate.cgi new file mode 100755 index 000000000..df7c4672e --- /dev/null +++ b/httemplate/edit/process/rate.cgi @@ -0,0 +1,4 @@ +<% +my $server = new FS::rate::JSRPC; +$server->process; +%> diff --git a/httemplate/edit/rate.cgi b/httemplate/edit/rate.cgi index 4a4b70ea3..3443f81d4 100644 --- a/httemplate/edit/rate.cgi +++ b/httemplate/edit/rate.cgi @@ -1,52 +1,7 @@ <% -my($rate, $error); - -if ( $cgi->param('magic') eq 'process' ) { - - my $ratenum = $cgi->param('ratenum'); - - my $old = qsearchs('rate', { 'ratenum' => $ratenum } ) if $ratenum; - - my @rate_detail = map { - my $regionnum = $_->regionnum; - if ( $cgi->param("sec_granularity$regionnum") ) { - new FS::rate_detail { - 'dest_regionnum' => $regionnum, - map { $_ => scalar($cgi->param("$_$regionnum")) } - qw( min_included min_charge sec_granularity ) - }; - } else { - new FS::rate_detail { - 'dest_regionnum' => $regionnum, - 'min_included' => 0, - 'min_charge' => 0, - 'sec_granularity' => '60' - }; - } - } qsearch('rate_region', {} ); - - $rate = new FS::rate ( { - map { - $_, scalar($cgi->param($_)); - } fields('rate') - } ); - - if ( $ratenum ) { - warn "$rate replacing $old ($ratenum)\n"; - $error = $rate->replace($old, 'rate_detail' => \@rate_detail ); - } else { - warn "inserting $rate\n"; - $error = $rate->insert( 'rate_detail' => \@rate_detail ); - $ratenum = $rate->getfield('ratenum'); - } - - unless ( $error ) { - print $cgi->redirect("${p}browse/rate.cgi"); - myexit; - } - -} elsif ( $cgi->keywords ) { +my $rate; +if ( $cgi->keywords ) { my($query) = $cgi->keywords; $query =~ /^(\d+)$/; $rate = qsearchs( 'rate', { 'ratenum' => $1 } ); @@ -77,12 +32,41 @@ END )) %> -<% if ( $error ) { %> -Error: <%= $error %>
    -<% } %> + + + + -
    - + Rate plan @@ -135,11 +119,12 @@ Rate plan -
    "> -Please be patient, <%= $rate->ratenum ? 'editing' : 'adding' %> -a rate plan can take a few minutes... +%>" onClick="document.OneTrueForm.submit.disabled=true; process();"> +Please make sure to allow popups from this site in order to view the progress window. +
    diff --git a/httemplate/elements/jsrsClient.js b/httemplate/elements/jsrsClient.js new file mode 100644 index 000000000..3a2572ccb --- /dev/null +++ b/httemplate/elements/jsrsClient.js @@ -0,0 +1,356 @@ +// +// jsrsClient.js - javascript remote scripting client include +// +// Author: Brent Ashley [jsrs@megahuge.com] +// +// make asynchronous remote calls to server without client page refresh +// +// see license.txt for copyright and license information + +/* +see history.txt for full history +2.0 26 Jul 2001 - added POST capability for IE/MOZ +2.2 10 Aug 2003 - added Opera support +2.3(beta) 10 Oct 2003 - added Konqueror support - **needs more testing** +*/ + +// callback pool needs global scope +var jsrsContextPoolSize = 0; +var jsrsContextMaxPool = 10; +var jsrsContextPool = new Array(); +var jsrsBrowser = jsrsBrowserSniff(); +var jsrsPOST = true; +var containerName; + +// constructor for context object +function jsrsContextObj( contextID ){ + + // properties + this.id = contextID; + this.busy = true; + this.callback = null; + this.container = contextCreateContainer( contextID ); + + // methods + this.GET = contextGET; + this.POST = contextPOST; + this.getPayload = contextGetPayload; + this.setVisibility = contextSetVisibility; +} + +// method functions are not privately scoped +// because Netscape's debugger chokes on private functions +function contextCreateContainer( containerName ){ + // creates hidden container to receive server data + var container; + switch( jsrsBrowser ) { + case 'NS': + container = new Layer(100); + container.name = containerName; + container.visibility = 'hidden'; + container.clip.width = 100; + container.clip.height = 100; + break; + + case 'IE': + document.body.insertAdjacentHTML( "afterBegin", '' ); + var span = document.all( "SPAN" + containerName ); + var html = ''; + span.innerHTML = html; + span.style.display = 'none'; + container = window.frames[ containerName ]; + break; + + case 'MOZ': + var span = document.createElement('SPAN'); + span.id = "SPAN" + containerName; + document.body.appendChild( span ); + var iframe = document.createElement('IFRAME'); + iframe.name = containerName; + iframe.id = containerName; + span.appendChild( iframe ); + container = iframe; + break; + + case 'OPR': + var span = document.createElement('SPAN'); + span.id = "SPAN" + containerName; + document.body.appendChild( span ); + var iframe = document.createElement('IFRAME'); + iframe.name = containerName; + iframe.id = containerName; + span.appendChild( iframe ); + container = iframe; + break; + + case 'KONQ': + var span = document.createElement('SPAN'); + span.id = "SPAN" + containerName; + document.body.appendChild( span ); + var iframe = document.createElement('IFRAME'); + iframe.name = containerName; + iframe.id = containerName; + span.appendChild( iframe ); + container = iframe; + + // Needs to be hidden for Konqueror, otherwise it'll appear on the page + span.style.display = none; + iframe.style.display = none; + iframe.style.visibility = hidden; + iframe.height = 0; + iframe.width = 0; + + break; + } + return container; +} + +function contextPOST( rsPage, func, parms ){ + + var d = new Date(); + var unique = d.getTime() + '' + Math.floor(1000 * Math.random()); + var doc = (jsrsBrowser == "IE" ) ? this.container.document : this.container.contentDocument; + doc.open(); + doc.write(''); + doc.write('
    '); + doc.write(''); + + // func and parms are optional + if (func != null){ + doc.write(''); + + if (parms != null){ + if (typeof(parms) == "string"){ + // single parameter + doc.write( ''); + } else { + // assume parms is array of strings + for( var i=0; i < parms.length; i++ ){ + doc.write( ''); + } + } // parm type + } // parms + } // func + + doc.write('
    '); + doc.close(); + doc.forms['jsrsForm'].submit(); +} + +function contextGET( rsPage, func, parms ){ + + // build URL to call + var URL = rsPage; + + // always send context + URL += "?C=" + this.id; + + // func and parms are optional + if (func != null){ + URL += "&F=" + escape(func); + + if (parms != null){ + if (typeof(parms) == "string"){ + // single parameter + URL += "&P0=[" + escape(parms+'') + "]"; + } else { + // assume parms is array of strings + for( var i=0; i < parms.length; i++ ){ + URL += "&P" + i + "=[" + escape(parms[i]+'') + "]"; + } + } // parm type + } // parms + } // func + + // unique string to defeat cache + var d = new Date(); + URL += "&U=" + d.getTime(); + + // make the call + switch( jsrsBrowser ) { + case 'NS': + this.container.src = URL; + break; + case 'IE': + this.container.document.location.replace(URL); + break; + case 'MOZ': + this.container.src = ''; + this.container.src = URL; + break; + case 'OPR': + this.container.src = ''; + this.container.src = URL; + break; + case 'KONQ': + this.container.src = ''; + this.container.src = URL; + break; + } +} + +function contextGetPayload(){ + switch( jsrsBrowser ) { + case 'NS': + return this.container.document.forms['jsrs_Form'].elements['jsrs_Payload'].value; + case 'IE': + return this.container.document.forms['jsrs_Form']['jsrs_Payload'].value; + case 'MOZ': + return window.frames[this.container.name].document.forms['jsrs_Form']['jsrs_Payload'].value; + case 'OPR': + var textElement = window.frames[this.container.name].document.getElementById("jsrs_Payload"); + case 'KONQ': + var textElement = window.frames[this.container.name].document.getElementById("jsrs_Payload"); + return textElement.value; + } +} + +function contextSetVisibility( vis ){ + switch( jsrsBrowser ) { + case 'NS': + this.container.visibility = (vis)? 'show' : 'hidden'; + break; + case 'IE': + document.all("SPAN" + this.id ).style.display = (vis)? '' : 'none'; + break; + case 'MOZ': + document.getElementById("SPAN" + this.id).style.visibility = (vis)? '' : 'hidden'; + case 'OPR': + document.getElementById("SPAN" + this.id).style.visibility = (vis)? '' : 'hidden'; + this.container.width = (vis)? 250 : 0; + this.container.height = (vis)? 100 : 0; + break; + } +} + +// end of context constructor + +function jsrsGetContextID(){ + var contextObj; + for (var i = 1; i <= jsrsContextPoolSize; i++){ + contextObj = jsrsContextPool[ 'jsrs' + i ]; + if ( !contextObj.busy ){ + contextObj.busy = true; + return contextObj.id; + } + } + // if we got here, there are no existing free contexts + if ( jsrsContextPoolSize <= jsrsContextMaxPool ){ + // create new context + var contextID = "jsrs" + (jsrsContextPoolSize + 1); + jsrsContextPool[ contextID ] = new jsrsContextObj( contextID ); + jsrsContextPoolSize++; + return contextID; + } else { + alert( "jsrs Error: context pool full" ); + return null; + } +} + +function jsrsExecute( rspage, callback, func, parms, visibility ){ + // call a server routine from client code + // + // rspage - href to asp file + // callback - function to call on return + // or null if no return needed + // (passes returned string to callback) + // func - sub or function name to call + // parm - string parameter to function + // or array of string parameters if more than one + // visibility - optional boolean to make container visible for debugging + + // get context + var contextObj = jsrsContextPool[ jsrsGetContextID() ]; + contextObj.callback = callback; + + var vis = (visibility == null)? false : visibility; + contextObj.setVisibility( vis ); + + if ( jsrsPOST && ((jsrsBrowser == 'IE') || (jsrsBrowser == 'MOZ'))){ + contextObj.POST( rspage, func, parms ); + } else { + contextObj.GET( rspage, func, parms ); + } + + return contextObj.id; +} + +function jsrsLoaded( contextID ){ + // get context object and invoke callback + var contextObj = jsrsContextPool[ contextID ]; + if( contextObj.callback != null){ + contextObj.callback( jsrsUnescape( contextObj.getPayload() ), contextID ); + } + // clean up and return context to pool + contextObj.callback = null; + contextObj.busy = false; +} + +function jsrsError( contextID, str ){ + alert( unescape(str) ); + jsrsContextPool[ contextID ].busy = false +} + +function jsrsEscapeQQ( thing ){ + return thing.replace(/'"'/g, '\\"'); +} + +function jsrsUnescape( str ){ + // payload has slashes escaped with whacks + return str.replace( /\\\//g, "/" ); +} + +function jsrsBrowserSniff(){ + if (document.layers) return "NS"; + if (document.all) { + // But is it really IE? + // convert all characters to lowercase to simplify testing + var agt=navigator.userAgent.toLowerCase(); + var is_opera = (agt.indexOf("opera") != -1); + var is_konq = (agt.indexOf("konqueror") != -1); + if(is_opera) { + return "OPR"; + } else { + if(is_konq) { + return "KONQ"; + } else { + // Really is IE + return "IE"; + } + } + } + if (document.getElementById) return "MOZ"; + return "OTHER"; +} + +///////////////////////////////////////////////// +// +// user functions + +function jsrsArrayFromString( s, delim ){ + // rebuild an array returned from server as string + // optional delimiter defaults to ~ + var d = (delim == null)? '~' : delim; + return s.split(d); +} + +function jsrsDebugInfo(){ + // use for debugging by attaching to f1 (works with IE) + // with onHelp = "return jsrsDebugInfo();" in the body tag + var doc = window.open().document; + doc.open; + doc.write( 'Pool Size: ' + jsrsContextPoolSize + '
    ' ); + for( var i in jsrsContextPool ){ + var contextObj = jsrsContextPool[i]; + doc.write( '
    ' + contextObj.id + ' : ' + (contextObj.busy ? 'busy' : 'available') + '
    '); + doc.write( contextObj.container.document.location.pathname + '
    '); + doc.write( contextObj.container.document.location.search + '
    '); + doc.write( '
    ' + contextObj.container.document.body.innerHTML + '
    ' ); + } + doc.write(''); + doc.close(); + return false; +} diff --git a/httemplate/elements/qlib/box.js b/httemplate/elements/qlib/box.js new file mode 100644 index 000000000..537aac4c8 --- /dev/null +++ b/httemplate/elements/qlib/box.js @@ -0,0 +1,29 @@ +/** + * QLIB 1.0 Box Control + * Copyright (C) 2002 2003, Quazzle.com Serge Dolgov + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * http://qlib.quazzle.com + */ + +function QBox(parent, name, res, x, y, width, height, body, visible, effects, opacity, zindex) { + this.init(parent, name); + if (this.res = res) { + this.x = x - 0; + this.y = y - 0; + this.width = width - 0; + this.height = (typeof(height) == "number") ? height : null; + this.body = body || " "; + var j = QBox.arguments.length; + this.visible = (j > 8) ? visible : true; + this.effects = (j > 9) ? effects : (res.effects || 0); + this.opacity = (j > 10) ? opacity : (res.opacity != null ? res.opacity : 100); + this.zindex = (j > 11) ? zindex : null; + this.create(); + } else { + this.document.write("invalid resource"); + } +} +QBox.prototype = new QBoxCtrl(); diff --git a/httemplate/elements/qlib/boxctrl.js b/httemplate/elements/qlib/boxctrl.js new file mode 100644 index 000000000..417b204e4 --- /dev/null +++ b/httemplate/elements/qlib/boxctrl.js @@ -0,0 +1,48 @@ +/** + * QLIB 1.0 Box Abstraction + * Copyright (C) 2002 2003, Quazzle.com Serge Dolgov + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * http://qlib.quazzle.com + */ + +function QBoxCtrl_content() { + with (this) { + if (res) { + this.cwidth = width - res.L - res.R - 8; + this.cheight = height && (height - res.T - res.B - 8); + var ec = '">
    '; + document.write('
    '); + if (typeof(body) == "function") { + this.body(); + } else { + document.write(body); + } + document.write('

    '); + } + } +} + +function QBoxCtrl() { + this.res = false; + this.body = " "; + this.cwidth = this.cheight = 0; + this.content = QBoxCtrl_content; +} +QBoxCtrl.prototype = new QWndCtrl(); diff --git a/httemplate/elements/qlib/boxres.js b/httemplate/elements/qlib/boxres.js new file mode 100644 index 000000000..087817211 --- /dev/null +++ b/httemplate/elements/qlib/boxres.js @@ -0,0 +1,42 @@ +/** + * QLIB 1.0 Box Resource + * Copyright (C) 2002 2003, Quazzle.com Serge Dolgov + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * http://qlib.quazzle.com + */ + +function QBoxRes(t, r, b, l, tc, tr, mr, br, bc, bl, ml, tl, bgcolor, bgtile, effects, opacity) { + var args = QBoxRes.arguments.length; + this.T = t; + this.R = r; + this.B = b; + this.L = l; + this.TC = new Image(); + this.TC.src = tc; + this.TR = new Image(r, t); + this.TR.src = tr; + this.MR = new Image(); + this.MR.src = mr; + this.BR = new Image(r, b); + this.BR.src = br; + this.BC = new Image(); + this.BC.src = bc; + this.BL = new Image(l, b); + this.BL.src = bl; + this.ML = new Image(); + this.ML.src = ml; + this.TL = new Image(l, t); + this.TL.src = tl; + this.bgcolor = bgcolor || "#FFFFFF"; + if (bgtile) { + this.bgtile = new Image(); + this.bgtile.src = bgtile; + } else { + this.bgtile = false; + } + this.effects = (args > 13) ? effects : null; + this.opacity = (args > 14) ? opacity : null; +} diff --git a/httemplate/elements/qlib/button.js b/httemplate/elements/qlib/button.js new file mode 100644 index 000000000..05247d5f8 --- /dev/null +++ b/httemplate/elements/qlib/button.js @@ -0,0 +1,74 @@ +/** + * QLIB 1.0 Button Control + * Copyright (C) 2002 2003, Quazzle.com Serge Dolgov + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * http://qlib.quazzle.com + */ + +function QButton_update() { + with (this) { + image.src = ((!enabled && res.imgD) || (value ? res.imgP : res.imgN)).src; + } +} + +function QButton_doEvent() { + with (this) { + if (enabled) { + if (res.style == 1) { + this.value = value ? 0 : 1; + update(); + } + onClick(value, tag); + } + } + return false; +} + +function QButton_enable(state) { + this.enabled = state; + this.update(); +} + +function QButton_set(value) { + if (this.enabled) { + this.value = value ? 1 : 0; + this.update(); + } + return true; +} + +function QButton(parent, name, res, tooltip) { + this.init(parent, name); + if (res) { + this.res = res; + this.tip = tooltip || ""; + this.enabled = true; + this.value = 0; + this.set = QButton_set; + this.enable = QButton_enable; + this.update = QButton_update; + this.doEvent = QButton_doEvent; + this.onClick = QControl.event; + with (this) { + document.write(''); + this.image = document.images[id] || new Image(1, 1); + } + } else { + this.document.write("invalid resource"); + } +} +QButton.prototype = new QControl(); +QButton.NORMAL = 0; +QButton.CHECKBOX = 1; +QButton.WEB = 2; +QButton.SIGNAL = 3; diff --git a/httemplate/elements/qlib/buttonres.js b/httemplate/elements/qlib/buttonres.js new file mode 100644 index 000000000..97f6dfccc --- /dev/null +++ b/httemplate/elements/qlib/buttonres.js @@ -0,0 +1,23 @@ +/** + * QLIB 1.0 Button Resource + * Copyright (C) 2002 2003, Quazzle.com Serge Dolgov + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * http://qlib.quazzle.com + */ + +function QButtonRes(style, width, height, normal, pressed, disabled) { + this.style = style; + this.width = width; + this.height = height; + this.imgN = new Image(width, height); + this.imgN.src = normal; + this.imgP = new Image(width, height); + this.imgP.src = pressed; + if (disabled) { + this.imgD = new Image(width, height); + this.imgD.src = disabled; + } +} diff --git a/httemplate/elements/qlib/control.js b/httemplate/elements/qlib/control.js new file mode 100644 index 000000000..f50206e27 --- /dev/null +++ b/httemplate/elements/qlib/control.js @@ -0,0 +1,51 @@ +/** + * QLIB 1.0 Base Abstract Control + * Copyright (C) 2002 2003, Quazzle.com Serge Dolgov + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * http://qlib.quazzle.com + */ + +function QControl_init(parent, name) { + this.parent = parent || self; + this.window = (parent && parent.window) || self; + this.document = (parent && parent.document) || self.document; + this.name = (parent && parent.name) ? (parent.name + "." + name) : ("self." + name); + this.id = "Q"; + var h = this.hash(this.name); + for (var j=0; j<8; j++) { + this.id += QControl.HEXTABLE.charAt(h & 15); + h >>>= 4; + } +} + +function QControl_hash(str) { + var h = 0; + if (str) { + for (var j=str.length-1; j>=0; j--) { + h ^= QControl.ANTABLE.indexOf(str.charAt(j)) + 1; + for (var i=0; i<3; i++) { + var m = (h = h<<7 | h>>>25) & 150994944; + h ^= m ? (m == 150994944 ? 1 : 0) : 1; + } + } + } + return h; +} + +function QControl_nop() { +} + +function QControl() { + this.init = QControl_init; + this.hash = QControl_hash; + this.window = self; + this.document = self.document; + this.tag = null; +} +QControl.ANTABLE = "w5Q2KkFts3deLIPg8Nynu_JAUBZ9YxmH1XW47oDpa6lcjMRfi0CrhbGSOTvqzEV"; +QControl.HEXTABLE = "0123456789ABCDEF"; +QControl.nop = QControl_nop; +QControl.event = QControl_nop; diff --git a/httemplate/elements/qlib/counter.js b/httemplate/elements/qlib/counter.js new file mode 100644 index 000000000..72aeddbdb --- /dev/null +++ b/httemplate/elements/qlib/counter.js @@ -0,0 +1,81 @@ +/** + * QLIB 1.0 Animated Digital Counter + * Copyright (C) 2002 2003, Quazzle.com Serge Dolgov + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * http://qlib.quazzle.com + */ + +function QCounter_update() { + with (this) { + var v = Math.max(value, 0); + var mod; + for (var j=0; j= 1) || (!j) ? res.list[mod].src : res.list[10].src; + v /= 10; + } + } +} + +function QCounter_count(value, step) { + this._cntt = false; + this.value += step; + if ((step * (this.value - value)) >= 0) { + this.value = value - 0; // convert to number + } else { + this._cntt = setTimeout(this.name + ".count(" + value + "," + step + ")", 50); + } + this.update(); +} + +function QCounter_set(value) { + this.setval = value; + if (value != this.value) { + if (this._cntt) { + clearTimeout(this._cntt); + this._cntt = false; + } + var dv = value - this.value; + if (this.effect == 2) { + dv = dv / Math.min(10, Math.abs(dv)); + } else if (this.effect == 3) { + dv = dv / Math.abs(dv); + } + this.count(value, dv); + } +} + +function QCounter(parent, name, res, size, effect) { + this.init(parent, name); + if (res) { + this.res = res; + this.setval = this.value = 0; + this.size = size || 4; + this.effect = effect || 2; + this._cntt = false; + this.images = new Array(this.size); + this.set = QCounter_set; + this.update = QCounter_update; + this.count = QCounter_count; + with (this) { + document.write(''); + for (var j=(size - 1); j>=0; j--) { + document.write(''); + images[j] = document.images[id + j] || new Image(1, 1); + } + document.write('
    '); + } + } else { + this.document.write("invalid resource"); + } +} +QCounter.prototype = new QControl(); +QCounter.INSTANT = 1; +QCounter.FAST = 2; +QCounter.SLOW = 3; diff --git a/httemplate/elements/qlib/imagelist.js b/httemplate/elements/qlib/imagelist.js new file mode 100644 index 000000000..9f12de053 --- /dev/null +++ b/httemplate/elements/qlib/imagelist.js @@ -0,0 +1,25 @@ +/** + * QLIB 1.0 ImageList Resource + * Copyright (C) 2002 2003, Quazzle.com Serge Dolgov + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * http://qlib.quazzle.com + */ + +function QImageList(width, height) { + var len = QImageList.arguments.length - 2; + if (len > 0) { + this.list = new Array(len); + this.length = len; + this.width = width; + this.height = height; + var im; + for (var j=0; j' + (clickable ? '' + value + '' : value) + ''); + document.close(); + } +} + +function QLabel_doEvent() { + this.onClick(this.value, this.tag); + return false; +} + +function QLabel(parent, name, value, clickable, tooltip) { + this.init(parent, name); + this.value = value || ""; + this.clickable = clickable || false; + this.tooltip = tooltip || ""; + this.doEvent = QLabel_doEvent; + this.onClick = QControl.event; + with (this) { + if (document.getElementById || document.all) { + document.write(clickable ? '' : '
    ' + + (value || ' ') + '
    '); + this.label = document.getElementById ? document.getElementById(id) : + (document.all.item ? document.all.item(id) : document.all[id]); + this.set = (label && (label.innerText ? QLabel_set_ie : + (label.replaceChild && QLabel_set_dom2))) || QControl.nop; + } else if (document.layers) { + var suffix = ""; + for (var j=value.length; j
    ' + + (clickable ? '' + value + suffix + '' : + value + suffix) + '
    '); + this.label = (this.label = document.layers["i" + id]) && label.document.layers[id]; + this.document = label && label.document; + this.set = (label && document) ? QLabel_set_ns4 : QControl.nop; + } else { + document.write("Object is not supported"); + } + } +} +QLabel.prototype = new QControl(); +QLabel.TEXTQUOTA = 50; diff --git a/httemplate/elements/qlib/messagebox.js b/httemplate/elements/qlib/messagebox.js new file mode 100644 index 000000000..2e458393d --- /dev/null +++ b/httemplate/elements/qlib/messagebox.js @@ -0,0 +1,57 @@ +/** + * QLIB 1.0 Message Box Control + * Copyright (C) 2002 2003, Quazzle.com Serge Dolgov + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * http://qlib.quazzle.com + */ + +function QMessageBox_alert(msg) { + if (typeof(msg) == "string") { + this.label.set(this.value = msg); + } + this.center(); + this.focus(); + this.show(true); +} + +function QMessageBox_close() { + with (this.parent) { + if (!onClose(tag)) show(false); + } +} + +function QMessageBox_body() { + with (this) { + document.write('
    '); + this.label = new QLabel(this, "label", value); + document.write('
    '); + this.button = new QButton(this, "button", bres, "Close"); + document.write('
    '); + button.onClick = QMessageBox_close; + } +} + +function QMessageBox(parent, name, box, btn, msg, effects, opacity) { + this.init(parent, name); + if ((this.res = box) && (this.bres = btn)) { + this.value = typeof(msg) == "string" ? msg : ""; + this.width = Math.max(200, Math.floor(Math.sqrt(555 * this.value.length))); + this.height = null; + this.x = this.y = 0; + this.visible = false; + this.zindex = null; + this.body = QMessageBox_body; + var j = QMessageBox.arguments.length; + this.effects = j > 5 ? effects : (box.effects != null ? box.effects : 0); + this.opacity = j > 6 ? opacity : (box.opacity != null ? box.opacity : 100); + this.create(); + this.alert = QMessageBox_alert; + this.onClose = QControl.event; + } else { + this.document.write("invalid resource"); + } +} +QMessageBox.prototype = new QBoxCtrl(); diff --git a/httemplate/elements/qlib/progress.js b/httemplate/elements/qlib/progress.js new file mode 100644 index 000000000..2de077eac --- /dev/null +++ b/httemplate/elements/qlib/progress.js @@ -0,0 +1,73 @@ +/** + * QLIB 1.0 Progress Control + * Copyright (C) 2002 2003, Quazzle.com Serge Dolgov + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * http://qlib.quazzle.com + */ + +function QProgress_update() { + with (this) { + var i = low; + for (var j=0; j' : 'width="' + res.width + + '" height="' + (size * res.height) + '">')); + for (var j=0; j') + '' + (hor ? '' : '')); + } + document.write((hor ? '' : '') + ''); + for (var j=0; j'); + if (document.all && document.all.item) { + this._out = document.all.item(id); + if (_out && (typeof _out.src != "undefined") && (_out.volume === volume)) { + document.write(''); + this._buf = document.all.item("b" + id); + if (_buf) { + this.play = QSound_play; + this.stop = QSound_stop; + this.setVolume = QSound_setVolume; + + _out.onreadystatechange = new Function("alert(0)"); + } + } + } + } +} +QSound.prototype = new QControl(); diff --git a/httemplate/elements/qlib/sprite.js b/httemplate/elements/qlib/sprite.js new file mode 100644 index 000000000..72a68fb7c --- /dev/null +++ b/httemplate/elements/qlib/sprite.js @@ -0,0 +1,125 @@ +/** + * QLIB 1.0 Sprite Object + * Copyright (C) 2002 2003, Quazzle.com Serge Dolgov + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * http://qlib.quazzle.com + */ + +function QSprite_load(src) { + if (src) { + this.face = new Image(this.cwidth, this.cheight); + this.face.src = src; + this.valid = false; + } +} + +function QSprite_show(show) { + if (show && !this.valid && this.face.complete) { + this._img.src = this.face.src; + this.valid = true; + } + this._show(show); +} + +function QSprite_moveTo(x, y) { + this.stop(); + this._move(x, y); +} + +function QSprite_slideTo(x, y) { + this.stop(); + if (this.visible) { + this.doSlide(++this._spro, x, y); + } else { + this.moveTo(x, y); + } +} + +function QSprite_shake() { + this.stop(); + if (this.visible) { + this.doShake(++this._spro, 0, this.x, this.y); + } +} + +function QSprite_stop() { + this._spro++; + if (this._sprt) { + clearTimeout(this._sprt); + this._sprt = false; + } +} + +function QSprite_doSlide(id, x, y) { + if (this._spro == id) { + this._sprt = false; + var dx = Math.round(x - this.x); + var dy = Math.round(y - this.y); + if (dx || dy) { + if (dx) dx = dx > 0 ? Math.ceil(dx/4) : Math.floor(dx/4); + if (dy) dy = dy > 0 ? Math.ceil(dy/4) : Math.floor(dy/4); + this._move(this.x + dx, this.y + dy); + this._sprt = setTimeout(this.name + ".doSlide(" + id + "," + x + "," + y + ")", 30); + } else { + this._move(x, y); + } + } +} + +function QSprite_doShake(id, phase, x, y) { + if (this._spro == id) { + this._sprt = false; + if (phase < 20) { + var m = 3 * Math.sin(.16 * phase); + this._move(x + m * Math.sin(phase), y + m * Math.cos(phase)); + this._sprt = setTimeout(this.name + ".doShake(" + id + "," + (++phase) + "," + x + "," + y + ")", 20); + } else { + this._move(x, y); + } + } +} + +function QSprite_doClick() { + if (!this._sprt) { + this.onClick(this.tag); + } + return false; +} + +function QSprite(parent, name, x, y, width, height, src, visible, effects, opacity, zindex) { + this.init(parent, name); + this.x = x - 0; + this.y = y - 0; + this.width = (this.cwidth = width - 0) + 8; + this.height = (this.cheight = height - 0) + 8; + var j = QSprite.arguments.length; + this.visible = (j > 7) ? visible : true; + this.effects = (j > 8) ? effects : 0; + this.opacity = (j > 9) ? opacity : 100; + this.zindex = (j > 10) ? zindex : null; + this.valid = !!src; + this.content = ''; + this.doClick = QSprite_doClick; + this.doSlide = QSprite_doSlide; + this.doShake = QSprite_doShake; + this.onClick = QControl.event; + this.create(); + this.face = this._img = this.document.images[this.id] || new Image(1, 1); + this._spro = 0; + this._sprt = false; + this._show = this.show; + this._move = this.moveTo; + this.load = QSprite_load; + this.show = QSprite_show; + this.moveTo = QSprite_moveTo; + this.slideTo = QSprite_slideTo; + this.shake = QSprite_shake; + this.stop = QSprite_stop; +} +QSprite.prototype = new QWndCtrl(); diff --git a/httemplate/elements/qlib/window.js b/httemplate/elements/qlib/window.js new file mode 100644 index 000000000..6056fda9b --- /dev/null +++ b/httemplate/elements/qlib/window.js @@ -0,0 +1,25 @@ +/** + * QLIB 1.0 Window Control + * Copyright (C) 2002 2003, Quazzle.com Serge Dolgov + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * http://qlib.quazzle.com + */ + +function QWindow(parent, name, x, y, width, height, content, visible, effects, opacity, zindex) { + this.init(parent, name); + this.x = x - 0; + this.y = y - 0; + this.width = width - 0; + this.height = (typeof(height) == "number") ? height : null; + this.content = content; + var j = QWindow.arguments.length; + this.visible = (j > 7) ? visible : true; + this.effects = (j > 8) ? effects : 0; + this.opacity = (j > 9) ? opacity : 100; + this.zindex = (j > 10) ? zindex : null; + this.create(); +} +QWindow.prototype = new QWndCtrl(); diff --git a/httemplate/elements/qlib/wndctrl.js b/httemplate/elements/qlib/wndctrl.js new file mode 100644 index 000000000..b3bde4e92 --- /dev/null +++ b/httemplate/elements/qlib/wndctrl.js @@ -0,0 +1,322 @@ +/** + * QLIB 1.0 Window Abstraction + * Copyright (C) 2002 2003, Quazzle.com Serge Dolgov + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * http://qlib.quazzle.com + */ + +function QWndCtrl_center_ie4() { + var b = this.document.body; + this.moveTo(b.scrollLeft + Math.max(0, Math.floor((b.clientWidth - + this.width) / 2)), b.scrollTop + 100); +} + +function QWndCtrl_center_moz() { + this.moveTo(self.pageXOffset + Math.max(0, Math.floor((self.innerWidth - + this.width) / 2)), self.pageYOffset + 100); +} + +function QWndCtrl_setEffects_ie4(fx) { + this.effects = fx; + with (this.wnd) { + filters[0].enabled = (fx & 256) != 0; + filters[1].enabled = (fx & 512) != 0; + filters[2].enabled = (fx & 1024) != 0; + filters[4].enabled = (fx & 2048) != 0; + } +} + +function QWndCtrl_setEffects_moz(fx) { + this.effects = fx; +} + +function QWndCtrl_setOpacity_ie4(op) { + this.opacity = Math.max(0, Math.min(100, Math.floor(op - 0))); + this.wnd.filters[3].opacity = this.opacity; + this.wnd.filters[3].enabled = (this.opacity < 100); +} + +function QWndCtrl_setOpacity_moz(op) { + this.opacity = Math.max(0, Math.min(100, Math.floor(op - 0))); + this.wnd.style.MozOpacity = this.opacity + "%"; +} + +function QWndCtrl_setSize_css(w, h) { + this.wnd.style.width = (this.width = Math.floor(w - 0)) + "px"; + this.wnd.style.height = typeof(h) == "number" ? (this.height = Math.floor(h)) + "px" : "auto"; +} + +function QWndCtrl_setSize_ns4(w, h) { + this.wnd.clip.width = this.width = Math.floor(w - 0); + if (typeof(h) == "number") { + this.wnd.clip.height = this.height = Math.floor(h); + } +} + +function QWndCtrl_focus() { + this.setZIndex(QWndCtrl.TOPZINDEX++); +} + +function QWndCtrl_setZIndex_css(z) { + this.wnd.style.zIndex = this.zindex = z || 0; +} + +function QWndCtrl_setZIndex_ns4(z) { + this.wnd.zIndex = this.zindex = z || 0; +} + +function QWndCtrl_moveTo_css(x, y) { + this.wnd.style.left = (this.x = Math.floor(x - 0)) + "px"; + this.wnd.style.top = (this.y = Math.floor(y - 0)) + "px"; +} + +function QWndCtrl_moveTo_ns4(x, y) { + this.wnd.moveTo(this.x = Math.floor(x - 0), this.y = Math.floor(y - 0)); +} + +function QWndCtrl_fxhandler() { + this.fxhandler = QControl.nop; + this.onShow(this.visible, this.tag); +} + +function QWndCtrl_show_ie4(show) { + if (this.visible != show) { + var fx = false; + switch (show ? this.effects & 15 : (this.effects & 240) >>> 4) { + case 1: + fx = this.wnd.filters[5]; + break; + case 2: + (fx = this.wnd.filters[6]).transition = show ? 1 : 0; + break; + case 3: + (fx = this.wnd.filters[6]).transition = show ? 3 : 2; + break; + case 4: + (fx = this.wnd.filters[6]).transition = show ? 5 : 4; + break; + case 5: + (fx = this.wnd.filters[6]).transition = show ? 14 : 13; + break; + case 6: + (fx = this.wnd.filters[6]).transition = show ? 16 : 15; + break; + case 7: + (fx = this.wnd.filters[6]).transition = 12; + break; + case 8: + (fx = this.wnd.filters[6]).transition = 8; + break; + case 9: + (fx = this.wnd.filters[6]).transition = 9; + } + if (fx) { + fx.apply(); + this.wnd.style.visibility = (this.visible = show) ? "visible" : "hidden"; + this.fxhandler = QWndCtrl_fxhandler; + fx.play(0.3); + } else { + this.wnd.style.visibility = (this.visible = show) ? "visible" : "hidden"; + this.onShow(show, this.tag); + } + } +} + +function QWndCtrl_fade_moz(op, step) { + this._wndt = false; + if (step) { + op += step; + if ((op > 0) && (op < this.opacity)) { + this.wnd.style.MozOpacity = op + "%"; + this._wndt = setTimeout(this.name + ".fade(" + op + "," + step + ")", 50); + } else { + if (op <= 0) { + this.wnd.style.visibility = "hidden"; + this.visible = false; + } + this.wnd.style.MozOpacity = this.opacity + "%"; + this.onShow(this.visible, this.tag); + } + } +} + +function QWndCtrl_show_moz(show) { + if (this.visible != show) { + if (this._wndt) { + clearTimeout(this._wndt); + this._wndt = false; + } + var step = show ? ((this.effects & 15) == 1) && Math.floor(this.opacity / 5) : + ((this.effects & 240) == 16) && -Math.floor(this.opacity / 5); + if (step) { + if (this.visible) { + this.fade(this.opacity - 0, step); + } else { + this.wnd.style.MozOpacity = "0%"; + this.wnd.style.visibility = "visible"; + this.visible = true; + this.fade(0, step); + } + } else { + this.wnd.style.visibility = (this.visible = show) ? "visible" : "hidden"; + this.onShow(show, this.tag); + } + } +} + +function QWndCtrl_show_css(show) { + if (this.visible != show) { + this.wnd.style.visibility = (this.visible = show) ? "visible" : "hidden"; + this.onShow(show, this.tag); + } +} + +function QWndCtrl_show_ns4(show) { + if (this.visible != show) { + this.wnd.visibility = (this.visible = show) ? "show" : "hidden"; + this.onShow(show, this.tag); + } +} + +function QWndCtrl_create_dom2() { + with (this) { + this.fxhandler = QControl.nop; + var ie4 = document.body && document.body.filters; + var moz = document.body && document.body.style && + typeof(document.body.style.MozOpacity) == "string"; + document.write('
    '); + if (typeof(content) == "function") { + this.content(); + } else { + document.write(content); + } + document.write('
    '); + if (this.wnd = document.getElementById ? document.getElementById(id) : + (document.all.item ? document.all.item(id) : document.all[id])) { + if (wnd.style) { + ie4 = ie4 && wnd.filters; + moz = moz && typeof(wnd.style.MozOpacity) == "string"; + this.moveTo = QWndCtrl_moveTo_css; + this.setZIndex = QWndCtrl_setZIndex_css; + this.focus = QWndCtrl_focus; + this.setSize = QWndCtrl_setSize_css; + this.show = ie4 ? QWndCtrl_show_ie4 : (moz ? QWndCtrl_show_moz : QWndCtrl_show_css); + this.fade = moz ? QWndCtrl_fade_moz : QControl.nop; + this.setOpacity = ie4 ? QWndCtrl_setOpacity_ie4 : (moz ? QWndCtrl_setOpacity_moz : QControl.nop); + this.setEffects = ie4 ? QWndCtrl_setEffects_ie4 : (moz ? QWndCtrl_setEffects_moz : QControl.nop); + this.center = self.innerWidth ? QWndCtrl_center_moz : + (document.body && document.body.clientWidth ? QWndCtrl_center_ie4 : QControl.nop); + } + } + } +} + +function QWndCtrl_create_ns4(finalize) { + with (this) { + if (finalize) { + if (_wnde) { + parent.window.onload = _wnde; + parent.window.onload(); + } + document.open(); + document.write('
    '); + this.content(); + document.write('
    '); + document.close(); + } else { + document.write('
    ' + content + '
    ' : '"> ')); + if (this.window = this.wnd = document.layers[id]) { + if (this.document = wnd.document) { + this.show = QWndCtrl_show_ns4; + this.moveTo = QWndCtrl_moveTo_ns4; + this.setZIndex = QWndCtrl_setZIndex_ns4; + this.focus = QWndCtrl_focus; + this.center = QWndCtrl_center_moz; + this.setSize = QWndCtrl_setSize_ns4; + if (typeof(content) == "function") { + this._wnde = parent.window.onload; + parent.window.onload = new Function(name + ".create(true)"); + } + } + } + } + } +} + +function QWndCtrl_create_na() { + this.document.write('Object is not supported.'); + this.wnd = null; +} + +function QWndCtrl_create() { + with (this) { + this.create = (document.getElementById || document.all) ? QWndCtrl_create_dom2 : + (document.layers ? QWndCtrl_create_ns4 : QWndCtrl_create_na); + create(); + } +} + +function QWndCtrl() { + this.x = this.y = 0; + this.width = this.height = 0; + this.content = ""; + this.visible = true; + this.effects = 0; + this.opacity = 100; + this.zindex = null; + this._wndt = this._wnde = false; + this.create = QWndCtrl_create; + this.show = QControl.nop; + this.focus = QControl.nop; + this.center = QControl.nop; + this.moveTo = QControl.nop; + this.setSize = QControl.nop; + this.setOpacity = QControl.nop; + this.setEffects = QControl.nop; + this.setZIndex = QControl.nop; + this.onShow = QControl.event; +} +QWndCtrl.prototype = new QControl(); +QWndCtrl.TOPZINDEX = 1000; +QWndCtrl.GRAY = 256; +QWndCtrl.XRAY = 512; +QWndCtrl.INVERT = 1024; +QWndCtrl.SHADOW = 2048; +QWndCtrl.FADEIN = 1; +QWndCtrl.FADEOUT = 16; +QWndCtrl.BOXIN = 2; +QWndCtrl.BOXOUT = 32; +QWndCtrl.CIRCLEIN = 3; +QWndCtrl.CIRCLEOUT = 48; +QWndCtrl.WIPEIN = 4; +QWndCtrl.WIPEOUT = 64; +QWndCtrl.HBARNIN = 5; +QWndCtrl.HBARNOUT = 80; +QWndCtrl.VBARNIN = 6; +QWndCtrl.VBARNOUT = 96; +QWndCtrl.DISSOLVEIN = 7; +QWndCtrl.DISSOLVEOUT = 112; +QWndCtrl.HBLINDSIN = 8; +QWndCtrl.HBLINDSOUT = 128; +QWndCtrl.VBLINDSIN = 9; +QWndCtrl.VBLINDSOUT = 144; diff --git a/httemplate/images/progressbar-empty.png b/httemplate/images/progressbar-empty.png new file mode 100644 index 000000000..318219c77 Binary files /dev/null and b/httemplate/images/progressbar-empty.png differ diff --git a/httemplate/images/progressbar-full.png b/httemplate/images/progressbar-full.png new file mode 100644 index 000000000..863d8e1ee Binary files /dev/null and b/httemplate/images/progressbar-full.png differ diff --git a/httemplate/misc/progress.html b/httemplate/misc/progress.html new file mode 100644 index 000000000..cbff08b7b --- /dev/null +++ b/httemplate/misc/progress.html @@ -0,0 +1,88 @@ +<% + my( $jobnum ) = $cgi->param('jobnum'); + my( $url ) = $cgi->param('url'); + my $job = ''; + if ( $jobnum =~ /^(\d+)$/ ) { + $job = qsearchs('queue', { 'jobnum' => $jobnum } ); + } + if ( $job && $job->status ne 'failed' ) { +%> + + + + + Please wait... + + + + + + + + + +

    Please wait... + + + +

    + +
    <%= $job->statustext %>% +

    (progress of job #<%= $jobnum %>) + + + +<% + } elsif ( !$job ) { #handle job gone case : job sucessful + # so close popup, redirect parent window... + #eidiot("write success handler (jobnum $jobnum)"); +%> + + + + + Operation successful + + + + + + + + + + + +<% + } else { +%> + + + + Error + + + + + + +

    Error: <%= $job ? $job->statustext : $jobnum %> +

    + + + +<% } %> + + +