Skip to content

Commit

Permalink
Item13727: Item12923: improved json representation
Browse files Browse the repository at this point in the history
- don't expand macros in web/topic/text/summary
- preparing final release
  • Loading branch information
MichaelDaum committed Sep 22, 2015
1 parent 4500638 commit bf3a8ef
Show file tree
Hide file tree
Showing 5 changed files with 227 additions and 60 deletions.
191 changes: 174 additions & 17 deletions data/System/ListyPlugin.txt
@@ -1,31 +1,188 @@
%META:TOPICINFO{author="ProjectContributor" comment="reprev" date="1394206737" format="1.1" reprev="2" version="2"}%
%META:TOPICINFO{author="ProjectContributor" comment="" date="1442921713" format="1.1" version="1"}%
---+!! %TOPIC%
%SHORTDESCRIPTION%
%$SHORTDESCRIPTION%

%TOC%

This plugin implements an interactive list manager. A "Listy" is a collection of text or links that can be
maintained easily using modal dialogs, dragged and dropped to sort or move around between multiple listies.

There are a couple of ways to use a Listy:

* as a customizable sidebar navigation
* as a list of links on a frontpage
* as a kanban-like task manager

All of these use cases have in common that you may freely interact with items on a listy.

Technically speaking, a listy is stored as [[%SYSTEMWEB%.MetaData][MetaData]] attached to a topic. A listy is
made up of multiple entries of the form =%META:LISTY= to the same topic. Multiple independent listies can
be stored on a single topic by defining the "collection" identifier. Also, multiple independent listies of the
same collection can be stored in separate topics.

---++ Usage

---++ Examples
---+++ Simple

Just type

<verbatim class="tml">
%LISTY%
</verbatim>

anywhere on a topic to get started. Data will be stored into the current topic.

---+++ My Links

To store "My Links" of the currently logged in user, use:

<verbatim class="tml">
%LISTY{
"mylinks"
topic="%WIKIUSERNAME%"
}%
</verbatim>

This will store the set of links organized by this widget into the user's profile page and have them in a "mylinks" collection.

---+++ Kanban-ish
To create a simple three-state task manager use this:

(with the help of [[Foswiki:Extensions/GridLayoutPlugin][GridLayoutPlugin]])

<verbatim class="tml">
%BEGINGRID{border="on"}%
%BEGINCOL{"4"}%
---++ Todo
%LISTY{
"todo"
collections="todo, inprogress, done"
}%
%BEGINCOL{"4"}%
---++ In progress
%LISTY{
"inprogress"
collections="todo, inprogress, done"
}%
%BEGINCOL{"4"}%
---++ Done
%LISTY{
"done"
collections="todo, inprogress, done"
}%
%ENDGRID%
</verbatim>

This will display three listies next to each
other, a "todo", an "inprogress" and a "done" listy. You will be able to create entries for each listy, assign them to one of the
collections and move them around using drag and drop.

---+++ Custom formatting

A listy can be integrated in a wiki application specifying a customized formatting for each listy item. Below
renders each topic in a listy by displaying an image and part of its [[%SYSTEMWEB%.DataForms][DataForm]].

(with the help of [[Foswiki:Extensions/ImagePlugin][ImagePlugin]] and [[Foswiki:Extensions/FlexFormPlugin][FlexFormPlugin]] and a custom !DataForm for movies)

<verbatim class="tml">
%LISTY{
type="topic"
width="500px"
buttons="both"
format="<div class='$class clearfix'>$tools
$percntIMAGE{\"$percntFORMFIELD{\"Image\"}$percnt\" size=\"100\" align=\"left\" type=\"plain\"}$percnt
<h3>
<span class='foswikiGrayText foswikiRight foswikiSmall'>#$index</span>
<a href='$url'>$title</a>
</h3>
<div class='foswikiGrayText'>
$percntRENDERFORDISPLAY{
fields=\"Rating, Release, AgeRating_i, Genre\"
format=\"$title: $value\"
separator=\"%BR%\"
hidenull=\"on\"
}$percnt
</div>
</div>"
}%
</verbatim>

---++ Syntax

=%<nop>LISTY{"&lt;collection>" ...}%=

| *Parameter* | *Description* | *Default* |
| =topic= | | =%<nop>BASETOPIC%= |
| =collection= | the collection ID, can be just any string; leave it empty to refer to the "default" collection | =&lt;empty>= |
| =collections= | list of known collections stored at =topic=; this lets you move a listy item between collectiosn without having a drag'n drop | |
| =hidenull= | boolean flag to hide the listy when there are no items in it | =false= |
| =showcollections= | boolean flag to show/hide the collections select box in the item editor | =true= |
| =sort= | sort listies using the specified property; possible values are =index=, =title=, =summary=, =date= | =index= |
| =reverse= | boolean flag to reverse the sorting order as specified in =sort= | =off= |
| =types= | specify types of listy items, possible values are =topic=, =text=, =external= | =topic, text, external= |
| =autosave= | boolean flag to enable/disable saving changes automatically on every action; if switched off you will need to hit the "save" button to make any changes to the listy permanent; if switched on (default) any change will be stored immediately | =true= |
| =format=, =topic_format=, =text_format=, =external_format= | format string of listy items; there are a number of variables to be used in the format (see below) | defined in =listyplugin.tmpl= |
| =buttons= | specify where the UI buttons are located; possible values are =top=, =bottom=, =both= | =bottom= |
| =width= | width of listy widget, e.g. =width="500px" | |
| =class= | additional css class to be added to the listy widget | |

The parameters =format=, =topic_format=, =text_format=, =external_format= may use the following variables:

| *Name* | *Description* |
| =$tools= | expands to the tools to interact with a listy item |
| =$class= | css class of a listy item |
| =$date= | date when the listy item was last changed |
| =$index= | index of listy item within collection |
| =$url= | link url of listy item |
| =$type= | type of this item ("topic", "text" or "external") |
| =$title= | title text of listy item |
| =$topic= | topic value of a "topic" listy item |
| =$web= | web value of a "topic" listy item |
| =$name= | name/id of this listy item |
| =$summary= | summary |
| =$json= | listy item as a json object; this is used by the widget to interact with the backend |

There are a couple of additional variables that are used in the =listyplugin.tmpl= default strings:

| *Name* | *Description* |
| =$item= | inserts the listy item into the result |
| =$buttons= | button format |
| =$topbuttons= | buttons located at the top |
| =$bottombuttons= | buttons located at the bottom |
| =$sourceweb= | |
| =$sourcetopic= | |
| =$collection= | collection id |
| =$showcollections= | true/false |
| =$types= | selected types of this listy |
| =$autosave= | true/false |
| =$count= | number of listy items |
| =$style= | extra css |
| =$class= | extra class |
| =$allcollections= | list of collections known by the current listy |
| =$listyID= | id of the current listy |
| =$tml= | url-escaped TML used to render this listy; this is used to re-render the widget after an update |

---++ Installation Instructions

%$INSTALL_INSTRUCTIONS%

---++ Info
<!--
* Set SHORTDESCRIPTION = %$SHORTDESCRIPTION%
-->

| Author(s): | Michael Daum|
| Copyright: | &copy; 2015 Michael Daum http://michaeldaumconsulting.com |
| License: | [[http://www.gnu.org/licenses/gpl.html][GPL (Gnu General Public License)]] |
| Release: | %$RELEASE% |
| Version: | %$VERSION% |
| Change History: | <!-- versions below in reverse order -->&nbsp; |
---++ Dependencies
%$DEPENDENCIES%

---++ Change History

%TABLE{columnwidths="7em" tablewidth="100%"}%
| 22 Sep 2015: | first final relase |
| 31 Aug 2015: | fourth beta release |
| 17 Jul 2015: | third beta release |
| 24 Jan 2014: | renamed from <nop>BookmarksPlugin to ListyPlugin |
| Dependencies: | %$DEPENDENCIES% |
| Home page: | Foswiki:Extensions/%TOPIC% |
| Support: | Foswiki:Support/%TOPIC% |

%META:FORM{name="PackageForm"}%
%META:FIELD{name="Author" title="Author" value="Michael Daum"}%
%META:FIELD{name="Version" title="Version" value="%25$VERSION%25"}%
%META:FIELD{name="Release" title="Release" value="%25$RELEASE%25"}%
%META:FIELD{name="Repository" title="Repository" value="https://github.com/foswiki/ListyPlugin"}%
%META:FIELD{name="Copyright" title="Copyright" value="&copy; 2015 Michael Daum http://michaeldaumconsulting.com"}%
%META:FIELD{name="License" title="License" value="[[http://www.gnu.org/licenses/gpl.html][GPL (Gnu General Public License)]]"}%
%META:FIELD{name="Home" title="Home" value="http://foswiki.org/Extensions/ListyPlugin"}%
%META:FIELD{name="Support" title="Support" value="Foswiki:Support/ListyPlugin"}%
4 changes: 2 additions & 2 deletions lib/Foswiki/Plugins/ListyPlugin.pm
Expand Up @@ -28,8 +28,8 @@ use Foswiki::Func ();
use Foswiki::Plugins ();
use Foswiki::Contrib::JsonRpcContrib ();

our $VERSION = '1.00_004';
our $RELEASE = '31 Aug 2015';
our $VERSION = '1.00';
our $RELEASE = '22 Sep 2015';
our $SHORTDESCRIPTION = 'Fancy list manager';
our $NO_PREFS_IN_TOPIC = 1;
our $core;
Expand Down
65 changes: 38 additions & 27 deletions lib/Foswiki/Plugins/ListyPlugin/Core.pm
Expand Up @@ -14,14 +14,16 @@
# http://www.gnu.org/copyleft/gpl.html

package Foswiki::Plugins::ListyPlugin::Core;

use strict;
use warnings;

use Foswiki::Plugins::JQueryPlugin ();
use Foswiki::Contrib::JsonRpcContrib::Error ();
use Error qw(:try);
use JSON ();
#use Data::Dump qw(dump);

use strict;
use warnings;

=begin TML
---+ package ListyPlugin::Core
Expand Down Expand Up @@ -120,18 +122,18 @@ sub LISTY {
my $theCollection = $params->{_DEFAULT} || $params->{collection} || '';
my $theHidenull = Foswiki::Func::isTrue($params->{hidenull}, 0);
my $theTopic = $params->{topic} || $this->{baseTopic};
my $theWeb = $params->{web} || $this->{baseWeb};
my $theCollections = $params->{collections};
my $theShowCollections = Foswiki::Func::isTrue($params->{showcollections}, defined($theCollections));
($theWeb, $theTopic) = Foswiki::Func::normalizeWebTopicName($theWeb, $theTopic);
my $theReverse = Foswiki::Func::isTrue($params->{reverse}, 0);
my $theSort = $params->{sort};
$theSort = "index" if !defined($theSort) || $theSort !~ /^(index|title|summary|date)$/;
my $theReverse = Foswiki::Func::isTrue($params->{reverse}, 0);

my $theTypes = $params->{type} || 'text, topic, external';
my %types = map {$_ => 1} split(/\s*,\s*/, $theTypes);
my $theAutoSave = Foswiki::Func::isTrue($params->{autosave}, 1) ? 'true':'false';

my $theWeb;
($theWeb, $theTopic) = Foswiki::Func::normalizeWebTopicName($this->{baseWeb}, $theTopic);
#writeDebug("called LISTY ... web=$theWeb, topic=$theTopic");

unless (Foswiki::Func::checkAccessPermission('VIEW', $wikiName, undef, $theTopic, $theWeb)) {
Expand Down Expand Up @@ -222,14 +224,12 @@ sub LISTY {
$line =~ s/\$index\b/$item->{index}+1/ge;
$line =~ s/\$url\b/$url/g;
$line =~ s/\$type\b/$item->{type}/g;
$line =~ s/\$title\(encode\)/_urlEncode($title)/ge;
$line =~ s/\$title\b/$title/g;
$line =~ s/\$topic\b/$topic/g;
$line =~ s/\$web\b/$web/g;
$line =~ s/\$name\(encode\)/_urlEncode($item->{name})/ge;
$line =~ s/\$name\b/$item->{name}/g;
$line =~ s/\$summary\(encode\)/_urlEncode($summary)/ge;
$line =~ s/\$summary\b/$summary/g;
$line =~ s/\$json\b/$this->_formatAsJson($item)/ge;
push @results, $line;
}

Expand Down Expand Up @@ -304,29 +304,36 @@ sub LISTY {
<script src="%PUBURLPATH%/%SYSTEMWEB%/ListyPlugin/jquery.listy.js"></script>
HERE

$origTml = '%LISTY{'.$params->stringify.'}%';
$origTml =~ s/([^0-9a-zA-Z-_.:~!*'\/])/_urlEncode($1)/ge; # url encode
$origTml = _urlEncode('%LISTY{'.$params->stringify.'}%');
$origTml = '<div class="jqListyTml" style="display:none">'.$origTml.'</div>';
}

Foswiki::Func::addToZone("head", "LISTY::PLUGIN", <<'HERE', "JQUERYPLUGIN::UI");
<link rel="stylesheet" href="%PUBURLPATH%/%SYSTEMWEB%/ListyPlugin/jquery.listy.css" media="all" />
HERE

$result =~ s/\$encode\((.*?)\)/_entityEncode($1)/ges;
$result =~ s/\$urlEncode\((.*?)\)/_urlEncode($1)/ges;
$result =~ s/\$tml\b/$origTml/g;

return $result;
}

sub _entityEncode {
my $text = shift;
return unless defined $text;
sub json {
my $this = shift;

$text =~ s/([[\x01-\x09\x0b\x0c\x0e-\x1f"%&'*<=>@[_\|])/'&#'.ord($1).';'/ge;
unless (defined $this->{json}) {
$this->{json} = JSON->new->pretty(TRACE)->convert_blessed(1);
}

return $text;
return $this->{json};
}

sub _formatAsJson {
my ($this, $item) = @_;

return "{}" unless $item;

my %copy = map {$_ => _urlEncode($item->{$_})} keys %$item;
return $this->json->encode(\%copy);
}

sub _urlEncode {
Expand All @@ -339,11 +346,12 @@ sub _urlEncode {
return $text;
}


sub _urlDecode {
my ($text, $doDecode) = @_;
return unless defined $text;
return "" unless defined $text;

$text =~ s/%([\da-f]{2})/chr(hex($1))/gei;
$text =~ s/%([\da-f]{2})/chr(hex($1))/ge;
$text = Encode::decode_utf8($text) if $doDecode && $Foswiki::UNICODE;

return $text;
Expand Down Expand Up @@ -438,11 +446,11 @@ sub _getListyFromRequest {
collection => _urlDecode($request->param("collection")),
summary => _urlDecode($request->param("summary")),
title => _urlDecode($request->param("title")),
web => $request->param("listyWeb"),
topic => $request->param("listyTopic"),
type => $request->param("type"),
url => $request->param("url"),
index => $request->param("index"),
web => _urlDecode($request->param("listyWeb")),
topic => _urlDecode($request->param("listyTopic")),
type => _urlDecode($request->param("type")),
url => _urlDecode($request->param("url")),
index => _urlDecode($request->param("index")),
};

#print STDERR "item from request:".dump($item)."\n";
Expand All @@ -460,10 +468,13 @@ sub _getListyFromJson {

#print STDERR "before json:".dump($item)."\n";

foreach my $key (keys %$item) {
my $val = _urlDecode($item->{$key}, 1);
$item->{$key} = $val;
}

$item->{date} = time();
$item->{name} = $name;
$item->{title} = _urlDecode($item->{title}, 1);
$item->{summary} = _urlDecode($item->{summary}, 1);

#print STDERR "after json:".dump($item)."\n";

Expand Down

0 comments on commit bf3a8ef

Please sign in to comment.