Index: trunk/extensions/ArticleFeedbackv5/modules/jquery.articleFeedbackv5/jquery.articleFeedbackv5.special.css |
— | — | @@ -0,0 +1,2 @@ |
| 2 | +/* css here */ |
| 3 | +div.aft5-feedback { border:1px solid red; } |
Property changes on: trunk/extensions/ArticleFeedbackv5/modules/jquery.articleFeedbackv5/jquery.articleFeedbackv5.special.css |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 4 | + native |
Index: trunk/extensions/ArticleFeedbackv5/modules/jquery.articleFeedbackv5/jquery.articleFeedbackv5.special.js |
— | — | @@ -0,0 +1,70 @@ |
| 2 | +( function ( $ ) { |
| 3 | + $.articleFeedbackv5special = {}; |
| 4 | + |
| 5 | + // TODO: Pass this in from the PHP side. Add it to mwConfig or w/e? |
| 6 | + //$.articleFeedbackv5special.page = mw.config.get( 'wgPageId' ); |
| 7 | + $.articleFeedbackv5special.page = 0; |
| 8 | +console.log('oage id is ' + hackPageId); |
| 9 | + $.articleFeedbackv5special.filter = 'visible'; |
| 10 | + $.articleFeedbackv5special.sort = 'newest'; |
| 11 | + $.articleFeedbackv5special.limit = 5; |
| 12 | + $.articleFeedbackv5special.offset = 0; |
| 13 | + |
| 14 | + $.articleFeedbackv5special.apiUrl = mw.config.get( 'wgScriptPath' ) |
| 15 | + + '/api.php'; |
| 16 | + |
| 17 | + |
| 18 | + $.articleFeedbackv5special.setBinds = function() { |
| 19 | + $( '#aft5-filter' ).bind( 'change', function(e) { |
| 20 | + $.articleFeedbackv5special.filter = $(this).val(); |
| 21 | + $.articleFeedbackv5special.loadFeedback(); |
| 22 | + return false; |
| 23 | + } ); |
| 24 | + $( '#aft5-sort' ).bind( 'change', function(e) { |
| 25 | + $.articleFeedbackv5special.sort = $(this).val(); |
| 26 | + $.articleFeedbackv5special.loadFeedback(); |
| 27 | + return false; |
| 28 | + } ); |
| 29 | + $( '#aft5-more' ).bind( 'click', function(e) { |
| 30 | + $.articleFeedbackv5special.offset += |
| 31 | + $.articleFeedbackv5special.limit; |
| 32 | + $.articleFeedbackv5special.loadFeedback(); |
| 33 | + return false; |
| 34 | + } ); |
| 35 | + // TODO: need to handle: upvote, downvote, hide, flag as abuse |
| 36 | + // PROTIP use 'live' instead of 'bind' because dynamic loading. |
| 37 | + } |
| 38 | + |
| 39 | + $.articleFeedbackv5special.loadFeedback = function () { |
| 40 | + |
| 41 | + $.ajax( { |
| 42 | + 'url' : $.articleFeedbackv5special.apiUrl, |
| 43 | + 'type' : 'GET', |
| 44 | + 'dataType': 'json', |
| 45 | + 'data' : { |
| 46 | + 'afpageid': $.articleFeedbackv5special.page, |
| 47 | + 'affilter': $.articleFeedbackv5special.filter, |
| 48 | + 'afsort' : $.articleFeedbackv5special.sort, |
| 49 | + 'aflimit' : $.articleFeedbackv5special.limit, |
| 50 | + 'afoffset': $.articleFeedbackv5special.offset, |
| 51 | + 'action' : 'query', |
| 52 | + 'format' : 'json', |
| 53 | + 'list' : 'articlefeedbackv5-view-feedback', |
| 54 | + 'maxage' : 0, |
| 55 | + }, |
| 56 | + 'success': function ( data ) { |
| 57 | + // TODO check output and error if needed |
| 58 | + $( '#aft5-show-feedback' ).html( |
| 59 | +$( '#aft5-show-feedback' ).html() + data.query['articlefeedbackv5-view-feedback'].feedback |
| 60 | + ); |
| 61 | + } |
| 62 | + // TODO have a callback for failures. |
| 63 | + } ); |
| 64 | + return false; |
| 65 | + } |
| 66 | +} )( jQuery ); |
| 67 | + |
| 68 | +$( document ).ready( function() { |
| 69 | + $.articleFeedbackv5special.setBinds(); |
| 70 | + $.articleFeedbackv5special.loadFeedback(); |
| 71 | +} ); |
Property changes on: trunk/extensions/ArticleFeedbackv5/modules/jquery.articleFeedbackv5/jquery.articleFeedbackv5.special.js |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 72 | + native |
Index: trunk/extensions/ArticleFeedbackv5/ArticleFeedbackv5.php |
— | — | @@ -187,13 +187,14 @@ |
188 | 188 | |
189 | 189 | // Autoloading |
190 | 190 | $dir = dirname( __FILE__ ) . '/'; |
191 | | -$wgAutoloadClasses['ApiArticleFeedbackv5Utils'] = $dir . 'api/ApiArticleFeedbackv5Utils.php'; |
192 | | -$wgAutoloadClasses['ApiArticleFeedbackv5'] = $dir . 'api/ApiArticleFeedbackv5.php'; |
193 | | -$wgAutoloadClasses['ApiViewRatingsArticleFeedbackv5'] = $dir . 'api/ApiViewRatingsArticleFeedbackv5.php'; |
194 | | -$wgAutoloadClasses['ArticleFeedbackv5Hooks'] = $dir . 'ArticleFeedbackv5.hooks.php'; |
195 | | -$wgAutoloadClasses['SpecialArticleFeedbackv5'] = $dir . 'SpecialArticleFeedbackv5.php'; |
196 | | -$wgExtensionMessagesFiles['ArticleFeedbackv5'] = $dir . 'ArticleFeedbackv5.i18n.php'; |
197 | | -$wgExtensionAliasesFiles['ArticleFeedbackv5'] = $dir . 'ArticleFeedbackv5.alias.php'; |
| 191 | +$wgAutoloadClasses['ApiArticleFeedbackv5Utils'] = $dir . 'api/ApiArticleFeedbackv5Utils.php'; |
| 192 | +$wgAutoloadClasses['ApiArticleFeedbackv5'] = $dir . 'api/ApiArticleFeedbackv5.php'; |
| 193 | +$wgAutoloadClasses['ApiViewRatingsArticleFeedbackv5'] = $dir . 'api/ApiViewRatingsArticleFeedbackv5.php'; |
| 194 | +$wgAutoloadClasses['ApiViewFeedbackArticleFeedbackv5'] = $dir . 'api/ApiViewFeedbackArticleFeedbackv5.php'; |
| 195 | +$wgAutoloadClasses['ArticleFeedbackv5Hooks'] = $dir . 'ArticleFeedbackv5.hooks.php'; |
| 196 | +$wgAutoloadClasses['SpecialArticleFeedbackv5'] = $dir . 'SpecialArticleFeedbackv5.php'; |
| 197 | +$wgExtensionMessagesFiles['ArticleFeedbackv5'] = $dir . 'ArticleFeedbackv5.i18n.php'; |
| 198 | +$wgExtensionAliasesFiles['ArticleFeedbackv5'] = $dir . 'ArticleFeedbackv5.alias.php'; |
198 | 199 | |
199 | 200 | // Hooks |
200 | 201 | $wgHooks['LoadExtensionSchemaUpdates'][] = 'ArticleFeedbackv5Hooks::loadExtensionSchemaUpdates'; |
— | — | @@ -207,10 +208,10 @@ |
208 | 209 | $wgHooks['ArticleSaveComplete'][] = 'ArticleFeedbackv5Hooks::trackEdit'; |
209 | 210 | |
210 | 211 | // API Registration |
211 | | -$wgAPIListModules['articlefeedbackv5-view-ratings'] = 'ApiViewRatingsArticleFeedbackv5'; |
212 | | -$wgAPIModules['articlefeedbackv5'] = 'ApiArticleFeedbackv5'; |
| 212 | +$wgAPIListModules['articlefeedbackv5-view-ratings'] = 'ApiViewRatingsArticleFeedbackv5'; |
| 213 | +$wgAPIListModules['articlefeedbackv5-view-feedback'] = 'ApiViewFeedbackArticleFeedbackv5'; |
| 214 | +$wgAPIModules['articlefeedbackv5'] = 'ApiArticleFeedbackv5'; |
213 | 215 | |
214 | 216 | // Special Page |
215 | 217 | $wgSpecialPages['ArticleFeedbackv5'] = 'SpecialArticleFeedbackv5'; |
216 | 218 | $wgSpecialPageGroups['ArticleFeedbackv5'] = 'other'; |
217 | | - |
Index: trunk/extensions/ArticleFeedbackv5/api/ApiArticleFeedbackv5.php |
— | — | @@ -143,7 +143,6 @@ |
144 | 144 | * @param $revision int the revision id |
145 | 145 | */ |
146 | 146 | public function updateRollupTables( $page, $revision ) { |
147 | | -# Select rollup doesn't work yet |
148 | 147 | # foreach( array( 'rating', 'boolean', 'select' ) as $type ) { |
149 | 148 | foreach( array( 'rating', 'boolean' ) as $type ) { |
150 | 149 | $this->updateRollup( $page, $revision, $type ); |
— | — | @@ -158,19 +157,40 @@ |
159 | 158 | * @param $type string the type (rating, select, or boolean) |
160 | 159 | */ |
161 | 160 | private function updateRollup($pageId, $revId, $type) { |
162 | | - global $wgArticleFeedbackv5RatingLifetime; |
163 | | - $dbr = wfGetDB( DB_SLAVE ); |
164 | | - $dbw = wfGetDB( DB_MASTER ); |
165 | | - $limit = ApiArticleFeedbackv5Utils::getRevisionLimit( $pageId ); |
166 | | - |
167 | 161 | # sanity check |
168 | 162 | if ( $type != 'rating' && $type != 'select' && $type != 'boolean' ) { |
169 | 163 | return 0; |
170 | 164 | } |
171 | 165 | |
| 166 | + global $wgArticleFeedbackv5RatingLifetime; |
| 167 | + $dbr = wfGetDB( DB_SLAVE ); |
| 168 | + $dbw = wfGetDB( DB_MASTER ); |
| 169 | + $limit = ApiArticleFeedbackv5Utils::getRevisionLimit( $pageId ); |
| 170 | + $page_data = array(); |
| 171 | + $rev_data = array(); |
| 172 | + $rev_table = 'aft_article_revision_feedback_' |
| 173 | + . ( $type == 'select' ? 'select' : 'ratings' ) |
| 174 | + . '_rollup'; |
| 175 | + $page_table = 'aft_article_feedback_' |
| 176 | + . ( $type == 'select' ? 'select' : 'ratings' ) |
| 177 | + . '_rollup'; |
| 178 | + |
| 179 | + if ( $type == 'select' ) { |
| 180 | + $page_prefix = 'afsr_'; |
| 181 | + $rev_prefix = 'arfsr_'; |
| 182 | + $select = array( 'aa_field_id', 'aa_response_option_id', 'COUNT(aa_response_option_id) AS earned' ); |
| 183 | + $group = array( 'GROUP BY' => 'aa_response_option_id' ); |
| 184 | + } else { |
| 185 | + $page_prefix = 'arr_'; |
| 186 | + $rev_prefix = 'afrr_'; |
| 187 | + $select = array( 'aa_field_id', "SUM(aa_response_$type) AS earned", 'COUNT(*) AS submits' ); |
| 188 | + $group = array( 'GROUP BY' => 'aa_field_id' ); |
| 189 | + |
| 190 | + } |
| 191 | + |
172 | 192 | $rows = $dbr->select( |
173 | 193 | array( 'aft_article_answer', 'aft_article_feedback', 'aft_article_field' ), |
174 | | - array( 'aa_field_id', "SUM(aa_response_$type) AS earned", 'COUNT(*) AS submits' ), |
| 194 | + $select, |
175 | 195 | array( |
176 | 196 | 'afi_data_type' => $type, |
177 | 197 | 'af_page_id' => $pageId, |
— | — | @@ -179,24 +199,9 @@ |
180 | 200 | "af_revision_id >= $limit", |
181 | 201 | ), |
182 | 202 | __METHOD__, |
183 | | - array( 'GROUP BY' => 'aa_field_id' ) |
| 203 | + $group |
184 | 204 | ); |
185 | 205 | |
186 | | - if ( $type == 'select' ) { |
187 | | - $page_prefix = 'afsr_'; |
188 | | - $rev_prefix = 'arfsr_'; |
189 | | - } else { |
190 | | - $page_prefix = 'arr_'; |
191 | | - $rev_prefix = 'afrr_'; |
192 | | - } |
193 | | - $page_data = array(); |
194 | | - $rev_data = array(); |
195 | | - $rev_table = 'aft_article_revision_feedback_' |
196 | | - . ( $type == 'select' ? 'select' : 'ratings' ) |
197 | | - . '_rollup'; |
198 | | - $page_table = 'aft_article_feedback_' |
199 | | - . ( $type == 'select' ? 'select' : 'ratings' ) |
200 | | - . '_rollup'; |
201 | 206 | |
202 | 207 | foreach ( $rows as $row ) { |
203 | 208 | if ( !array_key_exists( $row->aa_field_id, $page_data ) ) { |
Index: trunk/extensions/ArticleFeedbackv5/api/ApiViewRatingsArticleFeedbackv5.php |
— | — | @@ -98,7 +98,7 @@ |
99 | 99 | } |
100 | 100 | $where[$prefix . '_page_id'] = $pageId; |
101 | 101 | $where[] = $prefix . '_rating_id = afi_id'; |
102 | | - $where['afi_bucket_id'] = 5; // TODO: Pass this in |
| 102 | +# $where['afi_bucket_id'] = 5; // TODO: Pass this in |
103 | 103 | |
104 | 104 | $rows = $dbr->select( |
105 | 105 | array( 'aft_' . $table, 'aft_article_field' ), |
Index: trunk/extensions/ArticleFeedbackv5/SpecialArticleFeedbackv5.php |
— | — | @@ -1,564 +1,109 @@ |
2 | 2 | <?php |
3 | | -/** |
4 | | - * SpecialPage for ArticleFeedback extension |
5 | | - * |
6 | | - * @file |
7 | | - * @ingroup Extensions |
8 | | - */ |
9 | | - |
10 | 3 | class SpecialArticleFeedbackv5 extends SpecialPage { |
| 4 | + private $api; |
11 | 5 | |
12 | | - /* Methods */ |
13 | | - |
14 | 6 | public function __construct() { |
15 | | - parent::__construct( 'ArticleFeedback' ); |
| 7 | + parent::__construct( 'ArticleFeedbackv5' ); |
16 | 8 | } |
17 | 9 | |
18 | | - public function execute( $par ) { |
19 | | - global $wgOut, $wgLang, $wgArticleFeedbackDashboard, $wgArticleFeedbackDashboardTalkPage; |
20 | | - |
21 | | - $wgOut->addModules( 'ext.articleFeedback.dashboard' ); |
22 | | - $this->setHeaders(); |
23 | | - if ( $wgArticleFeedbackDashboard ) { |
24 | | - // fetch the highest and lowest rated articles |
25 | | - $highs_lows = $this->getDailyHighsAndLows(); |
26 | | - |
27 | | - // determine the highest rated articles |
28 | | - $highs = $this->getDailyHighs( $highs_lows ); |
29 | | - |
30 | | - // .. and the lowest rated articles |
31 | | - $lows = $this->getDailyLows( $highs_lows ); |
32 | | - |
33 | | - // provide some messaging above high/low tables |
34 | | - $wgOut->addWikiMsg( 'articleFeedback-copy-above-highlow-tables', $wgArticleFeedbackDashboardTalkPage ); |
35 | | - |
36 | | - //render daily highs table |
37 | | - $this->renderDailyHighsAndLows( $highs, wfMsg( 'articleFeedback-table-caption-dailyhighs', $wgLang->date( time() ))); |
38 | | - |
39 | | - //render daily lows table |
40 | | - $this->renderDailyHighsAndLows( $lows, wfMsg( 'articleFeedback-table-caption-dailylows', $wgLang->date( time() ))); |
41 | | - |
42 | | - /* |
43 | | - This functionality does not exist yet. |
44 | | - $this->renderWeeklyMostChanged();*/ |
45 | | - $this->renderProblems(); |
46 | | - |
47 | | - $wgOut->addWikiMsg( 'articlefeedback-dashboard-bottom' ); |
48 | | - } else { |
49 | | - $wgOut->addWikiText( 'This page has been disabled.' ); |
50 | | - } |
51 | | - } |
52 | | - |
53 | | - /* Protected Methods */ |
54 | | - |
55 | | - /** |
56 | | - * Returns an HTML table containing data from a given two dimensional array. |
57 | | - * |
58 | | - * @param $headings Array: List of rows, each a list of column data (values will be escaped) |
59 | | - * @param $rows Array: List of rows, each a list of either calss/column data pairs (values will |
60 | | - * be escaped), or arrays containing attr, text and html fields, used to set attributes, text or |
61 | | - * HTML content of the cell |
62 | | - * @param $attribs Array: List of HTML attributes to apply to the table |
63 | | - * @return String: HTML table code |
64 | | - */ |
65 | | - protected function renderTable( $caption, array $headings, array $rows, $id = null ) { |
| 10 | + public function execute( $title ) { |
66 | 11 | global $wgOut; |
| 12 | + $pageId = $this->pageIdFromTitle( $title ); |
67 | 13 | |
68 | | - $table = Html::openElement( 'table', array( |
69 | | - 'class' => 'articleFeedback-table sortable', 'id' => $id |
70 | | - ) ); |
71 | | - // Caption |
72 | | - $table .= Html::element( 'caption', array(), $caption ); |
73 | | - // Head |
74 | | - $table .= Html::openElement( 'thead' ); |
75 | | - $table .= Html::openElement( 'tr' ); |
76 | | - foreach ( $headings as $heading ) { |
77 | | - $table .= Html::element( 'th', array(), $heading ); |
| 14 | + if( !$pageId ) { |
| 15 | + # Probably this is bad. |
| 16 | + print "That ain't no good kind of page."; |
| 17 | + die(); |
78 | 18 | } |
79 | | - $table .= Html::closeElement( 'tr' ); |
80 | | - $table .= Html::closeElement( 'thead' ); |
81 | | - // Body |
82 | | - $table .= Html::openElement( 'tbody' ); |
83 | | - foreach ( $rows as $row ) { |
84 | | - $table .= Html::openElement( 'tr' ); |
85 | | - foreach ( $row as $column ) { |
86 | | - $attr = array(); |
87 | | - if ( is_array( $column ) ) { |
88 | | - if ( isset( $column['attr'] ) && is_array( $column['attr'] ) ) { |
89 | | - $attr = $column['attr']; |
90 | | - } |
91 | | - if ( isset( $column['text'] ) ) { |
92 | | - $table .= Html::element( 'td', $attr, $column['text'] ); |
93 | | - } elseif ( isset( $column['html'] ) ) { |
94 | | - $table .= Html::rawElement( 'td', $attr, $column['html'] ); |
95 | | - } else { |
96 | | - $table .= Html::element( 'td', $attr ); |
97 | | - } |
98 | | - } else { |
99 | | - $table .= Html::rawElement( 'td', $attr, $column ); |
100 | | - } |
101 | | - } |
102 | | - $table .= Html::closeElement( 'tr' ); |
103 | | - } |
104 | | - $table .= Html::closeElement( 'tbody' ); |
105 | | - $table .= Html::closeElement( 'table' ); |
106 | | - $wgOut->addHtml( $table ); |
107 | | - } |
108 | 19 | |
109 | | - /** |
110 | | - * Renders daily highs and lows |
111 | | - * |
112 | | - * @return String: HTML table of daily highs and lows |
113 | | - */ |
114 | | - protected function renderDailyHighsAndLows( $pages, $caption ) { |
115 | | - global $wgUser; |
| 20 | + $wgOut->setPagetitle( "Feedback for $title" ); |
| 21 | +# $wgOut->addModules( 'jquery.articleFeedbackv5.special' ); |
116 | 22 | |
117 | | - // Pre-fill page ID cache |
118 | | - $ids = array(); |
119 | | - foreach ( $pages as $page ) { |
120 | | - $ids[] = $page['page']; |
121 | | - } |
122 | | - self::populateTitleCache( $ids ); |
123 | | - |
124 | | - $categories = self::getCategories(); |
| 23 | + $this->api = $this->getApi(); |
| 24 | + $output = ''; |
| 25 | + $ratings = $this->api->fetchOverallRating( $pageId ); |
| 26 | + $found = $ratings['found']; |
| 27 | + $rating = $ratings['rating']; |
125 | 28 | |
126 | | - $rows = array(); |
127 | | - if ( $pages ) { |
128 | | - foreach ( $pages as $page ) { |
129 | | - $row = array(); |
130 | | - $pageTitle = self::getTitleFromID( $page['page'] ); |
131 | | - if ( !$pageTitle ) { |
132 | | - continue; |
133 | | - } |
134 | | - $row['page'] = $wgUser->getSkin()->link( $pageTitle, $pageTitle->getPrefixedText() ); |
135 | | - foreach ( $categories as $catid => $catmsg ) { |
136 | | - if ( isset( $page['ratings'][$catid] ) ) { |
137 | | - $number = $this->formatNumber( $page['ratings'][$catid] ); |
138 | | - $class = round( $page['ratings'][$catid] ); |
139 | | - } else { |
140 | | - $number = wfMsg( 'articlefeedback-table-noratings' ); |
141 | | - $class = 'none'; |
142 | | - } |
143 | | - $row[] = array( |
144 | | - 'text' => $number, |
145 | | - 'attr' => array( |
146 | | - 'class' => 'articleFeedback-table-column-rating ' . |
147 | | - 'articleFeedback-table-column-score-' . $class |
148 | | - ) |
149 | | - ); |
150 | | - } |
151 | | - $row[] = array( |
152 | | - 'text' => $this->formatNumber( $page['average'] ), |
153 | | - 'attr' => array( |
154 | | - 'class' => 'articleFeedback-table-column-average ' . |
155 | | - 'articleFeedback-table-column-score-' . round( $page['average'] ) |
156 | | - ) |
157 | | - ); |
158 | | - $rows[] = $row; |
159 | | - } |
160 | | - } |
| 29 | + $output .= "[[Wikipedia:$title|Go to Article]] |
| 30 | + | [[Wikipedia:$title|Discussion page]] |
| 31 | + | [[Wikipedia:$title|What's this?]]\n"; |
161 | 32 | |
162 | | - $this->renderTable( |
163 | | - $caption, |
164 | | - array_merge( |
165 | | - array( wfMsg( 'articleFeedback-table-heading-page' ) ), |
166 | | - $categories, |
167 | | - array( wfMsg( 'articleFeedback-table-heading-average' ) ) |
168 | | - ), |
169 | | - $rows, |
170 | | - 'articleFeedback-table-highsandlows' |
171 | | - ); |
172 | | - } |
173 | | - |
174 | | - /** |
175 | | - * Renders weekly most changed |
176 | | - * |
177 | | - * @return String: HTML table of weekly most changed |
178 | | - */ |
179 | | - protected function renderWeeklyMostChanged() { |
180 | | - global $wgUser; |
181 | | - |
182 | | - $categories = self::getCategories(); |
183 | | - |
184 | | - $rows = array(); |
185 | | - foreach ( $this->getWeeklyMostChanged() as $page ) { |
186 | | - $row = array(); |
187 | | - $pageTitle = Title::newFromText( $page['page'] ); |
188 | | - $row['page'] = $wgUser->getSkin()->link( $pageTitle, $pageTitle->getPrefixedText() ); |
189 | | - foreach ( $categories as $catid => $catmsg ) { |
190 | | - if ( isset( $page['changes'][$catid] ) ) { |
191 | | - $number = $this->formatNumber( $page['changes'][$catid] ); |
192 | | - } else { |
193 | | - $number = wfMsg( 'articlefeedback-table-noratings' ); |
194 | | - } |
195 | | - $row[] = array( |
196 | | - 'text' => $number, |
197 | | - 'attr' => array( |
198 | | - 'class' => 'articleFeedback-table-column-changes' |
199 | | - ) |
200 | | - ); |
201 | | - } |
202 | | - $rows[] = $row; |
| 33 | + if( $found ) { |
| 34 | + $output .= " $found% of users found what they were looking for. "; |
203 | 35 | } |
204 | | - $this->renderTable( |
205 | | - wfMsg( 'articleFeedback-table-caption-weeklymostchanged' ), |
206 | | - array_merge( |
207 | | - array( wfMsg( 'articleFeedback-table-heading-page' ) ), |
208 | | - $categories |
209 | | - ), |
210 | | - $rows, |
211 | | - 'articleFeedback-table-weeklymostchanged' |
212 | | - ); |
213 | | - } |
214 | 36 | |
215 | | - /** |
216 | | - * Renders problem articles table |
217 | | - * |
218 | | - * @return String: HTML table of recent lows |
219 | | - */ |
220 | | - protected function renderProblems() { |
221 | | - global $wgUser; |
222 | | - |
223 | | - $problems = $this->getProblems(); |
224 | | - $categories = self::getCategories(); |
225 | | - |
226 | | - // Pre-fill page ID cache |
227 | | - $ids = array(); |
228 | | - foreach ( $problems as $page ) { |
229 | | - $ids[] = $page['page']; |
| 37 | + if( $rating ) { |
| 38 | + $output .= " Rating: $rating/5 "; |
230 | 39 | } |
231 | | - self::populateTitleCache( $ids ); |
232 | 40 | |
233 | | - $rows = array(); |
234 | | - foreach ( $problems as $page ) { |
235 | | - $row = array(); |
236 | | - $pageTitle = self::getTitleFromID( $page['page'] ); |
237 | | - if ( !$pageTitle ) { |
238 | | - continue; |
239 | | - } |
240 | | - $row['page'] = $wgUser->getSkin()->link( $pageTitle, $pageTitle->getPrefixedText() ); |
241 | | - foreach ( $categories as $catid => $catmsg ) { |
242 | | - if ( isset( $page['ratings'][$catid] ) ) { |
243 | | - $number = $this->formatNumber( $page['ratings'][$catid] ); |
244 | | - $class = round( $page['ratings'][$catid] ); |
245 | | - } else { |
246 | | - $number = wfMsg( 'articlefeedback-table-noratings' ); |
247 | | - $class = 'none'; |
248 | | - } |
249 | | - $row[] = array( |
250 | | - 'text' => $number, |
251 | | - 'attr' => array( |
252 | | - 'class' => 'articleFeedback-table-column-rating ' . |
253 | | - 'articleFeedback-table-column-score-' . $class |
254 | | - ) |
255 | | - ); |
256 | | - } |
257 | | - $row[] = array( |
258 | | - 'text' => $this->formatNumber( $page['average'] ), |
259 | | - 'attr' => array( |
260 | | - 'class' => 'articleFeedback-table-column-average ' . |
261 | | - 'articleFeedback-table-column-score-' . round( $page['average'] ) |
262 | | - ) |
263 | | - ); |
264 | | - $rows[] = $row; |
265 | | - } |
266 | | - $this->renderTable( |
267 | | - wfMsg( 'articleFeedback-table-caption-recentlows' ), |
268 | | - array_merge( |
269 | | - array( wfMsg( 'articleFeedback-table-heading-page' ) ), |
270 | | - $categories, |
271 | | - array( wfMsg( 'articleFeedback-table-heading-average' ) ) |
272 | | - ), |
273 | | - $rows, |
274 | | - 'articleFeedback-table-recentlows' |
275 | | - ); |
276 | | - } |
| 41 | + $output .= "\n== Feedback ==\n"; |
277 | 42 | |
278 | | - /** |
279 | | - * Gets a list of articles which were rated exceptionally low |
280 | | - */ |
281 | | - protected function getProblems() { |
282 | | - global $wgMemc; |
283 | | - // check if we've got results in the cache |
284 | | - $key = wfMemcKey( 'article_feedback_stats_problems' ); |
285 | | - $cache = $wgMemc->get( $key ); |
286 | | - if ( is_array( $cache )) { |
287 | | - $problems = $cache; |
288 | | - } else { |
289 | | - $dbr = wfGetDB( DB_SLAVE ); |
290 | | - $typeID = self::getStatsTypeId( 'problems' ); |
291 | | - // first find the freshest timestamp |
292 | | - $row = $dbr->selectRow( |
293 | | - 'article_feedback_stats', |
294 | | - array( 'afs_ts' ), |
295 | | - array( 'afs_stats_type_id' => $typeID ), |
296 | | - __METHOD__, |
297 | | - array( "ORDER BY" => "afs_ts DESC", "LIMIT" => 1 ) |
298 | | - ); |
299 | | - |
300 | | - // if we have no results, just return |
301 | | - if ( !$row || !$row->afs_ts ) { |
302 | | - return array(); |
| 43 | +/* |
| 44 | + $feedback = $this->api->fetchFeedback( $pageId ); |
| 45 | + foreach($feedback as $record) { |
| 46 | + # add a table or something |
| 47 | + $output .= " \n record: ".$record[0]->af_id; |
| 48 | + foreach($record as $answer) { |
| 49 | + $func = 'aa_response_'.$answer->afi_data_type; |
| 50 | + $output .= " \n ".$answer->afi_name.': ' |
| 51 | + .$answer->$func; |
303 | 52 | } |
304 | | - |
305 | | - // select ratings with that ts |
306 | | - $result = $dbr->select( |
307 | | - 'article_feedback_stats', |
308 | | - array( |
309 | | - 'afs_page_id', |
310 | | - 'afs_orderable_data', |
311 | | - 'afs_data' |
312 | | - ), |
313 | | - array( |
314 | | - 'afs_ts' => $row->afs_ts, |
315 | | - 'afs_stats_type_id' => $typeID |
316 | | - ), |
317 | | - __METHOD__, |
318 | | - array( "ORDER BY" => "afs_orderable_data" ) |
319 | | - ); |
320 | | - $problems = $this->buildProblems( $result ); |
321 | | - $wgMemc->set( $key, $problems, 86400 ); |
| 53 | + $output .= " \n ----------- "; |
| 54 | + |
322 | 55 | } |
| 56 | +*/ |
323 | 57 | |
324 | | - return $problems; |
325 | | - } |
| 58 | + $wgOut->addWikiText( $output ); |
326 | 59 | |
327 | | - /** |
328 | | - * Gets a list of articles which were rated exceptionally high or low. |
329 | | - * |
330 | | - * - Based on average of all rating categories |
331 | | - * - Gets 50 highest rated and 50 lowest rated |
332 | | - * - Only consider articles with 10+ ratings in the last 24 hours |
333 | | - * |
334 | | - * This data should be updated daily, ideally though a scheduled batch job |
335 | | - */ |
336 | | - protected function getDailyHighsAndLows() { |
337 | | - global $wgMemc; |
338 | | - // check if we've got results in the cache |
339 | | - $key = wfMemcKey( 'article_feedback_stats_highs_lows' ); |
340 | | - $cache = $wgMemc->get( $key ); |
341 | | - if ( is_array( $cache )) { |
342 | | - $highs_lows = $cache; |
343 | | - } else { |
344 | | - $dbr = wfGetDB( DB_SLAVE ); |
345 | | - $typeID = self::getStatsTypeId( 'highs_and_lows' ); |
346 | | - // first find the freshest timestamp |
347 | | - $row = $dbr->selectRow( |
348 | | - 'article_feedback_stats', |
349 | | - array( 'afs_ts' ), |
350 | | - array( 'afs_stats_type_id' => $typeID ), |
351 | | - __METHOD__, |
352 | | - array( "ORDER BY" => "afs_ts DESC", "LIMIT" => 1 ) |
353 | | - ); |
354 | | - |
355 | | - // if we have no results, just return |
356 | | - if ( !$row || !$row->afs_ts ) { |
357 | | - return array(); |
358 | | - } |
359 | | - |
360 | | - // select ratings with that ts |
361 | | - $result = $dbr->select( |
362 | | - 'article_feedback_stats', |
363 | | - array( |
364 | | - 'afs_page_id', |
365 | | - 'afs_orderable_data', |
366 | | - 'afs_data' |
367 | | - ), |
368 | | - array( |
369 | | - 'afs_ts' => $row->afs_ts, |
370 | | - 'afs_stats_type_id' => $typeID, |
371 | | - ), |
372 | | - __METHOD__, |
373 | | - array( "ORDER BY" => "afs_orderable_data" ) |
374 | | - ); |
375 | | - $highs_lows = $this->buildHighsAndLows( $result ); |
376 | | - $wgMemc->set( $key, $highs_lows, 86400 ); |
377 | | - } |
378 | | - |
379 | | - return $highs_lows; |
380 | | - } |
381 | | - |
382 | | - /** |
383 | | - * Determine the 'highest' rated articles |
384 | | - * |
385 | | - * Divides the number of ratings in half to determine the range of |
386 | | - * articles to consider 'highest'. In the event of an odd number |
387 | | - * of articles, (determined by checking for modulus of # of ratings / 2), |
388 | | - * round up, giving preference to the 'highs' so |
389 | | - * everyone feels warm and fuzzy about having more 'highs', as |
390 | | - * it were... |
391 | | - * |
392 | | - * @param array Pre-orderd from highest to lowest |
393 | | - * @return array Containing the... highest rated article data |
394 | | - */ |
395 | | - protected function getDailyHighs( $highs_lows ) { |
396 | | - $num_ratings = count( $highs_lows ); |
397 | | - if ( $num_ratings % 2 ) { |
398 | | - $num_highs = round( $num_ratings / 2 ); |
399 | | - } else { |
400 | | - $num_highs = $num_ratings / 2; |
401 | | - } |
402 | | - $highs = array_slice( $highs_lows, -$num_highs, $num_highs ); |
403 | | - |
404 | | - // Sort descending |
405 | | - return array_reverse( $highs ); |
406 | | - } |
407 | | - |
408 | | - /** |
409 | | - * Determine the 'lowest' rated articles |
410 | | - * |
411 | | - * @see getDailyHighs() However, if we are dealing with an odd number of |
412 | | - * ratings, round up and then subtract 1 since we are giving preference |
413 | | - * to the 'highs' when dealing with an odd number of ratings. We do this |
414 | | - * rather than rely on PHP's rounding 'modes' for compaitibility with |
415 | | - * PHP < 5.3 |
416 | | - * @param array Pre-orderd from lowest to highest |
417 | | - * @return array Containing the... lowest rated article data |
418 | | - */ |
419 | | - protected function getDailyLows( $highs_lows ) { |
420 | | - $num_ratings = count( $highs_lows ); |
421 | | - if ( $num_ratings % 2 ) { |
422 | | - $num_lows = round( $num_ratings / 2 ) - 1; |
423 | | - } else { |
424 | | - $num_lows = $num_ratings / 2; |
425 | | - } |
426 | | - return array_slice( $highs_lows, 0, $num_lows ); |
427 | | - } |
428 | | - |
429 | | - /** |
430 | | - * Build data store of highs/lows for use when rendering table |
431 | | - * @param object Database result or array of rows |
432 | | - * @return array |
433 | | - */ |
434 | | - public static function buildHighsAndLows( $result ) { |
435 | | - $highs_lows = array(); |
436 | | - foreach ( $result as $row ) { |
437 | | - if ( is_array( $row ) ) { |
438 | | - $row = (object)$row; |
439 | | - } |
440 | | - $highs_lows[] = array( |
441 | | - 'page' => $row->afs_page_id, |
442 | | - 'ratings' => FormatJson::decode( $row->afs_data, true ), |
443 | | - 'average' => $row->afs_orderable_data |
444 | | - ); |
445 | | - } |
446 | | - return $highs_lows; |
447 | | - } |
448 | | - |
449 | | - /** |
450 | | - * Build data store of problems for use when rendering table |
451 | | - * @param object Database result or array of rows |
452 | | - * @return array |
453 | | - */ |
454 | | - public static function buildProblems( $result ) { |
455 | | - $problems = array(); |
456 | | - foreach( $result as $row ) { |
457 | | - if ( is_array( $row ) ) { |
458 | | - $row = (object)$row; |
459 | | - } |
460 | | - $problems[] = array( |
461 | | - 'page' => $row->afs_page_id, |
462 | | - 'ratings' => FormatJson::decode( $row->afs_data, true ), |
463 | | - 'average' => $row->afs_orderable_data |
464 | | - ); |
465 | | - } |
466 | | - return $problems; |
467 | | - } |
468 | | - |
469 | | - /** |
470 | | - * Get the stats type id for a given stat type |
471 | | - * @param string $stats_type |
472 | | - */ |
473 | | - public static function getStatsTypeId( $stats_type ) { |
474 | | - global $wgMemc; |
475 | | - $key = wfMemcKey( 'article_feedback_stats_type_' . $stats_type ); |
476 | | - $cache = $wgMemc->get( $key ); |
477 | | - if ( $cache ) { |
478 | | - return $cache; |
479 | | - } |
480 | | - |
481 | | - $dbr = wfGetDB( DB_SLAVE ); |
482 | | - $row = $dbr->selectRow( |
483 | | - 'article_feedback_stats_types', |
484 | | - array( 'afst_id' ), |
485 | | - array( 'afst_type' => $stats_type ), |
486 | | - __METHOD__, |
487 | | - array( ) |
| 60 | + $wgOut->addHTML(<<<EOH |
| 61 | +<!-- This is a terrible, terrible hack. I'm taking it out as soon as I stop |
| 62 | + being an idiot and sort this ResourceLoader thing out --> |
| 63 | +<script> var hackPageId = $pageId; </script> |
| 64 | +<script src="http://wikidev.int.omniti.net/extensions/ArticleFeedbackv5/modules/jquery.articleFeedbackv5/jquery.articleFeedbackv5.special.js"></script> |
| 65 | +<!-- |
| 66 | +Show only: <select id="aft5-filter"> |
| 67 | +<option>visible</option> |
| 68 | +<option>all</option> |
| 69 | +</select> |
| 70 | +<br/> |
| 71 | +Sort: |
| 72 | +<select id="aft5-sort"> |
| 73 | +<option>newest</option> |
| 74 | +<option>oldest</option> |
| 75 | +</select> |
| 76 | +--> |
| 77 | +<br> |
| 78 | +<span id="aft5-showing"> |
| 79 | +Showing 0 posts (of 0) |
| 80 | +</span> |
| 81 | +<br> |
| 82 | +<div style="border:1px solid red;" id="aft5-show-feedback">Loading...</div> |
| 83 | +<a href="#" id="aft5-more">More</a> |
| 84 | +EOH |
488 | 85 | ); |
489 | | - $wgMemc->set( $key, $row->afst_id ); |
490 | | - return $row->afst_id; |
| 86 | + # "more" link to load the next 50 and append it. |
491 | 87 | } |
492 | 88 | |
493 | | - /** |
494 | | - * Gets a list of articles which have quickly changing ratings. |
495 | | - * |
496 | | - * - Based on any rating category |
497 | | - * - Gets 50 most improved and 50 most worsened |
498 | | - * - Only consider articles with 100+ ratings in the last 7 days |
499 | | - * |
500 | | - * This data should be updated daily, ideally though a scheduled batch job |
501 | | - */ |
502 | | - protected function getWeeklyMostChanged() { |
503 | | - return array( |
504 | | - array( |
505 | | - 'page' => 'Main Page', |
506 | | - // List of differences for each rating in the past 7 days |
507 | | - 'changes' => array( |
508 | | - 1 => 1, |
509 | | - 2 => 2, |
510 | | - 3 => 0, |
511 | | - 4 => 0, |
512 | | - ), |
513 | | - ), |
514 | | - array( |
515 | | - 'page' => 'Test Article', |
516 | | - 'changes' => array( |
517 | | - 1 => 0, |
518 | | - 2 => 0, |
519 | | - 3 => 1, |
520 | | - 4 => 2, |
521 | | - ), |
522 | | - ) |
523 | | - ); |
524 | | - } |
525 | | - |
526 | | - /* Protected Static Members */ |
527 | | - |
528 | | - protected static $categories; |
529 | | - protected static $titleCache = array(); |
530 | | - |
531 | | - /* Protected Static Methods */ |
532 | | - |
533 | 89 | protected static function formatNumber( $number ) { |
534 | 90 | global $wgLang; |
535 | | - |
536 | 91 | return $wgLang->formatNum( number_format( $number, 2 ) ); |
537 | 92 | } |
538 | 93 | |
539 | | - protected static function getCategories() { |
540 | | - global $wgArticleFeedbackRatingTypes; |
541 | | - |
542 | | - if ( !isset( self::$categories ) ) { |
543 | | - foreach ( $wgArticleFeedbackRatingTypes as $id => $rating ) { |
544 | | - self::$categories[$id] = wfMsg( "articlefeedback-field-$rating-label" ); |
545 | | - } |
546 | | - } |
547 | | - return self::$categories; |
| 94 | + protected function pageIdFromTitle( $title ) { |
| 95 | + $dbr = wfGetDB( DB_SLAVE ); |
| 96 | + return $dbr->selectField( |
| 97 | + 'page', |
| 98 | + 'page_id', |
| 99 | + array( 'page_title' => $title ) |
| 100 | + ); |
548 | 101 | } |
549 | 102 | |
550 | | - protected static function getTitleFromID( $id ) { |
551 | | - // There's no caching in Title::newFromId() so we hack our own around it |
552 | | - if ( !isset( self::$titleCache[$id] ) ) { |
553 | | - self::$titleCache[$id] = Title::newFromId( $id ); |
554 | | - } |
555 | | - return self::$titleCache[$id]; |
| 103 | + private function getApi() { |
| 104 | + $q = new ApiQuery( |
| 105 | + 'ApiQuery', 'articlefeedbackv5-view-feedback' ); |
| 106 | + $api = new ApiViewFeedbackArticleFeedbackv5( |
| 107 | + $q, 'articlefeedbackv5-view-feedback' ); |
| 108 | + return $api; |
556 | 109 | } |
557 | | - |
558 | | - protected static function populateTitleCache( $ids ) { |
559 | | - $toQuery = array_diff( $ids, array_keys( self::$titleCache ) ); |
560 | | - $titles = Title::newFromIds( $toQuery ); |
561 | | - foreach ( $titles as $title ) { |
562 | | - self::$titleCache[$title->getArticleID()] = $title; |
563 | | - } |
564 | | - } |
565 | 110 | } |
Index: trunk/extensions/ArticleFeedbackv5/ArticleFeedbackv5.hooks.php |
— | — | @@ -115,6 +115,10 @@ |
116 | 116 | 'jquery.clickTracking', |
117 | 117 | ), |
118 | 118 | ), |
| 119 | + 'jquery.articleFeedbackv5.special' => array( |
| 120 | + 'scripts ' => 'jquery.articleFeedbackv5/jquery.articleFeedbackv5.special.js', |
| 121 | + 'styles' => 'jquery.articleFeedbackv5/jquery.articleFeedbackv5.special.css', |
| 122 | + ), |
119 | 123 | ); |
120 | 124 | |
121 | 125 | public static function addFeedbackLink($template, &$content_actions) { |
— | — | @@ -122,7 +126,7 @@ |
123 | 127 | $content_actions['namespaces'][] = array( |
124 | 128 | 'class' => false or 'selected', |
125 | 129 | 'text' => 'Feedback', |
126 | | - 'href' => '/wiki-dev/index.php/Feedback:Greg', #TODO |
| 130 | + 'href' => '/wiki-dev/index.php/Special:ArticleFeedbackv5', #TODO |
127 | 131 | 'context' => 'feedback' |
128 | 132 | ); |
129 | 133 | return true; |
— | — | @@ -194,6 +198,7 @@ |
195 | 199 | $resources['messages'][] = $prefix . $field . '-tooltip-5'; |
196 | 200 | } |
197 | 201 | } |
| 202 | + |
198 | 203 | $resourceLoader->register( |
199 | 204 | $name, new ResourceLoaderFileModule( $resources, $localpath, $remotepath ) |
200 | 205 | ); |