From a2e354942288fb1d8d30dc4b9b664cc58b6dd23e Mon Sep 17 00:00:00 2001 From: MichaelDaum Date: Fri, 17 Jul 2015 19:50:47 +0200 Subject: [PATCH] Item13536: rewrite as jQuery plugin --- data/System/RedDotPlugin.txt | 5 +- lib/Foswiki/Plugins/RedDotPlugin.pm | 242 ++---------------- lib/Foswiki/Plugins/RedDotPlugin/Core.pm | 223 ++++++++++++++++ lib/Foswiki/Plugins/RedDotPlugin/MANIFEST | 2 + pub/System/RedDotPlugin/Makefile | 2 +- .../RedDotPlugin/reddot.uncompressed.js | 63 +++-- 6 files changed, 294 insertions(+), 243 deletions(-) create mode 100644 lib/Foswiki/Plugins/RedDotPlugin/Core.pm diff --git a/data/System/RedDotPlugin.txt b/data/System/RedDotPlugin.txt index fc345f0..ff19721 100644 --- a/data/System/RedDotPlugin.txt +++ b/data/System/RedDotPlugin.txt @@ -1,4 +1,4 @@ -%META:TOPICINFO{author="ProjectContributor" date="1407719200" format="1.1" version="1"}% +%META:TOPICINFO{author="ProjectContributor" date="1437155427" format="1.1" version="1"}% ---+!! %TOPIC% This plugin renders a clickable red dot (.) to ease the edit access to @@ -49,11 +49,12 @@ Arguments: | Plugin Author: | Michael Daum | -| Copyright ©: | 2005-2014, Michael Daum http://michaeldaumconsulting.com | +| Copyright ©: | 2005-2015, Michael Daum http://michaeldaumconsulting.com | | License: | GPL ([[http://www.gnu.org/copyleft/gpl.html][GNU General Public License]]) | | Release: | %$RELEASE% | | Version: | %$VERSION% | | Change History: |   | +| 05 Mar 2015: | rewrite as a jQuery plugin | | 13 Mar 2013: | modernizing some parts | | 11 Nov 2010: | use JQICON instead of own getIconUrl() procedure; \ adding js to animate the pencil; \ diff --git a/lib/Foswiki/Plugins/RedDotPlugin.pm b/lib/Foswiki/Plugins/RedDotPlugin.pm index ab32f5d..9c1bcfd 100644 --- a/lib/Foswiki/Plugins/RedDotPlugin.pm +++ b/lib/Foswiki/Plugins/RedDotPlugin.pm @@ -1,6 +1,6 @@ # Plugin for Foswiki - The Free and Open Source Wiki, http://foswiki.org/ # -# Copyright (C) 2005-2014 Michael Daum http://michaeldaumconsulting.com +# Copyright (C) 2005-2015 Michael Daum http://michaeldaumconsulting.com # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -10,245 +10,41 @@ # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details, published at +# GNU General Public License for more details, published at # http://www.gnu.org/copyleft/gpl.html # -############################################################################### package Foswiki::Plugins::RedDotPlugin; use strict; use warnings; -############################################################################### +use Foswiki::Func (); +use Foswiki::Plugins (); +use Foswiki::Plugins::JQueryPlugin (); - -our $VERSION = '3.12'; -our $RELEASE = '3.12'; +our $VERSION = '4.00'; +our $RELEASE = '5 Mar 2015'; our $NO_PREFS_IN_TOPIC = 1; -our $SHORTDESCRIPTION = 'Renders edit-links as little red dots'; -our $baseTopic; -our $baseWeb; -our $counter; -our $currentAction; -our $user; - -use constant TRACE => 0; # toggle me - -############################################################################### -sub writeDebug { - #Foswiki::Func::writeDebug("- RedDotPlugin - " . $_[0]) if TRACE; - print STDERR "- RedDotPlugin - " . $_[0] . "\n" if TRACE; -} +our $SHORTDESCRIPTION = 'Quick-edit links'; +our $core; -############################################################################### sub initPlugin { - ($baseTopic, $baseWeb, $user) = @_; - - Foswiki::Func::registerTagHandler('REDDOT', \&renderRedDot); - Foswiki::Func::registerTagHandler('REDDOTINIT', \&renderRedDotInit); - - $counter = 0; - $baseWeb =~ s/\//\./go; - $currentAction = ''; - - return 1; -} - -############################################################################### -sub renderRedDotInit { - my ($session, $params, $theTopic, $theWeb) = @_; - - my $theAnimate = Foswiki::Func::isTrue($params->{animate}, 1); - - addStuffToHead($theAnimate); - return ""; -} - -############################################################################### -sub addStuffToHead { - my $animated = shift; - - Foswiki::Func::addToZone('head', 'REDDOTPLUGIN::CSS', <<'HERE'); - -HERE - - if ($animated) { - Foswiki::Func::addToZone('script', 'REDDOTPLUGIN::JS', <<'HERE', "JQUERYPLUGIN::FOSWIKI"); - -HERE - } -} - -############################################################################### -sub renderRedDot { - my ($session, $params, $theTopic, $theWeb) = @_; - - #writeDebug("called renderRedDot($theWeb, $theTopic), parms=".$params->stringify); - - my $requestAction = getRequestAction(); - return '' unless $requestAction =~ /^view/; - - my $theWebTopics = $params->{_DEFAULT} || "$theWeb.$theTopic"; - my $theRedirect = $params->{redirect}; - my $theText = $params->{text}; - my $theStyle = $params->{style} || ''; - my $theClass = $params->{class} || ''; - my $theIcon = $params->{icon} || 'pencil'; - my $theGrant = $params->{grant} || '.*'; - my $theTitle = $params->{title}; - my $theAnimate = Foswiki::Func::isTrue($params->{animate}, 1); - my $theAction = $params->{action}; - my $theTemplate = $params->{template}; - my $theParent = $params->{parent}; - - my $mode = 'redDotIconMode'; - if ($theText) { - if (defined $theText) { - $mode = 'redDotTextMode'; - } else { - $mode = 'redDotDefaultMode'; - $theText = '.'; - } - $theText = "$theText"; - } else { - $theText = '%JQICON{"'.$theIcon.'" format=""}%'; - } - if ($theAnimate) { - $mode .= ' redDotAnimated'; - } - - my $query = Foswiki::Func::getCgiQuery(); - unless ($theRedirect) { - my $redirectPref = Foswiki::Func::getPreferencesValue("REDDOT_REDIRECT"); - if ($redirectPref) { - $redirectPref = Foswiki::Func::expandCommonVariables($redirectPref); - my ($redirectWeb, $redirectTopic) = Foswiki::Func::normalizeWebTopicName($baseWeb, $redirectPref); - $theRedirect = Foswiki::Func::getScriptUrl($redirectWeb, $redirectTopic, 'view'); - } else { - my $queryString = $query->query_string; - - # SMELL: double quotes, even encoded truncate the redirectto. - # so we double encode them - $queryString =~ s/\%22/\%2522/g; - $theRedirect = Foswiki::Func::getScriptUrl($baseWeb, $baseTopic, 'view'). - '?'.$queryString; - } - $theRedirect .= "#reddot$counter"; - } + Foswiki::Plugins::JQueryPlugin::registerPlugin('reddot', 'Foswiki::Plugins::RedDotPlugin::Core'); - # find the first webtopic that we have access to - my $thisWeb; - my $thisTopic; - my $hasEditAccess = 0; - my $wikiName = Foswiki::Func::getWikiName(); + $core = undef; + + Foswiki::Func::registerTagHandler('REDDOT', sub { + my $session = shift; - foreach my $webTopic (split(/\s*,\s*/, $theWebTopics)) { - #writeDebug("testing webTopic=$webTopic"); + $core = Foswiki::Plugins::JQueryPlugin::createPlugin('reddot', $session) + unless defined $core; - ($thisWeb, $thisTopic) = - Foswiki::Func::normalizeWebTopicName($baseWeb, $webTopic); - $thisWeb =~ s/\//\./go; - - if (Foswiki::Func::topicExists($thisWeb, $thisTopic)) { - #writeDebug("checking access on $thisWeb.$thisTopic for $wikiName"); - $hasEditAccess = Foswiki::Func::checkAccessPermission("CHANGE", - $wikiName, undef, $thisTopic, $thisWeb); - if ($hasEditAccess) { - $hasEditAccess = 0 unless $wikiName =~ /$theGrant/; - # SMELL: use the users and groups functions to check - # if we are in theGrant - } - if ($hasEditAccess) { - #writeDebug("granted"); - last; - } - } - } - - if (!$hasEditAccess) { + return $core->handleRedDot(@_) if $core; return ''; - } - - #writeDebug("rendering red dot on $thisWeb.$thisTopic for $wikiName"); - - my %params = (); - $params{t} = time(); - $params{action} = $theAction if defined $theAction; - $params{template} = $theTemplate if defined $theTemplate; - $params{redirectto} = $theRedirect if $theRedirect ne "$thisWeb.$thisTopic"; - - # red dotting - my $result = - "action)) { - $currentAction = $request->action(); - } else { - my $context = Foswiki::Func::getContext(); - - # not all cgi actions we want to distinguish set their context - # so only use those we are sure of - return 'edit' if $context->{'edit'}; - return 'view' if $context->{'view'}; - return 'save' if $context->{'save'}; - # TODO: more - - # fall back to analyzing the path info - my $pathInfo = $ENV{'PATH_INFO'} || ''; - $currentAction = $ENV{'REQUEST_URI'} || ''; - if ($currentAction =~ /^.*?\/([^\/]+)$pathInfo.*$/) { - $currentAction = $1; - } else { - $currentAction = 'view'; - } - #writeDebug("PATH_INFO=$ENV{'PATH_INFO'}"); - #writeDebug("REQUEST_URI=$ENV{'REQUEST_URI'}"); - #writeDebug("currentAction=$currentAction"); - - } - - return $currentAction; + return 1; } 1; diff --git a/lib/Foswiki/Plugins/RedDotPlugin/Core.pm b/lib/Foswiki/Plugins/RedDotPlugin/Core.pm new file mode 100644 index 0000000..76378f8 --- /dev/null +++ b/lib/Foswiki/Plugins/RedDotPlugin/Core.pm @@ -0,0 +1,223 @@ +# Plugin for Foswiki - The Free and Open Source Wiki, http://foswiki.org/ +# +# Copyright (C) 2005-2015 Michael Daum http://michaeldaumconsulting.com +# +# 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. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details, published at +# http://www.gnu.org/copyleft/gpl.html +# +package Foswiki::Plugins::RedDotPlugin::Core; + +use strict; +use warnings; + +use Foswiki::Func (); +use Foswiki::Plugins (); +use Foswiki::Plugins::JQueryPlugin (); +use Foswiki::Plugins::JQueryPlugin::Plugin (); + +our @ISA = qw( Foswiki::Plugins::JQueryPlugin::Plugin ); + +use constant TRACE => 0; # toggle me + +############################################################################### +# static +sub writeDebug { + #Foswiki::Func::writeDebug("- RedDotPlugin - " . $_[0]) if TRACE; + print STDERR "- RedDotPlugin - " . $_[0] . "\n" if TRACE; +} + +############################################################################### +sub new { + my $class = shift; + my $session = shift || $Foswiki::Plugins::SESSION; + + my $this = bless($class->SUPER::new( + $session, + name => 'RedDot', + version => '4.00', + author => 'Michael Daum', + homepage => 'http://foswiki.org/Extensions/RedDotPlugin', + puburl => '%PUBURLPATH%/%SYSTEMWEB%/RedDotPlugin', + documentation => '%SYSTEMWEB%.RedDotPlugin', + javascript => ['reddot.js'], + css => ['reddot.css'], + dependencies => ['livequery', 'JQUERYPLUGIN::FOSWIKI'], + currentAction => undef, + counter => 0, + ), $class); + + return $this; +} + +############################################################################### +sub handleRedDot { + my ($this, $params, $theTopic, $theWeb) = @_; + + #writeDebug("called handleRedDot($theWeb, $theTopic), parms=".$params->stringify); + + my $requestAction = $this->getRequestAction(); + return '' unless $requestAction =~ /^view/; + + my $theWebTopics = $params->{_DEFAULT} || "$theWeb.$theTopic"; + my $theRedirect = $params->{redirect}; + my $theText = $params->{text}; + my $theStyle = $params->{style} || ''; + my $theClass = $params->{class} || ''; + my $theIcon = $params->{icon} || 'pencil'; + my $theGrant = $params->{grant} || '.*'; + my $theTitle = $params->{title}; + my $theAnimate = Foswiki::Func::isTrue($params->{animate}, 1); + my $theAction = $params->{action}; + my $theTemplate = $params->{template}; + my $theParent = $params->{parent}; + + my $mode = 'redDotIconMode'; + if ($theText) { + if (defined $theText) { + $mode = 'redDotTextMode'; + } else { + $mode = 'redDotDefaultMode'; + $theText = '.'; + } + $theText = "$theText"; + } else { + $theText = '%JQICON{"' . $theIcon . '" format=""}%'; + } + if ($theAnimate) { + $mode .= ' redDotAnimated'; + } + + my $baseWeb = $this->{session}{webName}; + my $baseTopic = $this->{session}{topicName}; + + my $query = Foswiki::Func::getCgiQuery(); + unless ($theRedirect) { + my $redirectPref = Foswiki::Func::getPreferencesValue("REDDOT_REDIRECT"); + if ($redirectPref) { + $redirectPref = Foswiki::Func::expandCommonVariables($redirectPref); + my ($redirectWeb, $redirectTopic) = Foswiki::Func::normalizeWebTopicName($baseWeb, $redirectPref); + $theRedirect = Foswiki::Func::getScriptUrl($redirectWeb, $redirectTopic, 'view'); + } else { + my $queryString = $query->query_string; + + # SMELL: double quotes, even encoded truncate the redirectto. + # so we double encode them + $queryString =~ s/\%22/\%2522/g; + + $theRedirect = Foswiki::Func::getScriptUrl($baseWeb, $baseTopic, 'view') . '?' . $queryString; + } + $theRedirect .= "#reddot".$this->{counter}; + } + + # find the first webtopic that we have access to + my $thisWeb; + my $thisTopic; + my $hasEditAccess = 0; + my $wikiName = Foswiki::Func::getWikiName(); + + foreach my $webTopic (split(/\s*,\s*/, $theWebTopics)) { + #writeDebug("testing webTopic=$webTopic"); + + ($thisWeb, $thisTopic) = Foswiki::Func::normalizeWebTopicName($baseWeb, $webTopic); + $thisWeb =~ s/\//\./go; + + if (Foswiki::Func::topicExists($thisWeb, $thisTopic)) { + #writeDebug("checking access on $thisWeb.$thisTopic for $wikiName"); + $hasEditAccess = Foswiki::Func::checkAccessPermission("CHANGE", $wikiName, undef, $thisTopic, $thisWeb); + if ($hasEditAccess) { + $hasEditAccess = 0 unless $wikiName =~ /$theGrant/; + # SMELL: use the users and groups functions to check + # if we are in theGrant + } + if ($hasEditAccess) { + #writeDebug("granted"); + last; + } + } + } + + if (!$hasEditAccess) { + return ''; + } + + #writeDebug("rendering red dot on $thisWeb.$thisTopic for $wikiName"); + + my %params = (); + $params{t} = time(); + $params{action} = $theAction if defined $theAction; + $params{template} = $theTemplate if defined $theTemplate; + $params{redirectto} = $theRedirect if $theRedirect ne "$thisWeb.$thisTopic"; + + # red dotting + my $result = "{counter}++) . '\' ' . 'href=\'' . Foswiki::Func::getScriptUrl($thisWeb, $thisTopic, 'edit', %params); + + $result .= '\' '; + if ($theTitle) { + $result .= "title='%ENCODE{\"$theTitle\" type=\"entity\"}%'"; + } else { + $result .= "title='Edit $thisWeb.$thisTopic'"; + } + $result .= ">$theText"; + + #writeDebug("done handleRedDot"); + + return $result; +} + +############################################################################### +# take the REQUEST_URI, strip off the PATH_INFO from the end, the last word +# is the action; this is done that complicated as there may be different +# paths for the same action depending on the apache configuration (rewrites, aliases) +sub getRequestAction { + my $this = shift; + + my $currentAction = $this->{currentAction}; + + unless (defined $currentAction) { + + my $request = Foswiki::Func::getCgiQuery(); + + if (defined($request->action)) { + $currentAction = $request->action(); + } else { + my $context = Foswiki::Func::getContext(); + + # not all cgi actions we want to distinguish set their context + # so only use those we are sure of + return 'edit' if $context->{'edit'}; + return 'view' if $context->{'view'}; + return 'save' if $context->{'save'}; + # TODO: more + + # fall back to analyzing the path info + my $pathInfo = $ENV{'PATH_INFO'} || ''; + $currentAction = $ENV{'REQUEST_URI'} || ''; + if ($currentAction =~ /^.*?\/([^\/]+)$pathInfo.*$/) { + $currentAction = $1; + } else { + $currentAction = 'view'; + } + #writeDebug("PATH_INFO=$ENV{'PATH_INFO'}"); + #writeDebug("REQUEST_URI=$ENV{'REQUEST_URI'}"); + #writeDebug("currentAction=$currentAction"); + + } + + $this->{currentAction} = $currentAction; + } + + return $currentAction; +} + +1; diff --git a/lib/Foswiki/Plugins/RedDotPlugin/MANIFEST b/lib/Foswiki/Plugins/RedDotPlugin/MANIFEST index 58b2382..4f16e9e 100644 --- a/lib/Foswiki/Plugins/RedDotPlugin/MANIFEST +++ b/lib/Foswiki/Plugins/RedDotPlugin/MANIFEST @@ -1,4 +1,6 @@ data/System/RedDotPlugin.txt 0644 +lib/Foswiki/Plugins/RedDotPlugin/Core.pm 0644 +lib/Foswiki/Plugins/RedDotPlugin/DEPENDENCIES 0644 lib/Foswiki/Plugins/RedDotPlugin.pm 0644 pub/System/RedDotPlugin/Makefile 0644 pub/System/RedDotPlugin/reddot.css 0644 diff --git a/pub/System/RedDotPlugin/Makefile b/pub/System/RedDotPlugin/Makefile index 22852bd..5e74583 100644 --- a/pub/System/RedDotPlugin/Makefile +++ b/pub/System/RedDotPlugin/Makefile @@ -1,4 +1,4 @@ -FOSWIKI_ROOT?=~/foswiki/trunk/core +FOSWIKI_ROOT?=~/foswiki/core TARGET=reddot.css reddot.js -include $(FOSWIKI_ROOT)/pub/System/JQueryPlugin/Makefile.include diff --git a/pub/System/RedDotPlugin/reddot.uncompressed.js b/pub/System/RedDotPlugin/reddot.uncompressed.js index a5df9bd..ed99aaf 100644 --- a/pub/System/RedDotPlugin/reddot.uncompressed.js +++ b/pub/System/RedDotPlugin/reddot.uncompressed.js @@ -1,38 +1,67 @@ /* - * reddot helper + * jQuery.RedDot plugin * - * Copyright (c) 2010-2014 Michael Daum http://michaeldaumconsulting.com + * Copyright (c) 2010-2015 Michael Daum http://michaeldaumconsulting.com * * Dual licensed under the MIT and GPL licenses: * http://www.opensource.org/licenses/mit-license.php * http://www.gnu.org/licenses/gpl.html * - * Revision: $Id$ - * */ jQuery(function($) { - $('.redDotAnimated:not(.redDotInited)').livequery(function() { - var $this = $(this), - opts = $this.data(), - parentElem; +"use strict"; + + /*************************************************************************** + * class definition + */ + function RedDot(elem, opts) { + var self = this; + + self.elem = $(elem); + self.opts = $.extend({}, opts, self.elem.data()); + self.init(); + } + + /*************************************************************************** + * init redDot instance + */ + RedDot.prototype.init = function() { + var self = this; - if (typeof(opts.parent) === 'undefined') { - parentElem = $this.parent(); + if (typeof(self.opts.parent) === 'undefined') { + self.parentElem = self.elem.parent(); } else { - parentElem = $this.parents(opts.parent).first(); + self.parentElem = self.elem.parents(self.opts.parent).first(); } - $this.addClass('redDotInited'); - parentElem.hoverIntent({ + self.parentElem.hoverIntent({ over: function() { - $this.fadeIn(500, function() { - $this.css({opacity: 1.0}); + self.elem.fadeIn(500, function() { + self.elem.css({opacity: 1.0}); }); }, out: function() { - $this.stop(); - $this.css({display:'none', opacity: 1.0}); + self.elem.stop(); + self.elem.css({display:'none', opacity: 1.0}); } }); + }; + + /*************************************************************************** + * make it a jQuery plugin + */ + $.fn.redDot = function(opts) { + return this.each(function() { + if (!$.data(this, "redDot")) { + $.data(this, "redDot", new RedDot(this, opts)); + } + }); + }; + + /*************************************************************************** + * enable declarative widget instanziation + */ + $(".redDotAnimated:not(.redDotInited)").livequery(function() { + $(this).addClass("redDotInited").redDot(); }); });