summaryrefslogtreecommitdiff
path: root/httemplate/elements/progress-init.html
blob: de3c6b761393cbb397b75043a2d9eb9c923ebb75 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
<%doc>
Example:
In misc/something.html:

  <FORM NAME="MyForm">
  <INPUT TYPE="hidden" NAME="recordnum" VALUE="42">
  <INPUT TYPE="hidden" NAME="what_to_do" VALUE="delete">
  <% include( '/elements/progress-init.html',
             'MyForm', 
             [ 'recordnum', 'what_to_do' ],
             $p.'misc/process_something.html',
             { url => $p.'where_to_go_next.html' },
         #or { message => 'Finished!' },
         #or { url => $p.'where_to_go.html',
               message => 'Finished' },
         # which recirects to the URL and displays the message as a status
         #or { popup_url => $p.'popup_contents.html' }
         # which loads that URL into the popup after completion
         #or { url => $p.'where_to_go.html',
               error_url => $p.'where_we_just_were.html' }
         # to redirect somewhere different on error
         ) %>
  </FORM>
  <SCRIPT TYPE="text/javascript>process();</SCRIPT>

In misc/process_something.html:

<%init>
my $server = FS::UI::Web::JSRPC->new('FS::something::process_whatever', $cgi);
</%init>
<% $server->process %>

In FS/something.pm:

sub process_whatever { #class method
  my $job = shift;
  my $param = thaw(base64_decode(shift));
  # param = { 'recordnum' => 42, 'what_to_do' => delete }
  # make use of this as you like
  do_phase1;
  $job->update_statustext(20);
  do_phase2;
  $job->update_statustext(40);
  do_phase3;
  $job->update_statustext(60);
  # etc.
  return 'this value will be ignored';
}

Internal notes:

This component creates two JS functions: process(), which starts the 
submission process, and start_job(), which starts the job on the 
server side.

process() does the following:
- disable the form submit button
- for all form fields named in "fields", collect their values into an array
- declare a callback function "myCallback"
- pass the array and callback to start_job()

start_job() is an xmlhttp standard function that turns the array of values 
into a JSON string, posts it to the location given in $action, receives a 
job number back, and then invokes the callback with the job number as an 
argument. Normally, the post target script will use FS::UI::Web::JSRPC to insert
a queue job (with the form field values as arguments), and return its
job number.

myCallback() opens an Overlib popup containing progress-popup.html, with 
the job number, form name, and destination options (url, message, popup_url,
error_url) as URL parameters. This popup will poll the server for the status
of the job, display a progress bar, and on completion, either redirect to 
'url' or 'popup_url', display 'message' in the popup window, or (on failure)
display the job statustext as an error message. If 'error_url' is specified,
the "Close" button in the popup will then redirect the user to that location.

</%doc>
<% include('/elements/xmlhttp.html',
              'method' => 'POST',
              'url'    => $action,
              'subs'   => [ 'start_job' ],
              'key'    => $key,
           )
%>

<& /elements/init_overlib.html &>

<SCRIPT TYPE="text/javascript">

function <%$key%>process () {

  //alert('<%$key%>process for form <%$formname%>');

  if ( document.<%$formname%>.submit.disabled == false ) {
    document.<%$formname%>.submit.disabled=true;
  }

  overlib( 'Submitting job to server...', WIDTH, 444, HEIGHT, 168, CAPTION, 'Please wait...', STICKY, AUTOSTATUSCAP, CLOSETEXT, '', CLOSECLICK, MIDX, 0, MIDY, 0, TEXTPADDING, 0, BASE, 0, BGCOLOR, '#333399', CGCOLOR, '#333399', FGCOLOR, '#f8f8f8' );

  // jQuery .serializeArray() maybe?
  var copy_fields = <% encode_json(\%copy_fields) %>;
  var Hash = new Array();
  var x = 0;
  var fieldName;
  for (var i = 0; i<document.<%$formname%>.elements.length; i++) {
    field  = document.<%$formname%>.elements[i];
    if ( <% $all_fields %> || copy_fields[ field.name ] ) {
        if ( field.type == 'select-multiple' ) {
          //alert('select-multiple ' + field.name);
          for (var j=0; j < field.options.length; j++) {
            if ( field.options[j].selected ) {
              //alert(field.name + ' => ' + field.options[j].value);
              Hash[x++] = field.name;
              Hash[x++] = field.options[j].value;
            }
          }
        } else if (    ( field.type != 'radio'  && field.type != 'checkbox' )
                    || ( ( field.type == 'radio' || field.type == 'checkbox' )
                         && document.<%$formname%>.elements[i].checked
                       )
                  )
        {
          Hash[x++] = field.name;
          Hash[x++] = field.value;
        }
    }
  }

  Hash.push('key', '<%$key%>');

  // jsrsPOST = true;
  // jsrsExecute( '<% $action %>', <%$key%>myCallback, 'start_job', Hash );

  //alert('start_job( ' + Hash + ', <%$key%>myCallback )' );
  //alert('start_job()' );
  <%$key%>start_job( Hash, <%$key%>myCallback );

}

function <%$key%>myCallback( jobnum ) {

  var url = <% $progress_url->as_string |js_string %>;
  url = url.replace('_JOBNUM_', jobnum);
  overlib( OLiframeContent(url, 444, 168, '<% $popup_name %>', 0), CAPTION, 'Please wait...', STICKY, AUTOSTATUSCAP, CLOSETEXT, '', CLOSECLICK, MIDX, 0, MIDY, 0, TEXTPADDING, 0, BASE, 0, BGCOLOR, '#333399', CGCOLOR, '#333399', FGCOLOR, '#f8f8f8' );

}

</SCRIPT>

<%init>

my( $formname, $fields, $action, $url_or_message, $key ) = @_;
$key = '' unless defined $key;

my %dest_info;
if ( ref($url_or_message) ) { #its a message or something
  %dest_info = map { $_ => $url_or_message->{$_} }
               grep { $url_or_message->{$_} }
               qw( message url popup_url error_url reload_with_error );
} else {
  # it can also just be a url
  %dest_info = ( 'url' => $url_or_message );
}

my $progress_url = URI->new($fsurl.'misc/progress-popup.html');
$progress_url->query_form(
  'jobnum'    => '_JOBNUM_',
  'formname'  => $formname,
  %dest_info,
);

my $all_fields = 0;
my %copy_fields;
if (grep '/^ALL$/', @$fields) {
  $all_fields = 1;
} else {
  %copy_fields = map { $_ => 1 } @$fields;
}

#stupid safari is caching the "location" of popup iframs, and submitting them
#instead of displaying them.  this should prevent that.
my $popup_name = 'popup-'.random_id();

</%init>