Index: trunk/extensions/NSFileRepo/README |
— | — | @@ -1,144 +1,144 @@ |
2 | | -{{Page security extension disclaimer}}
|
3 | | -{{Extension by patch warning|version=}}
|
4 | | -{{Extension|templatemode=
|
5 | | -|name = NSFileRepo
|
6 | | -|status = beta
|
7 | | -|type1 = user rights
|
8 | | -|type2 =
|
9 | | -|hook1 = userCan
|
10 | | -|hook2 = ImgAuthBeforeStream
|
11 | | -|username = [[User:Jpond|Jack D. Pond]]
|
12 | | -|author = <!-- add only if different from user name -->
|
13 | | -|description = implements per-namespace group permissions for image and file rights protection
|
14 | | -|image =
|
15 | | -|version = 0.0
|
16 | | -|update = 2009-07-11
|
17 | | -|mediawiki = 1.13, 1.14, 1.15
|
18 | | -|license = GNU General Public Licence 2.0
|
19 | | -|download = {{WikimediaDownload|NSFileRepo}}
|
20 | | -|readme = [http://svn.wikimedia.org/svnroot/mediawiki/trunk/extensions/NSFileRepo/README README]
|
21 | | -|changelog = [http://svn.wikimedia.org/viewvc/mediawiki/trunk/extensions/NSFileRepo/?view=log log]
|
22 | | -|parameters = <!-- configuration parameters, for use in LocalSettings.php -->
|
23 | | -|rights = <!-- user rights, for use with $wgGroupPermissions -->
|
24 | | -|example =
|
25 | | -}}
|
26 | | -
|
27 | | -==What can this extension do?==
|
28 | | -
|
29 | | -The '''NSFileRepo''' extension implements a way to restrict access to specific files and images to a given set of user groups. This provides a more fine grained security model and allows access restriction to users in specified groups.
|
30 | | -
|
31 | | -__TOC__
|
32 | | -==Usage==
|
33 | | -
|
34 | | -Generically, you use the same syntax as a normal file/image reference link, adding the namespace between the file specifier ("File","Image", or "Media"), and the file name:
|
35 | | -
|
36 | | -<pre>[[{FILE_NS}:{Namespace}:{Filename}]]</pre>
|
37 | | -
|
38 | | -Example(Where "Project" is the protected namespace and "ProjectFile.pdf" is the file to which you wish to limit access):
|
39 | | -
|
40 | | -<pre>[[File:Project:ProjectFile.pdf]]</pre>
|
41 | | -<br>
|
42 | | -The standard for accessing files/images is generally:
|
43 | | -<pre>
|
44 | | -[[File:Filename.txt]]
|
45 | | -[[Image:Filename.jpg]]
|
46 | | -[[Media:Filename.pdf]]
|
47 | | -</pre>
|
48 | | -
|
49 | | -This extension allows you to protect access to files/images, by adding the namespace text identifier after the file namespace identifier, for example(Where "Project" is the protected namespace and "ProjectFile.xxx" is the file to which you wish to limit access):
|
50 | | -<pre>
|
51 | | -[[File:Project:Filename.txt]]
|
52 | | -[[Image:Project:Filename.jpg]]
|
53 | | -[[Media:Project:Filename.pdf]]
|
54 | | -</pre>
|
55 | | -
|
56 | | -It may be helpful to understand the default security model used by MediaWiki using the instructions below:
|
57 | | -
|
58 | | -* [[Manual:User rights]]
|
59 | | -* [[Manual:$wgGroupPermissions]]
|
60 | | -
|
61 | | -Limitations of security are the same as for Extension Lockdown. To review these limitations, [[Extension:Lockdown#Additional_measures | please reference here]].
|
62 | | -
|
63 | | -To use the full capabilities of this extension (e.g., specific namespace protections), you will need to install and use the namespace protections provided through [[Extension:Lockdown]].
|
64 | | -
|
65 | | -This extension was made possible by the introduction of Repository Classes by Tim Starling - an elegant and brilliant implementation. It uses a new Local Repository class mechanism. Technical details on how this extension works can be found [[Extension:NSFileRepo/DOC | here]].
|
66 | | -
|
67 | | -== Announcements ==
|
68 | | -
|
69 | | -* The first version of this (Rel 0.0) was released 2009-07-11. The following activities are underway to make this extension easier to install and use, including:
|
70 | | -** Modifying and updating the standard version of img_auth.php to include localization and a hook necessary for this extension. Will hopefully be approved for version 1.16
|
71 | | -** Discussing ways to allow modification of wfStripIllegalFilenameChars so that future patching will not be needed.
|
72 | | -
|
73 | | -==Download instructions==
|
74 | | -
|
75 | | -This Extension and the necessary patch/files may be downloaded from one of the following (SVN preferred)
|
76 | | -
|
77 | | -* Revision 0.0 (beta)
|
78 | | -** [http://wiki.montcopa.org/PublicDownloads/NSFileRepo.tar tar] (May require eol conversion)
|
79 | | -** [http://wiki.montcopa.org/PublicDownloads/NSFileRepo.tar zip]
|
80 | | -** [http://svn.wikimedia.org/svnroot/mediawiki/trunk/extensions/NSFileRepo SVN]
|
81 | | -
|
82 | | -Copy all files and directories into directory:
|
83 | | -
|
84 | | -<pre>
|
85 | | -$IP/extensions/NSFileRepo
|
86 | | -</pre>
|
87 | | -
|
88 | | -==Installation==
|
89 | | -
|
90 | | -You will need to read and understand two other required enhancements to MediaWiki:
|
91 | | -
|
92 | | -* [[Manual:Image Authorization | Image Authorization]].
|
93 | | -* [[Extension:Lockdown | Extension Lockdown]]
|
94 | | -
|
95 | | -Please read and understand the above before executing the following instructions
|
96 | | -
|
97 | | -# Download and install [[Extension:Lockdown | Extension Lockdown]]
|
98 | | -# Download and copy the NSFileRepo extension into directory <nowiki>$IP/extensions/NSFileRepo</nowiki>
|
99 | | -# Activate the Image Authorization according to instructions found in [[Manual:Image Authorization | Image Authorization]]
|
100 | | -# Copy the img_auth.php and img_auth.i18.php from the distribution in directory <nowiki>{release}/phase3/</nowiki> to your wiki code base directory ($IP). This will overwrite the existing img_auth.php file. Alternately you could copy img_auth.php to another name in the same directory, then use that file name instead of img_auth.php (but still must be in the $IP directory and the localization file must still be img_auth.i18.php).
|
101 | | -# <nowiki>$IP/include/GlobalFunctions.php</nowiki> Must be patched. This is a very minor patch to remove the disabling of colons (':'). You can do this one of three ways (whichever you're most comfortable with):
|
102 | | -## Edit the file according to instructions [[#Patch_GlobalFunctions.php | below]]
|
103 | | -## If you have not otherwise patched the file, you may want to copy it from the distribution, which will be in a directory corresponding to the release you are using under <nowiki>{release}/phase3/includes/GlobalFunctions.php</nowiki>
|
104 | | -## Apply the patch which will be in a directory corresponding to the release you are using under <nowiki>{release}/phase3/includes/GlobalFunctions.patch</nowiki>
|
105 | | -# To activate this extension, add the following to [[Manual:LocalSettings.php|LocalSettings.php]]:
|
106 | | -<source lang="php">
|
107 | | -require_once("$IP/extensions/NSFileRepo/NSFileRepo.php");
|
108 | | -</source>
|
109 | | -
|
110 | | -===Configuration parameters===
|
111 | | -
|
112 | | -The user rights and configuration requiremements are are the same as described in [[Extension:Lockdown#Configuration | Extension Lockdown]].
|
113 | | -
|
114 | | -==Patch GlobalFunctions.php==
|
115 | | -
|
116 | | -In version 1_13_0, a new function wfStripIllegalFilenameChars was added to <nowiki>includes/GlobalFunctions.php</nowiki>. This prevents the protection namespace from being detectd.
|
117 | | -
|
118 | | -<pre>
|
119 | | -Index: GlobalFunctions.php
|
120 | | -===================================================================
|
121 | | -+++ GlobalFunctions.php (working copy)
|
122 | | -@@ -3034,6 +3034,6 @@
|
123 | | - */
|
124 | | - function wfStripIllegalFilenameChars( $name ) {
|
125 | | - $name = wfBaseName( $name );
|
126 | | -- $name = preg_replace ( "/[^".Title::legalChars()."]|:/", '-', $name );
|
127 | | -+ $name = preg_replace ( "/[^".Title::legalChars()."]/", '-', $name );
|
128 | | - return $name;
|
129 | | - }
|
130 | | -</pre>
|
131 | | -<br>
|
132 | | -<br>
|
133 | | -You need to remove the "or :" clause from the REGEX expression of wfStripIllegalFilenameChars by deleting the characters <nowiki>"|:"</nowiki>
|
134 | | -<br>
|
135 | | -
|
136 | | -==See also==
|
137 | | -
|
138 | | -* [[Manual:Image Authorization | Image Authorization]].
|
139 | | -* [[Extension:Lockdown | Extension Lockdown]]
|
140 | | -
|
141 | | -[[Category:View page extensions]]
|
142 | | -[[Category:Edit extensions]]
|
143 | | -
|
144 | | -{{languages}}
|
| 2 | +{{Page security extension disclaimer}} |
| 3 | +{{Extension by patch warning|version=}} |
| 4 | +{{Extension|templatemode= |
| 5 | +|name = NSFileRepo |
| 6 | +|status = beta |
| 7 | +|type1 = user rights |
| 8 | +|type2 = |
| 9 | +|hook1 = userCan |
| 10 | +|hook2 = ImgAuthBeforeStream |
| 11 | +|username = [[User:Jpond|Jack D. Pond]] |
| 12 | +|author = <!-- add only if different from user name --> |
| 13 | +|description = implements per-namespace group permissions for image and file rights protection |
| 14 | +|image = |
| 15 | +|version = 0.0 |
| 16 | +|update = 2009-07-11 |
| 17 | +|mediawiki = 1.13, 1.14, 1.15 |
| 18 | +|license = GNU General Public Licence 2.0 |
| 19 | +|download = {{WikimediaDownload|NSFileRepo}} |
| 20 | +|readme = [http://svn.wikimedia.org/svnroot/mediawiki/trunk/extensions/NSFileRepo/README README] |
| 21 | +|changelog = [http://svn.wikimedia.org/viewvc/mediawiki/trunk/extensions/NSFileRepo/?view=log log] |
| 22 | +|parameters = <!-- configuration parameters, for use in LocalSettings.php --> |
| 23 | +|rights = <!-- user rights, for use with $wgGroupPermissions --> |
| 24 | +|example = |
| 25 | +}} |
| 26 | + |
| 27 | +==What can this extension do?== |
| 28 | + |
| 29 | +The '''NSFileRepo''' extension implements a way to restrict access to specific files and images to a given set of user groups. This provides a more fine grained security model and allows access restriction to users in specified groups. |
| 30 | + |
| 31 | +__TOC__ |
| 32 | +==Usage== |
| 33 | + |
| 34 | +Generically, you use the same syntax as a normal file/image reference link, adding the namespace between the file specifier ("File","Image", or "Media"), and the file name: |
| 35 | + |
| 36 | +<pre>[[{FILE_NS}:{Namespace}:{Filename}]]</pre> |
| 37 | + |
| 38 | +Example(Where "Project" is the protected namespace and "ProjectFile.pdf" is the file to which you wish to limit access): |
| 39 | + |
| 40 | +<pre>[[File:Project:ProjectFile.pdf]]</pre> |
| 41 | +<br> |
| 42 | +The standard for accessing files/images is generally: |
| 43 | +<pre> |
| 44 | +[[File:Filename.txt]] |
| 45 | +[[Image:Filename.jpg]] |
| 46 | +[[Media:Filename.pdf]] |
| 47 | +</pre> |
| 48 | + |
| 49 | +This extension allows you to protect access to files/images, by adding the namespace text identifier after the file namespace identifier, for example(Where "Project" is the protected namespace and "ProjectFile.xxx" is the file to which you wish to limit access): |
| 50 | +<pre> |
| 51 | +[[File:Project:Filename.txt]] |
| 52 | +[[Image:Project:Filename.jpg]] |
| 53 | +[[Media:Project:Filename.pdf]] |
| 54 | +</pre> |
| 55 | + |
| 56 | +It may be helpful to understand the default security model used by MediaWiki using the instructions below: |
| 57 | + |
| 58 | +* [[Manual:User rights]] |
| 59 | +* [[Manual:$wgGroupPermissions]] |
| 60 | + |
| 61 | +Limitations of security are the same as for Extension Lockdown. To review these limitations, [[Extension:Lockdown#Additional_measures | please reference here]]. |
| 62 | + |
| 63 | +To use the full capabilities of this extension (e.g., specific namespace protections), you will need to install and use the namespace protections provided through [[Extension:Lockdown]]. |
| 64 | + |
| 65 | +This extension was made possible by the introduction of Repository Classes by Tim Starling - an elegant and brilliant implementation. It uses a new Local Repository class mechanism. Technical details on how this extension works can be found [[Extension:NSFileRepo/DOC | here]]. |
| 66 | + |
| 67 | +== Announcements == |
| 68 | + |
| 69 | +* The first version of this (Rel 0.0) was released 2009-07-11. The following activities are underway to make this extension easier to install and use, including: |
| 70 | +** Modifying and updating the standard version of img_auth.php to include localization and a hook necessary for this extension. Will hopefully be approved for version 1.16 |
| 71 | +** Discussing ways to allow modification of wfStripIllegalFilenameChars so that future patching will not be needed. |
| 72 | + |
| 73 | +==Download instructions== |
| 74 | + |
| 75 | +This Extension and the necessary patch/files may be downloaded from one of the following (SVN preferred) |
| 76 | + |
| 77 | +* Revision 0.0 (beta) |
| 78 | +** [http://wiki.montcopa.org/PublicDownloads/NSFileRepo.tar tar] (May require eol conversion) |
| 79 | +** [http://wiki.montcopa.org/PublicDownloads/NSFileRepo.tar zip] |
| 80 | +** [http://svn.wikimedia.org/svnroot/mediawiki/trunk/extensions/NSFileRepo SVN] |
| 81 | + |
| 82 | +Copy all files and directories into directory: |
| 83 | + |
| 84 | +<pre> |
| 85 | +$IP/extensions/NSFileRepo |
| 86 | +</pre> |
| 87 | + |
| 88 | +==Installation== |
| 89 | + |
| 90 | +You will need to read and understand two other required enhancements to MediaWiki: |
| 91 | + |
| 92 | +* [[Manual:Image Authorization | Image Authorization]]. |
| 93 | +* [[Extension:Lockdown | Extension Lockdown]] |
| 94 | + |
| 95 | +Please read and understand the above before executing the following instructions |
| 96 | + |
| 97 | +# Download and install [[Extension:Lockdown | Extension Lockdown]] |
| 98 | +# Download and copy the NSFileRepo extension into directory <nowiki>$IP/extensions/NSFileRepo</nowiki> |
| 99 | +# Activate the Image Authorization according to instructions found in [[Manual:Image Authorization | Image Authorization]] |
| 100 | +# Copy the img_auth.php and img_auth.i18.php from the distribution in directory <nowiki>{release}/phase3/</nowiki> to your wiki code base directory ($IP). This will overwrite the existing img_auth.php file. Alternately you could copy img_auth.php to another name in the same directory, then use that file name instead of img_auth.php (but still must be in the $IP directory and the localization file must still be img_auth.i18.php). |
| 101 | +# <nowiki>$IP/include/GlobalFunctions.php</nowiki> Must be patched. This is a very minor patch to remove the disabling of colons (':'). You can do this one of three ways (whichever you're most comfortable with): |
| 102 | +## Edit the file according to instructions [[#Patch_GlobalFunctions.php | below]] |
| 103 | +## If you have not otherwise patched the file, you may want to copy it from the distribution, which will be in a directory corresponding to the release you are using under <nowiki>{release}/phase3/includes/GlobalFunctions.php</nowiki> |
| 104 | +## Apply the patch which will be in a directory corresponding to the release you are using under <nowiki>{release}/phase3/includes/GlobalFunctions.patch</nowiki> |
| 105 | +# To activate this extension, add the following to [[Manual:LocalSettings.php|LocalSettings.php]]: |
| 106 | +<source lang="php"> |
| 107 | +require_once("$IP/extensions/NSFileRepo/NSFileRepo.php"); |
| 108 | +</source> |
| 109 | + |
| 110 | +===Configuration parameters=== |
| 111 | + |
| 112 | +The user rights and configuration requiremements are are the same as described in [[Extension:Lockdown#Configuration | Extension Lockdown]]. |
| 113 | + |
| 114 | +==Patch GlobalFunctions.php== |
| 115 | + |
| 116 | +In version 1_13_0, a new function wfStripIllegalFilenameChars was added to <nowiki>includes/GlobalFunctions.php</nowiki>. This prevents the protection namespace from being detectd. |
| 117 | + |
| 118 | +<pre> |
| 119 | +Index: GlobalFunctions.php |
| 120 | +=================================================================== |
| 121 | +--- GlobalFunctions.php (revision 52849) |
| 122 | +@@ -3034,6 +3034,6 @@ |
| 123 | + */ |
| 124 | + function wfStripIllegalFilenameChars( $name ) { |
| 125 | + $name = wfBaseName( $name ); |
| 126 | +- $name = preg_replace ( "/[^".Title::legalChars()."]|:/", '-', $name ); |
| 127 | ++ $name = preg_replace ( "/[^".Title::legalChars()."]/", '-', $name ); |
| 128 | + return $name; |
| 129 | + } |
| 130 | +</pre> |
| 131 | +<br> |
| 132 | +<br> |
| 133 | +You need to remove the "or :" clause from the REGEX expression of wfStripIllegalFilenameChars by deleting the characters <nowiki>"|:"</nowiki> |
| 134 | +<br> |
| 135 | + |
| 136 | +==See also== |
| 137 | + |
| 138 | +* [[Manual:Image Authorization | Image Authorization]]. |
| 139 | +* [[Extension:Lockdown | Extension Lockdown]] |
| 140 | + |
| 141 | +[[Category:View page extensions]] |
| 142 | +[[Category:Edit extensions]] |
| 143 | + |
| 144 | +{{languages}} |
Property changes on: trunk/extensions/NSFileRepo/README |
___________________________________________________________________ |
Name: svn:eol-style |
145 | 145 | + native |
Property changes on: trunk/extensions/SlippyMap/SlippyMapExportCgiBin.class.php |
___________________________________________________________________ |
Name: svn:eol-style |
146 | 146 | + native |
Index: trunk/extensions/SemanticResultFormats/Ploticus/SRF_PloticusVBar.php |
— | — | @@ -1,41 +1,41 @@ |
2 | | -<?php
|
3 | | -/**
|
4 | | - * A query printer using Ploticus drawing vertical bars.
|
5 | | - * loosely based on the Ploticus Extension by Flavien Scheurer
|
6 | | - * and CSV result printer
|
7 | | - *
|
8 | | - * @note AUTOLOADED
|
9 | | - * @author Joel Natividad
|
10 | | - * @author Denny Vrandecic
|
11 | | - */
|
12 | | -
|
13 | | -/**
|
14 | | - * Result printer using Ploticus to plot vertical bars.
|
15 | | - * TODO: Create expanded doxygen comments
|
16 | | - *
|
17 | | - * @ingroup SMWQuery
|
18 | | - */
|
19 | | -
|
20 | | -if( !defined( 'MEDIAWIKI' ) ) {
|
21 | | - die( 'Not an entry point.' );
|
22 | | -}
|
23 | | -
|
24 | | -include_once( "SRF_Ploticus.php" );
|
25 | | -
|
26 | | -/**
|
27 | | - * This class only specifies the the SRFPloticus superclass. Since the
|
28 | | - * current working of the SRFPloticus class is unsafe, this specialization
|
29 | | - * filters out this unsecure parameter passing (and the power of Ploticus)
|
30 | | - * and allows only for vertical bars.
|
31 | | - */
|
32 | | -class SRFPloticusVBar extends SRFPloticus {
|
33 | | -
|
34 | | - protected function readParameters($params, $outputmode) {
|
35 | | - SRFPloticus::readParameters($params, $outputmode);
|
36 | | -
|
37 | | - // All other options will be simply ignored;
|
38 | | - $this->m_ploticusmode === 'prefab';
|
39 | | - $this->m_ploticusparams = "-prefab vbars x=1 y=2";
|
40 | | - }
|
41 | | -
|
| 2 | +<?php |
| 3 | +/** |
| 4 | + * A query printer using Ploticus drawing vertical bars. |
| 5 | + * loosely based on the Ploticus Extension by Flavien Scheurer |
| 6 | + * and CSV result printer |
| 7 | + * |
| 8 | + * @note AUTOLOADED |
| 9 | + * @author Joel Natividad |
| 10 | + * @author Denny Vrandecic |
| 11 | + */ |
| 12 | + |
| 13 | +/** |
| 14 | + * Result printer using Ploticus to plot vertical bars. |
| 15 | + * TODO: Create expanded doxygen comments |
| 16 | + * |
| 17 | + * @ingroup SMWQuery |
| 18 | + */ |
| 19 | + |
| 20 | +if( !defined( 'MEDIAWIKI' ) ) { |
| 21 | + die( 'Not an entry point.' ); |
| 22 | +} |
| 23 | + |
| 24 | +include_once( "SRF_Ploticus.php" ); |
| 25 | + |
| 26 | +/** |
| 27 | + * This class only specifies the the SRFPloticus superclass. Since the |
| 28 | + * current working of the SRFPloticus class is unsafe, this specialization |
| 29 | + * filters out this unsecure parameter passing (and the power of Ploticus) |
| 30 | + * and allows only for vertical bars. |
| 31 | + */ |
| 32 | +class SRFPloticusVBar extends SRFPloticus { |
| 33 | + |
| 34 | + protected function readParameters($params, $outputmode) { |
| 35 | + SRFPloticus::readParameters($params, $outputmode); |
| 36 | + |
| 37 | + // All other options will be simply ignored; |
| 38 | + $this->m_ploticusmode === 'prefab'; |
| 39 | + $this->m_ploticusparams = "-prefab vbars x=1 y=2"; |
| 40 | + } |
| 41 | + |
42 | 42 | } |
\ No newline at end of file |
Property changes on: trunk/extensions/SemanticResultFormats/Ploticus/SRF_PloticusVBar.php |
___________________________________________________________________ |
Name: svn:eol-style |
43 | 43 | + native |
Property changes on: trunk/extensions/IndexFunction/IndexFunction_body.php |
___________________________________________________________________ |
Name: svn:eol-style |
44 | 44 | + native |
Property changes on: trunk/extensions/IndexFunction/IndexFunction.i18n.php |
___________________________________________________________________ |
Name: svn:eol-style |
45 | 45 | + native |
Property changes on: trunk/extensions/IndexFunction/IndexFunction.php |
___________________________________________________________________ |
Name: svn:eol-style |
46 | 46 | + native |
Property changes on: trunk/extensions/IndexFunction/indexes.sql |
___________________________________________________________________ |
Name: svn:eol-style |
47 | 47 | + native |
Property changes on: trunk/extensions/IndexFunction/SpecialIndex.php |
___________________________________________________________________ |
Name: svn:eol-style |
48 | 48 | + native |
Index: trunk/extensions/ReaderFeedback/ReaderFeedback.hooks.php |
— | — | @@ -1,205 +1,205 @@ |
2 | | -<?php
|
3 | | -
|
4 | | -class ReaderFeedbackHooks {
|
5 | | - /**
|
6 | | - * Add ReaderFeedback css/js.
|
7 | | - */
|
8 | | - public static function injectStyleAndJS() {
|
9 | | - global $wgOut, $wgTitle;
|
10 | | - if( $wgOut->hasHeadItem( 'ReaderFeedback' ) )
|
11 | | - return true; # Don't double-load
|
12 | | - if( !isset($wgTitle) || !$wgOut->isArticleRelated() ) {
|
13 | | - return self::InjectStyleForSpecial(); // try special page CSS?
|
14 | | - }
|
15 | | - # Try to only add to relevant pages
|
16 | | - if( !ReaderFeedback::isPageRateable($wgTitle) ) {
|
17 | | - return true;
|
18 | | - }
|
19 | | - global $wgScriptPath, $wgJsMimeType, $wgFeedbackStylePath, $wgFeedbackStyleVersion;
|
20 | | - # Load required messages
|
21 | | - wfLoadExtensionMessages( 'ReaderFeedback' );
|
22 | | -
|
23 | | - $stylePath = str_replace( '$wgScriptPath', $wgScriptPath, $wgFeedbackStylePath );
|
24 | | - $fTags = ReaderFeedback::getJSFeedbackParams();
|
25 | | -
|
26 | | - $encCssFile = htmlspecialchars( "$stylePath/readerfeedback.css?$wgFeedbackStyleVersion" );
|
27 | | - $encJsFile = htmlspecialchars( "$stylePath/readerfeedback.js?$wgFeedbackStyleVersion" );
|
28 | | -
|
29 | | - $wgOut->addExtensionStyle( $encCssFile );
|
30 | | -
|
31 | | - $ajaxFeedback = Xml::encodeJsVar( (object) array(
|
32 | | - 'sendingMsg' => wfMsgHtml('readerfeedback-submitting'),
|
33 | | - 'sentMsg' => wfMsgHtml('readerfeedback-finished')
|
34 | | - )
|
35 | | - );
|
36 | | -
|
37 | | - $head = <<<EOT
|
38 | | -<script type="$wgJsMimeType">
|
39 | | -var wgFeedbackParams = $fTags;
|
40 | | -var wgAjaxFeedback = $ajaxFeedback
|
41 | | -</script>
|
42 | | -<script type="$wgJsMimeType" src="$encJsFile"></script>
|
43 | | -
|
44 | | -EOT;
|
45 | | - $wgOut->addHeadItem( 'ReaderFeedback', $head );
|
46 | | - return true;
|
47 | | - }
|
48 | | -
|
49 | | - /**
|
50 | | - * Add ReaderFeedback css for relevant special pages.
|
51 | | - */
|
52 | | - public static function InjectStyleForSpecial() {
|
53 | | - global $wgTitle, $wgOut, $wgUser;
|
54 | | - if( empty($wgTitle) || $wgTitle->getNamespace() !== NS_SPECIAL ) {
|
55 | | - return true;
|
56 | | - }
|
57 | | - $spPages = array( 'RatingHistory' );
|
58 | | - foreach( $spPages as $n => $key ) {
|
59 | | - if( $wgTitle->isSpecial( $key ) ) {
|
60 | | - global $wgScriptPath, $wgFeedbackStylePath, $wgFeedbacktyleVersion;
|
61 | | - $stylePath = str_replace( '$wgScriptPath', $wgScriptPath, $wgFeedbackStylePath );
|
62 | | - $encCssFile = htmlspecialchars( "$stylePath/readerfeedback.css?$wgFeedbacktyleVersion" );
|
63 | | - $wgOut->addExtensionStyle( $encCssFile );
|
64 | | - break;
|
65 | | - }
|
66 | | - }
|
67 | | - return true;
|
68 | | - }
|
69 | | -
|
70 | | - /**
|
71 | | - * Is this a view page action?
|
72 | | - * @param $action string
|
73 | | - * @returns bool
|
74 | | - */
|
75 | | - protected static function isViewAction( $action ) {
|
76 | | - return ( $action == 'view' || $action == 'purge' || $action == 'render' );
|
77 | | - }
|
78 | | -
|
79 | | - public static function addFeedbackForm( &$data ) {
|
80 | | - global $wgOut, $wgArticle, $wgTitle;
|
81 | | - if( $wgOut->isArticleRelated() && isset($wgArticle) ) {
|
82 | | - global $wgRequest, $wgUser, $wgOut;
|
83 | | - if( !$wgTitle->exists() || !ReaderFeedback::isPageRateable($wgTitle) || !$wgOut->getRevisionId() ) {
|
84 | | - return true;
|
85 | | - }
|
86 | | - # Check action and if page is protected
|
87 | | - $action = $wgRequest->getVal( 'action', 'view' );
|
88 | | - if( !self::isViewAction($action) ) {
|
89 | | - return true;
|
90 | | - }
|
91 | | - if( $wgUser->isAllowed( 'feedback' ) ) {
|
92 | | - # Only allow votes on the latest revision!
|
93 | | - $id = $wgOut->getRevisionId();
|
94 | | - if( $id != $wgArticle->getLatest() ) {
|
95 | | - return true;
|
96 | | - }
|
97 | | - # If the user already voted, then don't show the form.
|
98 | | - # Always show for IPs however, due to squid caching...
|
99 | | - if( !$wgUser->getId() || !ReaderFeedbackPage::userAlreadyVoted( $wgTitle, $id ) ) {
|
100 | | - self::addQuickFeedback( $data, false, $wgTitle );
|
101 | | - }
|
102 | | - }
|
103 | | - return true;
|
104 | | - }
|
105 | | - return true;
|
106 | | - }
|
107 | | -
|
108 | | - /**
|
109 | | - * Adds a brief feedback form to a page.
|
110 | | - * @param OutputPage $out
|
111 | | - * @param bool $top, should this form always go on top?
|
112 | | - * @param Title $title
|
113 | | - */
|
114 | | - protected static function addQuickFeedback( &$data, $top = false, $title ) {
|
115 | | - global $wgOut, $wgUser, $wgRequest, $wgFeedbackTags;
|
116 | | - # Are there any reader input tags?
|
117 | | - if( empty($wgFeedbackTags) ) {
|
118 | | - return false;
|
119 | | - }
|
120 | | - # Revision being displayed
|
121 | | - $id = $wgOut->getRevisionId();
|
122 | | - # Load required messages
|
123 | | - wfLoadExtensionMessages( 'ReaderFeedback' );
|
124 | | - $reviewTitle = SpecialPage::getTitleFor( 'ReaderFeedback' );
|
125 | | - $action = $reviewTitle->getLocalUrl( 'action=submit' );
|
126 | | - $form = Xml::openElement( 'form', array( 'method' => 'post', 'action' => $action,
|
127 | | - 'id' => 'mw-feedbackform' ) );
|
128 | | - $form .= Xml::openElement( 'fieldset', array('class' => 'feedback_reviewform noprint') );
|
129 | | - $form .= "<legend><strong>" . wfMsgHtml( 'readerfeedback' ) . "</strong></legend>\n";
|
130 | | - # Avoid clutter
|
131 | | - if( !$wgUser->isAllowed('review') ) {
|
132 | | - $form .= wfMsgExt( 'readerfeedback-text', array('parse') );
|
133 | | - }
|
134 | | - $form .= Xml::openElement( 'span', array('id' => 'mw-feedbackselects') );
|
135 | | - # Loop through all different flag types
|
136 | | - foreach( ReaderFeedback::getFeedbackTags() as $quality => $levels ) {
|
137 | | - $label = array();
|
138 | | - $selected = ( isset($flags[$quality]) && $flags[$quality] > 0 ) ? $flags[$quality] : -1;
|
139 | | - $form .= "<b>" . Xml::label( wfMsgHtml("readerfeedback-$quality"), "wp$quality" ) . ":</b>";
|
140 | | - $attribs = array( 'name' => "wp$quality", 'id' => "wp$quality",
|
141 | | - 'onchange' => "updateFeedbackForm()" );
|
142 | | - $form .= ' ' . Xml::openElement( 'select', $attribs );
|
143 | | - $levels = array_reverse($levels,true);
|
144 | | - foreach( $levels as $i => $name ) {
|
145 | | - $optionClass = array( 'class' => "rfb-rating-option-$i" );
|
146 | | - $form .= Xml::option( wfMsg("readerfeedback-level-$i"), $i, ($i == $selected), $optionClass ) ."\n";
|
147 | | - }
|
148 | | - $form .= Xml::option( wfMsg("readerfeedback-level-none"), -1, (-1 == $selected) ) ."\n";
|
149 | | - $form .= Xml::closeElement( 'select' )."\n";
|
150 | | - }
|
151 | | - $form .= Xml::closeElement( 'span' );
|
152 | | - $form .= Xml::submitButton( wfMsg('readerfeedback-submit'),
|
153 | | - array('id' => 'submitfeedback','accesskey' => wfMsg('revreview-ak-review'),
|
154 | | - 'title' => wfMsg('revreview-tt-review').' ['.wfMsg('revreview-ak-review').']' )
|
155 | | - );
|
156 | | - # Hidden params
|
157 | | - $form .= Xml::hidden( 'title', $reviewTitle->getPrefixedText() ) . "\n";
|
158 | | - $form .= Xml::hidden( 'target', $title->getPrefixedDBKey() ) . "\n";
|
159 | | - $form .= Xml::hidden( 'oldid', $id ) . "\n";
|
160 | | - $form .= Xml::hidden( 'validatedParams', ReaderFeedbackPage::validationKey( $id, $wgUser->getId() ) );
|
161 | | - $form .= Xml::hidden( 'action', 'submit') . "\n";
|
162 | | - $form .= Xml::hidden( 'wpEditToken', $wgUser->editToken() ) . "\n";
|
163 | | - # Honeypot input
|
164 | | - $form .= Xml::input( 'commentary', 12, '', array('style' => 'display:none;') ) . "\n";
|
165 | | - $form .= Xml::closeElement( 'fieldset' );
|
166 | | - $form .= Xml::closeElement( 'form' );
|
167 | | - if( $top ) {
|
168 | | - $wgOut->prependHTML( $form );
|
169 | | - } else {
|
170 | | - $data .= $form;
|
171 | | - }
|
172 | | - return true;
|
173 | | - }
|
174 | | -
|
175 | | - public static function addRatingLink( &$skintemplate, &$nav_urls, &$oldid, &$revid ) {
|
176 | | - global $wgTitle;
|
177 | | - # Add rating tab
|
178 | | - if( isset($wgTitle) && ReaderFeedback::isPageRateable($wgTitle) ) {
|
179 | | - wfLoadExtensionMessages( 'RatingHistory' );
|
180 | | - $nav_urls['ratinghist'] = array(
|
181 | | - 'text' => wfMsg( 'ratinghistory-link' ),
|
182 | | - 'href' => $skintemplate->makeSpecialUrl( 'RatingHistory',
|
183 | | - "target=" . wfUrlencode( "{$skintemplate->thispage}" ) )
|
184 | | - );
|
185 | | - }
|
186 | | - return true;
|
187 | | - }
|
188 | | -
|
189 | | - public static function ratingToolboxLink( &$skin ) {
|
190 | | - if( isset( $skin->data['nav_urls']['ratinghist'] ) ) {
|
191 | | - ?><li id="t-rating"><?php
|
192 | | - ?><a href="<?php echo htmlspecialchars( $skin->data['nav_urls']['ratinghist']['href'] ) ?>"><?php
|
193 | | - echo $skin->msg( 'ratinghistory-link' );
|
194 | | - ?></a><?php
|
195 | | - ?></li><?php
|
196 | | - }
|
197 | | - return true;
|
198 | | - }
|
199 | | -
|
200 | | - public static function onParserTestTables( &$tables ) {
|
201 | | - $tables[] = 'reader_feedback';
|
202 | | - $tables[] = 'reader_feedback_history';
|
203 | | - $tables[] = 'reader_feedback_pages';
|
204 | | - return true;
|
205 | | - }
|
206 | | -}
|
| 2 | +<?php |
| 3 | + |
| 4 | +class ReaderFeedbackHooks { |
| 5 | + /** |
| 6 | + * Add ReaderFeedback css/js. |
| 7 | + */ |
| 8 | + public static function injectStyleAndJS() { |
| 9 | + global $wgOut, $wgTitle; |
| 10 | + if( $wgOut->hasHeadItem( 'ReaderFeedback' ) ) |
| 11 | + return true; # Don't double-load |
| 12 | + if( !isset($wgTitle) || !$wgOut->isArticleRelated() ) { |
| 13 | + return self::InjectStyleForSpecial(); // try special page CSS? |
| 14 | + } |
| 15 | + # Try to only add to relevant pages |
| 16 | + if( !ReaderFeedback::isPageRateable($wgTitle) ) { |
| 17 | + return true; |
| 18 | + } |
| 19 | + global $wgScriptPath, $wgJsMimeType, $wgFeedbackStylePath, $wgFeedbackStyleVersion; |
| 20 | + # Load required messages |
| 21 | + wfLoadExtensionMessages( 'ReaderFeedback' ); |
| 22 | + |
| 23 | + $stylePath = str_replace( '$wgScriptPath', $wgScriptPath, $wgFeedbackStylePath ); |
| 24 | + $fTags = ReaderFeedback::getJSFeedbackParams(); |
| 25 | + |
| 26 | + $encCssFile = htmlspecialchars( "$stylePath/readerfeedback.css?$wgFeedbackStyleVersion" ); |
| 27 | + $encJsFile = htmlspecialchars( "$stylePath/readerfeedback.js?$wgFeedbackStyleVersion" ); |
| 28 | + |
| 29 | + $wgOut->addExtensionStyle( $encCssFile ); |
| 30 | + |
| 31 | + $ajaxFeedback = Xml::encodeJsVar( (object) array( |
| 32 | + 'sendingMsg' => wfMsgHtml('readerfeedback-submitting'), |
| 33 | + 'sentMsg' => wfMsgHtml('readerfeedback-finished') |
| 34 | + ) |
| 35 | + ); |
| 36 | + |
| 37 | + $head = <<<EOT |
| 38 | +<script type="$wgJsMimeType"> |
| 39 | +var wgFeedbackParams = $fTags; |
| 40 | +var wgAjaxFeedback = $ajaxFeedback |
| 41 | +</script> |
| 42 | +<script type="$wgJsMimeType" src="$encJsFile"></script> |
| 43 | + |
| 44 | +EOT; |
| 45 | + $wgOut->addHeadItem( 'ReaderFeedback', $head ); |
| 46 | + return true; |
| 47 | + } |
| 48 | + |
| 49 | + /** |
| 50 | + * Add ReaderFeedback css for relevant special pages. |
| 51 | + */ |
| 52 | + public static function InjectStyleForSpecial() { |
| 53 | + global $wgTitle, $wgOut, $wgUser; |
| 54 | + if( empty($wgTitle) || $wgTitle->getNamespace() !== NS_SPECIAL ) { |
| 55 | + return true; |
| 56 | + } |
| 57 | + $spPages = array( 'RatingHistory' ); |
| 58 | + foreach( $spPages as $n => $key ) { |
| 59 | + if( $wgTitle->isSpecial( $key ) ) { |
| 60 | + global $wgScriptPath, $wgFeedbackStylePath, $wgFeedbacktyleVersion; |
| 61 | + $stylePath = str_replace( '$wgScriptPath', $wgScriptPath, $wgFeedbackStylePath ); |
| 62 | + $encCssFile = htmlspecialchars( "$stylePath/readerfeedback.css?$wgFeedbacktyleVersion" ); |
| 63 | + $wgOut->addExtensionStyle( $encCssFile ); |
| 64 | + break; |
| 65 | + } |
| 66 | + } |
| 67 | + return true; |
| 68 | + } |
| 69 | + |
| 70 | + /** |
| 71 | + * Is this a view page action? |
| 72 | + * @param $action string |
| 73 | + * @returns bool |
| 74 | + */ |
| 75 | + protected static function isViewAction( $action ) { |
| 76 | + return ( $action == 'view' || $action == 'purge' || $action == 'render' ); |
| 77 | + } |
| 78 | + |
| 79 | + public static function addFeedbackForm( &$data ) { |
| 80 | + global $wgOut, $wgArticle, $wgTitle; |
| 81 | + if( $wgOut->isArticleRelated() && isset($wgArticle) ) { |
| 82 | + global $wgRequest, $wgUser, $wgOut; |
| 83 | + if( !$wgTitle->exists() || !ReaderFeedback::isPageRateable($wgTitle) || !$wgOut->getRevisionId() ) { |
| 84 | + return true; |
| 85 | + } |
| 86 | + # Check action and if page is protected |
| 87 | + $action = $wgRequest->getVal( 'action', 'view' ); |
| 88 | + if( !self::isViewAction($action) ) { |
| 89 | + return true; |
| 90 | + } |
| 91 | + if( $wgUser->isAllowed( 'feedback' ) ) { |
| 92 | + # Only allow votes on the latest revision! |
| 93 | + $id = $wgOut->getRevisionId(); |
| 94 | + if( $id != $wgArticle->getLatest() ) { |
| 95 | + return true; |
| 96 | + } |
| 97 | + # If the user already voted, then don't show the form. |
| 98 | + # Always show for IPs however, due to squid caching... |
| 99 | + if( !$wgUser->getId() || !ReaderFeedbackPage::userAlreadyVoted( $wgTitle, $id ) ) { |
| 100 | + self::addQuickFeedback( $data, false, $wgTitle ); |
| 101 | + } |
| 102 | + } |
| 103 | + return true; |
| 104 | + } |
| 105 | + return true; |
| 106 | + } |
| 107 | + |
| 108 | + /** |
| 109 | + * Adds a brief feedback form to a page. |
| 110 | + * @param OutputPage $out |
| 111 | + * @param bool $top, should this form always go on top? |
| 112 | + * @param Title $title |
| 113 | + */ |
| 114 | + protected static function addQuickFeedback( &$data, $top = false, $title ) { |
| 115 | + global $wgOut, $wgUser, $wgRequest, $wgFeedbackTags; |
| 116 | + # Are there any reader input tags? |
| 117 | + if( empty($wgFeedbackTags) ) { |
| 118 | + return false; |
| 119 | + } |
| 120 | + # Revision being displayed |
| 121 | + $id = $wgOut->getRevisionId(); |
| 122 | + # Load required messages |
| 123 | + wfLoadExtensionMessages( 'ReaderFeedback' ); |
| 124 | + $reviewTitle = SpecialPage::getTitleFor( 'ReaderFeedback' ); |
| 125 | + $action = $reviewTitle->getLocalUrl( 'action=submit' ); |
| 126 | + $form = Xml::openElement( 'form', array( 'method' => 'post', 'action' => $action, |
| 127 | + 'id' => 'mw-feedbackform' ) ); |
| 128 | + $form .= Xml::openElement( 'fieldset', array('class' => 'feedback_reviewform noprint') ); |
| 129 | + $form .= "<legend><strong>" . wfMsgHtml( 'readerfeedback' ) . "</strong></legend>\n"; |
| 130 | + # Avoid clutter |
| 131 | + if( !$wgUser->isAllowed('review') ) { |
| 132 | + $form .= wfMsgExt( 'readerfeedback-text', array('parse') ); |
| 133 | + } |
| 134 | + $form .= Xml::openElement( 'span', array('id' => 'mw-feedbackselects') ); |
| 135 | + # Loop through all different flag types |
| 136 | + foreach( ReaderFeedback::getFeedbackTags() as $quality => $levels ) { |
| 137 | + $label = array(); |
| 138 | + $selected = ( isset($flags[$quality]) && $flags[$quality] > 0 ) ? $flags[$quality] : -1; |
| 139 | + $form .= "<b>" . Xml::label( wfMsgHtml("readerfeedback-$quality"), "wp$quality" ) . ":</b>"; |
| 140 | + $attribs = array( 'name' => "wp$quality", 'id' => "wp$quality", |
| 141 | + 'onchange' => "updateFeedbackForm()" ); |
| 142 | + $form .= ' ' . Xml::openElement( 'select', $attribs ); |
| 143 | + $levels = array_reverse($levels,true); |
| 144 | + foreach( $levels as $i => $name ) { |
| 145 | + $optionClass = array( 'class' => "rfb-rating-option-$i" ); |
| 146 | + $form .= Xml::option( wfMsg("readerfeedback-level-$i"), $i, ($i == $selected), $optionClass ) ."\n"; |
| 147 | + } |
| 148 | + $form .= Xml::option( wfMsg("readerfeedback-level-none"), -1, (-1 == $selected) ) ."\n"; |
| 149 | + $form .= Xml::closeElement( 'select' )."\n"; |
| 150 | + } |
| 151 | + $form .= Xml::closeElement( 'span' ); |
| 152 | + $form .= Xml::submitButton( wfMsg('readerfeedback-submit'), |
| 153 | + array('id' => 'submitfeedback','accesskey' => wfMsg('revreview-ak-review'), |
| 154 | + 'title' => wfMsg('revreview-tt-review').' ['.wfMsg('revreview-ak-review').']' ) |
| 155 | + ); |
| 156 | + # Hidden params |
| 157 | + $form .= Xml::hidden( 'title', $reviewTitle->getPrefixedText() ) . "\n"; |
| 158 | + $form .= Xml::hidden( 'target', $title->getPrefixedDBKey() ) . "\n"; |
| 159 | + $form .= Xml::hidden( 'oldid', $id ) . "\n"; |
| 160 | + $form .= Xml::hidden( 'validatedParams', ReaderFeedbackPage::validationKey( $id, $wgUser->getId() ) ); |
| 161 | + $form .= Xml::hidden( 'action', 'submit') . "\n"; |
| 162 | + $form .= Xml::hidden( 'wpEditToken', $wgUser->editToken() ) . "\n"; |
| 163 | + # Honeypot input |
| 164 | + $form .= Xml::input( 'commentary', 12, '', array('style' => 'display:none;') ) . "\n"; |
| 165 | + $form .= Xml::closeElement( 'fieldset' ); |
| 166 | + $form .= Xml::closeElement( 'form' ); |
| 167 | + if( $top ) { |
| 168 | + $wgOut->prependHTML( $form ); |
| 169 | + } else { |
| 170 | + $data .= $form; |
| 171 | + } |
| 172 | + return true; |
| 173 | + } |
| 174 | + |
| 175 | + public static function addRatingLink( &$skintemplate, &$nav_urls, &$oldid, &$revid ) { |
| 176 | + global $wgTitle; |
| 177 | + # Add rating tab |
| 178 | + if( isset($wgTitle) && ReaderFeedback::isPageRateable($wgTitle) ) { |
| 179 | + wfLoadExtensionMessages( 'RatingHistory' ); |
| 180 | + $nav_urls['ratinghist'] = array( |
| 181 | + 'text' => wfMsg( 'ratinghistory-link' ), |
| 182 | + 'href' => $skintemplate->makeSpecialUrl( 'RatingHistory', |
| 183 | + "target=" . wfUrlencode( "{$skintemplate->thispage}" ) ) |
| 184 | + ); |
| 185 | + } |
| 186 | + return true; |
| 187 | + } |
| 188 | + |
| 189 | + public static function ratingToolboxLink( &$skin ) { |
| 190 | + if( isset( $skin->data['nav_urls']['ratinghist'] ) ) { |
| 191 | + ?><li id="t-rating"><?php |
| 192 | + ?><a href="<?php echo htmlspecialchars( $skin->data['nav_urls']['ratinghist']['href'] ) ?>"><?php |
| 193 | + echo $skin->msg( 'ratinghistory-link' ); |
| 194 | + ?></a><?php |
| 195 | + ?></li><?php |
| 196 | + } |
| 197 | + return true; |
| 198 | + } |
| 199 | + |
| 200 | + public static function onParserTestTables( &$tables ) { |
| 201 | + $tables[] = 'reader_feedback'; |
| 202 | + $tables[] = 'reader_feedback_history'; |
| 203 | + $tables[] = 'reader_feedback_pages'; |
| 204 | + return true; |
| 205 | + } |
| 206 | +} |
Property changes on: trunk/extensions/ReaderFeedback/ReaderFeedback.hooks.php |
___________________________________________________________________ |
Name: svn:eol-style |
207 | 207 | + native |
Index: trunk/extensions/ReaderFeedback/ReaderFeedback.class.php |
— | — | @@ -1,265 +1,265 @@ |
2 | | -<?php
|
3 | | -
|
4 | | -class ReaderFeedback {
|
5 | | - protected static $feedbackTags = array();
|
6 | | - protected static $feedbackTagWeight = array();
|
7 | | - protected static $loaded = false;
|
8 | | -
|
9 | | - public static function load() {
|
10 | | - global $wgFeedbackTags;
|
11 | | - if( self::$loaded ) return true;
|
12 | | - foreach( $wgFeedbackTags as $tag => $weight ) {
|
13 | | - # Tag names used as part of file names. "Overall" tag is a
|
14 | | - # weighted aggregate, so it cannot be used either.
|
15 | | - if( !preg_match('/^[a-zA-Z]{1,20}$/',$tag) || $tag === 'overall' ) {
|
16 | | - throw new MWException( 'ReaderFeedback given invalid tag name!' );
|
17 | | - }
|
18 | | - self::$feedbackTagWeight[$tag] = $weight;
|
19 | | - for( $i=0; $i <= 4; $i++ ) {
|
20 | | - self::$feedbackTags[$tag][$i] = "feedback-{$tag}-{$i}";
|
21 | | - }
|
22 | | - }
|
23 | | - self::$loaded = true;
|
24 | | - }
|
25 | | -
|
26 | | - ################# Basic accessors #################
|
27 | | -
|
28 | | - /**
|
29 | | - * Get the array of tag feedback tags
|
30 | | - * @returns array
|
31 | | - */
|
32 | | - public static function getFeedbackTags() {
|
33 | | - self::load();
|
34 | | - return self::$feedbackTags;
|
35 | | - }
|
36 | | -
|
37 | | - /**
|
38 | | - * Get the the weight of a feedback tag
|
39 | | - * @param string $tag
|
40 | | - * @returns array
|
41 | | - */
|
42 | | - public static function getFeedbackWeight( $tag ) {
|
43 | | - self::load();
|
44 | | - return self::$feedbackTagWeight[$tag];
|
45 | | - }
|
46 | | -
|
47 | | - ################# Utility functions #################
|
48 | | -
|
49 | | - /**
|
50 | | - * @param string $val
|
51 | | - * @return obj array
|
52 | | - * Get a memcache storage object
|
53 | | - */
|
54 | | - public static function makeMemcObj( $val ) {
|
55 | | - $data = (object) array();
|
56 | | - $data->value = $val;
|
57 | | - $data->time = wfTimestampNow();
|
58 | | - return $data;
|
59 | | - }
|
60 | | -
|
61 | | - /**
|
62 | | - * @param mixed $data Memc data returned
|
63 | | - * @param Article $article
|
64 | | - * @return mixed
|
65 | | - * Return memc value if not expired
|
66 | | - */
|
67 | | - public static function getMemcValue( $data, $article ) {
|
68 | | - if( is_object($data) && $data->time >= $article->getTouched() ) {
|
69 | | - return $data->value;
|
70 | | - }
|
71 | | - return false;
|
72 | | - }
|
73 | | -
|
74 | | - /**
|
75 | | - * @param Article $article
|
76 | | - * @param string $tag
|
77 | | - * @param bool $forUpdate, use master?
|
78 | | - * @return array(real,int)
|
79 | | - * Get article rating for this tag for the last few days
|
80 | | - */
|
81 | | - public static function getAverageRating( $article, $tag, $forUpdate=false ) {
|
82 | | - global $wgFeedbackAge;
|
83 | | - $cutoff_unixtime = time() - $wgFeedbackAge;
|
84 | | - $db = $forUpdate ? wfGetDB( DB_MASTER ) : wfGetDB( DB_SLAVE );
|
85 | | - $row = $db->selectRow( 'reader_feedback_history',
|
86 | | - array('SUM(rfh_total)/SUM(rfh_count) AS ave, SUM(rfh_count) AS count'),
|
87 | | - array( 'rfh_page_id' => $article->getId(), 'rfh_tag' => $tag,
|
88 | | - "rfh_date >= {$cutoff_unixtime}" ),
|
89 | | - __METHOD__ );
|
90 | | - $data = $row && $row->count ?
|
91 | | - array($row->ave,$row->count) : array(0,0);
|
92 | | - return $data;
|
93 | | - }
|
94 | | -
|
95 | | - /**
|
96 | | - * Is this page in rateable namespace?
|
97 | | - * @param Title, $title
|
98 | | - * @return bool
|
99 | | - */
|
100 | | - public static function isPageRateable( $title ) {
|
101 | | - global $wgFeedbackNamespaces;
|
102 | | - # FIXME: Treat NS_MEDIA as NS_FILE
|
103 | | - $ns = ( $title->getNamespace() == NS_MEDIA ) ? NS_FILE : $title->getNamespace();
|
104 | | - # Check for MW: pages and whitelist for exempt pages
|
105 | | - if( $ns == NS_MEDIAWIKI ) {
|
106 | | - return false;
|
107 | | - }
|
108 | | - return ( in_array($ns,$wgFeedbackNamespaces) && !$title->isTalkPage() );
|
109 | | - }
|
110 | | -
|
111 | | - /**
|
112 | | - * Expand feedback ratings into an array
|
113 | | - * @param string $ratings
|
114 | | - * @returns Array
|
115 | | - */
|
116 | | - public static function expandRatings( $rating ) {
|
117 | | - $dims = array();
|
118 | | - $pairs = explode( "\n", $rating );
|
119 | | - foreach( $pairs as $pair ) {
|
120 | | - if( strpos($pair,'=') ) {
|
121 | | - list($tag,$value) = explode( '=', trim($pair), 2 );
|
122 | | - $dims[$tag] = intval($value);
|
123 | | - }
|
124 | | - }
|
125 | | - return $dims;
|
126 | | - }
|
127 | | -
|
128 | | - /**
|
129 | | - * Get a table of the vote totals for a page
|
130 | | - * @param Title $page
|
131 | | - * @param int $period, number of days back
|
132 | | - * @param array $add, optional vote to add on (used to visually avoid lag)
|
133 | | - * @param string $cache, optional param to not use cache
|
134 | | - * @returns string HTML table
|
135 | | - */
|
136 | | - public static function getVoteAggregates( $page, $period, $add = array(), $cache = 'useCache' ) {
|
137 | | - global $wgLang, $wgMemc;
|
138 | | - if( $period > 93 ) {
|
139 | | - return ''; // too big
|
140 | | - }
|
141 | | - $votes = null;
|
142 | | - $now = time();
|
143 | | - $key = wfMemcKey( 'feedback', 'ratingtally', $page->getArticleId(), $period );
|
144 | | - // Check cache
|
145 | | - if( $cache == 'useCache' ) {
|
146 | | - $set = $wgMemc->get($key);
|
147 | | - // Cutoff is at the 24 hour mark due to the way the aggregate
|
148 | | - // schema groups ratings by date for graphs.
|
149 | | - $cache_cutoff = $now - ($now % 86400);
|
150 | | - if( is_array($set) && count($set) == 2 ) {
|
151 | | - list($val,$time) = $set;
|
152 | | - $touched = wfTimestamp( TS_UNIX, RatingHistory::getTouched($page) );
|
153 | | - if( $time > $cache_cutoff && $time > $touched ) {
|
154 | | - $votes = $val;
|
155 | | - }
|
156 | | - }
|
157 | | - }
|
158 | | - // Do query, cache miss
|
159 | | - if( !isset($votes) ) {
|
160 | | - // Set cutoff time for period
|
161 | | - $dbr = wfGetDB( DB_SLAVE );
|
162 | | - $cutoff_unixtime = $now - ($period * 24 * 3600);
|
163 | | - // Use integral number of days to be consistent with graphs
|
164 | | - $cutoff_unixtime = $cutoff_unixtime - ($cutoff_unixtime % 86400);
|
165 | | - $cutoff = $dbr->addQuotes( wfTimestamp( TS_MW, $cutoff_unixtime ) );
|
166 | | - // Get the first revision possibly voted on in the range
|
167 | | - $firstRevTS = $dbr->selectField( 'revision',
|
168 | | - 'rev_timestamp',
|
169 | | - array( 'rev_page' => $page->getArticleId(), "rev_timestamp <= $cutoff" ),
|
170 | | - __METHOD__,
|
171 | | - array( 'ORDER BY' => 'rev_timestamp DESC' )
|
172 | | - );
|
173 | | - // Find average, median...
|
174 | | - $res = $dbr->select( array( 'revision', 'reader_feedback' ),
|
175 | | - array( 'rfb_ratings' ),
|
176 | | - array( 'rev_page' => $page->getArticleId(),
|
177 | | - "rev_id = rfb_rev_id",
|
178 | | - "rfb_timestamp >= $cutoff",
|
179 | | - // Trigger INDEX usage
|
180 | | - "rev_timestamp >= ".$dbr->addQuotes($firstRevTS) ),
|
181 | | - __METHOD__,
|
182 | | - array( 'USE INDEX' => array('revision' => 'page_timestamp') )
|
183 | | - );
|
184 | | - $votes = array();
|
185 | | - foreach( ReaderFeedback::getFeedbackTags() as $tag => $w ) {
|
186 | | - $votes[$tag] = array( 0 => 0, 1 => 0, 2 => 0, 3 => 0, 4 => 0 );
|
187 | | - }
|
188 | | - // Read votes and tally the numbers
|
189 | | - while( $row = $dbr->fetchObject($res) ) {
|
190 | | - $dims = ReaderFeedback::expandRatings( $row->rfb_ratings );
|
191 | | - foreach( $dims as $tag => $val ) {
|
192 | | - if( isset($votes[$tag]) && isset($votes[$tag][$val]) ) {
|
193 | | - $votes[$tag][$val]++;
|
194 | | - }
|
195 | | - }
|
196 | | - }
|
197 | | - // Tack on $add for display (used to avoid cache/lag)
|
198 | | - foreach( $add as $tag => $val ) {
|
199 | | - if( isset($votes[$tag]) && isset($votes[$tag][$val]) ) {
|
200 | | - $votes[$tag][$val]++;
|
201 | | - }
|
202 | | - }
|
203 | | - $wgMemc->set( $key, array( $votes, $now ), 24*3600 );
|
204 | | - }
|
205 | | - // Output multi-column list
|
206 | | - $html = "<table class='rfb-reader_feedback_table' cellspacing='0'><tr>";
|
207 | | - foreach( ReaderFeedback::getFeedbackTags() as $tag => $w ) {
|
208 | | - // Get tag average...
|
209 | | - $dist = isset($votes[$tag]) ? $votes[$tag] : array();
|
210 | | - $count = array_sum($dist);
|
211 | | - if( $count ) {
|
212 | | - $ave = ($dist[0] + 2*$dist[1] + 3*$dist[2] + 4*$dist[3] + 5*$dist[4])/$count;
|
213 | | - $ave = round($ave,1);
|
214 | | - } else {
|
215 | | - $ave = '-'; // DIV by zero
|
216 | | - }
|
217 | | - $html .= '<td align="center"><b>'.wfMsgHtml("readerfeedback-$tag").'</b> '.
|
218 | | - '<sup>('.wfMsgHtml('ratinghistory-ave',$wgLang->formatNum($ave)).')</sup></td>';
|
219 | | - }
|
220 | | - $html .= '</tr><tr>';
|
221 | | - foreach( $votes as $tag => $dist ) {
|
222 | | - $html .= '<td><table>';
|
223 | | - $html .= '<tr><th align="left">'.wfMsgHtml('ratinghistory-table-rating').'</th>';
|
224 | | - for( $i = 1; $i <= 5; $i++ ) {
|
225 | | - $html .= "<td align='center' class='rfb-rating-option-".($i-1)."'>$i</td>";
|
226 | | - }
|
227 | | - $html .= '</tr><tr>';
|
228 | | - $html .= '<th align="left">'.wfMsgHtml("ratinghistory-table-votes").'</th>';
|
229 | | - $html .= '<td align="center">'.$dist[0].'</td>';
|
230 | | - $html .= '<td align="center">'.$dist[1].'</td>';
|
231 | | - $html .= '<td align="center">'.$dist[2].'</td>';
|
232 | | - $html .= '<td align="center">'.$dist[3].'</td>';
|
233 | | - $html .= '<td align="center">'.$dist[4].'</td>';
|
234 | | - $html .= "</tr></table></td>\n";
|
235 | | - }
|
236 | | - $html .= '</tr></table>';
|
237 | | - return $html;
|
238 | | - }
|
239 | | -
|
240 | | - /**
|
241 | | - * Get JS script params for onloading
|
242 | | - */
|
243 | | - public static function getJSTagParams() {
|
244 | | - self::load();
|
245 | | - # Param to pass to JS function to know if tags are at quality level
|
246 | | - $tagsJS = array();
|
247 | | - foreach( self::$dimensions as $tag => $x ) {
|
248 | | - $tagsJS[$tag] = self::$minQL[$tag];
|
249 | | - }
|
250 | | - $params = array( 'tags' => (object)$tagsJS );
|
251 | | - return Xml::encodeJsVar( (object)$params );
|
252 | | - }
|
253 | | -
|
254 | | - /**
|
255 | | - * Get JS script params for onloading
|
256 | | - */
|
257 | | - public static function getJSFeedbackParams() {
|
258 | | - self::load();
|
259 | | - # Param to pass to JS function to know if tags are at quality level
|
260 | | - global $wgFeedbackTags;
|
261 | | - $params = array( 'tags' => (object)$wgFeedbackTags );
|
262 | | - return Xml::encodeJsVar( (object)$params );
|
263 | | - }
|
264 | | -
|
265 | | -}
|
266 | | -
|
| 2 | +<?php |
| 3 | + |
| 4 | +class ReaderFeedback { |
| 5 | + protected static $feedbackTags = array(); |
| 6 | + protected static $feedbackTagWeight = array(); |
| 7 | + protected static $loaded = false; |
| 8 | + |
| 9 | + public static function load() { |
| 10 | + global $wgFeedbackTags; |
| 11 | + if( self::$loaded ) return true; |
| 12 | + foreach( $wgFeedbackTags as $tag => $weight ) { |
| 13 | + # Tag names used as part of file names. "Overall" tag is a |
| 14 | + # weighted aggregate, so it cannot be used either. |
| 15 | + if( !preg_match('/^[a-zA-Z]{1,20}$/',$tag) || $tag === 'overall' ) { |
| 16 | + throw new MWException( 'ReaderFeedback given invalid tag name!' ); |
| 17 | + } |
| 18 | + self::$feedbackTagWeight[$tag] = $weight; |
| 19 | + for( $i=0; $i <= 4; $i++ ) { |
| 20 | + self::$feedbackTags[$tag][$i] = "feedback-{$tag}-{$i}"; |
| 21 | + } |
| 22 | + } |
| 23 | + self::$loaded = true; |
| 24 | + } |
| 25 | + |
| 26 | + ################# Basic accessors ################# |
| 27 | + |
| 28 | + /** |
| 29 | + * Get the array of tag feedback tags |
| 30 | + * @returns array |
| 31 | + */ |
| 32 | + public static function getFeedbackTags() { |
| 33 | + self::load(); |
| 34 | + return self::$feedbackTags; |
| 35 | + } |
| 36 | + |
| 37 | + /** |
| 38 | + * Get the the weight of a feedback tag |
| 39 | + * @param string $tag |
| 40 | + * @returns array |
| 41 | + */ |
| 42 | + public static function getFeedbackWeight( $tag ) { |
| 43 | + self::load(); |
| 44 | + return self::$feedbackTagWeight[$tag]; |
| 45 | + } |
| 46 | + |
| 47 | + ################# Utility functions ################# |
| 48 | + |
| 49 | + /** |
| 50 | + * @param string $val |
| 51 | + * @return obj array |
| 52 | + * Get a memcache storage object |
| 53 | + */ |
| 54 | + public static function makeMemcObj( $val ) { |
| 55 | + $data = (object) array(); |
| 56 | + $data->value = $val; |
| 57 | + $data->time = wfTimestampNow(); |
| 58 | + return $data; |
| 59 | + } |
| 60 | + |
| 61 | + /** |
| 62 | + * @param mixed $data Memc data returned |
| 63 | + * @param Article $article |
| 64 | + * @return mixed |
| 65 | + * Return memc value if not expired |
| 66 | + */ |
| 67 | + public static function getMemcValue( $data, $article ) { |
| 68 | + if( is_object($data) && $data->time >= $article->getTouched() ) { |
| 69 | + return $data->value; |
| 70 | + } |
| 71 | + return false; |
| 72 | + } |
| 73 | + |
| 74 | + /** |
| 75 | + * @param Article $article |
| 76 | + * @param string $tag |
| 77 | + * @param bool $forUpdate, use master? |
| 78 | + * @return array(real,int) |
| 79 | + * Get article rating for this tag for the last few days |
| 80 | + */ |
| 81 | + public static function getAverageRating( $article, $tag, $forUpdate=false ) { |
| 82 | + global $wgFeedbackAge; |
| 83 | + $cutoff_unixtime = time() - $wgFeedbackAge; |
| 84 | + $db = $forUpdate ? wfGetDB( DB_MASTER ) : wfGetDB( DB_SLAVE ); |
| 85 | + $row = $db->selectRow( 'reader_feedback_history', |
| 86 | + array('SUM(rfh_total)/SUM(rfh_count) AS ave, SUM(rfh_count) AS count'), |
| 87 | + array( 'rfh_page_id' => $article->getId(), 'rfh_tag' => $tag, |
| 88 | + "rfh_date >= {$cutoff_unixtime}" ), |
| 89 | + __METHOD__ ); |
| 90 | + $data = $row && $row->count ? |
| 91 | + array($row->ave,$row->count) : array(0,0); |
| 92 | + return $data; |
| 93 | + } |
| 94 | + |
| 95 | + /** |
| 96 | + * Is this page in rateable namespace? |
| 97 | + * @param Title, $title |
| 98 | + * @return bool |
| 99 | + */ |
| 100 | + public static function isPageRateable( $title ) { |
| 101 | + global $wgFeedbackNamespaces; |
| 102 | + # FIXME: Treat NS_MEDIA as NS_FILE |
| 103 | + $ns = ( $title->getNamespace() == NS_MEDIA ) ? NS_FILE : $title->getNamespace(); |
| 104 | + # Check for MW: pages and whitelist for exempt pages |
| 105 | + if( $ns == NS_MEDIAWIKI ) { |
| 106 | + return false; |
| 107 | + } |
| 108 | + return ( in_array($ns,$wgFeedbackNamespaces) && !$title->isTalkPage() ); |
| 109 | + } |
| 110 | + |
| 111 | + /** |
| 112 | + * Expand feedback ratings into an array |
| 113 | + * @param string $ratings |
| 114 | + * @returns Array |
| 115 | + */ |
| 116 | + public static function expandRatings( $rating ) { |
| 117 | + $dims = array(); |
| 118 | + $pairs = explode( "\n", $rating ); |
| 119 | + foreach( $pairs as $pair ) { |
| 120 | + if( strpos($pair,'=') ) { |
| 121 | + list($tag,$value) = explode( '=', trim($pair), 2 ); |
| 122 | + $dims[$tag] = intval($value); |
| 123 | + } |
| 124 | + } |
| 125 | + return $dims; |
| 126 | + } |
| 127 | + |
| 128 | + /** |
| 129 | + * Get a table of the vote totals for a page |
| 130 | + * @param Title $page |
| 131 | + * @param int $period, number of days back |
| 132 | + * @param array $add, optional vote to add on (used to visually avoid lag) |
| 133 | + * @param string $cache, optional param to not use cache |
| 134 | + * @returns string HTML table |
| 135 | + */ |
| 136 | + public static function getVoteAggregates( $page, $period, $add = array(), $cache = 'useCache' ) { |
| 137 | + global $wgLang, $wgMemc; |
| 138 | + if( $period > 93 ) { |
| 139 | + return ''; // too big |
| 140 | + } |
| 141 | + $votes = null; |
| 142 | + $now = time(); |
| 143 | + $key = wfMemcKey( 'feedback', 'ratingtally', $page->getArticleId(), $period ); |
| 144 | + // Check cache |
| 145 | + if( $cache == 'useCache' ) { |
| 146 | + $set = $wgMemc->get($key); |
| 147 | + // Cutoff is at the 24 hour mark due to the way the aggregate |
| 148 | + // schema groups ratings by date for graphs. |
| 149 | + $cache_cutoff = $now - ($now % 86400); |
| 150 | + if( is_array($set) && count($set) == 2 ) { |
| 151 | + list($val,$time) = $set; |
| 152 | + $touched = wfTimestamp( TS_UNIX, RatingHistory::getTouched($page) ); |
| 153 | + if( $time > $cache_cutoff && $time > $touched ) { |
| 154 | + $votes = $val; |
| 155 | + } |
| 156 | + } |
| 157 | + } |
| 158 | + // Do query, cache miss |
| 159 | + if( !isset($votes) ) { |
| 160 | + // Set cutoff time for period |
| 161 | + $dbr = wfGetDB( DB_SLAVE ); |
| 162 | + $cutoff_unixtime = $now - ($period * 24 * 3600); |
| 163 | + // Use integral number of days to be consistent with graphs |
| 164 | + $cutoff_unixtime = $cutoff_unixtime - ($cutoff_unixtime % 86400); |
| 165 | + $cutoff = $dbr->addQuotes( wfTimestamp( TS_MW, $cutoff_unixtime ) ); |
| 166 | + // Get the first revision possibly voted on in the range |
| 167 | + $firstRevTS = $dbr->selectField( 'revision', |
| 168 | + 'rev_timestamp', |
| 169 | + array( 'rev_page' => $page->getArticleId(), "rev_timestamp <= $cutoff" ), |
| 170 | + __METHOD__, |
| 171 | + array( 'ORDER BY' => 'rev_timestamp DESC' ) |
| 172 | + ); |
| 173 | + // Find average, median... |
| 174 | + $res = $dbr->select( array( 'revision', 'reader_feedback' ), |
| 175 | + array( 'rfb_ratings' ), |
| 176 | + array( 'rev_page' => $page->getArticleId(), |
| 177 | + "rev_id = rfb_rev_id", |
| 178 | + "rfb_timestamp >= $cutoff", |
| 179 | + // Trigger INDEX usage |
| 180 | + "rev_timestamp >= ".$dbr->addQuotes($firstRevTS) ), |
| 181 | + __METHOD__, |
| 182 | + array( 'USE INDEX' => array('revision' => 'page_timestamp') ) |
| 183 | + ); |
| 184 | + $votes = array(); |
| 185 | + foreach( ReaderFeedback::getFeedbackTags() as $tag => $w ) { |
| 186 | + $votes[$tag] = array( 0 => 0, 1 => 0, 2 => 0, 3 => 0, 4 => 0 ); |
| 187 | + } |
| 188 | + // Read votes and tally the numbers |
| 189 | + while( $row = $dbr->fetchObject($res) ) { |
| 190 | + $dims = ReaderFeedback::expandRatings( $row->rfb_ratings ); |
| 191 | + foreach( $dims as $tag => $val ) { |
| 192 | + if( isset($votes[$tag]) && isset($votes[$tag][$val]) ) { |
| 193 | + $votes[$tag][$val]++; |
| 194 | + } |
| 195 | + } |
| 196 | + } |
| 197 | + // Tack on $add for display (used to avoid cache/lag) |
| 198 | + foreach( $add as $tag => $val ) { |
| 199 | + if( isset($votes[$tag]) && isset($votes[$tag][$val]) ) { |
| 200 | + $votes[$tag][$val]++; |
| 201 | + } |
| 202 | + } |
| 203 | + $wgMemc->set( $key, array( $votes, $now ), 24*3600 ); |
| 204 | + } |
| 205 | + // Output multi-column list |
| 206 | + $html = "<table class='rfb-reader_feedback_table' cellspacing='0'><tr>"; |
| 207 | + foreach( ReaderFeedback::getFeedbackTags() as $tag => $w ) { |
| 208 | + // Get tag average... |
| 209 | + $dist = isset($votes[$tag]) ? $votes[$tag] : array(); |
| 210 | + $count = array_sum($dist); |
| 211 | + if( $count ) { |
| 212 | + $ave = ($dist[0] + 2*$dist[1] + 3*$dist[2] + 4*$dist[3] + 5*$dist[4])/$count; |
| 213 | + $ave = round($ave,1); |
| 214 | + } else { |
| 215 | + $ave = '-'; // DIV by zero |
| 216 | + } |
| 217 | + $html .= '<td align="center"><b>'.wfMsgHtml("readerfeedback-$tag").'</b> '. |
| 218 | + '<sup>('.wfMsgHtml('ratinghistory-ave',$wgLang->formatNum($ave)).')</sup></td>'; |
| 219 | + } |
| 220 | + $html .= '</tr><tr>'; |
| 221 | + foreach( $votes as $tag => $dist ) { |
| 222 | + $html .= '<td><table>'; |
| 223 | + $html .= '<tr><th align="left">'.wfMsgHtml('ratinghistory-table-rating').'</th>'; |
| 224 | + for( $i = 1; $i <= 5; $i++ ) { |
| 225 | + $html .= "<td align='center' class='rfb-rating-option-".($i-1)."'>$i</td>"; |
| 226 | + } |
| 227 | + $html .= '</tr><tr>'; |
| 228 | + $html .= '<th align="left">'.wfMsgHtml("ratinghistory-table-votes").'</th>'; |
| 229 | + $html .= '<td align="center">'.$dist[0].'</td>'; |
| 230 | + $html .= '<td align="center">'.$dist[1].'</td>'; |
| 231 | + $html .= '<td align="center">'.$dist[2].'</td>'; |
| 232 | + $html .= '<td align="center">'.$dist[3].'</td>'; |
| 233 | + $html .= '<td align="center">'.$dist[4].'</td>'; |
| 234 | + $html .= "</tr></table></td>\n"; |
| 235 | + } |
| 236 | + $html .= '</tr></table>'; |
| 237 | + return $html; |
| 238 | + } |
| 239 | + |
| 240 | + /** |
| 241 | + * Get JS script params for onloading |
| 242 | + */ |
| 243 | + public static function getJSTagParams() { |
| 244 | + self::load(); |
| 245 | + # Param to pass to JS function to know if tags are at quality level |
| 246 | + $tagsJS = array(); |
| 247 | + foreach( self::$dimensions as $tag => $x ) { |
| 248 | + $tagsJS[$tag] = self::$minQL[$tag]; |
| 249 | + } |
| 250 | + $params = array( 'tags' => (object)$tagsJS ); |
| 251 | + return Xml::encodeJsVar( (object)$params ); |
| 252 | + } |
| 253 | + |
| 254 | + /** |
| 255 | + * Get JS script params for onloading |
| 256 | + */ |
| 257 | + public static function getJSFeedbackParams() { |
| 258 | + self::load(); |
| 259 | + # Param to pass to JS function to know if tags are at quality level |
| 260 | + global $wgFeedbackTags; |
| 261 | + $params = array( 'tags' => (object)$wgFeedbackTags ); |
| 262 | + return Xml::encodeJsVar( (object)$params ); |
| 263 | + } |
| 264 | + |
| 265 | +} |
| 266 | + |
Property changes on: trunk/extensions/ReaderFeedback/ReaderFeedback.class.php |
___________________________________________________________________ |
Name: svn:eol-style |
267 | 267 | + native |
Index: trunk/extensions/ReaderFeedback/readerfeedback.js |
— | — | @@ -1,140 +1,140 @@ |
2 | | -/* -- (c) Aaron Schulz 2008 */
|
3 | | -
|
4 | | -/* Every time you change this JS please bump $wgFeedbackStyleVersion in ReaderFeedback.php */
|
5 | | -
|
6 | | -/*
|
7 | | -* Update colors when select changes (Opera already does this).
|
8 | | -*/
|
9 | | -function updateFeedbackForm() {
|
10 | | - var allzero = true;
|
11 | | - var ratingform = document.getElementById('mw-feedbackselects');
|
12 | | - if( !ratingform ) return;
|
13 | | - for( tag in wgFeedbackParams.tags ) {
|
14 | | - var controlName = "wp" + tag;
|
15 | | - var levels = document.getElementsByName(controlName);
|
16 | | - var selectedlevel = 2; // default
|
17 | | - if( levels[0].nodeName == 'SELECT' ) {
|
18 | | - selectedlevel = levels[0].selectedIndex;
|
19 | | - // Update color. Opera does this already, and doing so
|
20 | | - // seems to kill custom pretty opera skin form styling.
|
21 | | - if( navigator.appName != 'Opera') {
|
22 | | - levels[0].className = 'fr-rating-option-' + (4 - selectedlevel);
|
23 | | - }
|
24 | | - if( selectedlevel <= 4 ) {
|
25 | | - allzero = false;
|
26 | | - }
|
27 | | - }
|
28 | | - }
|
29 | | - var submit = document.getElementById('submitfeedback');
|
30 | | - submit.disabled = allzero ? 'disabled' : '';
|
31 | | -}
|
32 | | -
|
33 | | -addOnloadHook(updateFeedbackForm);
|
34 | | -
|
35 | | -// dependencies:
|
36 | | -// * ajax.js:
|
37 | | - /*extern sajax_init_object, sajax_do_call */
|
38 | | -// * wikibits.js:
|
39 | | - /*extern hookEvent, jsMsg */
|
40 | | -
|
41 | | -// These should have been initialized in the generated js
|
42 | | -if( typeof wgAjaxFeedback === "undefined" || !wgAjaxFeedback ) {
|
43 | | - wgAjaxFeedback = {
|
44 | | - sendingMsg: "Submitting...",
|
45 | | - sentMsg: "Thank you!"
|
46 | | - };
|
47 | | -}
|
48 | | -
|
49 | | -wgAjaxFeedback.supported = true; // supported on current page and by browser
|
50 | | -wgAjaxFeedback.inprogress = false; // ajax request in progress
|
51 | | -wgAjaxFeedback.timeoutID = null; // see wgAjaxFeedback.ajaxCall
|
52 | | -
|
53 | | -wgAjaxFeedback.ajaxCall = function() {
|
54 | | - if( !wgAjaxFeedback.supported ) {
|
55 | | - return true;
|
56 | | - } else if( wgAjaxFeedback.inprogress ) {
|
57 | | - return false;
|
58 | | - }
|
59 | | - if( !wfSupportsAjax() ) {
|
60 | | - // Lazy initialization so we don't toss up
|
61 | | - // ActiveX warnings on initial page load
|
62 | | - // for IE 6 users with security settings.
|
63 | | - wgAjaxFeedback.supported = false;
|
64 | | - return true;
|
65 | | - }
|
66 | | - var form = document.getElementById("mw-feedbackform");
|
67 | | - var submit = document.getElementById("submitfeedback");
|
68 | | - if( !form || !submit ) {
|
69 | | - return false;
|
70 | | - }
|
71 | | - wgAjaxFeedback.inprogress = true;
|
72 | | - submit.disabled = "disabled";
|
73 | | - submit.value = wgAjaxFeedback.sendingMsg;
|
74 | | - // Build up arguments
|
75 | | - var args = [];
|
76 | | - var inputs = form.getElementsByTagName("input");
|
77 | | - for( var i=0; i < inputs.length; i++) {
|
78 | | - // Ignore some useless items...
|
79 | | - if( inputs[i].name != "title" && inputs[i].type != "submit" ) {
|
80 | | - args.push( inputs[i].name + "|" + inputs[i].value );
|
81 | | - }
|
82 | | - }
|
83 | | - var selects = form.getElementsByTagName("select");
|
84 | | - for( var i=0; i < selects.length; i++) {
|
85 | | - // Get the selected tag level...
|
86 | | - if( selects[i].selectedIndex >= 0 ) {
|
87 | | - var soption = selects[i].getElementsByTagName("option")[selects[i].selectedIndex];
|
88 | | - args.push( selects[i].name + "|" + soption.value );
|
89 | | - }
|
90 | | - selects[i].disabled = "disabled";
|
91 | | - }
|
92 | | - // Send!
|
93 | | - sajax_do_call( "ReaderFeedbackPage::AjaxReview", args, wgAjaxFeedback.processResult );
|
94 | | - // If the request isn't done in 10 seconds, allow user to try again
|
95 | | - wgAjaxFeedback.timeoutID = window.setTimeout(
|
96 | | - function() { wgAjaxFeedback.inprogress = false; wgAjaxFeedback.unlockForm(); },
|
97 | | - 10000
|
98 | | - );
|
99 | | - return false;
|
100 | | -};
|
101 | | -
|
102 | | -wgAjaxFeedback.unlockForm = function() {
|
103 | | - var form = document.getElementById("mw-feedbackform");
|
104 | | - var submit = document.getElementById("submitfeedback");
|
105 | | - if( !form || !submit ) {
|
106 | | - return false;
|
107 | | - }
|
108 | | - submit.disabled = "";
|
109 | | - var selects = form.getElementsByTagName("select");
|
110 | | - for( var i=0; i < selects.length; i++) {
|
111 | | - selects[i].disabled = "";
|
112 | | - }
|
113 | | -};
|
114 | | -
|
115 | | -wgAjaxFeedback.processResult = function(request) {
|
116 | | - if( !wgAjaxFeedback.supported ) {
|
117 | | - return;
|
118 | | - }
|
119 | | - var response = request.responseText;
|
120 | | - if( msg = response.substr(6) ) {
|
121 | | - jsMsg( msg, 'feedback' );
|
122 | | - window.scroll(0,0);
|
123 | | - }
|
124 | | - wgAjaxFeedback.inprogress = false;
|
125 | | - if( wgAjaxFeedback.timeoutID ) {
|
126 | | - window.clearTimeout(wgAjaxFeedback.timeoutID);
|
127 | | - }
|
128 | | - var submit = document.getElementById("submitfeedback");
|
129 | | - if( submit ) {
|
130 | | - submit.value = wgAjaxFeedback.sentMsg;
|
131 | | - }
|
132 | | -};
|
133 | | -
|
134 | | -wgAjaxFeedback.onLoad = function() {
|
135 | | - var submit = document.getElementById("submitfeedback");
|
136 | | - if( submit ) {
|
137 | | - submit.onclick = wgAjaxFeedback.ajaxCall;
|
138 | | - }
|
139 | | -};
|
140 | | -
|
141 | | -hookEvent("load", wgAjaxFeedback.onLoad);
|
| 2 | +/* -- (c) Aaron Schulz 2008 */ |
| 3 | + |
| 4 | +/* Every time you change this JS please bump $wgFeedbackStyleVersion in ReaderFeedback.php */ |
| 5 | + |
| 6 | +/* |
| 7 | +* Update colors when select changes (Opera already does this). |
| 8 | +*/ |
| 9 | +function updateFeedbackForm() { |
| 10 | + var allzero = true; |
| 11 | + var ratingform = document.getElementById('mw-feedbackselects'); |
| 12 | + if( !ratingform ) return; |
| 13 | + for( tag in wgFeedbackParams.tags ) { |
| 14 | + var controlName = "wp" + tag; |
| 15 | + var levels = document.getElementsByName(controlName); |
| 16 | + var selectedlevel = 2; // default |
| 17 | + if( levels[0].nodeName == 'SELECT' ) { |
| 18 | + selectedlevel = levels[0].selectedIndex; |
| 19 | + // Update color. Opera does this already, and doing so |
| 20 | + // seems to kill custom pretty opera skin form styling. |
| 21 | + if( navigator.appName != 'Opera') { |
| 22 | + levels[0].className = 'fr-rating-option-' + (4 - selectedlevel); |
| 23 | + } |
| 24 | + if( selectedlevel <= 4 ) { |
| 25 | + allzero = false; |
| 26 | + } |
| 27 | + } |
| 28 | + } |
| 29 | + var submit = document.getElementById('submitfeedback'); |
| 30 | + submit.disabled = allzero ? 'disabled' : ''; |
| 31 | +} |
| 32 | + |
| 33 | +addOnloadHook(updateFeedbackForm); |
| 34 | + |
| 35 | +// dependencies: |
| 36 | +// * ajax.js: |
| 37 | + /*extern sajax_init_object, sajax_do_call */ |
| 38 | +// * wikibits.js: |
| 39 | + /*extern hookEvent, jsMsg */ |
| 40 | + |
| 41 | +// These should have been initialized in the generated js |
| 42 | +if( typeof wgAjaxFeedback === "undefined" || !wgAjaxFeedback ) { |
| 43 | + wgAjaxFeedback = { |
| 44 | + sendingMsg: "Submitting...", |
| 45 | + sentMsg: "Thank you!" |
| 46 | + }; |
| 47 | +} |
| 48 | + |
| 49 | +wgAjaxFeedback.supported = true; // supported on current page and by browser |
| 50 | +wgAjaxFeedback.inprogress = false; // ajax request in progress |
| 51 | +wgAjaxFeedback.timeoutID = null; // see wgAjaxFeedback.ajaxCall |
| 52 | + |
| 53 | +wgAjaxFeedback.ajaxCall = function() { |
| 54 | + if( !wgAjaxFeedback.supported ) { |
| 55 | + return true; |
| 56 | + } else if( wgAjaxFeedback.inprogress ) { |
| 57 | + return false; |
| 58 | + } |
| 59 | + if( !wfSupportsAjax() ) { |
| 60 | + // Lazy initialization so we don't toss up |
| 61 | + // ActiveX warnings on initial page load |
| 62 | + // for IE 6 users with security settings. |
| 63 | + wgAjaxFeedback.supported = false; |
| 64 | + return true; |
| 65 | + } |
| 66 | + var form = document.getElementById("mw-feedbackform"); |
| 67 | + var submit = document.getElementById("submitfeedback"); |
| 68 | + if( !form || !submit ) { |
| 69 | + return false; |
| 70 | + } |
| 71 | + wgAjaxFeedback.inprogress = true; |
| 72 | + submit.disabled = "disabled"; |
| 73 | + submit.value = wgAjaxFeedback.sendingMsg; |
| 74 | + // Build up arguments |
| 75 | + var args = []; |
| 76 | + var inputs = form.getElementsByTagName("input"); |
| 77 | + for( var i=0; i < inputs.length; i++) { |
| 78 | + // Ignore some useless items... |
| 79 | + if( inputs[i].name != "title" && inputs[i].type != "submit" ) { |
| 80 | + args.push( inputs[i].name + "|" + inputs[i].value ); |
| 81 | + } |
| 82 | + } |
| 83 | + var selects = form.getElementsByTagName("select"); |
| 84 | + for( var i=0; i < selects.length; i++) { |
| 85 | + // Get the selected tag level... |
| 86 | + if( selects[i].selectedIndex >= 0 ) { |
| 87 | + var soption = selects[i].getElementsByTagName("option")[selects[i].selectedIndex]; |
| 88 | + args.push( selects[i].name + "|" + soption.value ); |
| 89 | + } |
| 90 | + selects[i].disabled = "disabled"; |
| 91 | + } |
| 92 | + // Send! |
| 93 | + sajax_do_call( "ReaderFeedbackPage::AjaxReview", args, wgAjaxFeedback.processResult ); |
| 94 | + // If the request isn't done in 10 seconds, allow user to try again |
| 95 | + wgAjaxFeedback.timeoutID = window.setTimeout( |
| 96 | + function() { wgAjaxFeedback.inprogress = false; wgAjaxFeedback.unlockForm(); }, |
| 97 | + 10000 |
| 98 | + ); |
| 99 | + return false; |
| 100 | +}; |
| 101 | + |
| 102 | +wgAjaxFeedback.unlockForm = function() { |
| 103 | + var form = document.getElementById("mw-feedbackform"); |
| 104 | + var submit = document.getElementById("submitfeedback"); |
| 105 | + if( !form || !submit ) { |
| 106 | + return false; |
| 107 | + } |
| 108 | + submit.disabled = ""; |
| 109 | + var selects = form.getElementsByTagName("select"); |
| 110 | + for( var i=0; i < selects.length; i++) { |
| 111 | + selects[i].disabled = ""; |
| 112 | + } |
| 113 | +}; |
| 114 | + |
| 115 | +wgAjaxFeedback.processResult = function(request) { |
| 116 | + if( !wgAjaxFeedback.supported ) { |
| 117 | + return; |
| 118 | + } |
| 119 | + var response = request.responseText; |
| 120 | + if( msg = response.substr(6) ) { |
| 121 | + jsMsg( msg, 'feedback' ); |
| 122 | + window.scroll(0,0); |
| 123 | + } |
| 124 | + wgAjaxFeedback.inprogress = false; |
| 125 | + if( wgAjaxFeedback.timeoutID ) { |
| 126 | + window.clearTimeout(wgAjaxFeedback.timeoutID); |
| 127 | + } |
| 128 | + var submit = document.getElementById("submitfeedback"); |
| 129 | + if( submit ) { |
| 130 | + submit.value = wgAjaxFeedback.sentMsg; |
| 131 | + } |
| 132 | +}; |
| 133 | + |
| 134 | +wgAjaxFeedback.onLoad = function() { |
| 135 | + var submit = document.getElementById("submitfeedback"); |
| 136 | + if( submit ) { |
| 137 | + submit.onclick = wgAjaxFeedback.ajaxCall; |
| 138 | + } |
| 139 | +}; |
| 140 | + |
| 141 | +hookEvent("load", wgAjaxFeedback.onLoad); |
Property changes on: trunk/extensions/ReaderFeedback/readerfeedback.js |
___________________________________________________________________ |
Name: svn:eol-style |
142 | 142 | + native |
Index: trunk/extensions/ReaderFeedback/ReaderFeedback.sql |
— | — | @@ -1,44 +1,44 @@ |
2 | | -
|
3 | | -CREATE TABLE IF NOT EXISTS /*$wgDBprefix*/reader_feedback (
|
4 | | - -- Foreign key to revision.rev_id
|
5 | | - rfb_rev_id integer unsigned NOT NULL,
|
6 | | - -- Foreign key to user.user_id
|
7 | | - rfb_user integer unsigned NOT NULL,
|
8 | | - rfb_ip varchar(255) NOT NULL default '',
|
9 | | - rfb_timestamp char(14) NOT NULL default '',
|
10 | | - --Vote info
|
11 | | - rfb_ratings mediumblob NOT NULL,
|
12 | | - -- No double voting!
|
13 | | - PRIMARY KEY (rfb_rev_id,rfb_user,rfb_ip)
|
14 | | -) /*$wgDBTableOptions*/;
|
15 | | -
|
16 | | -CREATE TABLE IF NOT EXISTS /*$wgDBprefix*/reader_feedback_history (
|
17 | | - -- Foreign key to page.page_id
|
18 | | - rfh_page_id integer unsigned NOT NULL,
|
19 | | - rfh_tag char(20) NOT NULL default '',
|
20 | | - rfh_total integer unsigned NOT NULL default 0,
|
21 | | - rfh_count integer unsigned NOT NULL default 0,
|
22 | | - -- MW date of the day this average corresponds to
|
23 | | - rfh_date char(14) NOT NULL default '',
|
24 | | - PRIMARY KEY (rfh_page_id,rfh_tag,rfh_date)
|
25 | | -) /*$wgDBTableOptions*/;
|
26 | | -
|
27 | | -CREATE TABLE IF NOT EXISTS /*$wgDBprefix*/reader_feedback_pages (
|
28 | | - -- Foreign key to page.page_id
|
29 | | - rfp_page_id integer unsigned NOT NULL,
|
30 | | - rfp_tag char(20) NOT NULL default '',
|
31 | | - -- Value in last few days (14)
|
32 | | - rfp_ave_val real NOT NULL default 0,
|
33 | | - -- And said total (used as threshold)
|
34 | | - rfp_count integer unsigned NOT NULL default 0,
|
35 | | - rfp_touched char(14) NOT NULL default '',
|
36 | | - PRIMARY KEY (rfp_page_id,rfp_tag),
|
37 | | - INDEX rfp_tag_val_page (rfp_tag,rfp_ave_val,rfp_page_id)
|
38 | | -) /*$wgDBTableOptions*/;
|
| 2 | +-- (c) Aaron Schulz, 2007-2009, GPL |
| 3 | +-- Table structure for table `Reader Feedback` |
| 4 | +-- Replace /*$wgDBprefix*/ with the proper prefix |
| 5 | +-- Replace /*$wgDBTableOptions*/ with the correct options |
| 6 | + |
| 7 | +-- This stores reader feedback data to curb double-voting |
| 8 | +CREATE TABLE IF NOT EXISTS /*$wgDBprefix*/reader_feedback ( |
| 9 | + -- Foreign key to revision.rev_id |
| 10 | + rfb_rev_id integer unsigned NOT NULL, |
| 11 | + -- Foreign key to user.user_id |
| 12 | + rfb_user integer unsigned NOT NULL, |
| 13 | + rfb_ip varchar(255) NOT NULL default '', |
| 14 | + rfb_timestamp char(14) NOT NULL default '', |
| 15 | + --Vote info |
| 16 | + rfb_ratings mediumblob NOT NULL, |
| 17 | + -- No double voting! |
| 18 | + PRIMARY KEY (rfb_rev_id,rfb_user,rfb_ip) |
| 19 | +) /*$wgDBTableOptions*/; |
| 20 | + |
| 21 | +-- This stores reader feedback data for a page over time |
| 22 | +CREATE TABLE IF NOT EXISTS /*$wgDBprefix*/reader_feedback_history ( |
| 23 | + -- Foreign key to page.page_id |
| 24 | + rfh_page_id integer unsigned NOT NULL, |
| 25 | + rfh_tag char(20) NOT NULL default '', |
| 26 | + rfh_total integer unsigned NOT NULL default 0, |
| 27 | + rfh_count integer unsigned NOT NULL default 0, |
| 28 | + -- MW date of the day this average corresponds to |
| 29 | + rfh_date char(14) NOT NULL default '', |
| 30 | + PRIMARY KEY (rfh_page_id,rfh_tag,rfh_date) |
| 31 | +) /*$wgDBTableOptions*/; |
| 32 | + |
| 33 | +-- This stores reader feedback data for pages |
| 34 | +CREATE TABLE IF NOT EXISTS /*$wgDBprefix*/reader_feedback_pages ( |
| 35 | + -- Foreign key to page.page_id |
| 36 | + rfp_page_id integer unsigned NOT NULL, |
| 37 | + rfp_tag char(20) NOT NULL default '', |
| 38 | + -- Value in last few days (14) |
| 39 | + rfp_ave_val real NOT NULL default 0, |
| 40 | + -- And said total (used as threshold) |
| 41 | + rfp_count integer unsigned NOT NULL default 0, |
| 42 | + rfp_touched char(14) NOT NULL default '', |
| 43 | + PRIMARY KEY (rfp_page_id,rfp_tag), |
| 44 | + INDEX rfp_tag_val_page (rfp_tag,rfp_ave_val,rfp_page_id) |
| 45 | +) /*$wgDBTableOptions*/; |
Property changes on: trunk/extensions/ReaderFeedback/ReaderFeedback.sql |
___________________________________________________________________ |
Name: svn:eol-style |
39 | 46 | + native |
Index: trunk/extensions/ReaderFeedback/ReaderFeedback.pg.sql |
— | — | @@ -1,33 +1,33 @@ |
2 | | -
|
3 | | -BEGIN;
|
4 | | -
|
5 | | -CREATE TABLE reader_feedback (
|
6 | | - rfb_rev_id INTEGER NOT NULL DEFAULT 0,
|
7 | | - rfb_user INTEGER NULL REFERENCES mwuser(user_id) ON DELETE SET NULL,
|
8 | | - rfb_ip TEXT NOT NULL DEFAULT '',
|
9 | | - PRIMARY KEY (rfb_rev_id,rfb_user,rfb_ip)
|
10 | | -);
|
11 | | -
|
12 | | -CREATE TABLE reader_feedback_history (
|
13 | | - rfh_page_id INTEGER NOT NULL DEFAULT 0,
|
14 | | - rfh_tag TEXT NOT NULL DEFAULT '',
|
15 | | - rfh_total INTEGER NOT NULL DEFAULT 0,
|
16 | | - rfh_count INTEGER NOT NULL DEFAULT 0,
|
17 | | - -- MW date of the day this average corresponds to
|
18 | | - rfh_date TEXT NOT NULL DEFAULT '',
|
19 | | - PRIMARY KEY (rfh_page_id,rfh_tag,rfh_date)
|
20 | | -);
|
21 | | -
|
22 | | -CREATE TABLE reader_feedback_pages (
|
23 | | - rfp_page_id INTEGER NOT NULL DEFAULT 0,
|
24 | | - rfp_tag TEXT NOT NULL DEFAULT '',
|
25 | | - rfp_ave_val REAL NOT NULL DEFAULT 0,
|
26 | | - rfp_count INTEGER NOT NULL DEFAULT 0,
|
27 | | - rfp_touched TIMESTAMPTZ NULL,
|
28 | | - PRIMARY KEY (rfp_page_id,rfp_tag)
|
29 | | -);
|
30 | | -CREATE INDEX rfp_tag_val_page ON reader_feedback_pages (rfp_tag,rfp_ave_val,rfp_page_id);
|
31 | | -
|
32 | | -COMMIT;
|
| 2 | +-- (c) Aaron Schulz, 2007 |
| 3 | +-- See ReaderFeedback.sql for details |
| 4 | + |
| 5 | +BEGIN; |
| 6 | + |
| 7 | +CREATE TABLE reader_feedback ( |
| 8 | + rfb_rev_id INTEGER NOT NULL DEFAULT 0, |
| 9 | + rfb_user INTEGER NULL REFERENCES mwuser(user_id) ON DELETE SET NULL, |
| 10 | + rfb_ip TEXT NOT NULL DEFAULT '', |
| 11 | + PRIMARY KEY (rfb_rev_id,rfb_user,rfb_ip) |
| 12 | +); |
| 13 | + |
| 14 | +CREATE TABLE reader_feedback_history ( |
| 15 | + rfh_page_id INTEGER NOT NULL DEFAULT 0, |
| 16 | + rfh_tag TEXT NOT NULL DEFAULT '', |
| 17 | + rfh_total INTEGER NOT NULL DEFAULT 0, |
| 18 | + rfh_count INTEGER NOT NULL DEFAULT 0, |
| 19 | + -- MW date of the day this average corresponds to |
| 20 | + rfh_date TEXT NOT NULL DEFAULT '', |
| 21 | + PRIMARY KEY (rfh_page_id,rfh_tag,rfh_date) |
| 22 | +); |
| 23 | + |
| 24 | +CREATE TABLE reader_feedback_pages ( |
| 25 | + rfp_page_id INTEGER NOT NULL DEFAULT 0, |
| 26 | + rfp_tag TEXT NOT NULL DEFAULT '', |
| 27 | + rfp_ave_val REAL NOT NULL DEFAULT 0, |
| 28 | + rfp_count INTEGER NOT NULL DEFAULT 0, |
| 29 | + rfp_touched TIMESTAMPTZ NULL, |
| 30 | + PRIMARY KEY (rfp_page_id,rfp_tag) |
| 31 | +); |
| 32 | +CREATE INDEX rfp_tag_val_page ON reader_feedback_pages (rfp_tag,rfp_ave_val,rfp_page_id); |
| 33 | + |
| 34 | +COMMIT; |
Property changes on: trunk/extensions/ReaderFeedback/ReaderFeedback.pg.sql |
___________________________________________________________________ |
Name: svn:eol-style |
33 | 35 | + native |
Index: trunk/extensions/ReaderFeedback/ReaderFeedback.php |
— | — | @@ -1,144 +1,144 @@ |
2 | | -<?php
|
3 | | -/*
|
4 | | - (c) Aaron Schulz 2007-2009 GPL
|
5 | | -
|
6 | | - This program is free software; you can redistribute it and/or modify
|
7 | | - it under the terms of the GNU General Public License as published by
|
8 | | - the Free Software Foundation; either version 2 of the License, or
|
9 | | - (at your option) any later version.
|
10 | | -
|
11 | | - This program is distributed in the hope that it will be useful,
|
12 | | - but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 | | - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14 | | - GNU General Public License for more details.
|
15 | | -
|
16 | | - You should have received a copy of the GNU General Public License along
|
17 | | - with this program; if not, write to the Free Software Foundation, Inc.,
|
18 | | - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
19 | | - http://www.gnu.org/copyleft/gpl.html
|
20 | | -*/
|
21 | | -
|
22 | | -if( !defined('MEDIAWIKI') ) {
|
23 | | - echo "ReaderFeedback extension\n";
|
24 | | - exit( 1 );
|
25 | | -}
|
26 | | -
|
27 | | -# Number of recent reviews to be a decent sample size
|
28 | | -if( !defined('READER_FEEDBACK_SIZE') )
|
29 | | - define('READER_FEEDBACK_SIZE',15);
|
30 | | -
|
31 | | -$wgExtensionCredits['specialpage'][] = array(
|
32 | | - 'path' => __FILE__,
|
33 | | - 'name' => 'Reader Feedback',
|
34 | | - 'author' => array( 'Aaron Schulz' ),
|
35 | | - 'url' => 'http://www.mediawiki.org/wiki/Extension:ReaderFeedback',
|
36 | | - 'descriptionmsg' => 'readerfeedback-desc',
|
37 | | -);
|
38 | | -
|
39 | | -#########
|
40 | | -# IMPORTANT:
|
41 | | -# When configuring globals, add them to localsettings.php and edit them THERE
|
42 | | -
|
43 | | -# Users that can use the feedback form.
|
44 | | -$wgGroupPermissions['*']['feedback'] = true;
|
45 | | -
|
46 | | -# Allow readers to rate pages in these namespaces
|
47 | | -$wgFeedbackNamespaces = array();
|
48 | | -#$wgFeedbackNamespaces = array( NS_MAIN );
|
49 | | -# Reader feedback tags, positive and negative. [a-zA-Z] tag names only.
|
50 | | -# Each tag has five levels, which 3 being average. The tag names are
|
51 | | -# mapped to their weight. This is used to determine the "worst"/"best" pages.
|
52 | | -$wgFeedbackTags = array(
|
53 | | - 'reliability' => 3,
|
54 | | - 'completeness' => 2,
|
55 | | - 'npov' => 2,
|
56 | | - 'presentation' => 1
|
57 | | -);
|
58 | | -# How many seconds back should the average rating for a page be based on?
|
59 | | -$wgFeedbackAge = 7 * 24 * 3600;
|
60 | | -# How long before stats page is updated?
|
61 | | -$wgFeedbackStatsAge = 2 * 3600; // 2 hours
|
62 | | -
|
63 | | -# URL location for readerfeedback.css and readerfeedback.js
|
64 | | -# Use a literal $wgScriptPath as a placeholder for the runtime value of $wgScriptPath
|
65 | | -$wgFeedbackStylePath = '$wgScriptPath/extensions/ReaderFeedback';
|
66 | | -
|
67 | | -# End of configuration variables.
|
68 | | -#########
|
69 | | -
|
70 | | -# Bump this number every time you change readerfeedback.css/readerfeedback.js
|
71 | | -$wgFeedbackStyleVersion = 1;
|
72 | | -
|
73 | | -$dir = dirname(__FILE__) . '/';
|
74 | | -$langDir = $dir . 'language/';
|
75 | | -
|
76 | | -$wgSvgGraphDir = $dir . 'svggraph';
|
77 | | -$wgPHPlotDir = $dir . 'phplot-5.0.5';
|
78 | | -
|
79 | | -$wgAutoloadClasses['ReaderFeedback'] = $dir.'ReaderFeedback.class.php';
|
80 | | -$wgAutoloadClasses['ReaderFeedbackHooks'] = $dir.'ReaderFeedback.hooks.php';
|
81 | | -$wgExtensionMessagesFiles['ReaderFeedback'] = $langDir . 'ReaderFeedback.i18n.php';
|
82 | | -
|
83 | | -# Load reader feedback UI
|
84 | | -$wgAutoloadClasses['ReaderFeedbackPage'] = $dir . 'specialpages/ReaderFeedback_body.php';
|
85 | | -$wgAutoloadClasses['ReaderFeedbackXML'] = $dir.'ReaderFeedbackXML.php';
|
86 | | -
|
87 | | -# Page rating history
|
88 | | -$wgAutoloadClasses['RatingHistory'] = $dir . 'specialpages/RatingHistory_body.php';
|
89 | | -$wgExtensionMessagesFiles['RatingHistory'] = $langDir . 'RatingHistory.i18n.php';
|
90 | | -
|
91 | | -# To list ill-recieved pages
|
92 | | -$wgAutoloadClasses['ProblemPages'] = $dir . 'specialpages/ProblemPages_body.php';
|
93 | | -$wgExtensionMessagesFiles['ProblemPages'] = $langDir . 'ProblemPages.i18n.php';
|
94 | | -$wgSpecialPageGroups['ProblemPages'] = 'quality';
|
95 | | -# To list well-recieved pages
|
96 | | -$wgAutoloadClasses['LikedPages'] = $dir . 'specialpages/LikedPages_body.php';
|
97 | | -$wgExtensionMessagesFiles['LikedPages'] = $langDir . 'LikedPages.i18n.php';
|
98 | | -$wgSpecialPageGroups['LikedPages'] = 'quality';
|
99 | | -
|
100 | | -######### Hook attachments #########
|
101 | | -
|
102 | | -# Add review form and visiblity settings link
|
103 | | -$wgHooks['SkinAfterContent'][] = 'ReaderFeedbackHooks::addFeedbackForm';
|
104 | | -
|
105 | | -# Rating link
|
106 | | -$wgHooks['SkinTemplateBuildNavUrlsNav_urlsAfterPermalink'][] = 'ReaderFeedbackHooks::addRatingLink';
|
107 | | -$wgHooks['SkinTemplateToolboxEnd'][] = 'ReaderFeedbackHooks::ratingToolboxLink';
|
108 | | -
|
109 | | -# Add CSS/JS as needed
|
110 | | -$wgHooks['BeforePageDisplay'][] = 'ReaderFeedbackHooks::injectStyleAndJS';
|
111 | | -
|
112 | | -# Duplicate flagged* tables in parserTests.php
|
113 | | -$wgHooks['ParserTestTables'][] = 'ReaderFeedbackHooks::onParserTestTables';
|
114 | | -
|
115 | | -# Actually register special pages
|
116 | | -$wgHooks['SpecialPage_initList'][] = 'efLoadReaderFeedbackSpecialPages';
|
117 | | -
|
118 | | -#########
|
119 | | -
|
120 | | -/*
|
121 | | - * Register ReaderFeedback special pages as needed.
|
122 | | - * Also sets $wgSpecialPages just to be consistent.
|
123 | | - */
|
124 | | -function efLoadReaderFeedbackSpecialPages( &$list ) {
|
125 | | - global $wgSpecialPages, $wgFeedbackNamespaces;
|
126 | | - if( !empty($wgFeedbackNamespaces) ) {
|
127 | | - $list['ReaderFeedback'] = $wgSpecialPages['ReaderFeedback'] = 'ReaderFeedbackPage';
|
128 | | - $list['RatingHistory'] = $wgSpecialPages['RatingHistory'] = 'RatingHistory';
|
129 | | - $list['ProblemPages'] = $wgSpecialPages['ProblemPages'] = 'ProblemPages';
|
130 | | - $list['LikedPages'] = $wgSpecialPages['LikedPages'] = 'LikedPages';
|
131 | | - }
|
132 | | - return true;
|
133 | | -}
|
134 | | -
|
135 | | -# AJAX functions
|
136 | | -$wgAjaxExportList[] = 'ReaderFeedbackPage::AjaxReview';
|
137 | | -
|
138 | | -# Schema changes
|
139 | | -$wgHooks['LoadExtensionSchemaUpdates'][] = 'efReaderFeedbackSchemaUpdates';
|
140 | | -
|
141 | | -function efReaderFeedbackSchemaUpdates() {
|
142 | | - global $wgDBtype, $wgExtNewFields, $wgExtPGNewFields, $wgExtNewIndexes, $wgExtNewTables;
|
143 | | - $base = dirname(__FILE__);
|
144 | | - return true;
|
145 | | -}
|
| 2 | +<?php |
| 3 | +/* |
| 4 | + (c) Aaron Schulz 2007-2009 GPL |
| 5 | + |
| 6 | + This program is free software; you can redistribute it and/or modify |
| 7 | + it under the terms of the GNU General Public License as published by |
| 8 | + the Free Software Foundation; either version 2 of the License, or |
| 9 | + (at your option) any later version. |
| 10 | + |
| 11 | + This program is distributed in the hope that it will be useful, |
| 12 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | + GNU General Public License for more details. |
| 15 | + |
| 16 | + You should have received a copy of the GNU General Public License along |
| 17 | + with this program; if not, write to the Free Software Foundation, Inc., |
| 18 | + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| 19 | + http://www.gnu.org/copyleft/gpl.html |
| 20 | +*/ |
| 21 | + |
| 22 | +if( !defined('MEDIAWIKI') ) { |
| 23 | + echo "ReaderFeedback extension\n"; |
| 24 | + exit( 1 ); |
| 25 | +} |
| 26 | + |
| 27 | +# Number of recent reviews to be a decent sample size |
| 28 | +if( !defined('READER_FEEDBACK_SIZE') ) |
| 29 | + define('READER_FEEDBACK_SIZE',15); |
| 30 | + |
| 31 | +$wgExtensionCredits['specialpage'][] = array( |
| 32 | + 'path' => __FILE__, |
| 33 | + 'name' => 'Reader Feedback', |
| 34 | + 'author' => array( 'Aaron Schulz' ), |
| 35 | + 'url' => 'http://www.mediawiki.org/wiki/Extension:ReaderFeedback', |
| 36 | + 'descriptionmsg' => 'readerfeedback-desc', |
| 37 | +); |
| 38 | + |
| 39 | +######### |
| 40 | +# IMPORTANT: |
| 41 | +# When configuring globals, add them to localsettings.php and edit them THERE |
| 42 | + |
| 43 | +# Users that can use the feedback form. |
| 44 | +$wgGroupPermissions['*']['feedback'] = true; |
| 45 | + |
| 46 | +# Allow readers to rate pages in these namespaces |
| 47 | +$wgFeedbackNamespaces = array(); |
| 48 | +#$wgFeedbackNamespaces = array( NS_MAIN ); |
| 49 | +# Reader feedback tags, positive and negative. [a-zA-Z] tag names only. |
| 50 | +# Each tag has five levels, which 3 being average. The tag names are |
| 51 | +# mapped to their weight. This is used to determine the "worst"/"best" pages. |
| 52 | +$wgFeedbackTags = array( |
| 53 | + 'reliability' => 3, |
| 54 | + 'completeness' => 2, |
| 55 | + 'npov' => 2, |
| 56 | + 'presentation' => 1 |
| 57 | +); |
| 58 | +# How many seconds back should the average rating for a page be based on? |
| 59 | +$wgFeedbackAge = 7 * 24 * 3600; |
| 60 | +# How long before stats page is updated? |
| 61 | +$wgFeedbackStatsAge = 2 * 3600; // 2 hours |
| 62 | + |
| 63 | +# URL location for readerfeedback.css and readerfeedback.js |
| 64 | +# Use a literal $wgScriptPath as a placeholder for the runtime value of $wgScriptPath |
| 65 | +$wgFeedbackStylePath = '$wgScriptPath/extensions/ReaderFeedback'; |
| 66 | + |
| 67 | +# End of configuration variables. |
| 68 | +######### |
| 69 | + |
| 70 | +# Bump this number every time you change readerfeedback.css/readerfeedback.js |
| 71 | +$wgFeedbackStyleVersion = 1; |
| 72 | + |
| 73 | +$dir = dirname(__FILE__) . '/'; |
| 74 | +$langDir = $dir . 'language/'; |
| 75 | + |
| 76 | +$wgSvgGraphDir = $dir . 'svggraph'; |
| 77 | +$wgPHPlotDir = $dir . 'phplot-5.0.5'; |
| 78 | + |
| 79 | +$wgAutoloadClasses['ReaderFeedback'] = $dir.'ReaderFeedback.class.php'; |
| 80 | +$wgAutoloadClasses['ReaderFeedbackHooks'] = $dir.'ReaderFeedback.hooks.php'; |
| 81 | +$wgExtensionMessagesFiles['ReaderFeedback'] = $langDir . 'ReaderFeedback.i18n.php'; |
| 82 | + |
| 83 | +# Load reader feedback UI |
| 84 | +$wgAutoloadClasses['ReaderFeedbackPage'] = $dir . 'specialpages/ReaderFeedback_body.php'; |
| 85 | +$wgAutoloadClasses['ReaderFeedbackXML'] = $dir.'ReaderFeedbackXML.php'; |
| 86 | + |
| 87 | +# Page rating history |
| 88 | +$wgAutoloadClasses['RatingHistory'] = $dir . 'specialpages/RatingHistory_body.php'; |
| 89 | +$wgExtensionMessagesFiles['RatingHistory'] = $langDir . 'RatingHistory.i18n.php'; |
| 90 | + |
| 91 | +# To list ill-recieved pages |
| 92 | +$wgAutoloadClasses['ProblemPages'] = $dir . 'specialpages/ProblemPages_body.php'; |
| 93 | +$wgExtensionMessagesFiles['ProblemPages'] = $langDir . 'ProblemPages.i18n.php'; |
| 94 | +$wgSpecialPageGroups['ProblemPages'] = 'quality'; |
| 95 | +# To list well-recieved pages |
| 96 | +$wgAutoloadClasses['LikedPages'] = $dir . 'specialpages/LikedPages_body.php'; |
| 97 | +$wgExtensionMessagesFiles['LikedPages'] = $langDir . 'LikedPages.i18n.php'; |
| 98 | +$wgSpecialPageGroups['LikedPages'] = 'quality'; |
| 99 | + |
| 100 | +######### Hook attachments ######### |
| 101 | + |
| 102 | +# Add review form and visiblity settings link |
| 103 | +$wgHooks['SkinAfterContent'][] = 'ReaderFeedbackHooks::addFeedbackForm'; |
| 104 | + |
| 105 | +# Rating link |
| 106 | +$wgHooks['SkinTemplateBuildNavUrlsNav_urlsAfterPermalink'][] = 'ReaderFeedbackHooks::addRatingLink'; |
| 107 | +$wgHooks['SkinTemplateToolboxEnd'][] = 'ReaderFeedbackHooks::ratingToolboxLink'; |
| 108 | + |
| 109 | +# Add CSS/JS as needed |
| 110 | +$wgHooks['BeforePageDisplay'][] = 'ReaderFeedbackHooks::injectStyleAndJS'; |
| 111 | + |
| 112 | +# Duplicate flagged* tables in parserTests.php |
| 113 | +$wgHooks['ParserTestTables'][] = 'ReaderFeedbackHooks::onParserTestTables'; |
| 114 | + |
| 115 | +# Actually register special pages |
| 116 | +$wgHooks['SpecialPage_initList'][] = 'efLoadReaderFeedbackSpecialPages'; |
| 117 | + |
| 118 | +######### |
| 119 | + |
| 120 | +/* |
| 121 | + * Register ReaderFeedback special pages as needed. |
| 122 | + * Also sets $wgSpecialPages just to be consistent. |
| 123 | + */ |
| 124 | +function efLoadReaderFeedbackSpecialPages( &$list ) { |
| 125 | + global $wgSpecialPages, $wgFeedbackNamespaces; |
| 126 | + if( !empty($wgFeedbackNamespaces) ) { |
| 127 | + $list['ReaderFeedback'] = $wgSpecialPages['ReaderFeedback'] = 'ReaderFeedbackPage'; |
| 128 | + $list['RatingHistory'] = $wgSpecialPages['RatingHistory'] = 'RatingHistory'; |
| 129 | + $list['ProblemPages'] = $wgSpecialPages['ProblemPages'] = 'ProblemPages'; |
| 130 | + $list['LikedPages'] = $wgSpecialPages['LikedPages'] = 'LikedPages'; |
| 131 | + } |
| 132 | + return true; |
| 133 | +} |
| 134 | + |
| 135 | +# AJAX functions |
| 136 | +$wgAjaxExportList[] = 'ReaderFeedbackPage::AjaxReview'; |
| 137 | + |
| 138 | +# Schema changes |
| 139 | +$wgHooks['LoadExtensionSchemaUpdates'][] = 'efReaderFeedbackSchemaUpdates'; |
| 140 | + |
| 141 | +function efReaderFeedbackSchemaUpdates() { |
| 142 | + global $wgDBtype, $wgExtNewFields, $wgExtPGNewFields, $wgExtNewIndexes, $wgExtNewTables; |
| 143 | + $base = dirname(__FILE__); |
| 144 | + return true; |
| 145 | +} |
Property changes on: trunk/extensions/ReaderFeedback/ReaderFeedback.php |
___________________________________________________________________ |
Name: svn:eol-style |
146 | 146 | + native |
Index: trunk/extensions/ReaderFeedback/ReaderFeedbackXML.php |
— | — | @@ -1,19 +1,19 @@ |
2 | | -<?php
|
3 | | -
|
4 | | -class ReaderFeedbackXML {
|
5 | | - /**
|
6 | | - * Get tag dropdown select
|
7 | | - * @param int $selected, selected level
|
8 | | - */
|
9 | | - public static function getTagMenu( $selected = '' ) {
|
10 | | - wfLoadExtensionMessages( 'ReaderFeedback' );
|
11 | | - $s = "<label for='wpRatingTag'>" . wfMsgHtml('revreview-tagfilter') . "</label> ";
|
12 | | - $s .= Xml::openElement( 'select', array('name' => 'ratingtag', 'id' => 'wpRatingTag') );
|
13 | | - foreach( ReaderFeedback::getFeedbackTags() as $tag => $weight ) {
|
14 | | - $s .= Xml::option( wfMsg( "readerfeedback-$tag" ), $tag, $selected===$tag );
|
15 | | - }
|
16 | | - $s .= Xml::closeElement('select')."\n";
|
17 | | - return $s;
|
18 | | - }
|
19 | | -
|
20 | | -}
|
| 2 | +<?php |
| 3 | + |
| 4 | +class ReaderFeedbackXML { |
| 5 | + /** |
| 6 | + * Get tag dropdown select |
| 7 | + * @param int $selected, selected level |
| 8 | + */ |
| 9 | + public static function getTagMenu( $selected = '' ) { |
| 10 | + wfLoadExtensionMessages( 'ReaderFeedback' ); |
| 11 | + $s = "<label for='wpRatingTag'>" . wfMsgHtml('revreview-tagfilter') . "</label> "; |
| 12 | + $s .= Xml::openElement( 'select', array('name' => 'ratingtag', 'id' => 'wpRatingTag') ); |
| 13 | + foreach( ReaderFeedback::getFeedbackTags() as $tag => $weight ) { |
| 14 | + $s .= Xml::option( wfMsg( "readerfeedback-$tag" ), $tag, $selected===$tag ); |
| 15 | + } |
| 16 | + $s .= Xml::closeElement('select')."\n"; |
| 17 | + return $s; |
| 18 | + } |
| 19 | + |
| 20 | +} |
Property changes on: trunk/extensions/ReaderFeedback/ReaderFeedbackXML.php |
___________________________________________________________________ |
Name: svn:eol-style |
21 | 21 | + native |
Index: trunk/extensions/ReaderFeedback/readerfeedback.css |
— | — | @@ -1,55 +1,55 @@ |
2 | | -/* Every time you change this CSS please bump $wgFeedbackStyleVersion in ReaderFeedback.php */
|
3 | | -
|
4 | | -/* Review form */
|
5 | | -.feedback_reviewform {
|
6 | | - background-color: #f9f9f9;
|
7 | | - font-size: 90%;
|
8 | | - clear: both;
|
9 | | -}
|
10 | | -
|
11 | | -.rfb-rating-option-0 {
|
12 | | - background-color: #f5ecec;
|
13 | | -}
|
14 | | -.rfb-rating-option-1 {
|
15 | | - background-color: #f0f8ff;
|
16 | | -}
|
17 | | -.rfb-rating-option-2 {
|
18 | | - background-color: #f0fff0;
|
19 | | -}
|
20 | | -.rfb-rating-option-3 {
|
21 | | - background-color: #fef0db;
|
22 | | -}
|
23 | | -.rfb-rating-option-4 {
|
24 | | - background-color: #fffff0;
|
25 | | -}
|
26 | | -
|
27 | | -/* Reader feedback form */
|
28 | | -.rfb-reader_feedback_plot {
|
29 | | - background-color: #F8F8F8;
|
30 | | -}
|
31 | | -
|
32 | | -.rfb-reader_feedback_graph,
|
33 | | -.rfb-reader_feedback_ratings,
|
34 | | -.rfb-reader_feedback_users {
|
35 | | - width: 100%;
|
36 | | - overflow: auto;
|
37 | | -}
|
38 | | -
|
39 | | -.rfb-reader_feedback_users {
|
40 | | - background-color: #F0F0F0;
|
41 | | - max-height:410px;
|
42 | | - font-size: 90%;
|
43 | | -}
|
44 | | -
|
45 | | -.rfb-reader_feedback_table {
|
46 | | - margin: .5em .5em .5em .5em;
|
47 | | - background: #f9f9f9;
|
48 | | - border: 1px #AAA solid;
|
49 | | - border-collapse: collapse;
|
50 | | - font-size: 85%;
|
51 | | -}
|
52 | | -
|
53 | | -.rfb-reader_feedback_table th, .rfb-reader_feedback_table td {
|
54 | | - border: 1px #AAA solid;
|
55 | | - padding: 0.3em;
|
56 | | -}
|
| 2 | +/* Every time you change this CSS please bump $wgFeedbackStyleVersion in ReaderFeedback.php */ |
| 3 | + |
| 4 | +/* Review form */ |
| 5 | +.feedback_reviewform { |
| 6 | + background-color: #f9f9f9; |
| 7 | + font-size: 90%; |
| 8 | + clear: both; |
| 9 | +} |
| 10 | + |
| 11 | +.rfb-rating-option-0 { |
| 12 | + background-color: #f5ecec; |
| 13 | +} |
| 14 | +.rfb-rating-option-1 { |
| 15 | + background-color: #f0f8ff; |
| 16 | +} |
| 17 | +.rfb-rating-option-2 { |
| 18 | + background-color: #f0fff0; |
| 19 | +} |
| 20 | +.rfb-rating-option-3 { |
| 21 | + background-color: #fef0db; |
| 22 | +} |
| 23 | +.rfb-rating-option-4 { |
| 24 | + background-color: #fffff0; |
| 25 | +} |
| 26 | + |
| 27 | +/* Reader feedback form */ |
| 28 | +.rfb-reader_feedback_plot { |
| 29 | + background-color: #F8F8F8; |
| 30 | +} |
| 31 | + |
| 32 | +.rfb-reader_feedback_graph, |
| 33 | +.rfb-reader_feedback_ratings, |
| 34 | +.rfb-reader_feedback_users { |
| 35 | + width: 100%; |
| 36 | + overflow: auto; |
| 37 | +} |
| 38 | + |
| 39 | +.rfb-reader_feedback_users { |
| 40 | + background-color: #F0F0F0; |
| 41 | + max-height:410px; |
| 42 | + font-size: 90%; |
| 43 | +} |
| 44 | + |
| 45 | +.rfb-reader_feedback_table { |
| 46 | + margin: .5em .5em .5em .5em; |
| 47 | + background: #f9f9f9; |
| 48 | + border: 1px #AAA solid; |
| 49 | + border-collapse: collapse; |
| 50 | + font-size: 85%; |
| 51 | +} |
| 52 | + |
| 53 | +.rfb-reader_feedback_table th, .rfb-reader_feedback_table td { |
| 54 | + border: 1px #AAA solid; |
| 55 | + padding: 0.3em; |
| 56 | +} |
Property changes on: trunk/extensions/ReaderFeedback/readerfeedback.css |
___________________________________________________________________ |
Name: svn:eol-style |
57 | 57 | + native |