diff options
Diffstat (limited to 'httemplate')
-rw-r--r-- | httemplate/browse/msg_template.html | 3 | ||||
-rw-r--r-- | httemplate/browse/template_image.html | 68 | ||||
-rw-r--r-- | httemplate/edit/msg_template.html | 11 | ||||
-rw-r--r-- | httemplate/elements/form-file_upload.html | 1 | ||||
-rw-r--r-- | httemplate/elements/images/ui-icons_ef8c08_256x240.png | bin | 0 -> 4369 bytes | |||
-rw-r--r-- | httemplate/elements/template_image-dialog.html | 279 | ||||
-rw-r--r-- | httemplate/misc/email-customers.html | 2 | ||||
-rw-r--r-- | httemplate/misc/process/template_image-delete.cgi | 28 | ||||
-rw-r--r-- | httemplate/misc/process/template_image-upload.cgi | 26 | ||||
-rw-r--r-- | httemplate/misc/xmlhttp-template_image.cgi | 48 |
10 files changed, 462 insertions, 4 deletions
diff --git a/httemplate/browse/msg_template.html b/httemplate/browse/msg_template.html index ef0b2dafd..1646bc169 100644 --- a/httemplate/browse/msg_template.html +++ b/httemplate/browse/msg_template.html @@ -28,6 +28,7 @@ my @menubar = (); if ( $curuser->access_right(['Edit templates', 'Edit global templates']) ) { push @menubar, 'Add a new template' => $p.'edit/msg_template.html'; } +push @menubar, 'View template images' => $p.'browse/template_image.html'; my $link = [ "${p}edit/msg_template.html?msgnum=", 'msgnum' ]; @@ -52,7 +53,7 @@ my $disable_link = sub { action => $p.'misc/disable-msg_template.cgi?msgnum=' . $template->msgnum . ($template->disabled ? ';enable=1' : ''), - actionlabel => 'Disable lemplate', + actionlabel => 'Disable template', ); }; diff --git a/httemplate/browse/template_image.html b/httemplate/browse/template_image.html new file mode 100644 index 000000000..eb4325f15 --- /dev/null +++ b/httemplate/browse/template_image.html @@ -0,0 +1,68 @@ +<% include('/elements/init_overlib.html') %> + +<% include( 'elements/browse.html', + 'title' => 'Template images', + 'name_singular' => 'image', + 'menubar' => \@menubar, + 'query' => { 'table' => 'template_image', }, + 'count_query' => 'SELECT COUNT(*) FROM template_image', + 'agent_virt' => 1, + 'agent_null_right' => ['View global templates','Edit global templates'], + 'agent_pos' => 1, + 'header' => [ 'Name', '', '' ], + 'fields' => [ 'name', $tag, $delete_text ], + 'links' => [ '', '', '' ], + 'cell_style' => [ '', '', '' ], + ) +%> + +<% include('/elements/template_image-dialog.html', + 'url' => $p.'browse/template_image.html' + ) %> + +<%init> +use FS::template_image; + +my $curuser = $FS::CurrentUser::CurrentUser; + +die "access denied" + unless $curuser->access_right([ 'View templates', 'View global templates', + 'Edit templates', 'Edit global templates', ]); + +my $canedit = $curuser->access_right(['Edit templates', 'Edit global templates']); + +my @menubar = (); +if ($canedit) { + push @menubar, 'Upload a new image' => 'javascript:insertImageDialog(\'upload\')'; +} +push @menubar, ( 'View message templates' => $p.'browse/msg_template.html' ); + +my $tag = sub { qq!<A HREF="javascript:insertImageDialog(! . $_[0]->imgnum . qq!)">view</A>! }; + +my $delete_text = $canedit ? sub { + my $image = shift; + my $imgnum = $image->imgnum; + unless ($image->agentnum) { + unless ($FS::CurrentUser::CurrentUser->access_right('Edit global templates')) { + return ''; + } + } + my $out = <<EOF; +<FORM name="delete_template_image_$imgnum"> +<INPUT TYPE="hidden" name="imgnum" value="$imgnum"> +</FORM> +EOF + $out .= include('/elements/progress-init.html', + "delete_template_image_$imgnum", + [ 'imgnum' ], + $p.'misc/process/template_image-delete.cgi', + $p.'browse/template_image.html', + "imgnum$imgnum", + ); + my $onclick = 'if ( confirm(\''; + $onclick .= emt('Are you sure you want to delete template image ') . $imgnum; + $onclick .= '\') ) { imgnum' . $imgnum . 'process() }'; + return $out . '<A HREF="javascript:void(0)" ONCLICK="' . $onclick . '">delete</A>'; +} : ''; + +</%init> diff --git a/httemplate/edit/msg_template.html b/httemplate/edit/msg_template.html index 7f3824127..df72c5b66 100644 --- a/httemplate/edit/msg_template.html +++ b/httemplate/edit/msg_template.html @@ -27,6 +27,7 @@ 'no_submit' => $no_submit, &> <%init> +use FS::template_image; my $curuser = $FS::CurrentUser::CurrentUser; @@ -345,10 +346,16 @@ function areyousure(url, message) { <TD valign="top"><FORM name="dummy"> Substitutions: ' . $widget->html . -'<BR>Click links to insert. -<BR>Enclose substitutions and other Perl expressions in braces: +'<P>Click above links to insert substitution code.</P> +<P> +Enclose substitutions and other Perl expressions in braces: <BR>{ $name } = ExampleCo (Smith, John) <BR>{ time2str("%D", time) } = '.time2str("%D", time).' +</P>'; +$sidebar .= include('/elements/template_image-dialog.html', + 'callback' => 'insertHtml' + ); +$sidebar .= '<P><A HREF="javascript:insertImageDialog()">Insert Uploaded Image</A></P> </FONT></TD> '; diff --git a/httemplate/elements/form-file_upload.html b/httemplate/elements/form-file_upload.html index 45b6c97f2..3542a5a8e 100644 --- a/httemplate/elements/form-file_upload.html +++ b/httemplate/elements/form-file_upload.html @@ -69,6 +69,7 @@ Example: <div style="display:none:" id="uploadError"></div> <FORM NAME = "<% $opt{name} %>" + ID = "<% $opt{id} %>" ACTION = "<% $fsurl %>misc/file-upload.html" METHOD = "POST" ENCTYPE = "multipart/form-data" diff --git a/httemplate/elements/images/ui-icons_ef8c08_256x240.png b/httemplate/elements/images/ui-icons_ef8c08_256x240.png Binary files differnew file mode 100644 index 000000000..85e63e9f6 --- /dev/null +++ b/httemplate/elements/images/ui-icons_ef8c08_256x240.png diff --git a/httemplate/elements/template_image-dialog.html b/httemplate/elements/template_image-dialog.html new file mode 100644 index 000000000..5691d52b5 --- /dev/null +++ b/httemplate/elements/template_image-dialog.html @@ -0,0 +1,279 @@ +<%doc> + +Creates a jquery dialog box that opens when javascript function insertImageDialog +is called, allows user to select an image and specify attributes for it, then passes +img tag with base64 encoded data url to a callback javascript function. + +Accepts the following options: + +callback - pass the html for the selected img to this javascript function; +if omitted, will only include fields for viewing/uploading image + +url - to redirect to after upload, otherwise just refreshes dialog window + +</%doc> + +<% include('/elements/xmlhttp.html', + 'url' => $p.'misc/xmlhttp-template_image.cgi', + 'subs' => [ 'get_template_image' ], + ) %> + +<DIV ID="insert_image_dialog" title="Template Images"> + +<TABLE BORDER="0" STYLE="width: 100%"><TR><TD> + +<FORM ID="insert_image_form"> + +<% &ntable("#cccccc", 2) %> + + <TR> + <TH>Image</TH> + <TD> + <SELECT ID="insert_image_imgnum" ONCHANGE="insertImageDialog($('#insert_image_imgnum').val())"> + <OPTION VALUE="">(select an image)</OPTION> + </SELECT> + </TD> + </TR> +% if ($opt{'callback'}) { + <TR> + <TH>Width</TH> + <TD><INPUT TYPE="text" SIZE="5" ID="insert_image_width" ONCHANGE="previewInsertImage()"></TD> + </TR> + <TR> + <TH>Height</TH> + <TD><INPUT TYPE="text" SIZE="5" ID="insert_image_height" ONCHANGE="previewInsertImage()"></TD> + </TR> + <TR> + <TH>Align</TH> + <TD> + <SELECT ID="insert_image_float" ONCHANGE="previewInsertImage()"> + <OPTION VALUE="none">inline</OPTION> + <OPTION VALUE="left">left</OPTION> + <OPTION VALUE="right">right</OPTION> + </SELECT> + </TD> + </TR> + <TR> + <TH>Alt Text</TH> + <TD><INPUT TYPE="text" SIZE="20" ID="insert_image_alt" ONCHANGE="previewInsertImage()"></TD> + </TR> + <TR> + <TD COLSPAN="2" ALIGN="center" STYLE="padding-top:6px"> + <INPUT TYPE="button" ID="insert_image_button" VALUE="Insert Image" ONCLICK="insertImage()"> + </TD> + </TR> +% } # if $opt{'callback'} + +</TABLE> + +</FORM> + +% if ($canedit) { + +<P><B><% emt('Upload New Image') %></B></P> + +<% include('/elements/form-file_upload.html', + 'name' => 'TemplateImageUploadForm', + 'id' => 'TemplateImageUploadForm', + 'action' => $p.'misc/process/template_image-upload.cgi', + 'num_files' => 1, + 'fields' => [ 'name', 'agentnum' ], + 'url' => $opt{'url'} || 'javascript:refreshImageList(1)', + ) + %> + + <% &ntable("#cccccc", 2) %> + + <% include( '/elements/tr-input-text.html', + 'field' => 'name', + 'label' => 'Name', + 'required' => 1, + 'id' => 'upload_form_name', + ) + %> + + <% include( '/elements/tr-select-agent.html', + 'label' => "<B>Agent</B>", + 'empty_label' => 'Select agent', + 'agent_virt' => 1, + 'agent_null_right' => 'Edit global templates', + ) + %> + + <% include( '/elements/tr-file-upload.html', + 'field' => 'file', + 'label' => 'File', + ) + %> + + <TR> + <TD COLSPAN="2" ALIGN="center" STYLE="padding-top:6px"> + <INPUT TYPE = "submit" + NAME = "submitButton" + ID = "submitButton" + VALUE = "Upload image" + > + </TD> + </TR> + +</TABLE> + +</FORM> + +% } #if canedit + +</TD><TD width="100%"> + +<DIV ID="insert_image_preview_box"> + <P><B><% emt('Image Preview') %></B></P> + <SPAN ID="insert_image_loading"><B>(<% emt('Loading image...') %>)</B></SPAN> + <IMG SRC="" ID="insert_image_preview"> +</DIV> + +</TD></TR></TABLE> +</DIV> + +<SCRIPT> + +// initialize & close dialog window, initialize imgobj cache && image list +$( '#insert_image_dialog' ).dialog({ + width: 800, + height: 550, + resizable: true, + autoOpen: false, +}); +var imgobj = new Object; +refreshImageList(0); + +// this is the main func to invoke from links outside this file. +// opens dialog if needed +// updates dialog with passed imgnum +// caches image info through an xmlhttp request if needed +// pass 'upload' as imgnum for upload-only view +function insertImageDialog (imgnum) { + if (imgnum == 'upload') { + $('#insert_image_form').hide(); + $('#insert_image_preview_box').hide(); + imgnum = undefined; + } else { + $('#insert_image_form').show(); + $('#insert_image_preview_box').show(); + } + if (imgnum && !imgobj[imgnum]) { + clearInsertImageDialog(); + $('#insert_image_loading').show(); + $('#insert_image_imgnum').val(imgnum); + get_template_image('imgnum',imgnum, + function (result) { + var images = JSON.parse(result) || []; + for (i = 0; i < images.length; i++) { + imgobj[images[i].imgnum] = images[i]; + } + updateInsertImageDialog(); + } + ); + } else if (imgnum) { + $('#insert_image_imgnum').val(imgnum); + updateInsertImageDialog(); + } else { + clearInsertImageDialog(); + } + if (!$( '#insert_image_dialog' ).dialog( 'isOpen' )) { + $( '#insert_image_dialog' ).dialog( 'open' ); + } +} + +// sets dialog values to a default "Loading..." state, including imgnum +function clearInsertImageDialog () { + $('#insert_image_imgnum').val(''); + $('#insert_image_preview').attr('src',''); + $('#insert_image_loading').hide(); +} + +// updates preview src from cache based on imgnum from form +// then calls previewInsertImage +function updateInsertImageDialog () { + var imgnum = $('#insert_image_imgnum').val(); + $('#insert_image_loading').hide(); + $('#insert_image_preview').attr('src',imgobj[imgnum].src); + previewInsertImage(); +} + +// updates preview width/height/alt/float based on current form values +function previewInsertImage () { + $('#insert_image_preview').css('width',$('#insert_image_width').val()); + $('#insert_image_preview').css('height',$('#insert_image_height').val()); + $('#insert_image_preview').css('float',$('#insert_image_float').val()); + $('#insert_image_preview').attr('alt',$('#insert_image_alt').val()); +} + +// constructs html based on the form contents, +// passes it to callback & closes dialog +function insertImage() { + var imgnum = $('#insert_image_imgnum').val(); + if (!(imgnum && imgobj[imgnum])) { + return ''; + } + var width = $('#insert_image_width').val() || ''; + var height = $('#insert_image_height').val() || ''; + var alt = $('#insert_image_alt').val() || ''; + var float = $('#insert_image_float').val(); + var imgtag = '<IMG SRC="' + imgobj[imgnum].src + '"'; + if (width) { + imgtag += ' WIDTH="' + width + '"'; + } + if (height) { + imgtag += ' HEIGHT="' + height + '"'; + } + if (alt) { + imgtag += ' ALT="' + alt + '"'; + } + if (float) { + imgtag += ' STYLE="float: ' + float + '"'; + } + imgtag += '>'; + <% $opt{'callback'} %>(imgtag); + $( '#insert_image_dialog' ).dialog( 'close' ); +} + +// uses xmlhttp request to initialize image list & refresh it after uploads +function refreshImageList (fromupload) { + get_template_image('no_src','1', + function (result) { + if (fromupload) { + $("#TemplateImageUploadForm")[0].reset(); + } + var images = JSON.parse(result) || []; + var latest; + for (i = 0; i < images.length; i++) { + if ( $("#insert_image_imgnum option[value='" + images[i].imgnum + "']").length == 0 ) { + $("#insert_image_imgnum").append('<OPTION VALUE="'+images[i].imgnum+'">'+images[i].name+'</OPTION>'); + latest = images[i].imgnum; + } + } + if (fromupload) { + location.hash = "insert_image_dialog"; + if (latest) { + // small risk of a race condition with other newly-uploaded images, + // but does no real damage (our image still shows up in the list) + insertImageDialog(latest); + } + } + } + ); +} + +</SCRIPT> + +<%init> +my %opt = @_; + +my $curuser = $FS::CurrentUser::CurrentUser; + +die "access denied" + unless $curuser->access_right([ 'View templates', 'View global templates', + 'Edit templates', 'Edit global templates', ]); + +my $canedit = $curuser->access_right([ 'Edit templates', 'Edit global templates' ]); +</%init> + diff --git a/httemplate/misc/email-customers.html b/httemplate/misc/email-customers.html index 47e6a5b48..8ac44afc1 100644 --- a/httemplate/misc/email-customers.html +++ b/httemplate/misc/email-customers.html @@ -36,7 +36,7 @@ should be used to set msgnum or from/subject/html_body cgi params % } -<FORM NAME="OneTrueForm" ACTION="<% $form_action %>" METHOD="GET"> +<FORM NAME="OneTrueForm" ACTION="<% $form_action %>" METHOD="POST"> <INPUT TYPE="hidden" NAME="table" VALUE="<% $table %>"> %# Mixing search params with from address, subject, etc. required special-case %# handling of those, risked name conflicts, and caused massive problems with diff --git a/httemplate/misc/process/template_image-delete.cgi b/httemplate/misc/process/template_image-delete.cgi new file mode 100644 index 000000000..58c3f2c68 --- /dev/null +++ b/httemplate/misc/process/template_image-delete.cgi @@ -0,0 +1,28 @@ +<% $server->process %> + +<%init> + +my $curuser = $FS::CurrentUser::CurrentUser; + +# make sure user can generally edit +die "access denied" + unless $curuser->access_right([ 'Edit templates', 'Edit global templates' ]); + +# make sure user can edit this particular image +my %arg = $cgi->param('arg'); +my $imgnum = $arg{'imgnum'}; +die "bad imgnum" unless $imgnum =~ /^\d+$/; +die "access denied" unless qsearchs({ + 'table' => 'template_image', + 'select' => 'imgnum', + 'hashref' => { 'imgnum' => $imgnum }, + 'extra_sql' => ' AND ' . + $curuser->agentnums_sql( + 'null_right' => ['Edit global templates'] + ), + }); + +my $server = + new FS::UI::Web::JSRPC 'FS::template_image::process_image_delete', $cgi; + +</%init> diff --git a/httemplate/misc/process/template_image-upload.cgi b/httemplate/misc/process/template_image-upload.cgi new file mode 100644 index 000000000..c3c905981 --- /dev/null +++ b/httemplate/misc/process/template_image-upload.cgi @@ -0,0 +1,26 @@ +<% $server->process %> + +<%init> + +my $curuser = $FS::CurrentUser::CurrentUser; + +die "access denied" + unless $curuser->access_right([ 'Edit templates', 'Edit global templates' ]); + +my %arg = $cgi->param('arg'); +my $agentnum = $arg{'agentnum'}; + +if (!$agentnum) { + die "access denied" + unless $curuser->access_right([ 'Edit global templates' ]); +} else { + die "bad agentnum" + unless $agentnum =~ /^\d+$/; + die "access denied" + unless $curuser->agentnum($agentnum); +} + +my $server = + new FS::UI::Web::JSRPC 'FS::template_image::process_image_upload', $cgi; + +</%init> diff --git a/httemplate/misc/xmlhttp-template_image.cgi b/httemplate/misc/xmlhttp-template_image.cgi new file mode 100644 index 000000000..a8c50edf0 --- /dev/null +++ b/httemplate/misc/xmlhttp-template_image.cgi @@ -0,0 +1,48 @@ +<%doc> +Returns JSON encoded array of objects with details about FS::template_image +objects. Attributes in each returned object are imgnum, name, and src. + +Accepts the following options: + +imgnum - only return object for this imgnum + +no_src - do not include the src field + +</%doc> +<% encode_json(\@result) %>\ +<%init> +use FS::template_image; + +my $curuser = $FS::CurrentUser::CurrentUser; + +die "access denied" + unless $curuser->access_right([ 'View templates', 'View global templates', + 'Edit templates', 'Edit global templates', ]); + +my %arg = $cgi->param('arg'); + +my $search = { + 'table' => 'template_image', + 'hashref' => {}, +}; + +my $imgnum = $arg{'imgnum'} || ''; +die "Bad imgnum" unless $imgnum =~ /^\d*$/; +$search->{'hashref'}->{'imgnum'} = $imgnum if $imgnum; + +$search->{'select'} = 'imgnum, name' if $arg{'no_src'}; + +$search->{'extra_sql'} = ($imgnum ? ' AND ' : ' WHERE ') + . $curuser->agentnums_sql( + 'null_right' => ['View global templates','Edit global templates'] + ); + +my @images = qsearch($search); #needs agent virtualization + +my @result = map { +{ + 'imgnum' => $_->imgnum, + 'name' => $_->name, + 'src' => $arg{'no_src'} ? '' : $_->src, +} } @images; + +</%init> |