You can subscribe to this list here.
2000 |
Jan
|
Feb
|
Mar
|
Apr
(4) |
May
(38) |
Jun
(3) |
Jul
(12) |
Aug
(4) |
Sep
(12) |
Oct
(15) |
Nov
(26) |
Dec
(8) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2001 |
Jan
(14) |
Feb
(34) |
Mar
(105) |
Apr
(64) |
May
(56) |
Jun
(97) |
Jul
(180) |
Aug
(103) |
Sep
(54) |
Oct
(21) |
Nov
(44) |
Dec
(27) |
2002 |
Jan
(7) |
Feb
(10) |
Mar
(88) |
Apr
(57) |
May
(29) |
Jun
(12) |
Jul
(13) |
Aug
(35) |
Sep
(12) |
Oct
(16) |
Nov
(48) |
Dec
(94) |
2003 |
Jan
(36) |
Feb
(43) |
Mar
(124) |
Apr
(63) |
May
(77) |
Jun
(12) |
Jul
(7) |
Aug
(40) |
Sep
(41) |
Oct
(19) |
Nov
(22) |
Dec
(46) |
2004 |
Jan
(51) |
Feb
(129) |
Mar
(82) |
Apr
(96) |
May
(34) |
Jun
(28) |
Jul
(107) |
Aug
(87) |
Sep
(21) |
Oct
(50) |
Nov
(202) |
Dec
(110) |
2005 |
Jan
(174) |
Feb
(159) |
Mar
(250) |
Apr
(287) |
May
(159) |
Jun
(139) |
Jul
(305) |
Aug
(291) |
Sep
(558) |
Oct
(628) |
Nov
(539) |
Dec
(396) |
2006 |
Jan
(828) |
Feb
(470) |
Mar
(888) |
Apr
(524) |
May
(518) |
Jun
(424) |
Jul
(527) |
Aug
(208) |
Sep
(257) |
Oct
(276) |
Nov
(308) |
Dec
(342) |
2007 |
Jan
(366) |
Feb
(350) |
Mar
(265) |
Apr
(406) |
May
(481) |
Jun
(354) |
Jul
(195) |
Aug
(219) |
Sep
(506) |
Oct
(434) |
Nov
(467) |
Dec
(399) |
2008 |
Jan
(339) |
Feb
(185) |
Mar
(172) |
Apr
(191) |
May
(126) |
Jun
(149) |
Jul
(424) |
Aug
(317) |
Sep
(164) |
Oct
(246) |
Nov
(110) |
Dec
(123) |
2009 |
Jan
(82) |
Feb
(74) |
Mar
(125) |
Apr
(133) |
May
(51) |
Jun
(52) |
Jul
(37) |
Aug
(48) |
Sep
(60) |
Oct
(69) |
Nov
(52) |
Dec
(60) |
2010 |
Jan
(55) |
Feb
(69) |
Mar
(55) |
Apr
(144) |
May
(309) |
Jun
(318) |
Jul
(114) |
Aug
(128) |
Sep
(122) |
Oct
(96) |
Nov
(274) |
Dec
(219) |
2011 |
Jan
(223) |
Feb
(241) |
Mar
(266) |
Apr
(286) |
May
(251) |
Jun
(214) |
Jul
(308) |
Aug
(312) |
Sep
(192) |
Oct
(61) |
Nov
(20) |
Dec
(35) |
2012 |
Jan
(165) |
Feb
(70) |
Mar
(102) |
Apr
(96) |
May
(101) |
Jun
(125) |
Jul
(59) |
Aug
(108) |
Sep
(246) |
Oct
(372) |
Nov
(456) |
Dec
(374) |
2013 |
Jan
(215) |
Feb
(402) |
Mar
(386) |
Apr
(274) |
May
(117) |
Jun
(52) |
Jul
(125) |
Aug
(106) |
Sep
(188) |
Oct
(139) |
Nov
(74) |
Dec
(52) |
2014 |
Jan
(301) |
Feb
(62) |
Mar
(229) |
Apr
(85) |
May
(275) |
Jun
(138) |
Jul
(143) |
Aug
(121) |
Sep
(147) |
Oct
(278) |
Nov
(86) |
Dec
(100) |
2015 |
Jan
(113) |
Feb
(92) |
Mar
(96) |
Apr
(273) |
May
(122) |
Jun
(128) |
Jul
(41) |
Aug
(33) |
Sep
(161) |
Oct
(21) |
Nov
(71) |
Dec
(18) |
2016 |
Jan
(243) |
Feb
(35) |
Mar
(98) |
Apr
(102) |
May
(29) |
Jun
(7) |
Jul
(25) |
Aug
(25) |
Sep
(10) |
Oct
(10) |
Nov
(19) |
Dec
(8) |
2017 |
Jan
(18) |
Feb
(8) |
Mar
(4) |
Apr
(18) |
May
(22) |
Jun
(13) |
Jul
(12) |
Aug
(4) |
Sep
(3) |
Oct
(6) |
Nov
(5) |
Dec
(2) |
2018 |
Jan
(6) |
Feb
(2) |
Mar
(1) |
Apr
(4) |
May
(3) |
Jun
(2) |
Jul
(5) |
Aug
(2) |
Sep
(4) |
Oct
(2) |
Nov
|
Dec
|
2019 |
Jan
(1) |
Feb
(2) |
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2020 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
(1) |
Sep
|
Oct
(3) |
Nov
(2) |
Dec
|
2021 |
Jan
|
Feb
|
Mar
(1) |
Apr
|
May
|
Jun
|
Jul
(2) |
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2023 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
(2) |
Jul
(3) |
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2024 |
Jan
|
Feb
|
Mar
(1) |
Apr
(4) |
May
(2) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: <de...@de...> - 2017-07-26 06:29:25
|
Author: HideyoImazu Date: 2017-07-26 06:06:53 +0000 (Wed, 26 Jul 2017) New Revision: 30362 Trac url: http://develop.twiki.org/trac/changeset/30362 Modified: twiki/branches/TWikiRelease06x00/core/lib/TWiki/Access.pm Log: Item7791: Error in Detailed Items Query - Use of uninitialized value in concatenation Modified: twiki/branches/TWikiRelease06x00/core/lib/TWiki/Access.pm =================================================================== --- twiki/branches/TWikiRelease06x00/core/lib/TWiki/Access.pm 2017-07-26 06:06:22 UTC (rev 30361) +++ twiki/branches/TWikiRelease06x00/core/lib/TWiki/Access.pm 2017-07-26 06:06:53 UTC (rev 30362) @@ -162,7 +162,7 @@ package TWiki::Access::Helper; -sub MONITOR { 0 } +sub MONITOR { 0 } # don't forget to change the other MONITOR() sub new { my( $class, $access, $mode, $user, $topic, $web ) = @_; @@ -299,7 +299,7 @@ use Assert; # Enable this for debug. Done as a sub to allow perl to optimise it out. -sub MONITOR { 0 } +sub MONITOR { 0 } # don't forget to change the other MONITOR() =pod @@ -517,9 +517,9 @@ $allowText = $this->_expandVariables($allowText, $web, $topic); } - print STDERR "$web.$topic ALLOWTOPIC$mode = $allowText\n" - if MONITOR; } + print STDERR "$web.$topic ALLOWTOPIC$mode = $allowText\n" + if MONITOR; if( !$foreignWebAllowDynamic && $users->isInList( $user, $allowText, $topic, $web ) ) { |
From: <de...@de...> - 2017-07-26 06:28:54
|
Author: HideyoImazu Date: 2017-07-26 06:06:22 +0000 (Wed, 26 Jul 2017) New Revision: 30361 Trac url: http://develop.twiki.org/trac/changeset/30361 Modified: twiki/trunk/core/lib/TWiki/Access.pm Log: Item7791: Error in Detailed Items Query - Use of uninitialized value in concatenation Modified: twiki/trunk/core/lib/TWiki/Access.pm =================================================================== --- twiki/trunk/core/lib/TWiki/Access.pm 2017-07-26 06:02:54 UTC (rev 30360) +++ twiki/trunk/core/lib/TWiki/Access.pm 2017-07-26 06:06:22 UTC (rev 30361) @@ -162,7 +162,7 @@ package TWiki::Access::Helper; -sub MONITOR { 0 } +sub MONITOR { 0 } # don't forget to change the other MONITOR() sub new { my( $class, $access, $mode, $user, $topic, $web ) = @_; @@ -299,7 +299,7 @@ use Assert; # Enable this for debug. Done as a sub to allow perl to optimise it out. -sub MONITOR { 0 } +sub MONITOR { 0 } # don't forget to change the other MONITOR() =pod @@ -517,9 +517,9 @@ $allowText = $this->_expandVariables($allowText, $web, $topic); } - print STDERR "$web.$topic ALLOWTOPIC$mode = $allowText\n" - if MONITOR; } + print STDERR "$web.$topic ALLOWTOPIC$mode = $allowText\n" + if MONITOR; if( !$foreignWebAllowDynamic && $users->isInList( $user, $allowText, $topic, $web ) ) { |
From: <de...@de...> - 2017-07-26 06:25:26
|
Author: HideyoImazu Date: 2017-07-26 06:02:54 +0000 (Wed, 26 Jul 2017) New Revision: 30360 Trac url: http://develop.twiki.org/trac/changeset/30360 Modified: twiki/branches/TWikiRelease06x00/core/lib/TWiki/Store/RcsFile.pm Log: Item7818: TWiki::Store::RcsFile::moveTopic() may fail to move attachments Modified: twiki/branches/TWikiRelease06x00/core/lib/TWiki/Store/RcsFile.pm =================================================================== --- twiki/branches/TWikiRelease06x00/core/lib/TWiki/Store/RcsFile.pm 2017-07-26 06:01:57 UTC (rev 30359) +++ twiki/branches/TWikiRelease06x00/core/lib/TWiki/Store/RcsFile.pm 2017-07-26 06:02:54 UTC (rev 30360) @@ -632,6 +632,7 @@ my $from = $this->{pubDir}.'/'.$this->{web}.'/'.$this->{topic}; if( -e $from ) { my $to = $this->{pubDir}.'/'.$newWeb.'/'.$newTopic; + File::Path::rmtree( $to ); # Item7818 _moveFile( $from, $to ); } |
From: <de...@de...> - 2017-07-26 06:24:29
|
Author: HideyoImazu Date: 2017-07-26 06:01:57 +0000 (Wed, 26 Jul 2017) New Revision: 30359 Trac url: http://develop.twiki.org/trac/changeset/30359 Modified: twiki/trunk/core/lib/TWiki/Store/RcsFile.pm Log: Item7818: TWiki::Store::RcsFile::moveTopic() may fail to move attachments Modified: twiki/trunk/core/lib/TWiki/Store/RcsFile.pm =================================================================== --- twiki/trunk/core/lib/TWiki/Store/RcsFile.pm 2017-07-21 08:59:17 UTC (rev 30358) +++ twiki/trunk/core/lib/TWiki/Store/RcsFile.pm 2017-07-26 06:01:57 UTC (rev 30359) @@ -632,6 +632,7 @@ my $from = $this->{pubDir}.'/'.$this->{web}.'/'.$this->{topic}; if( -e $from ) { my $to = $this->{pubDir}.'/'.$newWeb.'/'.$newTopic; + File::Path::rmtree( $to ); # Item7818 _moveFile( $from, $to ); } |
From: <de...@de...> - 2017-07-21 09:20:46
|
Author: MahiroAndo Date: 2017-07-21 08:59:17 +0000 (Fri, 21 Jul 2017) New Revision: 30358 Trac url: http://develop.twiki.org/trac/changeset/30358 Added: twiki/trunk/EJSPlugin/.gitignore twiki/trunk/EJSPlugin/data/ twiki/trunk/EJSPlugin/data/TWiki/ twiki/trunk/EJSPlugin/data/TWiki/EJSPluginAPI.txt twiki/trunk/EJSPlugin/data/TWiki/EJSPluginTableAPI.txt twiki/trunk/EJSPlugin/data/TWiki/VarEJS_INCLUDE.txt twiki/trunk/EJSPlugin/lib/ twiki/trunk/EJSPlugin/lib/TWiki/ twiki/trunk/EJSPlugin/lib/TWiki/Plugins/ twiki/trunk/EJSPlugin/lib/TWiki/Plugins/EJSPlugin.pm twiki/trunk/EJSPlugin/lib/TWiki/Plugins/EJSPlugin/ twiki/trunk/EJSPlugin/lib/TWiki/Plugins/EJSPlugin/Config.spec twiki/trunk/EJSPlugin/lib/TWiki/Plugins/EJSPlugin/DEPENDENCIES twiki/trunk/EJSPlugin/lib/TWiki/Plugins/EJSPlugin/Func.pm twiki/trunk/EJSPlugin/lib/TWiki/Plugins/EJSPlugin/MANIFEST twiki/trunk/EJSPlugin/lib/TWiki/Plugins/EJSPlugin/build.pl twiki/trunk/EJSPlugin/t/ twiki/trunk/EJSPlugin/t/01-basics.t twiki/trunk/EJSPlugin/t/02-parseParam.t twiki/trunk/EJSPlugin/t/03-findTopics.t twiki/trunk/EJSPlugin/t/testenv.cfg Log: Item7817: Import initial code Added: twiki/trunk/EJSPlugin/.gitignore =================================================================== --- twiki/trunk/EJSPlugin/.gitignore (rev 0) +++ twiki/trunk/EJSPlugin/.gitignore 2017-07-21 08:59:17 UTC (rev 30358) @@ -0,0 +1,2 @@ +EJSPlugin.* +EJSPlugin_* Added: twiki/trunk/EJSPlugin/data/TWiki/EJSPluginAPI.txt =================================================================== --- twiki/trunk/EJSPlugin/data/TWiki/EJSPluginAPI.txt (rev 0) +++ twiki/trunk/EJSPlugin/data/TWiki/EJSPluginAPI.txt 2017-07-21 08:59:17 UTC (rev 30358) @@ -0,0 +1,710 @@ +%META:TOPICINFO{author="TWikiContributor" date="1495793747" format="1.1" version="$Rev$"}% +---+!! !EJSPlugin API + +This page lists all the API functions for [[EJSPlugin]]. See also [[EJSPluginTableAPI][EJS Table API List]]. + +<!-- + * Set EJS = off + * Set SAVE_ACTION_POLICIES = See also [[EJSPlugin#Save_Action_Policies][Save Action Policies]]. + * Set DATE_TIME_VALUES = See also [[EJSPlugin#Date_Time_Values][Date/Time Values]]. +--> + +%TOC% + +---++ print +<verbatim> +print("text"[, "text" ...]); +</verbatim> + +Appends output texts. +Multiple arguments are appended altogether. +If non-string objects are given, [[#JSON][JSON.stringify()]] is automatically used to serialize the data. + +---++ println +<verbatim> +println("text"[, "text" ...]); +</verbatim> + +Appends output texts in the same way as [[#print][print()]], followed by a line break at the end. + +---++ requireTopic +<verbatim> +requireTopic("[Web.]Topic"); +requireTopic({web: "Web", topic: "Topic"}); +</verbatim> + +Executes the topic content as EJS. A topic is loaded only once even when used multiple times. +It should usually be used to load !JavaScript libraries. + +An exception is thrown if the topic does not exist or if the VIEW permission is denied. + +---++ findWebs +<verbatim> +var webNames = findWebs("Web*"); +var webNames = findWebs({web: "Web*"}); +var formattedNames = findWebs("Web*", function (webName, loop) {}); +var formattedNames = findWebs({web: "Web*", callback: function (webName, loop) {}}); +</verbatim> + +Returns an array of web names that are matched with a pattern with wildcards. + +---++ findTopics +<verbatim> +var topicNames = findTopics("[Web*.]Topic*"); +var topicNames = findTopics({web: "Web*", topic: "Topic*"}); +var formattedNames = findTopics("[Web*.]Topic*", function (topicName, loop) {}); +var formattedNames = findTopics({web: "Web*", topic: "Topic*", callback: function (topicName, loop) {}}); +</verbatim> + +Returns an array of topic names that are matched with a pattern with wildcards. The web name can also include wildcards. + +If a web name is specified, the returned topic names will contain the web name prefix. + +For example: + +<verbatim> +findTopics('TestTopic*'); // returns ['TestTopic1', 'TestTopic2'] +findTopics('WebA.TestTopic*'); // returns ['WebA.TestTopic1', 'WebA.TestTopic2'] +findTopics('Web*.TestTopic*'); // returns ['WebA.TestTopic1', 'WebA.TestTopic2', 'WebB.TestTopic1', 'WebB.TestTopic2'] +</verbatim> + +---++ webExists +<verbatim> +var exists = webExists("Web"); +var exists = webExists({web: "Web"}); +</verbatim> + +Determines if the web exists. + +---++ topicExists +<verbatim> +var exists = topicExists("[Web.]Topic"); +var exists = topicExists({web: "Web", topic: "Topic"}); +</verbatim> + +Determines if the topic exists. + +---++ createWeb +<verbatim> +createWeb("%WEB%/SubWeb"); +createWeb("%WEB%/SubWeb", {baseWeb: "TemplateWeb"}); +createWeb({web: "%WEB%/SubWeb", baseWeb: "TemplateWeb"}); +</verbatim> + +Creates a new web or subweb. Because of the default same-web policy, this API is usually used to create a subweb rather than a top-level web. + +If the =baseWeb= parameter is given, the new web is copied from the baseWeb. +Otherwise, the baseWeb defaults to the configured value (=$TWiki::cfg{EJSPlugin}{DefaultBaseWeb}=). + +%SAVE_ACTION_POLICIES% + +---++ moveWeb +<verbatim> +moveWeb("%WEB%/SubWeb1", "%WEB%/SubWeb2"); +moveWeb({web: "%WEB%/SubWeb1", toWeb: "%WEB%/SubWeb2"}); +</verbatim> + +Renames a web or subweb, or moves it to another web or subweb. + +Note: Links are *not* automatically updated. + +%SAVE_ACTION_POLICIES% + +---++ removeWeb +<verbatim> +removeWeb("%WEB%/SubWeb"); +removeWeb("%WEB%/SubWeb", {toWeb: "%TRASHWEB%/SubWeb"}); +removeWeb({web: "%WEB%/SubWeb", toWeb: "%TRASHWEB%/SubWeb"}); +</verbatim> + +Removes a web or subweb. The target web will be moved to the trash web, rather than permanently deleted. + +%SAVE_ACTION_POLICIES% + +---++ readTopic +<verbatim> +var topicText = readTopic("[Web.]Topic"); +var topicText = readTopic("[Web.]Topic", {rev: revisionNumber}); +var topicText = readTopic({web: "Web", topic: "Topic", rev: revisionNumber}); +</verbatim> + +Returns the topic content. + +An exception is thrown if the topic does not exist or if the VIEW permission is denied. + +---++ saveTopic +<verbatim> +saveTopic("[Web.]Topic", "TopicText"); +saveTopic("[Web.]Topic", "TopicText", {forceNewRevision: true, minor: true, breakLock: true, parentTopic: "ParenTopic"}); +saveTopic({web: "Web", topic: "Topic", text: "TopicText", forceNewRevision: true, minor: true, breakLock: true, parentTopic: "ParentTopic"}); +</verbatim> + +Saves the topic content. If the topic does not exist, a new topic is created. + +An exception is thrown if the specified web does not exist or if the CHANGE permission is denied. + +Additional parameter(s) can be specified as below: + +| *Parameter* | *Value* | +| =forceNewRevision= | Force the revision to be incremented, even when the revision number should otherwise stay the same. | +| =minor= | Suppress notification (similarly to =checkpoint= or =quietsave=). | +| =breakLock= | Ignore the edit lock acquired by another user. | +| =parentTopic= | Set the parent topic name. If the value is either =undefined=, =null=, =""=, or ="none"=, then the parent topic will be unset. | +| =formName= | Set the form name (same as [[#setFormName][setFormName()]]) | +| _FormFieldName_ | Form field name/value pairs can be specified to update the values (same as [[#setFormField][setFormField()]]) | + +%SAVE_ACTION_POLICIES% + +---++ moveTopic +<verbatim> +moveTopic("[FromWeb.]FromTopic", "[ToWeb.]ToTopic"); +moveTopic("[FromWeb.]FromTopic", "[ToWeb.]ToTopic", {breakLock: true}); +moveTopic({web: "FromWeb", topic: "FromTopic", toWeb: "ToWeb", toTopic: "ToTopic", breakLock: true}); +</verbatim> + +Renames the topic or moves it to another web. + +An exception is thrown if the topic does not exist or if the CHANGE permission is denied. + +Additional parameter(s) can be specified as below: + +| *Parameter* | *Value* | +| =breakLock= | Ignore the edit lock acquired by another user. | + +%SAVE_ACTION_POLICIES% + +---++ removeTopic +<verbatim> +removeTopic("[Web.]Topic"); +removeTopic("[Web.]Topic", {toTopic: "ToTopic"}); +removeTopic({web: "Web", topic: "Topic", toWeb: "%TRASHWEB%", toTopic: "ToTopic"}); +</verbatim> + +Removes a topic. The target topic will be moved to the trash web, rather than permanently deleted. + +%SAVE_ACTION_POLICIES% + +---++ getFormName +<verbatim> +var formName = getFormName("[Web.]Topic"); +var formName = getFormName("[Web.]Topic", {rev: revisionNumber}); +var formName = getFormName({web: "Web", topic: "Topic", rev: revisionNumber}); +</verbatim> + +Retrieves the form name of the topic. + +An exception is thrown if the topic does not exist or if the VIEW permission is denied. + +---++ setFormName +<verbatim> +setFormName("[Web.]Topic", "ExampleForm"); +setFormName({web: "Web", topic: "Topic", name: "ExampleForm"}); +</verbatim> + +Saves the topic with the new form name. + +An exception is thrown if the topic does not exist or if the CHANGE permission is denied. + +The call of this function will eventually invoke the same logic as [[#saveTopic][saveTopic()]] so the same parameters are accepted. + +%SAVE_ACTION_POLICIES% + +---++ getFormField +<verbatim> +var fieldValue = getFormField("[Web.]Topic", "FieldName"); +var fieldValue = getFormField("[Web.]Topic", "FieldName", {rev: revisionNumber}); +var fieldValue = getFormField({web: "Web", topic: "Topic", name: "FieldName", rev: revisionNumber}); +</verbatim> + +Retrieves the form field value of the topic. + +An exception is thrown if the topic does not exist or if the VIEW permission is denied. + +---++ setFormField +<verbatim> +setFormField(["Web.]Topic", "FieldName", "FieldValue"); +setFormField({web: "Web", topic: "Topic", name: "FieldName", value: "FieldValue"}); +</verbatim> + +Saves the topic with the new form field name/value pair(s). + +An exception is thrown if the topic does not exist or if the CHANGE permission is denied. + +The call of this function will eventually invoke the same logic as [[#saveTopic][saveTopic()]] so the same parameters are accepted. +If multiple fields are to be set, it is more efficient to use [[#saveTopic][saveTopic()]] to set all the fields at the same time. + +%SAVE_ACTION_POLICIES% + +---++ getFormFields +<verbatim> +var fields = getFormFields("[Web.]Topic"); +var fields = getFormFields("[Web.]Topic", {rev: revisionNumber}); +var fields = getFormFields({web: "Web", topic: "Topic", rev: revisionNumber}); +</verbatim> + +Retrieves all the form fields of the topic. The return value is an object of field/value pairs. + +An exception is thrown if the topic does not exist or if the VIEW permission is denied. + +---++ checkPermission +<verbatim> +var allowed = checkPermission("[Web.]Topic", "VIEW"); // or "CHANGE" +var allowed = checkPermission({web: "Web", topic: "Topic", type: "VIEW"}); // or "CHANGE" +</verbatim> + +Determines if the specified permission type is allowed for the topic. + +An exception is thrown if the topic does not exist. + +---++ getRevisionInfo +<verbatim> +var revisionInfo = getRevisionInfo("[Web.]Topic"); +var revisionInfo = getRevisionInfo("[Web.]Topic", {rev: revisionNumber}); +var revisionInfo = getRevisionInfo({web: "Web", topic: "Topic", rev: revisionNumber}); +</verbatim> + +Retrieves the revision information. +An exception is thrown if the topic does not exist or if the VIEW permission is denied. + +| *Return Value* | *Description* | +| revisionInfo.rev | Revision number, such as 1, 2, 3, ... | +| revisionInfo.time | Unix timestamp | +| revisionInfo.user | User name stored in the revision management system | +| revisionInfo.userName | Converted user name, retrieved by [[#getUserName][getUserName()]] | + +%DATE_TIME_VALUES% + +---++ getRevisionAtTime +<verbatim> +var revisionNumber = getRevisionAtTime("[Web.]Topic", unixTimestamp); +var revisionNumber = getRevisionAtTime({web: "Web", topic: "Topic", time: unixTimestamp}); +</verbatim> + +Retrieves the revision number at the specified Unix timestamp. + +%DATE_TIME_VALUES% + +---++ getEditLock +<verbatim> +var editLock = getEditLock("[Web.]Topic"); +var editLock = getEditLock({web: "Web", topic: "Topic"}); +</verbatim> + +Retrieves the edit lock (a.k.a. lease file) of the topic. +Returns =undefined= if there are no lease files. + +An exception is thrown if the topic does not exist or if the VIEW permission is denied. + +| *Return Value* | *Description* | +| editLock.user | The user name stored in the lease file | +| editLock.userName | Converted user name, retrieved by [[#getUserName][getUserName()]] | +| editLock.conflict | A string indicating a lock conflict ("lease_active" or "lease_old"); or an empty string if no conflicts | +| editLock.taken | Unix timestamp at which the lock was taken | +| editLock.expires | Unix timestamp at which the lock is to expire | + +%DATE_TIME_VALUES% + +---++ acquireEditLock +<verbatim> +acquireEditLock("[Web.]Topic"); +acquireEditLock({web: "Web", topic: "Topic"}); +</verbatim> + +Acquires the edit lock (a.k.a. lease file) to prevent other users from editing the same topic. + +An exception is thrown if there is a lease conflict with another user, if the topic does not exist or if the CHANGE permission is denied. + +---++ releaseEditLock +<verbatim> +releaseEditLock("[Web.]Topic"); +releaseEditLock({web: "Web", topic: "Topic"}); +</verbatim> + +Releases the edit lock acquired by the current user if any. If there is an edit lock acquired by another user, the lease file is left unchanged. + +An exception is thrown if the topic does not exist. + +---++ getAttachmentList +<verbatim> +var fileNames = getAttachmentList("[Web.]Topic"); +var fileNames = getAttachmentList({web: "Web", topic: "Topic"}); +</verbatim> + +Returns an array of attachment names of the topic. + +An exception is thrown if the topic does not exist or if the VIEW permission is denied. + +---++ attachmentExists +<verbatim> +var exists = attachmentExists("[Web.]Topic", "FileName.txt"); +var exists = attachmentExists({web: "Web", topic: "Topic", file: "FileName.txt"}); +</verbatim> + +Determines if the attachment exists. + +---++ readAttachment +<verbatim> +var contentText = readAttachment("[Web.]Topic", "FileName.txt"); +var contentText = readAttachment("[Web.]Topic", "FileName.txt", {rev: fileRevisionNumber}); +var contentText = readAttachment({web: "Web", topic: "Topic", file: "FileName.txt", rev: fileRevisionNumber}); +</verbatim> + +Retrieves the attachment file content. + +An exception is thrown if the attachment does not exist or if the VIEW permission is denied. + +---++ saveAttachment +<verbatim> +saveAttachment("[Web.]Topic", "FileName.txt", "CataText"); +saveAttachment({web: "Web", topic: "Topic", file: "FileName.txt", data: "CataText"}); +</verbatim> + +Saves the attachment file content. If the attachment does not exist, a new attachment is created. + +An exceptiton is thrown if the topic does not exist or if the CHANGE permission is denied. + +%SAVE_ACTION_POLICIES% + +---++ moveAttachment +<verbatim> +moveAttachment("[FromWeb.]FromTopic", "FromFileName.txt", "[ToWeb.]ToTopic", "ToFileName.txt"); +moveAttachment({web: "FromWeb", topic: "FromTopic", file: "FromFileName.txt", toWeb: "ToWeb", toTopic: "ToTopic", toFile: "ToFileName.txt"}); +</verbatim> + +Renames the attachment or moves it to another topic. + +An exception is thrown if the attachment does not exist or if the CHANGE permission is denied. + +%SAVE_ACTION_POLICIES% + +---++ removeAttachment +<verbatim> +removeTopic("[Web.]Topic", "FileName.txt"); +removeTopic({web: "Web", topic: "Topic", file: "FileName.txt", toWeb: "%TRASHWEB%", toTopic: "ToTopic", toFile: "ToFileName.txt"}); +</verbatim> + +Removes an attachment. The target attachment will be moved to the =TrashAttachment= topic in the trash web, rather than permanently deleted. + +%SAVE_ACTION_POLICIES% + +---++ getMethod +<verbatim> +var method = getMethod(); // "GET" or "POST" +</verbatim> + +Retrieves the current HTTP request method. + +---++ isPost +<verbatim> +var condition = isPost(); +</verbatim> + +Determines if the current HTTP request method is POST. + +---++ getParam +<verbatim> +var paramValue = getParam("ParamName"); +var paramValue = getParam("ParamName", "DefaultValue"); +var paramValue = getParam({name: "ParamName", default: "DefaultValue"}); +</verbatim> + +Retrieves the URL parameter value (GET) or form-data value (POST). + +---++ setParam +<verbatim> +setParam("ParamName", "ParamValue"); +setParam({name: "ParamName", value: "ParamValue"}); +</verbatim> + +Sets the URL parameter value (GET) or form-data value (POST) for later use in the session. +It affects the actual usage of =%<nop>URLPARAM{...}%= in the TWiki markup after EJS preprocessing is done. + +---++ getUserName +<verbatim> +var userName = getUserName(); +var userName = getUserName("someUserName"); +var userName = getUserName({user: "someUserName"}); +</verbatim> + +Retrieves the current user name if there are no arguments. + +If the argument is given, it is converted to the canonical or login user name. + +---++ getWikiName +<verbatim> +var wikiName = getWikiName(); +var wikiName = getWikiName("someUserName"); +var wikiName = getWikiName({user: "someUserName"}); +</verbatim> + +Retrieves the current user's wiki name (such as =UserFoobar=) if there are no arguments. + +If the argument is given, it is converted to the user's wiki name. + +---++ getWikiUserName +<verbatim> +var wikiUserName = getWikiUserName(); +var wikiUserName = getWikiUserName("someUserName"); +var wikiUserName = getWikiUserName({user: "someUserName"}); +</verbatim> + +Retrieves the current user's wiki user name (such as =%USERSWEB%.UserFoobar=) if there are no arguments. + +If the argument is given, it is converted to the user's wiki user name. + +---++ getVariable +<verbatim> +var variableValue = getVariable("VARIABLE_NAME"[, {param: value, ...}]); +</verbatim> + +Retrieves the value of the TWiki variable (=%<nop>VARIABLE%=). + +Optionally, parameters can be specified as key/value pairs (=%<nop>VARIABLE{param="value"}%=). +The default parameter is passed as =_DEFAULT= key (=%<nop>VARIABLE{"The default value"}%=). + +---++ setVariable +<verbatim> +setVariable("VARIABLE_NAME", "VariableValue"); +</verbatim> + +Sets the value of the TWiki variable (=%<nop>VARIABLE%=) for later use. +It affects the actual usage of =%<nop>VARIABLE%= in the TWiki markup after EJS preprocessing is done. + +---++ expandVariables +<verbatim> +var expandedText = expandVariables("%FOO% %BAR% %BAZ{...}%"); +</verbatim> + +Expands all the occurrences of the TWiki variables (=%<nop>VARIABLE%=). + +---++ expandAutoInc +<verbatim> +var newTopicName = expandAutoInc("TopicNameAUTOINC001"); +</verbatim> + +Replaces the =AUTOINC= pattern in a topic name with the next number to make a new (non-existing) topic name. + +---++ formatText +<verbatim> +var formatedText = formatText("$foo $bar $baz", {foo: "Foo", bar: "Bar", baz: "Baz"}); +</verbatim> + +Converts the variable names in the =$variable= format, where the values are replaced by the given key/value pairs. +The standard escape variables (such as =$percnt= and =$dollar=) are also expanded. +Non-existing variable names are ignored, and the =$variable= will appear in the result string. + +---++ isTrue +<verbatim> +var condition = isTrue("on/off"); +var condition = isTrue("on/off", "default"); +</verbatim> + +Determines if the given text is a true value. +If it is either "off", "false" or "no", then the value is regarded as false. +If is it =undefined= or =null=, the default value is used instead. + +---++ normalizeWebTopicName +<verbatim> +var nameInfo = normalizeWebTopicName('[Web.]Topic'); +var nameInfo = normalizeWebTopicName('Web', 'Topic'); +var nameInfo = normalizeWebTopicName({web: 'Web', topic: 'Topic'}); +</verbatim> + +Normalizes the web name and topic name. + +| *Return Value* | *Description* | +| =nameInfo.web= | Normalized web name | +| =nameInfo.topic= | Normalized topic name | + +---++ escapeHTML +<verbatim> +var escapedText = escapeHTML("< unescaped >"); +</verbatim> + +Converts special HTML characters (such as =<= and =>=) into HTML entity strings (such as =&lt;= and =&gt;=). + +---++ unescapeHTML +<verbatim> +var unescapedText = unescapeHTML("< escaped >"); +</verbatim> + +Converts HTML entity strings (such as =&lt;= and =&gt;=) into the original HTML characters (such as =<= and =>=). + +---++ escapeQuote +<verbatim> +var escapedText = escapeQuote("\"unescaped\" text\n"); +</verbatim> + +Escapes special characters so that the text can be embedded in the JSON or !JavaScript string notation. + +---++ unescapeQuote +<verbatim> +var unescapedText = unescapeQuote("\\\"escaped\\\" text\\n"); +</verbatim> + +Unescapes special characters that are escaped by [[#escapeQuote][escapeQuote()]]. + +---++ escapeTable +<verbatim> +var escapedText = escapeTable("unescaped || text"); +</verbatim> + +Escapes special characters so that the text can be embedded in the !TWiki table notation. +Special HTML characters are also converted to HTML entity strings. + +---++ unescapeTable +<verbatim> +var unescapedText = unescapeTable("escaped %VBAR%%VBAR% text"); +</verbatim> + +Unescapes special characters that are escaped by [[#escapeTable][escapeTable()]]. +HTML entity strings are also converted to the original HTML characters. + +---++ parseTable +<verbatim> +var table = parseTable("| *A* | *B* |\n" + "| 1 | 2 |\n" + "| 3 | 4 |\n"); +var table = parseTable("| 1 | 2 |\n" + "| 3 | 4 |\n", {header: false}); +var table = parseTable("| 1 | 2 |\n" + "| 3 | 4 |\n", {header: false, fields: ['Field1', 'Field2']}); +var table = parseTable(readTopic("ManyTables"), {target: 2}); +var table = parseTable({text: "| *A* | *B* |\n" + "| 1 | 2 |\n" + "| 3 | 4 |\n"}); +var table = parseTable(..., function (row, loop) {}); +var table = parseTable({text: "...", header: false, fields: [...], target: 2, callback: function (row, loop) {}}); +</verbatim> + +Parses a TWiki table notation. + +| *Argument Parameter* | *Default Value* | *Description* | +| =header= | =true= | Indicates the parsed table has a header row. | +| =fields= | (none) | Specifies an array of field names. If there is already a header row in the parsed table, this parameter will override the field names used in the return value. | +| =target= | =1= | Select a table by number (starting from =1=) out of multiple tables in the input text. | +| =callback= | (none) | Callback function per row. Each =row= argument can be an object of field/value pairs or a simple array, depending on the context. | + +The return value is an object containing =fields= and =rows= if the =fields= are detected from the input or specified as an argument. +If there are no available =fields=, the return value is simply an array of arrays. + +| *Return Value* | *Description* | +| =table.fields= | Array of field names | +| =table.rows= | Array of rows, each of which is an object of field/value pairs | + +By default, the first row is assumed to be a header, and the values are detected as =fields=. +If the =header= parameter is set to =false=, the first row is not parsed as a header. + +If the =fields= parameter is given, the fields used as the keys of each row object are overridden regardless of the first row. + +If a =callback= function is given, each =row= can be altered by returning an updated row object, or excluded by returning nothing (=undefined= or =null=). + +When the input text contains multiple tables, the first table is parsed by default. If the =target= parameter is given, the table at the specified number is detected (starting from =1=). + +All the values are converted by [[#unescapeTable][unescapeTable()]]. + +See also [[EJSPluginTableAPI#parseTable][Table API]] for example code. + +---++ formatTable +<verbatim> +var formatedText = formatTable(table); +var formatedText = formatTable(table, {header: false}); +var formatedText = formatTable(table, function (row, loop) {}); +var formatedText = formatTable({fields: [...], rows: [...], header: false, callback: function (row, loop) {}}); +</verbatim> + +Builds a TWiki table notation from an object representing a table. + +| *Argument Parameter* | *Default Value* | *Description* | +| =fields= | (none) | Array of field names | +| =rows= | (none) | Array of rows, each of which is an object of field/value pairs | +| =header= | =true= | Indicates the header row is prepended to the result table. | +| =callback= | (none) | Callback function per row. Each =row= argument can be an object of field/value pairs or a simple array, depending on the context. | + +The structure of the =table= parameter (first argument) roughly corresponds to the return value of [[#parseTable][parseTable()]], either an object with =fields= and =rows= or an array of arrays. + +By default, the first row is prepended as a header based on the =fields= values. +If the =header= parameter is set to =false= or if there are no =fields=, the header row is not prepended. + +If a =callback= function is given, each =row= can be altered by returning an updated row object, or excluded by returning nothing (=undefined= or =null=). + +All the values are converted by [[#escapeTable][escapeTable()]]. + +Because of how this API works, it can also be used to generate a single row of a table: + +<verbatim> +formatTable([['Foo', 'Bar', 'Baz']]); +// returns "| Foo | Bar | Baz |" + +formatTable({fields: ['Foo', 'Bar', 'Baz']}); +// returns "| *Foo* | *Bar* | *Baz* |" +</verbatim> + +See also [[EJSPluginTableAPI#formatTable][Table API]] for example code. + +---++ parseCSV +<verbatim> +var table = parseCSV("A,B,C\n1,2,3\n4,5,6"); +var table = parseCSV("1,2,3\n4,5,6", {header: false}); +var table = parseCSV("1,2,3\n4,5,6", {header: false, fields: ['Field1', 'Field2', 'Field3']}); +var table = parseCSV({text: "A,B,C\n1,2,3\n4,5,6"}); +var table = parseCSV(..., function (row, loop) {}); +var table = parseCSV({text: "...", header: false, fields: [...], callback: function (row, loop) {}}); +</verbatim> + +Parses a CSV format. The input parameters and the return value are similar to [[#parseTable][parseTable()]]. + +See also [[EJSPluginTableAPI#parseTable][Table API]] for example code. + +---++ formatCSV +<verbatim> +var formatedText = formatCSV(table); +var formatedText = formatCSV(table, {header: false}); +var formatedText = formatCSV(table, function (row, loop) {}); +var formatedText = formatCSV({fields: [...], rows: [...], header: false, callback: function (row, loop) {}}); +</verbatim> + +Builds a CSV text from an object representing a table. The input object and the parameters are similar to [[#formatTable][formatTable()]]. + +See also [[EJSPluginTableAPI#parseTable][Table API]] for example code. + +---++ getJavaScriptEngine +<verbatim> +var engineName = getJavaScriptEngine(); +</verbatim> + +Retrieves the underlying !JavaScript engine name, such as =JE= and =JavaScript::V8=. + +---++ getEJSConfig +<verbatim> +var config = getEJSConfig(); +</verbatim> + +Retrieves the [[EJSPlugin]] configuration under the current execution context. + +| *Return Value* | *Description* | +| =config.namespace= | Namespace for EJSPlugin API functions. Default: =undefined= | +| =config.postMethodPolicy= | POST method policy | +| =config.saveWebPolicy= | Same-web policy | +| =config.timeout= | Timeout in seconds | + +The context may be affected by the system configurations (=$TWiki::cfg=), the preference variables (such as =EJS_NAMESPACE=), and the parameters passed to =%<nop>EJS_INCLUDE{...}%=. + +---++ console +<verbatim> +console.log("message"); +console.debug("message"); +console.info("message"); +console.warn("message"); +console.error("message"); +</verbatim> + +These methods are equivalent to invoking the following code, where the outputs are inserted into the browser-side console. + +<verbatim> +<script>console.log(...);</script> +</verbatim> + +The argument is serialized by =JSON.stringify()=, so non-string objects can also be examined in the console. + +---++ JSON +<verbatim> +var object = JSON.parse("{\"key\": \"value\"}"); +var jsonText = JSON.stringify({key: "value"}); +</verbatim> + +Converts a JSON string into a !JavaScript value, and vice versa. Added: twiki/trunk/EJSPlugin/data/TWiki/EJSPluginTableAPI.txt =================================================================== --- twiki/trunk/EJSPlugin/data/TWiki/EJSPluginTableAPI.txt (rev 0) +++ twiki/trunk/EJSPlugin/data/TWiki/EJSPluginTableAPI.txt 2017-07-21 08:59:17 UTC (rev 30358) @@ -0,0 +1,190 @@ +%META:TOPICINFO{author="TWikiContributor" date="1495793747" format="1.1" version="$Rev$"}% +---+!! !EJSPlugin Table API + +This page describes the usage of EJS Table API of [[EJSPlugin]]. See also [[EJSPluginAPI][EJS API List]]. + +<!-- + * Set EJS = off +--> + +%TOC% + +---++ parseTable + +<verbatim> +parseTable( + "| *A* | *B* |\n" + + "| 1 | 2 |\n" + + "| 3 | 4 |\n" +); +/* +Returns: { + fields: ['A', 'B'], + rows: [ + {A: 1, B: 2}, + {A: 3, B: 4} + ], +} +*/ +</verbatim> + +<verbatim> +parseTable( + "| 1 | 2 |\n" + + "| 3 | 4 |\n", + {header: false} +); +/* +Returns: [ + [1, 2], + [3, 4] +] +*/ +</verbatim> + +<verbatim> +parseTable( + "| *A* | *B* |\n" + + "| 1 | 2 |\n" + + "| 3 | 4 |\n", + {header: true, fields: ['Foo', 'Bar']} +); +/* +Returns: { + fields: ['Foo', 'Bar'], + rows: [ + {Foo: 1, Bar: 2}, + {Foo: 3, Bar: 4} + ], +} +*/ +</verbatim> + +<verbatim> +parseTable( + "| 1 | 2 |\n" + + "| 3 | 4 |\n", + {header: false, fields: ['Foo', 'Bar']} +); +/* +Returns: { + fields: ['Foo', 'Bar'], + rows: [ + {Foo: 1, Bar: 2}, + {Foo: 3, Bar: 4} + ], +} +*/ +</verbatim> + +<verbatim> +parseTable( + "| *A* | *B* |\n" + + "| 1 | 2 |\n" + + "| 3 | 4 |\n", + {fields: ['Foo', 'Bar']} + function (row) { + println(formatText("---++ Foo: $Foo", row)); + println(formatText("Bar: $Bar", row)); + } +); +/* +Prints: +---++ Foo: 1 +Bar: 2 +---++ Foo: 3 +Bar: 4 +*/ +</verbatim> + +---++ formatTable + +<verbatim> +formatTable({ + fields: ['A', 'B'], + rows: [ + {A: 1, B: 2}, + {A: 3, B: 4} + ] +}); +/* +Returns: +| *A* | *B* | +| 1 | 2 | +| 3 | 4 | +*/ +</verbatim> + +<verbatim> +formatTable({ + fields: ['A', 'B'], + rows: [ + {A: 1, B: 2}, + {A: 3, B: 4} + ] +}, {header: false}); +/* +Returns: +| 1 | 2 | +| 3 | 4 | +*/ +</verbatim> + +<verbatim> +formatTable([ + [1, 2], + [3, 4] +]); +/* +Returns: +| 1 | 2 | +| 3 | 4 | +*/ +</verbatim> + +<verbatim> +formatTable({ + fields: ['Foo', 'Bar'], + rows: [ + {Foo: 1, Bar: 2}, + {Foo: 3, Bar: 4} + ] +}, function (row) { + row.Bar = '%RED%' + row.Bar + '%ENDCOLOR%'; + return row; +}); +/* +Returns: +| *Foo* | *Bar* | +| 1 | %RED%2%ENDCOLOR% | +| 3 | %RED%4%ENDCOLOR% | +*/ +</verbatim> + +---++ Special Characters + +The EJSPlugin Table API treats the following character sequences in the special ways: + +| *Sequence* | *Descrpition* | +| %<nop>VBAR% | The vertical bar (<code>%VBAR%</code>) | +| \0 | Null byte | +| \n | Line feed | +| \r | Carriage return | +| \t | Tab | +| \b | Backspace | +| \f | Form feed | +| \v | Vertical tab | +| \\ | Backslash literal (<code>\</code>) | + +When formatting and parsing a table, it escapes and unescapes these sequences in addition to HTML entities. (=escapeTable()= and =unescapeTable()=) + +<verbatim> +// Topic name: TestTable +| <%VBAR%gt;\n | +<!-- Note: \n is encoded as a backslash followed by n --> + +// EJS Code +var table = parseTable(readTopic("TestTable"), {header: false}); +table[0][0] == "<|>\n"; // Note: \n is the actual line break +formatTable(table); // returns the same text as TestTable +</verbatim> Added: twiki/trunk/EJSPlugin/data/TWiki/VarEJS_INCLUDE.txt =================================================================== --- twiki/trunk/EJSPlugin/data/TWiki/VarEJS_INCLUDE.txt (rev 0) +++ twiki/trunk/EJSPlugin/data/TWiki/VarEJS_INCLUDE.txt 2017-07-21 08:59:17 UTC (rev 30358) @@ -0,0 +1,9 @@ +%META:TOPICINFO{author="TWikiContributor" date="1495793747" format="1.1" version="$Rev$"}% +%META:TOPICPARENT{name="TWikiVariables"}% +#VarEJS_INCLUDE +---+++ EJS_INCLUDE -- execute and include topic containing EJS tags + * See [[%SYSTEMWEB%.EJSPlugin]] for information about EJS (Embedded !JavaScript) template. + * This tag is used to embed an EJS-based component topic. The !JavaScript execution context (namespace) within this %<nop>EJS_INCLUDE{...}% tag is completely separate from the outside, even if the "including" topic is also EJS-enabled. + * Syntax: =%<nop>EJS_INCLUDE{"ComponentTopicName" namespace="NamespaceRequiredByComponent" timeout="TimeoutInSeconds"}%= + * Category: ApplicationsAndComponentsVariables, DevelopmentVariables, ImportVariables + * Related: [[%IF{"'%INCLUDINGTOPIC%'='TWikiVariables'" then="#"}%VarINCLUDE][INCLUDE]] Added: twiki/trunk/EJSPlugin/lib/TWiki/Plugins/EJSPlugin/Config.spec =================================================================== --- twiki/trunk/EJSPlugin/lib/TWiki/Plugins/EJSPlugin/Config.spec (rev 0) +++ twiki/trunk/EJSPlugin/lib/TWiki/Plugins/EJSPlugin/Config.spec 2017-07-21 08:59:17 UTC (rev 30358) @@ -0,0 +1,30 @@ +# ---+ Extensions +# ---++ EJSPlugin +# **BOOLEAN** +# Set this option to 1 to execute EJS code within <%...%> by default, without requiring the =EJS= preference setting +$TWiki::cfg{Plugins}{EJSPlugin}{DefaultExecute} = 0; +# **BOOLEAN** +# Set this option to 1 to enable EJS Dynamic Template by default +$TWiki::cfg{Plugins}{EJSPlugin}{DefaultDynamicTemplate} = 0; +# **STRING** +# Optionally set a default !JavaScript namespace for API functions +$TWiki::cfg{Plugins}{EJSPlugin}{DefaultNamespace} = ''; +# **BOOLEAN** +# Set this option to 0 to disable POST Method Policy by default +$TWiki::cfg{Plugins}{EJSPlugin}{DefaultPostMethodPolicy} = 1; +# **BOOLEAN** +# Set this option to 0 to disable Same-Web Policy by default +$TWiki::cfg{Plugins}{EJSPlugin}{DefaultSameWebPolicy} = 1; +# **STRING** +# Optionally set a Perl module name of !JavaScript engine +$TWiki::cfg{Plugins}{EJSPlugin}{JavaScriptEngine} = ''; +# **NUMBER** +# Set a default timeout in seconds for !JavaScript execution +$TWiki::cfg{Plugins}{EJSPlugin}{DefaultTimeout} = 5; +# **NUMBER** +# Set a maximum timeout in seconds that can be overridden by preference (Set 0 to indicate unlimited) +$TWiki::cfg{Plugins}{EJSPlugin}{MaxTimeout} = 180; +# **STRING** +# Set a default template web name used for [[EJSPluginAPI#createWeb][createWeb()]] API +$TWiki::cfg{Plugins}{EJSPlugin}{DefaultBaseWeb} = '_default'; +1; Added: twiki/trunk/EJSPlugin/lib/TWiki/Plugins/EJSPlugin/DEPENDENCIES =================================================================== --- twiki/trunk/EJSPlugin/lib/TWiki/Plugins/EJSPlugin/DEPENDENCIES (rev 0) +++ twiki/trunk/EJSPlugin/lib/TWiki/Plugins/EJSPlugin/DEPENDENCIES 2017-07-21 08:59:17 UTC (rev 30358) @@ -0,0 +1,9 @@ +TWiki::Plugins,>=1.1,perl,TWiki Dakar release. +EJS::Template,>=0.08,cpan,Required for EJS parsing and execution +JE,>=0.066,cpan,Either CPAN:JE or CPAN:JavaScript::V8 is required +JavaScript::V8,>=0.07,cpan,Either CPAN:JE or CPAN:JavaScript::V8 is required +HTML::Entities,>=3.72,cpan,Required +IO::String,>=1.08,cpan,Required +JSON,>=2.94,cpan,Required +Scalar::Util,>=1.48,cpan,Required +Text::CSV,>=1.95,cpan,Required Added: twiki/trunk/EJSPlugin/lib/TWiki/Plugins/EJSPlugin/Func.pm =================================================================== --- twiki/trunk/EJSPlugin/lib/TWiki/Plugins/EJSPlugin/Func.pm (rev 0) +++ twiki/trunk/EJSPlugin/lib/TWiki/Plugins/EJSPlugin/Func.pm 2017-07-21 08:59:17 UTC (rev 30358) @@ -0,0 +1,2047 @@ +use strict; +use warnings; + +package TWiki::Plugins::EJSPlugin::Func; +use base 'Exporter'; + +require TWiki::Func; + +use EJS::Template; +use EJS::Template::Util; +use File::Basename; +use HTML::Entities; +use IO::String; +use JSON; +use Scalar::Util qw(looks_like_number refaddr); +use Text::CSV; + +our @EJS_ROOT_FUNCTIONS = qw( + print + println +); + +our @EJS_FUNCTIONS = qw( + requireTopic + findWebs + findTopics + webExists + topicExists + createWeb + moveWeb + removeWeb + readTopic + saveTopic + moveTopic + removeTopic + getFormName + setFormName + getFormField + setFormField + getFormFields + checkPermission + getRevisionInfo + getRevisionAtTime + getEditLock + acquireEditLock + releaseEditLock + getAttachmentList + attachmentExists + readAttachment + saveAttachment + moveAttachment + removeAttachment + getMethod + isPost + getParam + setParam + getUserName + getWikiName + getWikiUserName + getVariable + setVariable + expandVariables + expandAutoInc + formatText + isTrue + normalizeWebTopicName + escapeHTML + unescapeHTML + escapeQuote + unescapeQuote + escapeTable + unescapeTable + parseTable + formatTable + parseCSV + formatCSV + getJavaScriptEngine + getEJSConfig +); + +our @EXPORT_OK = @EJS_FUNCTIONS; +our %EXPORT_TAGS = (all => \@EXPORT_OK); + +our $CONTEXT = {}; +my $alreadyRequiredTopics; +our $currentlyRequiredWeb; +our $currentlyRequiredTopic; +our $overrideDefaultWeb; +our $overrideDefaultTopic; + +my $alarmAlreadySet = 0; + +sub _executeEJS { + my ($textRef, $web, $topic, $meta, $ejsConfig) = @_; + + # If there are no EJS tags at all, do nothing. + if ($$textRef !~ /<%/) { + return; + } + + eval { + my $ejs = EJS::Template->new(engine => $ejsConfig->{jsEngine}); + my $adapter = $ejs->executor->adapter; + my $engine = $adapter->engine; + + local $CONTEXT = { + adapter => $adapter, + engine => $engine, + config => $ejsConfig, + web => $web, + topic => $topic, + meta => $meta, + requiredTopics => {}, + }; + + my $variables = _initializeVariables(); + + my $timeout = $ejsConfig->{timeout}; + local $SIG{ALRM} = sub {die "EJS took too long (timeout: $timeout sec.)\n"}; + + my $newAlarm = 0; + + if (!$alarmAlreadySet) { + $alarmAlreadySet = 1; + $newAlarm = 1; + alarm $timeout; + } + + EJS::Template->process($textRef, $variables, $textRef); + + if ($newAlarm) { + alarm 0; + $alarmAlreadySet = 0; + } + }; + + if ($@) { + $$textRef .= "\n\n".'%RED%'."EJS: $@".'%ENDCOLOR%'; + } +} + +sub _initializeVariables { + my ($class) = @_; + my $isJE = $CONTEXT->{engine}->isa('JE'); + + my $variables = { + JSON => { + stringify => _wrapFunction(\&TWiki::Plugins::EJSPlugin::Func::JSON_stringify, $isJE), + parse => _wrapFunction(\&TWiki::Plugins::EJSPlugin::Func::JSON_parse, $isJE), + }, + console => { + log => _wrapFunction(\&TWiki::Plugins::EJSPlugin::Func::console_log, $isJE), + debug => _wrapFunction(\&TWiki::Plugins::EJSPlugin::Func::console_debug, $isJE), + info => _wrapFunction(\&TWiki::Plugins::EJSPlugin::Func::console_info, $isJE), + warn => _wrapFunction(\&TWiki::Plugins::EJSPlugin::Func::console_warn, $isJE), + error => _wrapFunction(\&TWiki::Plugins::EJSPlugin::Func::console_error, $isJE), + }, + }; + + my $namespace = _makeNamespace($variables, $CONTEXT->{config}{namespace}); + + no strict 'refs'; + for my $name (@EJS_ROOT_FUNCTIONS) { + $variables->{$name} = _wrapFunction(\&{'TWiki::Plugins::EJSPlugin::Func::'.$name}, $isJE); + } + for my $name (@EJS_FUNCTIONS) { + $namespace->{$name} = _wrapFunction(\&{'TWiki::Plugins::EJSPlugin::Func::'.$name}, $isJE); + } + use strict 'refs'; + + $alreadyRequiredTopics = {}; + + return $variables; +} + +sub _makeNamespace { + my ($root, $spec) = @_; + return $root unless defined $spec; + + my $namespace = $root; + $spec =~ s/^\s+|\s+$//g; + + for my $name (split /\s*\.\s*/, $spec) { + if ($name =~ /^[A-Za-z_\$][A-Za-z_\$0-9]*$/) { + $namespace = ($namespace->{$name} ||= {}); + + if (ref($namespace) ne 'HASH') { + die "Invalid namespace (non-object): $spec\n"; + } + } else { + die "Invalid namespace (unknown characters): $spec\n"; + } + } + + return $namespace; +} + +sub _wrapFunction { + my ($func, $isJE) = @_; + + if ($isJE) { + return sub { + my $ret = eval {$func->(map {_je2perl($_)} @_)}; + die JE::Object::Error->new($CONTEXT->{engine}->global(), _perl2je($@)) if $@; + return _perl2je($ret); + }; + } else { + return sub { + my $ret = $func->(@_); + return _sanitizePerl($ret); + }; + } +} + +sub _sanitizePerl { + my ($value, $seen) = @_; + my $ref = ref $value; + my $addr = refaddr $value; + $seen ||= {}; + + if (!defined $value) { + return undef; + } elsif ($ref) { + if ($ref eq 'HASH') { + return $seen->{$addr} ||= {map {$_ => _sanitizePerl($value->{$_}, $seen)} keys %$value}; + } elsif ($ref eq 'ARRAY') { + return $seen->{$addr} ||= [map {_sanitizePerl($_, $seen)} @$value]; + } elsif ($ref eq 'CODE') { + return $seen->{$addr} ||= sub { + my $ret = $value->(@_); + return _sanitizePerl($ret); + }; + } else { + return undef; + } + } else { + my $class = ref $CONTEXT->{adapter}; + + no strict 'refs'; + my $encode_utf8 = ${$class.'::ENCODE_UTF8'}; + my $sanitize_utf8 = ${$class.'::SANITIZE_UTF8'}; + my $force_untaint = ${$class.'::FORCE_UNTAINT'}; + use strict 'refs'; + + my $newRef = EJS::Template::Util::clean_text_ref(\$value, + $encode_utf8, $sanitize_utf8, $force_untaint); + + return $$newRef; + } +} + +sub _perl2je { + my ($value, $seen) = @_; + my $engine = $CONTEXT->{engine}; + my $ref = ref $value; + my $addr = refaddr $value; + $seen ||= {}; + + if (!defined $value) { + return $engine->undefined(); + } elsif ($ref) { + if ($ref eq 'HASH') { + return $seen->{$addr} ||= $engine->upgrade({map {$_ => _perl2je($value->{$_}, $seen)} keys %$value}); + } elsif ($ref eq 'ARRAY') { + return $seen->{$addr} ||= $engine->upgrade([map {_perl2je($_, $seen)} @$value]); + } elsif ($ref eq 'CODE') { + return $seen->{$addr} ||= $engine->upgrade(sub { + my $ret = $value->(map {_je2perl($_)} @_); + return _perl2je($ret); + }); + } else { + # TODO: Throw an exception? + return $engine->undefined(); + } + } elsif (looks_like_number($value)) { + return JE::Number->new($engine, $value); + } else { + return $engine->upgrade($value); + } +} + +sub _je2perl { + my ($jeObj, $seen) = @_; + my $ref = ref $jeObj; + my $addr = refaddr $jeObj; + $seen ||= {}; + + if ($ref =~ /^JE::/) { + if ($ref =~ /^JE::(?:Object::)?(?:Null|Undefined)$/) { + return undef; + } elsif ($ref =~ /^JE::(?:Object::)?(?:String|Number|Boolean|Date|RegExp)$/) { + return $jeObj->value; + } elsif ($ref =~ /^JE::Object::Function(?:$|::)/) { + return $seen->{$addr} ||= sub { + my $jeRet = $jeObj->(map {_perl2je($_)} @_); + return _je2perl($jeRet); + }; + } elsif ($ref =~ /^JE::Object::Array(?:$|::)/) { + return $seen->{$addr} ||= [map {_je2perl($_, $seen)} @$jeObj]; + } elsif ($ref =~ /^JE::Object(?:$|::)/) { + return $seen->{$addr} ||= {map {$_ => _je2perl($jeObj->{$_}, $seen)} keys %$jeObj}; + } else { + return eval {$jeObj->value}; + } + } + + return $jeObj; +} + +sub _applyCallback { + my ($callback, $values, $param) = @_; + my $loop = {}; + my $results = []; + + for my $index (0..$#$values) { + my $value = $values->[$index]; + + $loop->{first} = ($index == 0 ? 1 : 0); + $loop->{last} = ($index == $#$values ? 1 : 0); + $loop->{index} = $index; + $loop->{value} = $value; + + my $result = $callback->($value, $loop); + push @$results, $result if defined $result; + } + + return $results; +} + +sub _flattenParam { + my ($args) = @_; + + my $param = {}; + my $positional = []; + my $traverse; + + $traverse = sub { + my ($args) = @_; + + for my $arg (@$args) { + my $ref = ref $arg; + + if (!$ref) { + push @$positional, $arg; + } elsif ($ref eq 'HASH') { + for my $key (keys %$arg) { + $param->{$key} = $arg->{$key}; + } + } elsif ($ref eq 'ARRAY') { + # Treat an array as a positional parameter + push @$positional, $arg; + } elsif ($ref eq 'CODE') { + $param->{callback} = $arg; + } + } + }; + + $traverse->($args); + return ($param, $positional); +} + +sub _parseParam { + my ($args, $fields) = @_; + my ($param, $positional) = _flattenParam($args); + + # Scan specification ($fields) + my $missingInParam = []; + my $optionalCount = 0; + my $isSpecified = {}; + my $isOptional = {}; + my $isWildcard = {}; + + for my $rawField (@$fields) { + my $field = $rawField; + my $optional = ($field =~ s/\?$//); + my $wildcard = ($field =~ s/\*$//); + $optional = 1 if $wildcard; + + if (!exists $param->{$field}) { + push @$missingInParam, [\$field, $optional]; + $optionalCount++ if $optional; + } + + $isSpecified->{$field} = 1; + $isOptional->{$field} = 1 if $optional; + $isWildcard->{$field} = 1 if $wildcard; + } + + # Assign scalar params + my $min = @$missingInParam - $optionalCount; + my $max = @$missingInParam; + + if (@$positional < $min) { + (my $func = (caller 1)[3]) =~ s/.*://; + die "Insufficient parameters: $func(".join(', ', @$fields).")\n"; + } elsif (@$positional > $max) { + (my $func = (caller 1)[3]) =~ s/.*://; + die "Too many parameters: $func(".join(', ', @$fields).")\n"; + } + + my $optionalToIgnore = @$missingInParam - @$positional; + my $mappedFields = []; + + for my $pair (@$missingInParam) { + if ($optionalToIgnore > 0 && $pair->[1]) { + $optionalToIgnore--; + } else { + push @$mappedFields, $pair->[0]; + } + } + + for my $i (0..$#$positional) { + my $fieldRef = $mappedFields->[$i]; + $param->{$$fieldRef} = $positional->[$i]; + } + + # Expand variables + for my $key (qw(web topic toWeb toTopic baseWeb user)) { + my $value = $param->{$key}; + + if (defined $value && $value =~ /%/) { + $TWiki::Plugins::SESSION->expandAllTags(\$param->{$key}, + $CONTEXT->{topic}, $CONTEXT->{web}, $CONTEXT->{meta}); + } + } + + # Normalize Web.Topic + for my $keys (['web', 'topic'], ['toWeb', 'toTopic']) { + my ($webKey, $topicKey) = @$keys; + + if ($isSpecified->{$webKey} || $isSpecified->{$topicKey} || + defined $param->{$webKey} || defined $param->{$topicKey}) { + my ($web, $topic) = ($param->{$webKey}, $param->{$topicKey}); + my ($origWeb, $origTopic) = ($web, $topic); + my ($webEmpty, $topicEmpty); + + if (!defined $web || $web eq '') { + $web = $CONTEXT->{web} || $TWiki::Plugins::SESSION->{webName}; + $webEmpty = 1; + } + + if (!defined $topic || $topic eq '') { + $topic = $CONTEXT->{topic} || $TWiki::Plugins::SESSION->{topicName}; + $topicEmpty = 1; + } else { + if ($topic =~ m{[./]}) { + $webEmpty = 0; + } + } + + ($web, $topic) = TWiki::Func::normalizeWebTopicName($web, $topic); + + if ($isWildcard->{$webKey} || $isWildcard->{$topicKey} || + (!$isSpecified->{$webKey} && defined $param->{$webKey}) || + (!$isSpecified->{$topicKey} && defined $param->{$topicKey})) { + $topic = $origTopic if $topicEmpty; + $web = $origWeb if $webEmpty; + } + + ($param->{$webKey}, $param->{$topicKey}) = ($web, $topic); + } + } + + return $param; +} + +sub _attrValue { + my ($text) = @_; + $text =~ s/"/\\"/g; + return '"'.$text.'"'; +} + +sub _wildcard2regex { + my ($wildcard) = @_; + my $regex = quotemeta $wildcard; + $regex =~ s/(?<!\\\\)\\\*/.*/g; + return qr/^$regex$/; +} + +sub _verifyChangePolicy { + my ($action, $webs) = @_; + my $session = $TWiki::Plugins::SESSION; + my $query = $session->{request}; + + # Check for POST policy + if ($CONTEXT->{config}{postMethodPolicy}) { + if ($query->request_method() ne 'POST') { + die "POST method is required for action '$action'\n"; + } + } + + # Check for Same-Web policy + if ($CONTEXT->{config}{sameWebPolicy}) { + my $baseWeb = $session->{SESSION_TAGS}{BASEWEB}; + my $quoted = quotemeta $baseWeb; + my $regex = qr{^$quoted(?:$|[/\.])}; + + for my $web (@{$webs || []}) { + if ($web !~ $regex) { + die "'$web' is outside the current web and cannot be modified\n"; + } + } + } + + # Check for CryptToken + if ($TWiki::cfg{CryptToken}{Enable} && $CONTEXT->{config}{secureActions}{lc $action}) { + eval {TWiki::UI::verifyCryptToken($session, $query->param('crypttoken'))}; + die "Invalid crypttoken\n" if $@; + } +} + +sub _getTopic { + my ($web, $topic, $rev, $permType) = @_; + + # If the topic does not exist, TWiki::Func::readTopic() returns an empty meta + my ($meta) = TWiki::Func::readTopic($web, $topic, $rev); + + my $allowed = TWiki::Func::checkAccessPermission($permType, + TWiki::Func::getWikiName(), $meta->{_text}, $topic, $web, $meta); + + if (!$allowed) { + die "$permType access denied: $web.$topic\n"; + } + + return $meta; +} + +sub _parentWeb { + my ($web) = @_; + return defined $web && $web =~ s/[\/\.][^\/\.]+$// ? $web : undef; +} + +sub requireTopic { + my $param = _parseParam(\@_, ['topic']); + my $web = $param->{web}; + my $topic = $param->{topic}; + + if (exists $CONTEXT->{requiredTopics}{"$web.$topic"}) { + return 0; + } else { + $CONTEXT->{requiredTopics}{"$web.$topic"} = 1; + } + + if (!TWiki::Func::topicExists($web, $topic)) { + die "Topic '$web.$topic' does not exist\n"; + } + + my $meta = _getTopic($web, $topic, $param->{rev}, 'VIEW'); + + local $CONTEXT->{web} = $web; + local $CONTEXT->{topic} = $topic; + local $CONTEXT->{meta} = $meta; + + # Workaround for EJS bug where Executor will unexpectedly overwrite print() and EJS object. + my $variables = {}; + my $isJE = $CONTEXT->{engine}->isa('JE'); + + no strict 'refs'; + for my $name (@EJS_ROOT_FUNCTIONS) { + $variables->{$name} = _wrapFunction(\&{'TWiki::Plugins::EJSPlugin::Func::'.$name}, $isJE); + } + use strict 'refs'; + + EJS::Template->context->process(\$meta->{_text}, $variables); + + return 1; +} + +sub _print { + EJS::Template->context->print(map {ref($_) ? JSON_stringify($_) : $_} @_); +} + +sub print { + _print(@_); + return undef; +} + +sub println { + _print(@_, "\n"); + return undef; +} + +sub findWebs { + my $param = _parseParam(\@_, ['web*']); + my $web = $param->{web}; + + my $filter = $param->{filter}; + my @webs; + + if (!defined $web || $web eq '' || $web eq '*') { + @webs = $TWiki::Plugins::SESSION->{store}->getListOfWebs($filter, undef, 1); + } else { + for my $chunk (split m{/}, $web) { + my @subwebs; + + if ($chunk =~ /\*/) { + my $regex = _wildcard2regex($chunk); + + if (@webs) { + @subwebs = map {$TWiki::Plugins::SESSION->{store}->getListOfWebs($filter, $_, 1)} @webs; + } else { + @subwebs = $TWiki::Plugins::SESSION->{store}->getListOfWebs($filter, undef, 1); + } + + @subwebs = grep {basename($_) =~ $regex} @subwebs; + } else { + if (@webs) { + @subwebs = grep {TWiki::Func::webExists($_)} map {"$_/$chunk"} @webs; + } else { + @subwebs = ($chunk) if TWiki::Func::webExists($chunk); + } + } + + @webs = @subwebs; + last unless @webs; + } + } + + if (my $callback = $param->{callback}) { + return _applyCallback($callback, \@webs, $param); + } else { + return \@webs; + } +} + +sub findTopics { + my $param = _parseParam(\@_, ['topic*']); + my $topic = $param->{topic}; + + my @webs; + my $webSpecified = defined $param->{web}; + + if ($webSpecified) { + if ($param->{web} =~ /\*/) { + @webs = @{findWebs($param->{web}, {filter => $param->{filter}})}; + } elsif (TWiki::Func::webExists($param->{web})) { + @webs = ($param->{web}); + } + } else { + @webs = ($TWiki::Plugins::SESSION->{webName}); + } + + my @topics; + + for my $web (@webs) { + my @foundTopics; + + if (!defined $topic || $topic eq '' || $topic eq '*') { + @foundTopics = TWiki::Func::getTopicList($web); + } elsif ($topic =~ /\*/) { + my $regex = _wildcard2regex($topic); + my @found = TWiki::Func::getTopicList($web); + @foundTopics = grep {$_ =~ $regex} @found; + } else { + if (TWiki::Func::topicExists($web, $topic)) { + @foundTopics = ($topic); + } + } + + if ($webSpecified) { + @foundTopics = map {"$web.$_"} @foundTopics; + } + + push @topics, @foundTopics; + } + + if (my $callback = $param->{callback}) { + my $ret = _applyCallback($callback, \@topics, $param); + return $ret; + } else { + return \@topics; + } +} + +sub webExists { + my $param = _parseParam(\@_, ['web']); + my $web = $param->{web}; + return TWiki::Func::webExists($web) ? 1 : 0; +} + +sub topicExists { + my $param = _parseParam(\@_, ['topic']); + my $web = $param->{web}; + my $topic = $param->{topic}; + return TWiki::Func::topicExists($web, $topic) ? 1 : 0; +} + +sub createWeb { + my $param = _parseParam(\@_, ['web']); + _verifyChangePolicy('createweb', [$param->{web}]); + + my $web = $param->{web}; + my $baseWeb = $param->{baseWeb}; + + unless (defined $baseWeb) { + $baseWeb = $CONTEXT->{config}{defaultBaseWeb}; + } + + my $session = $TWiki::Plugins::SESSION; + my $cUID = $session->{user}; + my $parentWeb = _parentWeb($web); + + # Check metadata + if ($TWiki::cfg{Mdrepo}{WebRecordRequired} && $session->{mdrepo} && + !$session->{mdrepo}->getRec('webs', TWiki::topLevelWeb($web))) { + die "No metadata exists for web '$web'\n"; + } + + # Check existence + if (TWiki::Func::webExists($web)) { + die "Web '$web' already exists\n"; + } elsif (TWiki::Func::topicExists(undef, $web)) { + die "Topic '$web' already exists\n"; + } elsif ($parentWeb && !TWiki::Func::webExists($parentWeb)) { + die "Web '$parentWeb' does not exist\n"; + } elsif (!TWiki::Func::webExists($baseWeb)) { + die "Base web '$baseWeb' does not exist\n"; + } + + # Check permission + if ($parentWeb) { + if (!$session->{users}->canCreateWeb($parentWeb)) { + if (!TWiki::Func::checkAccessPermission('CHANGE', + TWiki::Func::getWikiName(), undef, undef, $parentWeb, undef)) { + die "CREATEWEB access denied: $parentWeb\n"; + } + } + } + + # Execute changes + $session->{store}->createWeb($cUID, $web, $baseWeb, undef); + + return 1; +} + +sub moveWeb { + my $param = _parseParam(\@_, ['web', 'toWeb']); + _verifyChangePolicy('renameweb', [$param->{web}, $param->{toWeb}]); + + my $fromWeb = $param->{web}; + my $toWeb = $param->{toWeb}; + + my $session = $TWiki::Plugins::SESSION; + my $cUID = $session->{user}; + my $parentWeb = _parentWeb($toWeb); + + # Check metadata + if ($TWiki::cfg{Mdrepo}{WebRecordRequired} && $session->{mdrepo} && + !$session->{mdrepo}->getRec('webs', TWiki::topLevelWeb($toWeb))) { + die "No metadata exists for web '$toWeb'\n"; + } + + # Check existence + if (!TWiki::Func::webExists($fromWeb)) { + die "Web '$fromWeb' does not exist\n"; + } + + if (TWiki::Func::webExists($toWeb)) { + die "Web '$toWeb' already exists\n"; + } elsif (TWiki::Func::topicExists(undef, $toWeb)) { + die "Topic '$toWeb' already exists\n"; + } elsif ($parentWeb && !TWiki::Func::webExists($parentWeb)) { + die "Web '$parentWeb' does not exist\n"; + } + + # Check permission + if (!$session->{users}->canRenameWeb($fromWeb, $toWeb)) { + if (!TWiki::Func::checkAccessPermission('CHANGE', + TWiki::Func::getWikiName(), undef, undef, $fromWeb, undef)) { + die "RENAMEWEB access denied: $fromWeb, $toWeb\n"; + } + + if ($parentWeb) { + if (!TWiki::Func::checkAccessPermission('CHANGE', + TWiki::Func::getWikiName(), undef, undef, $parentWeb, undef)) { + die "CHANGE access denied: $parentWeb\n"; + } + } + } + + # TODO: Run something similar to TWiki::UI::Manage::_updateWebReferringTopics? + + # Execute changes + $session->{store}->moveWeb($fromWeb, $toWeb, $cUID); + + return 1; +} + +sub removeWeb { + my $param = _parseParam(\@_, ['web']); + _verifyChangePolicy('renameweb', [$param->{web}]); + + my $fromWeb = $param->{web}; + my $toWeb = $param->{toWeb}; + + my $session = $TWiki::Plugins::SESSION; + my $cUID = $session->{user}; + my $trashWeb = $session->trashWebName(web => $fromWeb); + my $parentWeb = _parentWeb($toWeb); + + if (defined $toWeb) { + if (substr($toWeb, 0, length $trashWeb + 1) ne "$trashWeb/") { + die "Web '$toWeb' must be under '$trashWeb'\n"; + } + } else { + (my $name = $fromWeb) =~ s/[\/\.]//g; + $toWeb .= "$trashWeb/$name"; + + my $base = $toWeb; + my $next = 1; + + while (TWiki::Func::webExists($toWeb) || TWiki::Func::topicExists(undef, $toWeb)) { + $toWeb = $base.$next; + $next++; + } + } + + # Check existence + if (!TWiki::Func::webExists($fromWeb)) { + die "Web '$fromWeb' does not exist\n"; + } + + if (TWiki::Func::webExists($toWeb)) { + die "Web '$toWeb' already exists\n"; + } elsif (TWiki::Func::topicExists(undef, $toWeb)) { + die "Topic '$toWeb' already exists\n"; + } elsif ($parentWeb && !TWiki::Func::webExists($parentWeb)) { + die "Web '$parentWeb' does not exist\n"; + } + + # Check permission + if (!$session->{users}->canRenameWeb($fromWeb, $toWeb)) { + if (!TWiki::Func::checkAccessPermission('CHANGE', + TWiki::Func::getWikiName(), undef, undef, $fromWeb, undef)) { + die "RENAMEWEB access denied: $fromWeb, $toWeb\n"; + } + + if ($parentWeb) { + if (!TWiki::Func::checkAccessPermission('CHANGE', + TWiki::Func::getWikiName(), undef, undef, $parentWeb, undef)) { + die "CHANGE access denied: $parentWeb\n"; + } + } + } + + # Execute changes + $session->{store}->moveWeb($fromWeb, $toWeb, $cUID); + + return 1; +} + +sub readTopic { + my $param = _parseParam(\@_, ['topic']); + my $web = $param->{web}; + my $topi... [truncated message content] |
From: <de...@de...> - 2017-07-21 08:55:15
|
Author: MahiroAndo Date: 2017-07-21 08:33:53 +0000 (Fri, 21 Jul 2017) New Revision: 30357 Trac url: http://develop.twiki.org/trac/changeset/30357 Added: twiki/trunk/EJSPlugin/ Log: Item7817: |
From: Peter T. <pe...@th...> - 2017-07-19 17:50:23
|
All: Please join our TWiki Kampala Release Meeting, http://twiki.org/cgi-bin/view/Codev/KampalaReleaseMeeting2017x07x20 scheduled for 2017-07-20 22:00 GMT [1] on IRC channel #twiki_release on the irc.freenode.net IRC network [2] - in about 28 hours from now. Proposed agenda: 1. Feature Requests for Kampala Release 2. Review Urgent and Not So Urgent Bugs 3. Extensions 4. TWiki Release Discussion 5. Miscellaneous The meeting is on Thursday or Friday, depending on your time zone. Meeting time in different time zones, tomorrow: * USA Pacific Time Zone: 03:00pm on Thu * USA Eastern Time Zone: 06:00pm on Thu * Central Europe: 24:00 on Thu/Fri night * Japan: 07:00 on Fri Please show up in time to save everybody's time. And remember that the release meeting is where decisions are made. We invite all TWiki.orgcontributors to join, as well as people with interest in the TWiki project in general. Cheers, Peter [1]: http://www.timeanddate.com/worldclock/converter.html?iso=20170720T220000&p1=tz_gmt&p2=248&p3=268&p4=224&p5=179 [2]: http://twiki.org/cgi-bin/view/Codev/TWikiIRC -- > Peter Thoeny - Peter09[at]Thoeny.org > http://TWiki.org/Mr.TWiki - consulting on enterprise collaboration > http://TWiki.org - is your team already TWiki enabled? > http://qualityHDR.com - Quality HDR Photography > Knowledge cannot be managed, it can be discovered and shared > This e-mail is: (_) private (_) ask first (x) public |
From: <de...@de...> - 2017-07-14 10:28:14
|
Author: HideyoImazu Date: 2017-07-14 10:08:31 +0000 (Fri, 14 Jul 2017) New Revision: 30356 Trac url: http://develop.twiki.org/trac/changeset/30356 Modified: twiki/branches/TWikiRelease06x00/core/lib/TWiki/Access.pm Log: Item7791: Error in Detailed Items Query - Use of uninitialized value in concatenation Modified: twiki/branches/TWikiRelease06x00/core/lib/TWiki/Access.pm =================================================================== --- twiki/branches/TWikiRelease06x00/core/lib/TWiki/Access.pm 2017-07-14 10:07:35 UTC (rev 30355) +++ twiki/branches/TWikiRelease06x00/core/lib/TWiki/Access.pm 2017-07-14 10:08:31 UTC (rev 30356) @@ -466,7 +466,7 @@ 'DENYTOPIC'.$mode, $web, $topic ); } if( defined( $denyText ) && $denyText =~ /\S/ ) { - $denyText =~ s/^\s*\+/$denyWeb, /; + $denyText =~ s/^\s*\+/$denyWeb, / if defined $denyWeb; my $foreignWebDenyDynamic = 0; if( $isDynamic && $denyText =~ /%/ ) { if( $session->{webName} ne $web ) { |
From: <de...@de...> - 2017-07-14 10:27:18
|
Author: HideyoImazu Date: 2017-07-14 10:07:35 +0000 (Fri, 14 Jul 2017) New Revision: 30355 Trac url: http://develop.twiki.org/trac/changeset/30355 Modified: twiki/trunk/core/lib/TWiki/Access.pm Log: Item7791: Error in Detailed Items Query - Use of uninitialized value in concatenation Modified: twiki/trunk/core/lib/TWiki/Access.pm =================================================================== --- twiki/trunk/core/lib/TWiki/Access.pm 2017-07-05 07:43:44 UTC (rev 30354) +++ twiki/trunk/core/lib/TWiki/Access.pm 2017-07-14 10:07:35 UTC (rev 30355) @@ -466,7 +466,7 @@ 'DENYTOPIC'.$mode, $web, $topic ); } if( defined( $denyText ) && $denyText =~ /\S/ ) { - $denyText =~ s/^\s*\+/$denyWeb, /; + $denyText =~ s/^\s*\+/$denyWeb, / if defined $denyWeb; my $foreignWebDenyDynamic = 0; if( $isDynamic && $denyText =~ /%/ ) { if( $session->{webName} ne $web ) { |
From: Peter T. <pe...@th...> - 2017-07-05 17:53:42
|
All: Please join our TWiki Kampala Release Meeting, http://twiki.org/cgi-bin/view/Codev/KampalaReleaseMeeting2017x07x06 scheduled for 2017-07-06 22:00 GMT [1] on IRC channel #twiki_release on the irc.freenode.net IRC network [2] - in about 28 hours from now. Proposed agenda: 1. Feature Requests for Kampala Release 2. Review Urgent and Not So Urgent Bugs 3. Extensions 4. TWiki Release Discussion 5. Miscellaneous The meeting is on Thursday or Friday, depending on your time zone. Meeting time in different time zones, tomorrow: * USA Pacific Time Zone: 03:00pm on Thu * USA Eastern Time Zone: 06:00pm on Thu * Central Europe: 24:00 on Thu/Fri night * Japan: 07:00 on Fri Please show up in time to save everybody's time. And remember that the release meeting is where decisions are made. We invite all TWiki.orgcontributors to join, as well as people with interest in the TWiki project in general. Cheers, Peter [1]: http://www.timeanddate.com/worldclock/converter.html?iso=20170706T220000&p1=tz_gmt&p2=248&p3=268&p4=224&p5=179 [2]: http://twiki.org/cgi-bin/view/Codev/TWikiIRC -- > Peter Thoeny - Peter09[at]Thoeny.org > http://TWiki.org/Mr.TWiki - consulting on enterprise collaboration > http://TWiki.org - is your team already TWiki enabled? > http://qualityHDR.com - Quality HDR Photography > Knowledge cannot be managed, it can be discovered and shared > This e-mail is: (_) private (_) ask first (x) public |
From: <de...@de...> - 2017-07-05 08:01:18
|
Author: HideyoImazu Date: 2017-07-05 07:43:44 +0000 (Wed, 05 Jul 2017) New Revision: 30354 Trac url: http://develop.twiki.org/trac/changeset/30354 Modified: twiki/branches/TWikiRelease06x00/core/data/TWiki/ManagingWebs.txt twiki/branches/TWikiRelease06x00/core/data/TWiki/TWikiPreferences.txt twiki/branches/TWikiRelease06x00/core/lib/TWiki/Store.pm Log: Item7816: Excluding specified topics when creating a new web Modified: twiki/branches/TWikiRelease06x00/core/data/TWiki/ManagingWebs.txt =================================================================== --- twiki/branches/TWikiRelease06x00/core/data/TWiki/ManagingWebs.txt 2017-07-05 07:42:42 UTC (rev 30353) +++ twiki/branches/TWikiRelease06x00/core/data/TWiki/ManagingWebs.txt 2017-07-05 07:43:44 UTC (rev 30354) @@ -34,6 +34,9 @@ __%X% Note:__ *Keep the number of webs to a minimum!* Don't create a new web for each little project. Cross-linking topics is easier, and searches are faster, if there are only a few larger webs. You can organize content within a web using categories, TWikiForms and FormattedSearch. | *Name of new web:* | <input name="newweb" class="twikiInputField" type="text" value="%URLPARAM{"newweb" encode="entity"}%" size="16" /> | The name must start with an upper case letter, followed by upper or lower case letters or numbers. Specify a short name to avoid long URLs. | | *Based on web:* | <select name="baseweb" class="twikiSelect"> %WEBLIST{ "<option $marker>$name</option>" webs="webtemplate%IF{"{NoInAllPublicWebs}" else=",public"}%" selection="_default" separator=" "}% </select> | Select a TemplateWeb. | +| *Exclude Topic:* | <input type="text" class="twikiInputField" name="excludetopic" value="" size="60" /><br /> Enter comma separated list of topics to exclude from the template web. For example, =Data*= excludes all topics whose name starts with Data.%BR%<noautolink>%TWISTY{mode="div" + showlink="Specify exception (you don't need to change most of the time) %ICONURL{toggleopen}%" + hidelink="Hide exception %ICONURL{toggleclose}%"}%<input name="excludeexception" class="twikiInputField" size="60" value="%VAR{CREATE_WEB_EXCLUDE_EXCEPTION}%"/>%BR%e.g. if =*Form= is specified as exception, =DataForm= is copied even if =Data*= is specified to be excluded. %ENDTWISTY%</noautolink>|| | *Web color:* | %COLORPICKER{ name="WEBBGCOLOR" size="16" value="#d0d0d0" class="twikiInputField" }% | Select color for the new web, shown in the list of webs.<br /><br /> __Note:__ Use a light color within the top 1/4th area of the center square depicting the saturation/luminance gradients. | | *Site Map:* | <input type="radio" name="SITEMAPLIST" value="on" checked="checked" /> Yes <input type="radio" name="SITEMAPLIST" value="" /> No | Include this web in the site map | | *Description:<br /> <br /> * | <input type="text" class="twikiInputField" name="SITEMAPWHAT" value="" size="60" /><br /> Enter a short description of the web. Write =[<nop>[Web.TopicName][title]]= instead of just =TopicName= if you include links. This description will be used in the %SYSTEMWEB%.SiteMap. || Modified: twiki/branches/TWikiRelease06x00/core/data/TWiki/TWikiPreferences.txt =================================================================== --- twiki/branches/TWikiRelease06x00/core/data/TWiki/TWikiPreferences.txt 2017-07-05 07:42:42 UTC (rev 30353) +++ twiki/branches/TWikiRelease06x00/core/data/TWiki/TWikiPreferences.txt 2017-07-05 07:43:44 UTC (rev 30354) @@ -84,6 +84,10 @@ * If not set: included TOC is shown * Possible values: =on= or nothing +#ExcludeException + * When you create a new web with ManagingWebs, topics are copied from the template web, which can be any web. In doing so, you can specify topics to exclude. And you can specify topics not to exclude. The following defines the default value of the exclude exception. + * Set CREATE_WEB_EXCLUDE_EXCEPTION = *Template, *Form, WebPreferences + #DefaultUserSettings ---++ Default User Settings Modified: twiki/branches/TWikiRelease06x00/core/lib/TWiki/Store.pm =================================================================== --- twiki/branches/TWikiRelease06x00/core/lib/TWiki/Store.pm 2017-07-05 07:42:42 UTC (rev 30353) +++ twiki/branches/TWikiRelease06x00/core/lib/TWiki/Store.pm 2017-07-05 07:43:44 UTC (rev 30354) @@ -1840,6 +1840,23 @@ # copy topics from base web my @topicList = $this->getTopicNames( $baseWeb ); + require TWiki::Search; + my $excludeTopic = + TWiki::Search::_makeTopicPattern($opts->{EXCLUDETOPIC}); + my $excludeException = + TWiki::Search::_makeTopicPattern($opts->{EXCLUDEEXCEPTION}); + delete $opts->{EXCLUDETOPIC}; + delete $opts->{EXCLUDEEXCEPTION}; + if ( $excludeTopic ) { + if ( $excludeException ) { + @topicList = grep { /$excludeException/ || !/$excludeTopic/ } + @topicList; + } + else { + @topicList = grep { !/$excludeTopic/ } @topicList; + } + } + foreach my $topic ( @topicList ) { $this->copyTopic( $user, $baseWeb, $topic, $newWeb, $topic ); } |
From: <de...@de...> - 2017-07-05 08:00:15
|
Author: HideyoImazu Date: 2017-07-05 07:42:42 +0000 (Wed, 05 Jul 2017) New Revision: 30353 Trac url: http://develop.twiki.org/trac/changeset/30353 Modified: twiki/trunk/core/data/TWiki/ManagingWebs.txt twiki/trunk/core/data/TWiki/TWikiPreferences.txt twiki/trunk/core/lib/TWiki/Store.pm Log: Item7816: Excluding specified topics when creating a new web Modified: twiki/trunk/core/data/TWiki/ManagingWebs.txt =================================================================== --- twiki/trunk/core/data/TWiki/ManagingWebs.txt 2017-06-29 10:02:26 UTC (rev 30352) +++ twiki/trunk/core/data/TWiki/ManagingWebs.txt 2017-07-05 07:42:42 UTC (rev 30353) @@ -34,6 +34,9 @@ __%X% Note:__ *Keep the number of webs to a minimum!* Don't create a new web for each little project. Cross-linking topics is easier, and searches are faster, if there are only a few larger webs. You can organize content within a web using categories, TWikiForms and FormattedSearch. | *Name of new web:* | <input name="newweb" class="twikiInputField" type="text" value="%URLPARAM{"newweb" encode="entity"}%" size="16" /> | The name must start with an upper case letter, followed by upper or lower case letters or numbers. Specify a short name to avoid long URLs. | | *Based on web:* | <select name="baseweb" class="twikiSelect"> %WEBLIST{ "<option $marker>$name</option>" webs="webtemplate%IF{"{NoInAllPublicWebs}" else=",public"}%" selection="_default" separator=" "}% </select> | Select a TemplateWeb. | +| *Exclude Topic:* | <input type="text" class="twikiInputField" name="excludetopic" value="" size="60" /><br /> Enter comma separated list of topics to exclude from the template web. For example, =Data*= excludes all topics whose name starts with Data.%BR%<noautolink>%TWISTY{mode="div" + showlink="Specify exception (you don't need to change most of the time) %ICONURL{toggleopen}%" + hidelink="Hide exception %ICONURL{toggleclose}%"}%<input name="excludeexception" class="twikiInputField" size="60" value="%VAR{CREATE_WEB_EXCLUDE_EXCEPTION}%"/>%BR%e.g. if =*Form= is specified as exception, =DataForm= is copied even if =Data*= is specified to be excluded. %ENDTWISTY%</noautolink>|| | *Web color:* | %COLORPICKER{ name="WEBBGCOLOR" size="16" value="#d0d0d0" class="twikiInputField" }% | Select color for the new web, shown in the list of webs.<br /><br /> __Note:__ Use a light color within the top 1/4th area of the center square depicting the saturation/luminance gradients. | | *Site Map:* | <input type="radio" name="SITEMAPLIST" value="on" checked="checked" /> Yes <input type="radio" name="SITEMAPLIST" value="" /> No | Include this web in the site map | | *Description:<br /> <br /> * | <input type="text" class="twikiInputField" name="SITEMAPWHAT" value="" size="60" /><br /> Enter a short description of the web. Write =[<nop>[Web.TopicName][title]]= instead of just =TopicName= if you include links. This description will be used in the %SYSTEMWEB%.SiteMap. || Modified: twiki/trunk/core/data/TWiki/TWikiPreferences.txt =================================================================== --- twiki/trunk/core/data/TWiki/TWikiPreferences.txt 2017-06-29 10:02:26 UTC (rev 30352) +++ twiki/trunk/core/data/TWiki/TWikiPreferences.txt 2017-07-05 07:42:42 UTC (rev 30353) @@ -84,6 +84,10 @@ * If not set: included TOC is shown * Possible values: =on= or nothing +#ExcludeException + * When you create a new web with ManagingWebs, topics are copied from the template web, which can be any web. In doing so, you can specify topics to exclude. And you can specify topics not to exclude. The following defines the default value of the exclude exception. + * Set CREATE_WEB_EXCLUDE_EXCEPTION = *Template, *Form, WebPreferences + #DefaultUserSettings ---++ Default User Settings Modified: twiki/trunk/core/lib/TWiki/Store.pm =================================================================== --- twiki/trunk/core/lib/TWiki/Store.pm 2017-06-29 10:02:26 UTC (rev 30352) +++ twiki/trunk/core/lib/TWiki/Store.pm 2017-07-05 07:42:42 UTC (rev 30353) @@ -1840,6 +1840,23 @@ # copy topics from base web my @topicList = $this->getTopicNames( $baseWeb ); + require TWiki::Search; + my $excludeTopic = + TWiki::Search::_makeTopicPattern($opts->{EXCLUDETOPIC}); + my $excludeException = + TWiki::Search::_makeTopicPattern($opts->{EXCLUDEEXCEPTION}); + delete $opts->{EXCLUDETOPIC}; + delete $opts->{EXCLUDEEXCEPTION}; + if ( $excludeTopic ) { + if ( $excludeException ) { + @topicList = grep { /$excludeException/ || !/$excludeTopic/ } + @topicList; + } + else { + @topicList = grep { !/$excludeTopic/ } @topicList; + } + } + foreach my $topic ( @topicList ) { $this->copyTopic( $user, $baseWeb, $topic, $newWeb, $topic ); } |
From: <de...@de...> - 2017-06-29 10:18:39
|
Author: HideyoImazu Date: 2017-06-29 10:02:26 +0000 (Thu, 29 Jun 2017) New Revision: 30352 Trac url: http://develop.twiki.org/trac/changeset/30352 Modified: twiki/branches/TWikiRelease06x00/core/lib/TWiki/Store/RcsWrap.pm twiki/branches/TWikiRelease06x00/core/lib/TWiki/UI/Save.pm twiki/branches/TWikiRelease06x00/core/templates/messages.tmpl Log: Item7815: Coping with zero byte RCS file Modified: twiki/branches/TWikiRelease06x00/core/lib/TWiki/Store/RcsWrap.pm =================================================================== --- twiki/branches/TWikiRelease06x00/core/lib/TWiki/Store/RcsWrap.pm 2017-06-29 10:00:57 UTC (rev 30351) +++ twiki/branches/TWikiRelease06x00/core/lib/TWiki/Store/RcsWrap.pm 2017-06-29 10:02:26 UTC (rev 30352) @@ -263,6 +263,11 @@ sub numRevisions { my( $this ) = @_; + if ( -e $this->{rcsFile} && -s $this->{rcsFile} == 0 ) { + $this->{session}->writeWarning('null RCS: ' . $this->{rcsFile}); + $this->{session}{rcsFileNull} = 1; + unlink $this->{rcsFile}; + } unless( -e $this->{rcsFile}) { return 1 if( -e $this->{file} ); return 0; Modified: twiki/branches/TWikiRelease06x00/core/lib/TWiki/UI/Save.pm =================================================================== --- twiki/branches/TWikiRelease06x00/core/lib/TWiki/UI/Save.pm 2017-06-29 10:00:57 UTC (rev 30351) +++ twiki/branches/TWikiRelease06x00/core/lib/TWiki/UI/Save.pm 2017-06-29 10:02:26 UTC (rev 30352) @@ -655,6 +655,15 @@ params => $merged ); } + if ( $session->{rcsFileNull} ) { + throw TWiki::OopsException( + 'attention', + def => 'prior_versions_lost', + web => $web, + topic => $topic, + params => "past revisions are lost." ); + } + $session->redirect( $redirecturl, undef, ( $saveaction ne 'checkpoint' ) ); } Modified: twiki/branches/TWikiRelease06x00/core/templates/messages.tmpl =================================================================== --- twiki/branches/TWikiRelease06x00/core/templates/messages.tmpl 2017-06-29 10:00:57 UTC (rev 30351) +++ twiki/branches/TWikiRelease06x00/core/templates/messages.tmpl 2017-06-29 10:02:26 UTC (rev 30352) @@ -459,6 +459,13 @@ %MAKETEXT{"Go back in your browser and save your changes locally."}% %TMPL:END% +%TMPL:DEF{"prior_versions_lost"}% +---+++ %MAKETEXT{"Prior versions lost"}% +%MAKETEXT{"During save of [_1] an error was found by the version control system. The latest and the previous versions of this topic are fine but all prior versions are lost. Your [_2] administrator may be able to recover the lost versions." args="<nop>%WEB%.<nop>%TOPIC%,%WIKITOOLNAME%"}% + +*[[%WEB%.%TOPIC%][%MAKETEXT{"OK"}%]]* + +%TMPL:END% %TMPL:DEF{"rename_web_prerequisites"}% ---+++ %MAKETEXT{"There are problems with renaming this web:"}% 1.%MAKETEXT{"You are denied access to the following topics in the web:"}% |
From: <de...@de...> - 2017-06-29 10:17:05
|
Author: HideyoImazu Date: 2017-06-29 10:00:57 +0000 (Thu, 29 Jun 2017) New Revision: 30351 Trac url: http://develop.twiki.org/trac/changeset/30351 Modified: twiki/trunk/core/lib/TWiki/Store/RcsWrap.pm twiki/trunk/core/lib/TWiki/UI/Save.pm twiki/trunk/core/templates/messages.tmpl Log: Item7815: Coping with zero byte RCS file Modified: twiki/trunk/core/lib/TWiki/Store/RcsWrap.pm =================================================================== --- twiki/trunk/core/lib/TWiki/Store/RcsWrap.pm 2017-06-01 06:13:38 UTC (rev 30350) +++ twiki/trunk/core/lib/TWiki/Store/RcsWrap.pm 2017-06-29 10:00:57 UTC (rev 30351) @@ -263,6 +263,11 @@ sub numRevisions { my( $this ) = @_; + if ( -e $this->{rcsFile} && -s $this->{rcsFile} == 0 ) { + $this->{session}->writeWarning('null RCS: ' . $this->{rcsFile}); + $this->{session}{rcsFileNull} = 1; + unlink $this->{rcsFile}; + } unless( -e $this->{rcsFile}) { return 1 if( -e $this->{file} ); return 0; Modified: twiki/trunk/core/lib/TWiki/UI/Save.pm =================================================================== --- twiki/trunk/core/lib/TWiki/UI/Save.pm 2017-06-01 06:13:38 UTC (rev 30350) +++ twiki/trunk/core/lib/TWiki/UI/Save.pm 2017-06-29 10:00:57 UTC (rev 30351) @@ -655,6 +655,15 @@ params => $merged ); } + if ( $session->{rcsFileNull} ) { + throw TWiki::OopsException( + 'attention', + def => 'prior_versions_lost', + web => $web, + topic => $topic, + params => "past revisions are lost." ); + } + $session->redirect( $redirecturl, undef, ( $saveaction ne 'checkpoint' ) ); } Modified: twiki/trunk/core/templates/messages.tmpl =================================================================== --- twiki/trunk/core/templates/messages.tmpl 2017-06-01 06:13:38 UTC (rev 30350) +++ twiki/trunk/core/templates/messages.tmpl 2017-06-29 10:00:57 UTC (rev 30351) @@ -459,6 +459,13 @@ %MAKETEXT{"Go back in your browser and save your changes locally."}% %TMPL:END% +%TMPL:DEF{"prior_versions_lost"}% +---+++ %MAKETEXT{"Prior versions lost"}% +%MAKETEXT{"During save of [_1] an error was found by the version control system. The latest and the previous versions of this topic are fine but all prior versions are lost. Your [_2] administrator may be able to recover the lost versions." args="<nop>%WEB%.<nop>%TOPIC%,%WIKITOOLNAME%"}% + +*[[%WEB%.%TOPIC%][%MAKETEXT{"OK"}%]]* + +%TMPL:END% %TMPL:DEF{"rename_web_prerequisites"}% ---+++ %MAKETEXT{"There are problems with renaming this web:"}% 1.%MAKETEXT{"You are denied access to the following topics in the web:"}% |
From: Peter T. <pe...@th...> - 2017-06-14 22:26:45
|
All: Please join our TWiki Kampala Release Meeting, http://twiki.org/cgi-bin/view/Codev/KampalaReleaseMeeting2017x06x15 scheduled for 2017-06-15 22:00 GMT [1] on IRC channel #twiki_release on the irc.freenode.net IRC network [2] - in about 24 hours from now. Proposed agenda: 1. Feature Requests for Kampala Release 2. Review Urgent and Not So Urgent Bugs 3. Extensions 4. TWiki Release Discussion 5. Miscellaneous The meeting is on Thursday or Friday, depending on your time zone. Meeting time in different time zones, tomorrow: * USA Pacific Time Zone: 03:00pm on Thu * USA Eastern Time Zone: 06:00pm on Thu * Central Europe: 24:00 on Thu/Fri night * Japan: 07:00 on Fri Please show up in time to save everybody's time. And remember that the release meeting is where decisions are made. We invite all TWiki.org contributors to join, as well as people with interest in the TWiki project in general. Cheers, Peter [1]: http://www.timeanddate.com/worldclock/converter.html?iso=20170615T220000&p1=tz_gmt&p2=248&p3=268&p4=224&p5=179 [2]: http://twiki.org/cgi-bin/view/Codev/TWikiIRC -- > Peter Thoeny - Peter09[at]Thoeny.org > http://TWiki.org/Mr.TWiki - consulting on enterprise collaboration > http://TWiki.org - is your team already TWiki enabled? > http://qualityHDR.com - Quality HDR Photography > Knowledge cannot be managed, it can be discovered and shared > This e-mail is: (_) private (_) ask first (x) public |
From: <rhk...@gm...> - 2017-06-09 13:52:19
|
Oops, sorry about the previous message--I clicked "send" by mistake before I wrote anything. This needs no response, but I just wanted to say: I've had problems with GMT vs. local times (and daylight savings times) several times in my career, and what I believe is the best approach is to use GMT as the "real" time in the system, but to allow users or others to choose to display times in other time zones as they wish. Thus, the system works on an "absolute clock" which never varies (i.e., has no daylight savings variation), while users can view times in their local times (if they wish), even if they occasionally switch to and from daylight savings times. Statistics kept in the system stay based on GMT and aren't confused by a switch to or from DST. Thus, I strongly recommend that TWiki always use GMT internally. Thanks for letting me stand on this soap box. ;-) Randy Kramer PS: Sorry for the top posting. On Sunday, June 04, 2017 07:19:39 PM Imazu, Hideyo wrote: > I further updated the summary: SERVERTIME to be in local time; DISPLAYTIME > and log time stamps to observe {DisplayTimeValues} > > -----Original Message----- > From: Imazu, Hideyo (Enterprise Infrastructure) > Sent: Monday, June 05, 2017 07:53 > To: TWiki-Dev list for developers > Cc: Imazu, Hideyo (Enterprise Infrastructure) > Subject: RE: [TWiki-Dev] [SVN] HideyoImazu r30349 - twiki/trunk/core/lib > > The summary of the item is misleading. I understand the person who > reported/created the item lives in the BST time zone and wanted a way to > have time stamps in their local time zone. > > So I've updated the summary as: TWiki always uses GMT for time stamps on > log files but local time should be an option. > > -----Original Message----- > From: rhk...@gm... [mailto:rhk...@gm...] > Sent: Saturday, June 03, 2017 01:24 > To: TWiki-Dev list for developers > Subject: Re: [TWiki-Dev] [SVN] HideyoImazu r30349 - twiki/trunk/core/lib > > On Thursday, June 01, 2017 09:48:52 PM Imazu, Hideyo wrote: > > The commit is not specifically about BST. The item is about using > > local time instead of GMT if so specified. And now, the code is made that > > way. > > Thanks--I noticed that, but I still wondered why you thought BST would be a > better choice than GMT. > > > -----Original Message----- > > > > On Thursday, June 01, 2017 02:12:55 AM de...@de... wrote: > > > Log: > > > Item7811: A few related GMT/BST (gmtime/localtime) / daylight-saving > > > time queries/problems. TWiki uses GMT but (I believe probably) > > > should use BST > > > > Really? Why? > |
From: <rhk...@gm...> - 2017-06-09 13:46:14
|
On Sunday, June 04, 2017 07:19:39 PM Imazu, Hideyo wrote: > I further updated the summary: SERVERTIME to be in local time; DISPLAYTIME > and log time stamps to observe {DisplayTimeValues} > > -----Original Message----- > From: Imazu, Hideyo (Enterprise Infrastructure) > Sent: Monday, June 05, 2017 07:53 > To: TWiki-Dev list for developers > Cc: Imazu, Hideyo (Enterprise Infrastructure) > Subject: RE: [TWiki-Dev] [SVN] HideyoImazu r30349 - twiki/trunk/core/lib > > The summary of the item is misleading. I understand the person who > reported/created the item lives in the BST time zone and wanted a way to > have time stamps in their local time zone. > > So I've updated the summary as: TWiki always uses GMT for time stamps on > log files but local time should be an option. > > -----Original Message----- > From: rhk...@gm... [mailto:rhk...@gm...] > Sent: Saturday, June 03, 2017 01:24 > To: TWiki-Dev list for developers > Subject: Re: [TWiki-Dev] [SVN] HideyoImazu r30349 - twiki/trunk/core/lib > > On Thursday, June 01, 2017 09:48:52 PM Imazu, Hideyo wrote: > > The commit is not specifically about BST. The item is about using > > local time instead of GMT if so specified. And now, the code is made that > > way. > > Thanks--I noticed that, but I still wondered why you thought BST would be a > better choice than GMT. > > > -----Original Message----- > > > > On Thursday, June 01, 2017 02:12:55 AM de...@de... wrote: > > > Log: > > > Item7811: A few related GMT/BST (gmtime/localtime) / daylight-saving > > > time queries/problems. TWiki uses GMT but (I believe probably) > > > should use BST > > > > Really? Why? > > --------------------------------------------------------------------------- > --- Check out the vibrant tech community on one of the world's most > engaging tech sites, Slashdot.org! http://sdm.link/slashdot > _______________________________________________ TWiki-Dev mailing list > TWi...@li... > https://lists.sourceforge.net/lists/listinfo/twiki-dev > > > --------------------------------------------------------------------------- > ----- > > NOTICE: Morgan Stanley is not acting as a municipal advisor and the > opinions or views contained herein are not intended to be, and do not > constitute, advice within the meaning of Section 975 of the Dodd-Frank > Wall Street Reform and Consumer Protection Act. If you have received this > communication in error, please destroy all electronic and paper copies and > notify the sender immediately. Mistransmission is not intended to waive > confidentiality or privilege. Morgan Stanley reserves the right, to the > extent permitted under applicable law, to monitor electronic > communications. This message is subject to terms available at the > following link: http://www.morganstanley.com/disclaimers If you cannot > access these links, please notify us by reply message and we will send the > contents to you. By communicating with Morgan Stanley you consent to the > foregoing and to the voice recording of conversations with personnel of > Morgan Stanley. > -------------------------------------------------------------------------- > ---- Check out the vibrant tech community on one of the world's most > engaging tech sites, Slashdot.org! http://sdm.link/slashdot > _______________________________________________ > TWiki-Dev mailing list > TWi...@li... > https://lists.sourceforge.net/lists/listinfo/twiki-dev |
From: <rhk...@gm...> - 2017-06-05 12:24:51
|
On Sunday, June 04, 2017 06:53:25 PM Imazu, Hideyo wrote: > The summary of the item is misleading. I understand the person who > reported/created the item lives in the BST time zone and wanted a way to > have time stamps in their local time zone. > > So I've updated the summary as: TWiki always uses GMT for time stamps on > log files but local time should be an option. Thanks for the clarification / explanation! |
From: Imazu, H. <Hid...@mo...> - 2017-06-04 23:19:53
|
I further updated the summary: SERVERTIME to be in local time; DISPLAYTIME and log time stamps to observe {DisplayTimeValues} -----Original Message----- From: Imazu, Hideyo (Enterprise Infrastructure) Sent: Monday, June 05, 2017 07:53 To: TWiki-Dev list for developers Cc: Imazu, Hideyo (Enterprise Infrastructure) Subject: RE: [TWiki-Dev] [SVN] HideyoImazu r30349 - twiki/trunk/core/lib The summary of the item is misleading. I understand the person who reported/created the item lives in the BST time zone and wanted a way to have time stamps in their local time zone. So I've updated the summary as: TWiki always uses GMT for time stamps on log files but local time should be an option. -----Original Message----- From: rhk...@gm... [mailto:rhk...@gm...] Sent: Saturday, June 03, 2017 01:24 To: TWiki-Dev list for developers Subject: Re: [TWiki-Dev] [SVN] HideyoImazu r30349 - twiki/trunk/core/lib On Thursday, June 01, 2017 09:48:52 PM Imazu, Hideyo wrote: > The commit is not specifically about BST. The item is about using > local time instead of GMT if so specified. And now, the code is made that way. Thanks--I noticed that, but I still wondered why you thought BST would be a better choice than GMT. > -----Original Message----- > On Thursday, June 01, 2017 02:12:55 AM de...@de... wrote: > > Log: > > Item7811: A few related GMT/BST (gmtime/localtime) / daylight-saving > > time queries/problems. TWiki uses GMT but (I believe probably) > > should use BST > > Really? Why? ------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot _______________________________________________ TWiki-Dev mailing list TWi...@li... https://lists.sourceforge.net/lists/listinfo/twiki-dev -------------------------------------------------------------------------------- NOTICE: Morgan Stanley is not acting as a municipal advisor and the opinions or views contained herein are not intended to be, and do not constitute, advice within the meaning of Section 975 of the Dodd-Frank Wall Street Reform and Consumer Protection Act. If you have received this communication in error, please destroy all electronic and paper copies and notify the sender immediately. Mistransmission is not intended to waive confidentiality or privilege. Morgan Stanley reserves the right, to the extent permitted under applicable law, to monitor electronic communications. This message is subject to terms available at the following link: http://www.morganstanley.com/disclaimers If you cannot access these links, please notify us by reply message and we will send the contents to you. By communicating with Morgan Stanley you consent to the foregoing and to the voice recording of conversations with personnel of Morgan Stanley. |
From: Imazu, H. <Hid...@mo...> - 2017-06-04 22:53:38
|
The summary of the item is misleading. I understand the person who reported/created the item lives in the BST time zone and wanted a way to have time stamps in their local time zone. So I've updated the summary as: TWiki always uses GMT for time stamps on log files but local time should be an option. -----Original Message----- From: rhk...@gm... [mailto:rhk...@gm...] Sent: Saturday, June 03, 2017 01:24 To: TWiki-Dev list for developers Subject: Re: [TWiki-Dev] [SVN] HideyoImazu r30349 - twiki/trunk/core/lib On Thursday, June 01, 2017 09:48:52 PM Imazu, Hideyo wrote: > The commit is not specifically about BST. The item is about using > local time instead of GMT if so specified. And now, the code is made that way. Thanks--I noticed that, but I still wondered why you thought BST would be a better choice than GMT. > -----Original Message----- > On Thursday, June 01, 2017 02:12:55 AM de...@de... wrote: > > Log: > > Item7811: A few related GMT/BST (gmtime/localtime) / daylight-saving > > time queries/problems. TWiki uses GMT but (I believe probably) > > should use BST > > Really? Why? ------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot _______________________________________________ TWiki-Dev mailing list TWi...@li... https://lists.sourceforge.net/lists/listinfo/twiki-dev -------------------------------------------------------------------------------- NOTICE: Morgan Stanley is not acting as a municipal advisor and the opinions or views contained herein are not intended to be, and do not constitute, advice within the meaning of Section 975 of the Dodd-Frank Wall Street Reform and Consumer Protection Act. If you have received this communication in error, please destroy all electronic and paper copies and notify the sender immediately. Mistransmission is not intended to waive confidentiality or privilege. Morgan Stanley reserves the right, to the extent permitted under applicable law, to monitor electronic communications. This message is subject to terms available at the following link: http://www.morganstanley.com/disclaimers If you cannot access these links, please notify us by reply message and we will send the contents to you. By communicating with Morgan Stanley you consent to the foregoing and to the voice recording of conversations with personnel of Morgan Stanley. |
From: <rhk...@gm...> - 2017-06-02 16:24:09
|
On Thursday, June 01, 2017 09:48:52 PM Imazu, Hideyo wrote: > The commit is not specifically about BST. The item is about using local > time instead of GMT if so specified. And now, the code is made that way. Thanks--I noticed that, but I still wondered why you thought BST would be a better choice than GMT. > -----Original Message----- > On Thursday, June 01, 2017 02:12:55 AM de...@de... wrote: > > Log: > > Item7811: A few related GMT/BST (gmtime/localtime) / daylight-saving > > time queries/problems. TWiki uses GMT but (I believe probably) should > > use BST > > Really? Why? |
From: Imazu, H. <Hid...@mo...> - 2017-06-02 01:49:03
|
The commit is not specifically about BST. The item is about using local time instead of GMT if so specified. And now, the code is made that way. -----Original Message----- From: rhk...@gm... [mailto:rhk...@gm...] Sent: Thursday, June 01, 2017 21:26 To: TWiki-Dev list for developers Subject: Re: [TWiki-Dev] [SVN] HideyoImazu r30349 - twiki/trunk/core/lib On Thursday, June 01, 2017 02:12:55 AM de...@de... wrote: > Log: > Item7811: A few related GMT/BST (gmtime/localtime) / daylight-saving > time queries/problems. TWiki uses GMT but (I believe probably) should > use BST Really? Why? ------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot _______________________________________________ TWiki-Dev mailing list TWi...@li... https://lists.sourceforge.net/lists/listinfo/twiki-dev -------------------------------------------------------------------------------- NOTICE: Morgan Stanley is not acting as a municipal advisor and the opinions or views contained herein are not intended to be, and do not constitute, advice within the meaning of Section 975 of the Dodd-Frank Wall Street Reform and Consumer Protection Act. If you have received this communication in error, please destroy all electronic and paper copies and notify the sender immediately. Mistransmission is not intended to waive confidentiality or privilege. Morgan Stanley reserves the right, to the extent permitted under applicable law, to monitor electronic communications. This message is subject to terms available at the following link: http://www.morganstanley.com/disclaimers If you cannot access these links, please notify us by reply message and we will send the contents to you. By communicating with Morgan Stanley you consent to the foregoing and to the voice recording of conversations with personnel of Morgan Stanley. |
From: <rhk...@gm...> - 2017-06-01 12:26:29
|
On Thursday, June 01, 2017 02:12:55 AM de...@de... wrote: > Log: > Item7811: A few related GMT/BST (gmtime/localtime) / daylight-saving time > queries/problems. TWiki uses GMT but (I believe probably) should use BST Really? Why? |
From: <de...@de...> - 2017-06-01 06:23:02
|
Author: HideyoImazu Date: 2017-06-01 06:13:38 +0000 (Thu, 01 Jun 2017) New Revision: 30350 Trac url: http://develop.twiki.org/trac/changeset/30350 Modified: twiki/branches/TWikiRelease06x00/core/lib/TWiki.pm Log: Item7811: A few related GMT/BST (gmtime/localtime) / daylight-saving time queries/problems. TWiki uses GMT but (I believe probably) should use BST Modified: twiki/branches/TWikiRelease06x00/core/lib/TWiki.pm =================================================================== --- twiki/branches/TWikiRelease06x00/core/lib/TWiki.pm 2017-06-01 06:12:55 UTC (rev 30349) +++ twiki/branches/TWikiRelease06x00/core/lib/TWiki.pm 2017-06-01 06:13:38 UTC (rev 30350) @@ -2384,7 +2384,8 @@ if ( $log ) { $log = _fileNameToPath( $log ); - my $time = TWiki::Time::formatTime( time(), '$year-$mo-$day - $hour:$min:$sec', 'gmtime' ); + my $time = TWiki::Time::formatTime( time(), '$year-$mo-$day - $hour:$min:$sec' ); + # ommitting the third argument ($outputTimeZone) to resort to $TWiki::cfg{DisplayTimeValues} as per Item7811 if( open( FILE, ">>$log" ) ) { print FILE "| $time | $message\n"; |
From: <de...@de...> - 2017-06-01 06:22:21
|
Author: HideyoImazu Date: 2017-06-01 06:12:55 +0000 (Thu, 01 Jun 2017) New Revision: 30349 Trac url: http://develop.twiki.org/trac/changeset/30349 Modified: twiki/trunk/core/lib/TWiki.pm Log: Item7811: A few related GMT/BST (gmtime/localtime) / daylight-saving time queries/problems. TWiki uses GMT but (I believe probably) should use BST Modified: twiki/trunk/core/lib/TWiki.pm =================================================================== --- twiki/trunk/core/lib/TWiki.pm 2017-05-31 09:07:58 UTC (rev 30348) +++ twiki/trunk/core/lib/TWiki.pm 2017-06-01 06:12:55 UTC (rev 30349) @@ -2386,7 +2386,8 @@ if ( $log ) { $log = _fileNameToPath( $log ); - my $time = TWiki::Time::formatTime( time(), '$year-$mo-$day - $hour:$min:$sec', 'gmtime' ); + my $time = TWiki::Time::formatTime( time(), '$year-$mo-$day - $hour:$min:$sec' ); + # ommitting the third argument ($outputTimeZone) to resort to $TWiki::cfg{DisplayTimeValues} as per Item7811 if( open( FILE, ">>$log" ) ) { print FILE "| $time | $message\n"; |