Skip to content

Commit

Permalink
Item14774: extend insert attachment feature
Browse files Browse the repository at this point in the history
- improved "insert link" action
- added "create link & hide file" action
- performance improvements to other actions
  • Loading branch information
MichaelDaum committed Oct 24, 2018
1 parent f982914 commit 8ebb009
Show file tree
Hide file tree
Showing 41 changed files with 2,860 additions and 2,258 deletions.
105 changes: 92 additions & 13 deletions data/System/TopicInteractionPlugin.txt
@@ -1,9 +1,11 @@
%META:TOPICINFO{author="ProjectContributor" comment="" date="1518773290" format="1.1" version="1"}%
%META:TOPICINFO{author="ProjectContributor" comment="" date="1540399921" format="1.1" version="1"}%
---+!! %TOPIC%
%FORMFIELD{"Description"}%

%TOC%

---++ Description

This plugin redesigns the way how users interact with topics and attachments in various ways:

* improved attachment handling
Expand All @@ -21,6 +23,19 @@ Other features are:
* filtering and pagination for topics with a lot of attachments
* drag & drop upload for browsers supporting it (currently firefox and chrome only)

---++ Screenshots

<a href='%ATTACHURLPATH%/TopicInteractionPluginSnap1.png' class='foswikiImage'><img src='%ATTACHURLPATH%/TopicInteractionPluginSnap1.png' width='500' /></a>

<a href='%ATTACHURLPATH%/TopicInteractionPluginSnap2.png' class='foswikiImage'><img src='%ATTACHURLPATH%/TopicInteractionPluginSnap2.png' width='500' /></a>

<a href='%ATTACHURLPATH%/TopicInteractionPluginSnap3.png' class='foswikiImage'><img src='%ATTACHURLPATH%/TopicInteractionPluginSnap3.png' width='500' /></a>

<a href='%ATTACHURLPATH%/TopicInteractionPluginSnap4.png' class='foswikiImage'><img src='%ATTACHURLPATH%/TopicInteractionPluginSnap4.png' width='500' /></a>

<a href='%ATTACHURLPATH%/TopicInteractionPluginSnap5.png' class='foswikiImage'><img src='%ATTACHURLPATH%/TopicInteractionPluginSnap5.png' width='500' /></a>

---++ Settings
To activate you'll need to add =topicinteraction= to your SKIN path setting in your !SitePreferences, like

<verbatim>
Expand All @@ -37,17 +52,80 @@ Use the =insidetab= setting of !MetaCommentPlugin to render comments inside a ta

Note you won't need using Foswiki:Extensions/NatSkin as that's integrated automatically.

---++ Screenshots
---++ Creating a link to an attachment

<a href='%ATTACHURLPATH%/TopicInteractionPluginSnap1.png' class='foswikiImage'><img src='%ATTACHURLPATH%/TopicInteractionPluginSnap1.png' width='500' /></a>
!TopicInteractionPlugin extens the standard way of inserting links to an attachment. Instead of only distinguishing between images and other kinds
of attachments you may now specify different code to be inserted into the topic based on the mime type of an attachment. You may specify a set of
various preference settings. The actual setting being used is chosen in the given precedence:

<a href='%ATTACHURLPATH%/TopicInteractionPluginSnap2.png' class='foswikiImage'><img src='%ATTACHURLPATH%/TopicInteractionPluginSnap2.png' width='500' /></a>
1 =ATTACHED_&lt;file-extension>_FORMAT=
1 =ATTACHED_&lt;mime-type>_FORMAT=
1 =ATTACHEDIMAGEFORMAT= (provided for compatibility, left out in below examples)
1 =ATTACHED_FILE_FORMAT=
1 =ATTACHEDFILELINKFORMAT= (provided for compatibility, left out in below examples)

<a href='%ATTACHURLPATH%/TopicInteractionPluginSnap3.png' class='foswikiImage'><img src='%ATTACHURLPATH%/TopicInteractionPluginSnap3.png' width='500' /></a>
(=&lt;file-extension>= and =&lt;mime-type>= are uppercase). For example, when inserting a link to an attachment named =screenshot.png= the following
settings are looked up:

<a href='%ATTACHURLPATH%/TopicInteractionPluginSnap4.png' class='foswikiImage'><img src='%ATTACHURLPATH%/TopicInteractionPluginSnap4.png' width='500' /></a>
1 =ATTACHED_PNG_FORMAT=
1 =ATTACHED_IMAGE_FORMAT=
1 =ATTACHED_FILE_FORMAT=

The one first found is used. When looking up the link format based on the mime type, the actual _mime type group_ is used, such as
=IMAGE=, =VIDEO=, =TEXT=, =AUDIO= etc just to name the most interesting ones. There are a couple of more mime types that are grouped together
in a meaningful way to form the group =DOCUMENT= which are =application/.*(document|msword|msexcel|rtf).*=, as well as =PDF= which are =application/pdf=
and =application/postscript=.

For example the following settings might be quite useful:

Using [[Foswiki:Extensions/DocumentViewerPlugin][DocumentViewerPlugin]]:

<verbatim class="tml">
* Set ATTACHED_ODT_FORMAT = $percntDOCUMENTVIEWER{"$filename"}$percnt
* Set ATTACHED_PDF_FORMAT = $percntDOCUMENTVIEWER{"$filename"}$percnt
</verbatim>

Using [[Foswiki:Extensions/ImagePlugin][ImagePlugin]]:

<verbatim class="tml">
* Set ATTACHED_IMAGE_FORMAT = $percntIMAGE{"$filename" size="200" caption="$comment"}$percnt
</verbatim>

Using [[Foswiki:Extensions/MediaElementPlugin][MediaElementPlugin]]:

<verbatim class="tml">
* Set ATTACHED_VIDEO_FORMAT = $percntVIDEO{"$filename"}$percnt
* Set ATTACHED_AUDIO_FORMAT = $percntAUDIO{"$filename"}$percnt
</verbatim>

Using !WebDAVContrib (please adjust the webdav://wiki/dav prefix to your needs):

<verbatim class="tml">
* Set OFFICELINK = <a href='webdav://wiki/dav/%WEB%/%TOPIC%/%DEFAULT{default=""}%' class='jqWebDAVLink' title='Edit Office Attachment' rel='nofollow'>%DEFAULT{default=""}%</a>
* Set ATTACHED_DOCUMENT_FORMAT = $percntOFFICELINK{"$filename"}$percnt
</verbatim>


The =..._FORMAT= strings support the following variables:

* =$filename=: the name of the file
* =$fileext=: the filename extension (string following the last period, if present) or an empty string.
* =$fileurl=: URL encoded version of the filename
* =$comment=: the file comment from the upload dialog
* =$size=: the filesize (=%<nop>ATTACHEDIMAGEFORMAT%= only)
* =$width=: image width
* =$height=: image width
* =$date=: modification date of attachment
* Any standard [[FormatTokens][formatting tokens]]: =$percnt=, =$dollar=, etc.

---+++ Incompatibilities

There is a significant difference how Foswiki's natively processes =ATTACHEDFILEFORMAT= settings and the way !TopicInteractionPlugin does.

* Any macro expression __must always be escaped__ using standard format tokens =$percnt= and =$dollar=. As such previous settings might be incompatible with !TopicInteractionPlugin
settings of the same kind.
* The __time format specifiers are not supported__. Use =$date= instead.

<a href='%ATTACHURLPATH%/TopicInteractionPluginSnap5.png' class='foswikiImage'><img src='%ATTACHURLPATH%/TopicInteractionPluginSnap5.png' width='500' /></a>

---++ Syntax

Expand Down Expand Up @@ -150,6 +228,7 @@ generates:

---++ Change History
%TABLE{columnwidths="7em" tablewidth="100%"}%
| 24 Oct 2018: | improved "insert link" action; added "create link & hide file" action; performance improvements to other actions |
| 05 Mar 2018: | fixed selecting attachments with brackets in its filename |
| 16 Feb 2018: | added a legacy uploader to be somewhat backwards compatible to the old plupload just enough to please natedit |
| 16 Jan 2018: | check access permissions in %ATTACHMENTS makro; fixed url encoding of unicode files |
Expand Down Expand Up @@ -212,9 +291,9 @@ generates:
%META:FIELD{name="Repository" title="Repository" value="https://github.com/foswiki/%25TOPIC%25"}%
%META:FIELD{name="Support" title="Support" value="Foswiki:Support/%25TOPIC%25"}%
%META:FIELD{name="Version" title="Version" value="%25$VERSION%25"}%
%META:FILEATTACHMENT{name="TopicInteractionPluginSnap5.png" attachment="TopicInteractionPluginSnap5.png" attr="" comment="" date="1518773290" size="36218" user="ProjectContributor" version="1"}%
%META:FILEATTACHMENT{name="TopicInteractionPluginSnap4.png" attachment="TopicInteractionPluginSnap4.png" attr="" comment="" date="1518773290" size="45039" user="ProjectContributor" version="1"}%
%META:FILEATTACHMENT{name="TopicInteractionPluginSnap3.png" attachment="TopicInteractionPluginSnap3.png" attr="" comment="" date="1518773290" size="99574" user="ProjectContributor" version="1"}%
%META:FILEATTACHMENT{name="TopicInteractionPluginSnap2.png" attachment="TopicInteractionPluginSnap2.png" attr="" comment="" date="1518773290" size="111026" user="ProjectContributor" version="1"}%
%META:FILEATTACHMENT{name="TopicInteractionPluginSnap1.png" attachment="TopicInteractionPluginSnap1.png" attr="" comment="" date="1518773290" size="16199" user="ProjectContributor" version="1"}%
%META:FILEATTACHMENT{name="LibreOfficeWebDAV.reg" attachment="LibreOfficeWebDAV.reg" attr="" comment="" date="1518773290" moveby="micha" movedto="System.TopicInteractionPlugin.LibreOfficeWebDAV.reg" movedwhen="1470922302" movefrom="Sandbox.OpenToEditTest.LibreOfficeWebDAV.reg" size="1126" user="ProjectContributor" version="1"}%
%META:FILEATTACHMENT{name="TopicInteractionPluginSnap5.png" attachment="TopicInteractionPluginSnap5.png" attr="" comment="" date="1540399921" size="36218" user="ProjectContributor" version="1"}%
%META:FILEATTACHMENT{name="TopicInteractionPluginSnap4.png" attachment="TopicInteractionPluginSnap4.png" attr="" comment="" date="1540399921" size="45039" user="ProjectContributor" version="1"}%
%META:FILEATTACHMENT{name="TopicInteractionPluginSnap3.png" attachment="TopicInteractionPluginSnap3.png" attr="" comment="" date="1540399921" size="99574" user="ProjectContributor" version="1"}%
%META:FILEATTACHMENT{name="TopicInteractionPluginSnap2.png" attachment="TopicInteractionPluginSnap2.png" attr="" comment="" date="1540399921" size="111026" user="ProjectContributor" version="1"}%
%META:FILEATTACHMENT{name="TopicInteractionPluginSnap1.png" attachment="TopicInteractionPluginSnap1.png" attr="" comment="" date="1540399921" size="16199" user="ProjectContributor" version="1"}%
%META:FILEATTACHMENT{name="LibreOfficeWebDAV.reg" attachment="LibreOfficeWebDAV.reg" attr="" comment="" date="1540399921" moveby="micha" movedto="System.TopicInteractionPlugin.LibreOfficeWebDAV.reg" movedwhen="1470922302" movefrom="Sandbox.OpenToEditTest.LibreOfficeWebDAV.reg" size="1126" user="ProjectContributor" version="1"}%
5 changes: 2 additions & 3 deletions lib/Foswiki/Plugins/TopicInteractionPlugin.pm
Expand Up @@ -18,15 +18,14 @@ package Foswiki::Plugins::TopicInteractionPlugin;
use strict;
use warnings;

our $VERSION = '7.10';
our $RELEASE = '5 Mar 2018';
our $VERSION = '8.00';
our $RELEASE = '24 Oct 2018';
our $SHORTDESCRIPTION = 'Improved interaction with attachments and !DataForms';
our $NO_PREFS_IN_TOPIC = 1;
our $core;

use Foswiki::Func ();
use Foswiki::Plugins::JQueryPlugin ();

use Foswiki::Request();

BEGIN {
Expand Down
1 change: 1 addition & 0 deletions lib/Foswiki/Plugins/TopicInteractionPlugin/Action.pm
Expand Up @@ -24,6 +24,7 @@ sub new {
my $class = shift;

my $this = bless({
session => $Foswiki::Plugins::SESSION,
@_
},
$class
Expand Down
189 changes: 160 additions & 29 deletions lib/Foswiki/Plugins/TopicInteractionPlugin/Action/CreateLinks.pm
Expand Up @@ -34,6 +34,7 @@ sub handle {
my $web = $params->{web};
my $topic = $params->{topic};
my $id = $params->{id};
my $doHideFile = Foswiki::Func::isTrue($params->{hidefile}, 0);

# check permissions
my $wikiName = Foswiki::Func::getWikiName();
Expand All @@ -43,57 +44,187 @@ sub handle {
return;
}

# disable dbcache handler during loop
my $dbCacheEnabled = Foswiki::Func::getContext()->{DBCachePluginEnabled};
if ($dbCacheEnabled) {
require Foswiki::Plugins::DBCachePlugin;
Foswiki::Plugins::DBCachePlugin::disableRenameHandler();
}
my ($meta, $text) = Foswiki::Func::readTopic($web, $topic);
$text = '' unless defined $text;

my $error;
foreach my $fileName (@{$params->{filenames}}) {
next unless $fileName;
$fileName = $this->sanitizeAttachmentName($fileName);

if (!Foswiki::Func::attachmentExists($web, $topic, $fileName)) {
my $attachment = $meta->get("FILEATTACHMENT", $fileName);
unless ($attachment) {
$this->printJSONRPC($response, 104, "Attachment $fileName does not exist", $id);
return;
}

if ($doHideFile) {
my %attrs = map {$_ => 1} split(//, ($attachment->{attr} || ''));
$attrs{h} = 1;
$attachment->{attr} = join("", sort keys %attrs);
}

$this->writeDebug("createlink fileName=$fileName, web=$web, topic=$topic");
$text .= $this->getAttachmentLink($meta, $fileName);
}

try {
unless (DRY) {
$meta->text($text);
$meta->save();
}
} catch Error::Simple with {
$error = shift->{-text};
$this->writeDebug("ERROR: $error");
};

if ($error) {
$this->printJSONRPC($response, 1, $error, $id);
} else {
$this->printJSONRPC($response, 0, undef, $id)
}
}

sub getAttachmentLink {
my ($this, $meta, $fileName) = @_;

my $attachment = $meta->get('FILEATTACHMENT', $fileName);
my $fileComment = $attachment->{comment} // '';
my $fileTime = Foswiki::Func::formatTime($attachment->{date} || 0);
my $filePath = $Foswiki::cfg{PubDir} . '/' . $meta->web . '/' . $meta->topic . '/' . $fileName;
my ($fileExt) = $fileName =~ m/(?:.*\.)*([^.]*)/;
$fileExt //= '';

my $width = "";
my $height = "";
my $geom = "";

my $format = $this->getAttachmentFormat($fileName);

# only support values if ImagePlugin is installed
if ($format =~ /\$width|\$height|\$size/) {
($width, $height) = $this->ping($filePath);
$geom = "width='$width' height='$height'";
}

$format =~ s/\$name/$fileName/; # deprecated
$format =~ s/\$filename/$fileName/g;
$format =~ s/\$fileurl/$fileName/g;
$format =~ s/\$fileext/$fileExt/;

# SMELL: backwards compatibility ...
$format =~ s/\\t/\t/g;
$format =~ s/\\n/\n/g;

$format =~ s/\$comment/$fileComment/g;
$format =~ s/\$size/$geom/g;

# new
$format =~ s/\$width/$width/g;
$format =~ s/\$height/$height/g;
$format =~ s/\$date/$fileTime/g;

# this is deliberatley orderd that way to prevent some makros from being executed
$format = Foswiki::Func::expandCommonVariables($format);
$format = Foswiki::Func::decodeFormatTokens($format);

return $format;
}

sub ping {
my ($this, $filePath) = @_;

eval "require Foswiki::Plugins::ImagePlugin";
return if $@;

return Foswiki::Plugins::ImagePlugin::getCore()->mage->Ping($filePath);
}

my ($meta, $text) = Foswiki::Func::readTopic($web, $topic);
sub getAttachmentFormat {
my ($this, $fileName) = @_;

try {
unless (DRY) {
my $session = $Foswiki::Plugins::SESSION;
$text = '' unless defined $text;
$text .= $session->attach->getAttachmentLink($meta, $fileName);
$meta->text($text);
$meta->save();
my $format;
my $prefName;

if ($fileName =~ /(?:.*\.)*([^.]*)/) {
$prefName = 'ATTACHED_'.uc($1).'_FORMAT';
$format = Foswiki::Func::getPreferencesValue($prefName);
}

unless ($format) {
my ($type) = $this->getMappedMimeType($fileName);
if ($type) {
$prefName = 'ATTACHED_'.uc($type).'_FORMAT';
$format = Foswiki::Func::getPreferencesValue($prefName);

# backwards compatibility
if ($type eq 'image' && !$format) {
$prefName = 'ATTACHEDIMAGEFORMAT';
$format = Foswiki::Func::getPreferencesValue($prefName);
}
} catch Error::Simple with {
$error = shift->{-text};
$this->writeDebug("ERROR: $error");
};
}
}

last if $error;
unless ($format) {
$format = Foswiki::Func::getPreferencesValue('ATTACHED_FILE_FORMAT');
$format = Foswiki::Func::getPreferencesValue('ATTACHEDFILELINKFORMAT') unless $format; # backwards compatibility
}

if ($dbCacheEnabled) {
# enabling dbcache handlers again
Foswiki::Plugins::DBCachePlugin::enableRenameHandler();
$format = ' * [[$percntATTACHURLPATH$percnt/$filename][$filename]]: $comment' unless $format;

return $format;
}


# manually update this topic
Foswiki::Plugins::DBCachePlugin::loadTopic($web, $topic);
sub types {
my $this = shift;

$this->{_types} = Foswiki::Func::readFile($Foswiki::cfg{MimeTypesFileName}) unless defined $this->{_types};
$this->{_types} //= "";

return $this->{_types};
}

sub getMimeType {
my ($this, $fileName) = @_;

my $mimeType;
my $suffix = $fileName;

if ($fileName =~ /\.([^.]+)$/) {
$suffix = $1;
}

if ($error) {
$this->printJSONRPC($response, 1, $error, $id);
} else {
$this->printJSONRPC($response, 0, undef, $id)
if ($this->types =~ /^([^#]\S*).*?\s$suffix(?:\s|$)/im) {
$mimeType = $1;
}

return unless defined $mimeType;

my ($type, $subType) = $mimeType =~ /^(.*)\/(.*)$/;

return wantarray ? ($type, $subType) : $mimeType;
}

sub getMappedMimeType {
my ($this, $fileName) = @_;

my ($type, $subType) = $this->getMimeType($fileName);
return unless defined $type;

if ($type eq 'application') {
if ($subType =~ /document|msword|msexcel|rtf/) {
$type = 'document';
} elsif ($subType =~ /pdf|postscript/) {
$type = 'pdf';
} elsif ($subType =~ /xcf/) {
$type = 'image';
}
}

return wantarray ? ($type, $subType) : "$type/$subType";
}


1;

0 comments on commit 8ebb009

Please sign in to comment.