r53146 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r53145‎ | r53146 | r53147 >
Date:20:35, 12 July 2009
Author:ialex
Status:ok
Tags:
Comment:
svn:eol-style native
Modified paths:
  • /trunk/extensions/IndexFunction/IndexFunction.i18n.php (modified) (history)
  • /trunk/extensions/IndexFunction/IndexFunction.php (modified) (history)
  • /trunk/extensions/IndexFunction/IndexFunction_body.php (modified) (history)
  • /trunk/extensions/IndexFunction/SpecialIndex.php (modified) (history)
  • /trunk/extensions/IndexFunction/indexes.sql (modified) (history)
  • /trunk/extensions/NSFileRepo/README (modified) (history)
  • /trunk/extensions/ReaderFeedback/ReaderFeedback.class.php (modified) (history)
  • /trunk/extensions/ReaderFeedback/ReaderFeedback.hooks.php (modified) (history)
  • /trunk/extensions/ReaderFeedback/ReaderFeedback.pg.sql (modified) (history)
  • /trunk/extensions/ReaderFeedback/ReaderFeedback.php (modified) (history)
  • /trunk/extensions/ReaderFeedback/ReaderFeedback.sql (modified) (history)
  • /trunk/extensions/ReaderFeedback/ReaderFeedbackXML.php (modified) (history)
  • /trunk/extensions/ReaderFeedback/readerfeedback.css (modified) (history)
  • /trunk/extensions/ReaderFeedback/readerfeedback.js (modified) (history)
  • /trunk/extensions/SemanticResultFormats/Ploticus/SRF_PloticusVBar.php (modified) (history)
  • /trunk/extensions/SlippyMap/SlippyMapExportCgiBin.class.php (modified) (history)

Diff [purge]

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
145145 + native
Property changes on: trunk/extensions/SlippyMap/SlippyMapExportCgiBin.class.php
___________________________________________________________________
Name: svn:eol-style
146146 + 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+
4242 }
\ No newline at end of file
Property changes on: trunk/extensions/SemanticResultFormats/Ploticus/SRF_PloticusVBar.php
___________________________________________________________________
Name: svn:eol-style
4343 + native
Property changes on: trunk/extensions/IndexFunction/IndexFunction_body.php
___________________________________________________________________
Name: svn:eol-style
4444 + native
Property changes on: trunk/extensions/IndexFunction/IndexFunction.i18n.php
___________________________________________________________________
Name: svn:eol-style
4545 + native
Property changes on: trunk/extensions/IndexFunction/IndexFunction.php
___________________________________________________________________
Name: svn:eol-style
4646 + native
Property changes on: trunk/extensions/IndexFunction/indexes.sql
___________________________________________________________________
Name: svn:eol-style
4747 + native
Property changes on: trunk/extensions/IndexFunction/SpecialIndex.php
___________________________________________________________________
Name: svn:eol-style
4848 + 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 .= '&nbsp;' . 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 .= '&nbsp;' . 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
207207 + 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>&nbsp;&nbsp;'.
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>&nbsp;&nbsp;'.
 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
267267 + 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
142142 + 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
3946 + 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
3335 + 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
146146 + 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>&nbsp;";
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>&nbsp;";
 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
2121 + 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
5757 + native

Status & tagging log