r96921 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r96920‎ | r96921 | r96922 >
Date:22:05, 12 September 2011
Author:jeroendedauw
Status:deferred
Tags:
Comment:
Tag for version 0.1.
Modified paths:
  • /tags/extensions/Survey/REL_0_1 (added) (history)

Diff [purge]

Index: tags/extensions/Survey/REL_0_1/test/SurveyQuestionTest.php
@@ -0,0 +1,27 @@
 2+<?php
 3+
 4+/**
 5+ * SurveyQuestion test case.
 6+ *
 7+ * @ingroup Survey
 8+ * @since 0.1
 9+ *
 10+ * @licence GNU GPL v3
 11+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
 12+ */
 13+class SurveyQuestionTest extends MediaWikiTestCase {
 14+
 15+ /**
 16+ * Tests SurveyQuestion::newFromUrlData and SurveyQuestion::toUrlData
 17+ */
 18+ public function testQuestionUrlSerialization() {
 19+ $question = new SurveyQuestion( 9001, 42, 'ohai there!', 0, true );
 20+
 21+ $this->assertEquals(
 22+ $question,
 23+ SurveyQuestion::newFromUrlData( $question->toUrlData() ),
 24+ "Serializaion test failed at " . __METHOD__
 25+ );
 26+ }
 27+
 28+}
Property changes on: tags/extensions/Survey/REL_0_1/test/SurveyQuestionTest.php
___________________________________________________________________
Added: svn:eol-style
129 + native
Index: tags/extensions/Survey/REL_0_1/Survey.settings.php
@@ -0,0 +1,51 @@
 2+<?php
 3+
 4+/**
 5+ * File defining the settings for the Survey extension.
 6+ * More info can be found at http://www.mediawiki.org/wiki/Extension:Survey#Settings
 7+ *
 8+ * NOTICE:
 9+ * Changing one of these settings can be done by assigning to $egSurveySettings,
 10+ * AFTER the inclusion of the extension itself.
 11+ *
 12+ * @since 0.1
 13+ *
 14+ * @file Survey.settings.php
 15+ * @ingroup Survey
 16+ *
 17+ * @licence GNU GPL v3+
 18+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
 19+ */
 20+class SurveySettings {
 21+
 22+ protected static function getDefaultSettings() {
 23+ return array(
 24+ 'JSDebug' => false,
 25+ 'defaultEnabled' => false,
 26+ 'defaultUserType' => Survey::$USER_ALL,
 27+ 'defaultNamespaces' => array(),
 28+ 'defaultRatio' => 100,
 29+ 'defaultExpiry' => 60 * 60 * 24 * 30,
 30+ 'defaultMinPages' => 0
 31+ );
 32+ }
 33+
 34+ public static function getSettings() {
 35+ static $settings = false;
 36+
 37+ if ( $settings === false ) {
 38+ $settings = array_merge(
 39+ self::getDefaultSettings(),
 40+ $GLOBALS['egSurveySettings']
 41+ );
 42+ }
 43+
 44+ return $settings;
 45+ }
 46+
 47+ public static function get( $settingName ) {
 48+ $settings = self::getSettings();
 49+ return array_key_exists( $settingName, $settings ) ? $settings[$settingName] : null;
 50+ }
 51+
 52+}
Property changes on: tags/extensions/Survey/REL_0_1/Survey.settings.php
___________________________________________________________________
Added: svn:eol-style
153 + native
Index: tags/extensions/Survey/REL_0_1/Survey.php
@@ -0,0 +1,202 @@
 2+<?php
 3+
 4+/**
 5+ * Initialization file for the Survey extension.
 6+ *
 7+ * Documentation: http://www.mediawiki.org/wiki/Extension:Survey
 8+ * Support http://www.mediawiki.org/wiki/Extension_talk:Survey
 9+ * Source code: http://svn.wikimedia.org/viewvc/mediawiki/trunk/extensions/Survey
 10+ *
 11+ * @file Survey.php
 12+ * @ingroup Survey
 13+ *
 14+ * @licence GNU GPL v3+
 15+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
 16+ */
 17+
 18+/**
 19+ * This documenation group collects source code files belonging to Survey.
 20+ *
 21+ * @defgroup Survey Survey
 22+ */
 23+
 24+if ( !defined( 'MEDIAWIKI' ) ) {
 25+ die( 'Not an entry point.' );
 26+}
 27+
 28+if ( version_compare( $wgVersion, '1.17', '<' ) ) {
 29+ die( '<b>Error:</b> Survey requires MediaWiki 1.17 or above.' );
 30+}
 31+
 32+define( 'Survey_VERSION', '0.1' );
 33+
 34+$wgExtensionCredits['other'][] = array(
 35+ 'path' => __FILE__,
 36+ 'name' => 'Survey',
 37+ 'version' => Survey_VERSION,
 38+ 'author' => array(
 39+ '[http://www.mediawiki.org/wiki/User:Jeroen_De_Dauw Jeroen De Dauw]',
 40+ ),
 41+ 'url' => 'http://www.mediawiki.org/wiki/Extension:Survey',
 42+ 'descriptionmsg' => 'survey-desc'
 43+);
 44+
 45+$wgExtensionMessagesFiles['Survey'] = dirname( __FILE__ ) . '/Survey.i18n.php';
 46+$wgExtensionMessagesFiles['SurveyAlias'] = dirname( __FILE__ ) . '/Survey.alias.php';
 47+
 48+$wgAutoloadClasses['SurveyHooks'] = dirname( __FILE__ ) . '/Survey.hooks.php';
 49+$wgAutoloadClasses['SurveySettings'] = dirname( __FILE__ ) . '/Survey.settings.php';
 50+
 51+$wgAutoloadClasses['ApiAddSurvey'] = dirname( __FILE__ ) . '/api/ApiAddSurvey.php';
 52+$wgAutoloadClasses['ApiDeleteSurvey'] = dirname( __FILE__ ) . '/api/ApiDeleteSurvey.php';
 53+$wgAutoloadClasses['ApiEditSurvey'] = dirname( __FILE__ ) . '/api/ApiEditSurvey.php';
 54+$wgAutoloadClasses['ApiQuerySurveyAnswers'] = dirname( __FILE__ ) . '/api/ApiQuerySurveyAnswers.php';
 55+$wgAutoloadClasses['ApiQuerySurveys'] = dirname( __FILE__ ) . '/api/ApiQuerySurveys.php';
 56+$wgAutoloadClasses['ApiQuerySurveySubmissions'] = dirname( __FILE__ ) . '/api/ApiQuerySurveySubmissions.php';
 57+$wgAutoloadClasses['ApiSubmitSurvey'] = dirname( __FILE__ ) . '/api/ApiSubmitSurvey.php';
 58+
 59+$wgAutoloadClasses['Survey'] = dirname( __FILE__ ) . '/includes/Survey.class.php';
 60+$wgAutoloadClasses['SurveyAnswer'] = dirname( __FILE__ ) . '/includes/SurveyAnswer.php';
 61+$wgAutoloadClasses['SurveyCompat'] = dirname( __FILE__ ) . '/includes/SurveyCompat.php';
 62+$wgAutoloadClasses['SurveyDBClass'] = dirname( __FILE__ ) . '/includes/SurveyDBClass.php';
 63+$wgAutoloadClasses['SurveyQuestion'] = dirname( __FILE__ ) . '/includes/SurveyQuestion.php';
 64+$wgAutoloadClasses['SurveySubmission'] = dirname( __FILE__ ) . '/includes/SurveySubmission.php';
 65+$wgAutoloadClasses['SurveyTag'] = dirname( __FILE__ ) . '/includes/SurveyTag.php';
 66+
 67+$wgAutoloadClasses['SpecialSurvey'] = dirname( __FILE__ ) . '/specials/SpecialSurvey.php';
 68+$wgAutoloadClasses['SpecialSurveyPage'] = dirname( __FILE__ ) . '/specials/SpecialSurveyPage.php';
 69+$wgAutoloadClasses['SpecialSurveys'] = dirname( __FILE__ ) . '/specials/SpecialSurveys.php';
 70+$wgAutoloadClasses['SpecialSurveyStats'] = dirname( __FILE__ ) . '/specials/SpecialSurveyStats.php';
 71+$wgAutoloadClasses['SpecialTakeSurvey'] = dirname( __FILE__ ) . '/specials/SpecialTakeSurvey.php';
 72+
 73+$wgSpecialPages['EditSurvey'] = 'SpecialSurvey';
 74+$wgSpecialPages['Surveys'] = 'SpecialSurveys';
 75+$wgSpecialPages['SurveyStats'] = 'SpecialSurveyStats';
 76+$wgSpecialPages['TakeSurvey'] = 'SpecialTakeSurvey';
 77+
 78+$wgSpecialPageGroups['EditSurvey'] = 'other';
 79+$wgSpecialPageGroups['Surveys'] = 'other';
 80+$wgSpecialPageGroups['SurveyStats'] = 'other';
 81+$wgSpecialPageGroups['TakeSurvey'] = 'other';
 82+
 83+$wgAPIModules['addsurvey'] = 'ApiAddSurvey';
 84+$wgAPIModules['deletesurvey'] = 'ApiDeleteSurvey';
 85+$wgAPIModules['editsurvey'] = 'ApiEditSurvey';
 86+$wgAPIModules['submitsurvey'] = 'ApiSubmitSurvey';
 87+$wgAPIListModules['surveys'] = 'ApiQuerySurveys';
 88+$wgAPIListModules['surveyanswers'] = 'ApiQuerySurveyAnswers';
 89+$wgAPIListModules['surveysubmissions'] = 'ApiQuerySurveySubmissions';
 90+
 91+$wgHooks['LoadExtensionSchemaUpdates'][] = 'SurveyHooks::onSchemaUpdate';
 92+$wgHooks['UnitTestsList'][] = 'SurveyHooks::registerUnitTests';
 93+$wgHooks['ParserFirstCallInit'][] = 'SurveyHooks::onParserFirstCallInit';
 94+$wgHooks['ArticleViewHeader'][] = 'SurveyHooks::onArticleViewHeader';
 95+$wgHooks['AdminLinks'][] = 'SurveyHooks::addToAdminLinks';
 96+
 97+$wgAvailableRights[] = 'surveyadmin';
 98+$wgAvailableRights[] = 'surveysubmit';
 99+
 100+# Users that can manage the surveys.
 101+$wgGroupPermissions['*' ]['surveyadmin'] = false;
 102+$wgGroupPermissions['user' ]['surveyadmin'] = false;
 103+$wgGroupPermissions['autoconfirmed']['surveyadmin'] = false;
 104+$wgGroupPermissions['bot' ]['surveyadmin'] = false;
 105+$wgGroupPermissions['sysop' ]['surveyadmin'] = true;
 106+
 107+# Users that can submit surveys.
 108+$wgGroupPermissions['*' ]['surveysubmit'] = true;
 109+$wgGroupPermissions['user' ]['surveysubmit'] = true;
 110+$wgGroupPermissions['autoconfirmed']['surveysubmit'] = true;
 111+$wgGroupPermissions['bot' ]['surveysubmit'] = false;
 112+$wgGroupPermissions['sysop' ]['surveysubmit'] = true;
 113+
 114+$moduleTemplate = array(
 115+ 'localBasePath' => dirname( __FILE__ ) . '/resources',
 116+ 'remoteExtPath' => 'Survey/resources'
 117+);
 118+
 119+$wgResourceModules['ext.survey'] = $moduleTemplate + array(
 120+ 'scripts' => array(
 121+ 'ext.survey.js'
 122+ ),
 123+);
 124+
 125+$wgResourceModules['ext.survey.special.surveys'] = $moduleTemplate + array(
 126+ 'scripts' => array(
 127+ 'ext.survey.special.surveys.js'
 128+ ),
 129+ 'dependencies' => array( 'ext.survey' ),
 130+ 'messages' => array(
 131+ 'surveys-special-confirm-delete',
 132+ 'surveys-special-delete-failed',
 133+ )
 134+);
 135+
 136+$wgResourceModules['ext.survey.special.survey'] = $moduleTemplate + array(
 137+ 'scripts' => array(
 138+ 'ext.survey.answerSelector.js',
 139+ 'ext.survey.special.survey.js'
 140+ ),
 141+ 'styles' => array(
 142+ 'ext.survey.special.survey.css'
 143+ ),
 144+ 'dependencies' => array( 'ext.survey', 'jquery.ui.button' ),
 145+ 'messages' => array(
 146+ 'survey-question-type-text',
 147+ 'survey-question-type-number',
 148+ 'survey-question-type-select',
 149+ 'survey-question-type-radio',
 150+ 'survey-question-type-textarea',
 151+ 'survey-question-type-check',
 152+ 'survey-question-label-nr',
 153+ 'survey-special-label-required',
 154+ 'survey-special-label-type',
 155+ 'survey-special-label-text',
 156+ 'survey-special-label-addquestion',
 157+ 'survey-special-label-add-first',
 158+ 'survey-special-label-add-another',
 159+ 'survey-special-remove',
 160+ 'survey-special-remove-confirm',
 161+ 'survey-special-label-answers'
 162+ )
 163+);
 164+
 165+$wgResourceModules['ext.survey.numeric'] = $moduleTemplate + array(
 166+ 'scripts' => array(
 167+ 'jquery.numeric.js'
 168+ )
 169+);
 170+
 171+$wgResourceModules['ext.survey.JSON'] = $moduleTemplate + array(
 172+ 'scripts' => array(
 173+ 'JSON.js'
 174+ )
 175+);
 176+
 177+$wgResourceModules['ext.survey.jquery'] = $moduleTemplate + array(
 178+ 'scripts' => array(
 179+ 'fancybox/jquery.fancybox-1.3.4.js',
 180+ 'jquery.survey.js'
 181+ ),
 182+ 'styles' => array(
 183+ 'jquery.survey.css',
 184+ 'fancybox/jquery.fancybox-1.3.4.css'
 185+ ),
 186+ 'dependencies' => array( 'ext.survey', 'jquery.ui.button', 'ext.survey.numeric', 'ext.survey.JSON' ),
 187+ 'messages' => array(
 188+ 'survey-jquery-submit',
 189+ 'survey-jquery-finish',
 190+ 'survey-jquery-load-failed',
 191+ )
 192+);
 193+
 194+$wgResourceModules['ext.survey.tag'] = $moduleTemplate + array(
 195+ 'scripts' => array(
 196+ 'ext.survey.tag.js'
 197+ ),
 198+ 'dependencies' => array( 'ext.survey.jquery', 'jquery.cookie' ),
 199+);
 200+
 201+unset( $moduleTemplate );
 202+
 203+$egSurveySettings = array();
Property changes on: tags/extensions/Survey/REL_0_1/Survey.php
___________________________________________________________________
Added: svn:eol-style
1204 + native
Index: tags/extensions/Survey/REL_0_1/Survey.sql
@@ -0,0 +1,47 @@
 2+-- MySQL version of the database schema for the Survey extension.
 3+-- Licence: GNU GPL v3+
 4+-- Author: Jeroen De Dauw < jeroendedauw@gmail.com >
 5+
 6+-- Surveys
 7+CREATE TABLE IF NOT EXISTS /*$wgDBprefix*/surveys (
 8+ survey_id SMALLINT unsigned NOT NULL auto_increment PRIMARY KEY,
 9+ survey_name VARCHAR(255) NOT NULL, -- String indentifier for the survey
 10+ survey_title VARCHAR(255) NOT NULL, -- Title of the survey
 11+ survey_enabled TINYINT NOT NULL default '0', -- If the survey can be taken by users
 12+ survey_header TEXT NOT NULL, -- Text to display above the survey
 13+ survey_footer TEXT NOT NULL, -- Text to display below the survey
 14+ survey_thanks TEXT NOT NULL, -- Text to display after survey submission
 15+ survey_user_type TINYINT unsigned NOT NULL default '0', -- Type of users that can participate in the survey
 16+ survey_namespaces BLOB NOT NULL, -- Namespaces on which the survey can be displayed
 17+ survey_ratio TINYINT unsigned NOT NULL, -- Percentage of users to show the survey to
 18+ survey_expiry INT unsigned NOT NULL, -- Coockie expiry time for the survey
 19+ survey_min_pages TINYINT unsigned NOT NULL -- Min amount of pages the user needs to view before getting the survey
 20+) /*$wgDBTableOptions*/;
 21+
 22+-- Questions
 23+CREATE TABLE IF NOT EXISTS /*$wgDBprefix*/survey_questions (
 24+ question_id INT(10) unsigned NOT NULL auto_increment PRIMARY KEY,
 25+ question_survey_id SMALLINT unsigned NOT NULL, -- Foreign key: surveys.survey_id
 26+ question_text TEXT NOT NULL,
 27+ question_type INT(2) unsigned NOT NULL,
 28+ question_required TINYINT NOT NULL,
 29+ question_answers BLOB NOT NULL,
 30+ question_removed TINYINT NOT NULL default '0'
 31+) /*$wgDBTableOptions*/;
 32+
 33+-- Submissions
 34+CREATE TABLE IF NOT EXISTS /*$wgDBprefix*/survey_submissions (
 35+ submission_id INT(10) unsigned NOT NULL auto_increment PRIMARY KEY,
 36+ submission_survey_id SMALLINT unsigned NOT NULL, -- Foreign key: surveys.survey_id
 37+ submission_user_name VARCHAR(255) NOT NULL, -- The person that made the submission (account name or ip)
 38+ submission_page_id INT(10) unsigned NULL, -- The id of the page the submission was made on
 39+ submission_time CHAR(14) binary NOT NULL default '' -- The time the submission was made
 40+) /*$wgDBTableOptions*/;
 41+
 42+-- Answers
 43+CREATE TABLE IF NOT EXISTS /*$wgDBprefix*/survey_answers (
 44+ answer_id SMALLINT unsigned NOT NULL auto_increment PRIMARY KEY,
 45+ answer_submission_id INT(10) unsigned NOT NULL, -- Foreign key: survey_submissions.submission_id
 46+ answer_question_id INT(10) unsigned NOT NULL, -- Foreign key: survey_questions.question_id
 47+ answer_text BLOB NOT NULL
 48+) /*$wgDBTableOptions*/;
\ No newline at end of file
Property changes on: tags/extensions/Survey/REL_0_1/Survey.sql
___________________________________________________________________
Added: svn:eol-style
149 + native
Index: tags/extensions/Survey/REL_0_1/README
@@ -0,0 +1,20 @@
 2+These is the readme file for the Survey extension.
 3+
 4+Extension page on mediawiki.org: http://www.mediawiki.org/wiki/Extension:Survey
 5+Latest version of the readme file: http://svn.wikimedia.org/viewvc/mediawiki/trunk/extensions/Survey/README?view=co
 6+
 7+== About ==
 8+
 9+Survey is a MediaWiki extension that allows administrators to define surveys
 10+that can then be shown to specified groups of users.
 11+
 12+=== Feature overview ===
 13+
 14+* Surveys get displayed to wiki users using a nice pop-up form.
 15+* Surveys can be created and modified via an admin panel (Special:Surveys).
 16+* Surveys can be shown to specific types of users (logged in, anonymouse, editor, confirmed, ...)
 17+* Surveys can be shown for a specified percentage of users, and only after a certain amount of page views.
 18+* Survey questions can have different types of inputs, of which some allow restricting answers.
 19+* Surveys can be tested by admins via Special:TakeSurvey without them being live on the wiki.
 20+* Summaries of survey submissions can be found on Special:SurveyStats.
 21+* The survey submission data (ie user answers) can be exported via an API.
Property changes on: tags/extensions/Survey/REL_0_1/README
___________________________________________________________________
Added: svn:eol-style
122 + native
Index: tags/extensions/Survey/REL_0_1/sql/Survey_indexSurveyName.sql
@@ -0,0 +1 @@
 2+CREATE UNIQUE INDEX /*i*/surveys_survey_name ON /*_*/surveys (survey_name);
\ No newline at end of file
Property changes on: tags/extensions/Survey/REL_0_1/sql/Survey_indexSurveyName.sql
___________________________________________________________________
Added: svn:eol-style
13 + native
Index: tags/extensions/Survey/REL_0_1/sql/Survey_indexQuestionId.sql
@@ -0,0 +1 @@
 2+CREATE INDEX /*i*/surveys_question_id ON /*_*/survey_answers (answer_question_id);
\ No newline at end of file
Property changes on: tags/extensions/Survey/REL_0_1/sql/Survey_indexQuestionId.sql
___________________________________________________________________
Added: svn:eol-style
13 + native
Index: tags/extensions/Survey/REL_0_1/sql/Survey_indexSubmissionId.sql
@@ -0,0 +1 @@
 2+CREATE INDEX /*i*/surveys_submission_id ON /*_*/survey_answers (answer_submission_id);
\ No newline at end of file
Property changes on: tags/extensions/Survey/REL_0_1/sql/Survey_indexSubmissionId.sql
___________________________________________________________________
Added: svn:eol-style
13 + native
Index: tags/extensions/Survey/REL_0_1/Survey.i18n.php
@@ -0,0 +1,164 @@
 2+<?php
 3+
 4+/**
 5+ * Internationalization file for the Survey extension.
 6+ *
 7+ * @since 0.1
 8+ *
 9+ * @file Survey.i18n.php
 10+ * @ingroup Survey
 11+ *
 12+ * @licence GNU GPL v3+
 13+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
 14+ */
 15+
 16+$messages = array();
 17+
 18+/** English
 19+ * @author Jeroen De Dauw
 20+ */
 21+$messages['en'] = array(
 22+ 'survey-desc' => 'Survey tool for MediaWiki',
 23+
 24+ // Rights
 25+ 'right-surveyadmin' => 'Manage surveys',
 26+ 'right-surveysubmit' => 'Participate in surveys',
 27+
 28+ // Special page names
 29+ 'special-editsurvey' => 'Survey admin',
 30+ 'special-surveys' => 'Surveys admin',
 31+ 'special-surveystats' => 'Survey statistics',
 32+ 'special-takesurvey' => 'Take survey',
 33+
 34+ // API errors
 35+ 'survey-err-id-xor-name' => 'You need to provide either the ID or the name of the survey to submit',
 36+ 'survey-err-survey-name-unknown' => 'There is no survey with the name "$1"',
 37+ 'survey-err-duplicate-name' => 'There already is a survey with the name "$1"',
 38+ 'survey-err-ids-xor-names' => 'You need to provide either the IDs or the names of the surveys to query',
 39+
 40+ // Question types
 41+ 'survey-question-type-text' => 'Single-line text field',
 42+ 'survey-question-type-number' => 'Number',
 43+ 'survey-question-type-select' => 'Dropdown menu',
 44+ 'survey-question-type-radio' => 'Radio buttons',
 45+ 'survey-question-type-textarea' => 'Multi-line text field',
 46+ 'survey-question-type-check' => 'Checkbox',
 47+
 48+ // User types
 49+ 'survey-user-type-all' => 'Everyone',
 50+ 'survey-user-type-loggedin' => 'Logged in users',
 51+ 'survey-user-type-confirmed' => 'Confirmed users',
 52+ 'survey-user-type-editor' => 'Editors',
 53+ 'survey-user-type-anon' => 'Anonymous users',
 54+
 55+ // Navigation
 56+ 'survey-navigation-edit' => '[[Special:Survey/$1|Edit this survey]]',
 57+ 'survey-navigation-take' => '[[Special:TakeSurvey/$1|Take this survey]]',
 58+ 'survey-navigation-list' => '[[Special:Surveys|Surveys list]]',
 59+ 'survey-navigation-stats' => '[[Special:SurveyStats/$1|View statistics]]',
 60+
 61+ // Special:Surveys
 62+ 'surveys-special-addnew' => 'Add a new survey',
 63+ 'surveys-special-namedoc' => 'Enter an unique identifier (ID) for the new survey. Can not be changed later. For example: editor-motivation.',
 64+ 'surveys-special-newname' => 'New survey ID:',
 65+ 'surveys-special-add' => 'Add survey',
 66+ 'surveys-special-existing' => 'Existing surveys',
 67+ 'surveys-special-title' => 'Title',
 68+ 'surveys-special-status' => 'Status',
 69+ 'surveys-special-stats' => 'Statistics',
 70+ 'surveys-special-edit' => 'Edit',
 71+ 'surveys-special-save' => 'Save',
 72+ 'surveys-special-delete' => 'Delete',
 73+ 'surveys-special-enabled' => 'Enabled',
 74+ 'surveys-special-disabled' => 'Disabled',
 75+ 'surveys-special-confirm-delete' => 'Are you sure you want to delete this survey?',
 76+ 'surveys-special-delete-failed' => 'Failed to delete survey.',
 77+ 'survey-special-label-usertype' => 'Users that should get the survey',
 78+ 'survey-special-label-minpages' => 'Minimun amount of pages the user needs to visit before getting the survey',
 79+
 80+ // Special:TakeSurvey
 81+ 'surveys-takesurvey-loading' => 'Loading survey...',
 82+ 'surveys-takesurvey-nosuchsurvey' => 'The requested survey does not exist.',
 83+ 'surveys-takesurvey-warn-notenabled' => 'This survey has not been enabled yet, and therefore is not visible to users.',
 84+ 'surveys-takesurvey-surveynotenabled' => 'The requested survey has not been enabled yet.',
 85+
 86+ // Special:SurveyStats
 87+ 'surveys-surveystats-nosuchsurvey' => 'The requested survey does not exist. A list of available surveys can be found on [[Special:Surveys]]',
 88+ 'surveys-surveystats-name' => 'Survey ID',
 89+ 'surveys-surveystats-title' => 'Survey title',
 90+ 'surveys-surveystats-status' => 'Survey status',
 91+ 'surveys-surveystats-questioncount' => 'Number of questions',
 92+ 'surveys-surveystats-submissioncount' => 'Number of submissions',
 93+ 'surveys-surveystats-enabled' => 'Enabled',
 94+ 'surveys-surveystats-disabled' => 'Disabled',
 95+ 'surveys-surveystats-questions' => 'Question statistics',
 96+ 'surveys-surveystats-question-nr' => '#',
 97+ 'surveys-surveystats-question-#' => '$1',
 98+ 'surveys-surveystats-question-type' => 'Question type',
 99+ 'surveys-surveystats-question-text' => 'Question text',
 100+ 'surveys-surveystats-question-answercount' => 'Number of answers',
 101+ 'surveys-surveystats-question-answers' => 'Most provided answers',
 102+ 'surveys-surveystats-question-answer' => '$1 ($2 {{PLURAL:$2|answer|answers}})',
 103+ 'surveys-surveystats-unchecked' => 'Unchecked',
 104+ 'surveys-surveystats-checked' => 'Checked',
 105+
 106+ // Special:Survey
 107+ 'surveys-special-unknown-name' => 'There is no survey with the requested ID.',
 108+ 'survey-special-label-name' => 'Survey ID',
 109+ 'survey-special-label-title' => 'Survey title',
 110+ 'survey-special-label-enabled' => 'Survey enabled',
 111+ 'survey-special-label-ratio' => 'Percentage of people to show the survey to',
 112+ 'survey-special-label-add-first' => 'Add question',
 113+ 'survey-special-label-add-another' => 'Add another question',
 114+ 'survey-special-label-addquestion' => 'New question',
 115+ 'survey-question-label-nr' => 'Question #$1',
 116+ 'survey-special-label-required' => 'Question is required',
 117+ 'survey-special-label-type' => 'Question type',
 118+ 'survey-special-label-text' => 'Question text',
 119+ 'survey-special-remove' => 'Remove question',
 120+ 'survey-special-remove-confirm' => 'Are you sure you want to remove this question?',
 121+ 'survey-special-label-header' => 'Text to display above the survey',
 122+ 'survey-special-label-footer' => 'Text to display below the survey',
 123+ 'survey-special-label-thanks' => 'Thanks message to display after submission of the survey',
 124+ 'survey-special-label-answers' => 'Available answers, one per line.',
 125+
 126+ // Survey jQuery
 127+ 'survey-jquery-submit' => 'Submit',
 128+ 'survey-jquery-finish' => 'Finish',
 129+ 'survey-jquery-load-failed' => 'Could not load the survey.',
 130+);
 131+
 132+/** Message docs
 133+ * @author Jeroen De Dauw
 134+ */
 135+$messages['qqq'] = array(
 136+ 'surveys-surveystats-question-answer' => 'Header for a column listing the amount of answers per question',
 137+ 'survey-question-type-number' => 'Indicates an input type that accepts a number (which can be multiple digits)',
 138+ 'surveys-surveystats-question-answers' => 'Header for a column listing the most provided answers per question',
 139+
 140+ 'survey-question-type-text' => 'Input type for a question, selectable in administration interface.',
 141+ 'survey-question-type-number' => 'Input type for a question, selectable in administration interface.',
 142+ 'survey-question-type-select' => 'Input type for a question, selectable in administration interface.',
 143+ 'survey-question-type-radio' => 'Input type for a question, selectable in administration interface.',
 144+ 'survey-question-type-textarea' => 'Input type for a question, selectable in administration interface.',
 145+ 'survey-question-type-check' => 'Input type for a question, selectable in administration interface.',
 146+
 147+ 'survey-user-type-all' => 'Group of users for which a survey can be available.',
 148+ 'survey-user-type-loggedin' => 'Group of users for which a survey can be available.',
 149+ 'survey-user-type-confirmed' => 'Group of users for which a survey can be available.',
 150+ 'survey-user-type-editor' => 'Group of users for which a survey can be available.',
 151+ 'survey-user-type-anon' => 'Group of users for which a survey can be available.',
 152+
 153+ 'survey-err-id-xor-name' => 'API error message.',
 154+ 'survey-err-survey-name-unknown' => 'API error message. $1 is the name of a survey.',
 155+ 'survey-err-duplicate-name' => 'API error message. $1 is the name of a survey.',
 156+ 'survey-err-ids-xor-names' => 'API error message.',
 157+
 158+ 'right-surveyadmin' => 'User right',
 159+ 'right-surveysubmit' => 'User right',
 160+
 161+ 'special-editsurvey' => 'Special page name/title',
 162+ 'special-surveys' => 'Special page name/title',
 163+ 'special-surveystats' => 'Special page name/title',
 164+ 'special-takesurvey' => 'Special page name/title',
 165+);
Property changes on: tags/extensions/Survey/REL_0_1/Survey.i18n.php
___________________________________________________________________
Added: svn:eol-style
1166 + native
Index: tags/extensions/Survey/REL_0_1/specials/SpecialSurveyPage.php
@@ -0,0 +1,135 @@
 2+<?php
 3+
 4+/**
 5+ * Base special page for special pages in the Survey extension,
 6+ * taking care of some common stuff and providing compatibility helpers.
 7+ *
 8+ * @since 0.1
 9+ *
 10+ * @file SpecialSurveyPage.php
 11+ * @ingroup Survey
 12+ *
 13+ * @licence GNU GPL v3 or later
 14+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
 15+ */
 16+abstract class SpecialSurveyPage extends SpecialPage {
 17+
 18+ /**
 19+ * @see SpecialPage::getDescription
 20+ *
 21+ * @since 0.1
 22+ */
 23+ public function getDescription() {
 24+ return wfMsg( 'special-' . strtolower( $this->getName() ) );
 25+ }
 26+
 27+ /**
 28+ * Sets headers - this should be called from the execute() method of all derived classes!
 29+ *
 30+ * @since 0.1
 31+ */
 32+ public function setHeaders() {
 33+ $out = $this->getOutput();
 34+ $out->setArticleRelated( false );
 35+ $out->setRobotPolicy( 'noindex,nofollow' );
 36+ $out->setPageTitle( $this->getDescription() );
 37+ }
 38+
 39+ /**
 40+ * Main method.
 41+ *
 42+ * @since 0.1
 43+ *
 44+ * @param string $arg
 45+ */
 46+ public function execute( $subPage ) {
 47+ global $wgUser;
 48+
 49+ $this->setHeaders();
 50+ $this->outputHeader();
 51+
 52+ // If the user is authorized, display the page, if not, show an error.
 53+ if ( !$this->userCanExecute( $wgUser ) ) {
 54+ $this->displayRestrictionError();
 55+ return false;
 56+ }
 57+
 58+ return true;
 59+ }
 60+
 61+ /**
 62+ * Get the OutputPage being used for this instance.
 63+ * This overrides the getOutput method of Specialpage added in MediaWiki 1.18,
 64+ * and returns $wgOut for older versions.
 65+ *
 66+ * @since 0.1
 67+ *
 68+ * @return OutputPage
 69+ */
 70+ public function getOutput() {
 71+ return version_compare( $GLOBALS['wgVersion'], '1.18', '>=' ) ? parent::getOutput() : $GLOBALS['wgOut'];
 72+ }
 73+
 74+ /**
 75+ * Shortcut to get user's language.
 76+ * This overrides the getLang method of Specialpage added in MediaWiki 1.18,
 77+ * and returns $wgLang for older versions.
 78+ *
 79+ * @since 0.1
 80+ *
 81+ * @return Language
 82+ */
 83+ public function getLang() {
 84+ return version_compare( $GLOBALS['wgVersion'], '1.18', '>=' ) ? parent::getLang() : $GLOBALS['wgLang'];
 85+ }
 86+
 87+ /**
 88+ * Add resource loader modules or use fallback code for
 89+ * earlier versions of MediaWiki.
 90+ *
 91+ * @since 0.1
 92+ *
 93+ * @param string|array $modules
 94+ */
 95+ public function addModules( $modules ) {
 96+ $this->getOutput()->addModules( $modules );
 97+ }
 98+
 99+ /**
 100+ * Show a message in an error box.
 101+ *
 102+ * @since 0.1
 103+ *
 104+ * @param string $message
 105+ */
 106+ protected function showError( $message ) {
 107+ $this->getOutput()->addHTML(
 108+ '<p class="visualClear errorbox">' . wfMsgExt( $message, 'parseinline' ) . '</p>'
 109+ );
 110+ }
 111+
 112+ /**
 113+ * Show a message in a warning box.
 114+ *
 115+ * @since 0.1
 116+ *
 117+ * @param string $message
 118+ */
 119+ protected function showWarning( $message ) {
 120+ $this->getOutput()->addHTML(
 121+ '<p class="visualClear warningbox">' . wfMsgExt( $message, 'parseinline' ) . '</p>'
 122+ );
 123+ }
 124+
 125+ /**
 126+ * Display navigation links.
 127+ *
 128+ * @since 0.1
 129+ *
 130+ * @param array $links
 131+ */
 132+ protected function displayNavigation( array $links ) {
 133+ $this->getOutput()->addHTML( Html::rawElement( 'p', array(), $this->getLang()->pipeList( $links ) ) );
 134+ }
 135+
 136+}
Property changes on: tags/extensions/Survey/REL_0_1/specials/SpecialSurveyPage.php
___________________________________________________________________
Added: svn:eol-style
1137 + native
Index: tags/extensions/Survey/REL_0_1/specials/SpecialSurveyStats.php
@@ -0,0 +1,267 @@
 2+<?php
 3+
 4+/**
 5+ * Statistics interface for surveys.
 6+ *
 7+ * @since 0.1
 8+ *
 9+ * @file SpecialSurveyStats.php
 10+ * @ingroup Survey
 11+ *
 12+ * @licence GNU GPL v3 or later
 13+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
 14+ */
 15+class SpecialSurveyStats extends SpecialSurveyPage {
 16+
 17+ /**
 18+ * Constructor.
 19+ *
 20+ * @since 0.1
 21+ */
 22+ public function __construct() {
 23+ parent::__construct( 'SurveyStats', 'surveyadmin', false );
 24+ }
 25+
 26+ /**
 27+ * Main method.
 28+ *
 29+ * @since 0.1
 30+ *
 31+ * @param string $arg
 32+ */
 33+ public function execute( $subPage ) {
 34+ if ( !parent::execute( $subPage ) ) {
 35+ return;
 36+ }
 37+
 38+ if ( is_null( $subPage ) || trim( $subPage ) === '' ) {
 39+ $this->getOutput()->redirect( SpecialPage::getTitleFor( 'Surveys' )->getLocalURL() );
 40+ } else {
 41+ $subPage = trim( $subPage );
 42+
 43+ if ( Survey::has( array( 'name' => $subPage ) ) ) {
 44+ $survey = Survey::newFromName( $subPage );
 45+
 46+ $this->displayNavigation( array(
 47+ wfMsgExt( 'survey-navigation-edit', 'parseinline', $survey->getField( 'name' ) ),
 48+ wfMsgExt( 'survey-navigation-take', 'parseinline', $survey->getField( 'name' ) ),
 49+ wfMsgExt( 'survey-navigation-list', 'parseinline' )
 50+ ) );
 51+
 52+ $this->displayStats( $survey );
 53+ }
 54+ else {
 55+ $this->showError( 'surveys-surveystats-nosuchsurvey' );
 56+ }
 57+ }
 58+ }
 59+
 60+ /**
 61+ * Display the statistics that go with the survey.
 62+ *
 63+ * @since 0.1
 64+ *
 65+ * @param Survey $survey
 66+ */
 67+ protected function displayStats( Survey $survey ) {
 68+ $this->displaySummary( $this->getSummaryData( $survey ) );
 69+
 70+ if ( count( $survey->getQuestions() ) > 0 ) {
 71+ $this->displayQuestions( $survey );
 72+ }
 73+ }
 74+
 75+ /**
 76+ * Gets the summary data.
 77+ *
 78+ * @since 0.1
 79+ *
 80+ * @param Survey $survey
 81+ *
 82+ * @return array
 83+ */
 84+ protected function getSummaryData( Survey $survey ) {
 85+ $stats = array();
 86+
 87+ $stats['name'] = $survey->getField( 'name' );
 88+ $stats['title'] = $survey->getField( 'title' );
 89+ $stats['status'] = wfMsg( 'surveys-surveystats-' . ( $survey->getField( 'enabled' ) ? 'enabled' : 'disabled' ) );
 90+ $stats['questioncount'] = count( $survey->getQuestions() ) ;
 91+ $stats['submissioncount'] = SurveySubmission::count( array( 'survey_id' => $survey->getId() ) );
 92+
 93+ return $stats;
 94+ }
 95+
 96+ /**
 97+ * Display a summary table with the provided data.
 98+ * The keys are messages that get prepended with surveys-surveystats-.
 99+ * message => value
 100+ *
 101+ * @since 0.1
 102+ *
 103+ * @param array $stats
 104+ */
 105+ protected function displaySummary( array $stats ) {
 106+ $out = $this->getOutput();
 107+
 108+ $out->addHTML( Html::openElement( 'table', array( 'class' => 'wikitable survey-stats' ) ) );
 109+
 110+ foreach ( $stats as $stat => $value ) {
 111+ $out->addHTML( '<tr>' );
 112+
 113+ $out->addHTML( Html::element(
 114+ 'th',
 115+ array( 'class' => 'survey-stat-name' ),
 116+ wfMsg( 'surveys-surveystats-' . $stat )
 117+ ) );
 118+
 119+ $out->addHTML( Html::element(
 120+ 'td',
 121+ array( 'class' => 'survey-stat-value' ),
 122+ $value
 123+ ) );
 124+
 125+ $out->addHTML( '</tr>' );
 126+ }
 127+
 128+ $out->addHTML( Html::closeElement( 'table' ) );
 129+ }
 130+
 131+ /**
 132+ * Displays a table with the surveys questions and some summary stats about them.
 133+ *
 134+ * @since 0.1
 135+ *
 136+ * @param Survey $survey
 137+ */
 138+ protected function displayQuestions( Survey $survey ) {
 139+ $out = $this->getOutput();
 140+
 141+ $out->addHTML( '<h2>' . wfMsgHtml( 'surveys-surveystats-questions' ) . '</h2>' );
 142+
 143+ $out->addHTML( Html::openElement( 'table', array( 'class' => 'wikitable sortable survey-questions' ) ) );
 144+
 145+ $out->addHTML(
 146+ '<thead><tr>' .
 147+ '<th>' . wfMsgHtml( 'surveys-surveystats-question-nr' ) . '</th>' .
 148+ '<th>' . wfMsgHtml( 'surveys-surveystats-question-type' ) . '</th>' .
 149+ '<th class="unsortable">' . wfMsgHtml( 'surveys-surveystats-question-text' ) . '</th>' .
 150+ '<th>' . wfMsgHtml( 'surveys-surveystats-question-answercount' ) . '</th>' .
 151+ '<th class="unsortable">' . wfMsgHtml( 'surveys-surveystats-question-answers' ) . '</th>' .
 152+ '</tr></thead>'
 153+ );
 154+
 155+ $out->addHTML( '<tbody>' );
 156+
 157+ foreach ( $survey->getQuestions() as /* SurveyQuestion */ $question ) {
 158+ $this->displayQuestionStats( $question );
 159+ }
 160+
 161+ $out->addHTML( '</tbody>' );
 162+
 163+ $out->addHTML( Html::closeElement( 'table' ) );
 164+ }
 165+
 166+ /**
 167+ * Adds a table row with the summary stats for the provided question.
 168+ *
 169+ * @since 0.1
 170+ *
 171+ * @param SurveyQuestion $question
 172+ */
 173+ protected function displayQuestionStats( SurveyQuestion $question ) {
 174+ static $qNr = 0;
 175+
 176+ $out = $this->getOutput();
 177+
 178+ $out->addHTML( '<tr>' );
 179+
 180+ $out->addHTML( Html::element(
 181+ 'td',
 182+ array( 'data-sort-value' => ++$qNr ),
 183+ wfMsgExt( 'surveys-surveystats-question-#', 'parsemag', $qNr )
 184+ ) );
 185+
 186+ $out->addHTML( Html::element(
 187+ 'td',
 188+ array(),
 189+ wfMsg( SurveyQuestion::getTypeMessage( $question->getField( 'type' ) ) )
 190+ ) );
 191+
 192+ $out->addHTML( Html::element(
 193+ 'td',
 194+ array(),
 195+ $question->getField( 'text' )
 196+ ) );
 197+
 198+ $out->addHTML( Html::element(
 199+ 'td',
 200+ array(),
 201+ SurveyAnswer::count( array( 'question_id' => $question->getId() ) )
 202+ ) );
 203+
 204+ $out->addHTML( Html::rawElement(
 205+ 'td',
 206+ array(),
 207+ $this->getAnswerList( $question )
 208+ ) );
 209+
 210+ $out->addHTML( '</tr>' );
 211+ }
 212+
 213+ /**
 214+ * Get a list of most provided answers for the question.
 215+ *
 216+ * @since 0.1
 217+ *
 218+ * @param SurveyQuestion $question
 219+ *
 220+ * @return string
 221+ */
 222+ protected function getAnswerList( SurveyQuestion $question ) {
 223+ if ( $question->isRestrictiveType() ) {
 224+ $list = '<ul>';
 225+
 226+ $answers = array();
 227+ $answerTranslations = array();
 228+
 229+ if ( $question->getField( 'type' ) == SurveyQuestion::$TYPE_CHECK ) {
 230+ $possibilities = array( '0', '1' );
 231+ $answerTranslations['0'] = wfMsg( 'surveys-surveystats-unchecked' );
 232+ $answerTranslations['1'] = wfMsg( 'surveys-surveystats-checked' );
 233+ }
 234+ else {
 235+ $possibilities = $question->getField( 'answers' );
 236+ }
 237+
 238+ foreach ( $possibilities as $answer ) {
 239+ $answers[$answer] = SurveyAnswer::count( array( 'text' => $answer ) );
 240+ }
 241+
 242+ asort( $answers, SORT_NUMERIC );
 243+
 244+ foreach ( array_reverse( $answers ) as $answer => $answerCount ) {
 245+ if ( array_key_exists( $answer, $answerTranslations ) ) {
 246+ $answer = $answerTranslations[$answer];
 247+ }
 248+
 249+ $list .= Html::element(
 250+ 'li',
 251+ array(),
 252+ wfMsgExt(
 253+ 'surveys-surveystats-question-answer',
 254+ 'parsemag',
 255+ $answer,
 256+ $this->getLang()->formatNum( $answerCount )
 257+ )
 258+ );
 259+ }
 260+
 261+ return $list . '</ul>';
 262+ }
 263+ else {
 264+ return '';
 265+ }
 266+ }
 267+
 268+}
Property changes on: tags/extensions/Survey/REL_0_1/specials/SpecialSurveyStats.php
___________________________________________________________________
Added: svn:eol-style
1269 + native
Index: tags/extensions/Survey/REL_0_1/specials/SpecialSurvey.php
@@ -0,0 +1,372 @@
 2+<?php
 3+
 4+/**
 5+ * Administration interface for a survey.
 6+ *
 7+ * @since 0.1
 8+ *
 9+ * @file SpecialSurvey.php
 10+ * @ingroup Survey
 11+ *
 12+ * @licence GNU GPL v3 or later
 13+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
 14+ */
 15+class SpecialSurvey extends SpecialSurveyPage {
 16+
 17+ /**
 18+ * Constructor.
 19+ *
 20+ * @since 0.1
 21+ */
 22+ public function __construct() {
 23+ parent::__construct( 'EditSurvey', 'surveyadmin', false );
 24+ }
 25+
 26+ /**
 27+ * Main method.
 28+ *
 29+ * @since 0.1
 30+ *
 31+ * @param string $arg
 32+ */
 33+ public function execute( $subPage ) {
 34+ if ( !parent::execute( $subPage ) ) {
 35+ return;
 36+ }
 37+
 38+ global $wgRequest, $wgUser;
 39+
 40+ if ( $wgRequest->wasPosted() && $wgUser->matchEditToken( $wgRequest->getVal( 'wpEditToken' ) ) ) {
 41+ $this->handleSubmission();
 42+ } else {
 43+ if ( is_null( $subPage ) || trim( $subPage ) === '' ) {
 44+ $this->getOutput()->redirect( SpecialPage::getTitleFor( 'Surveys' )->getLocalURL() );
 45+ } else {
 46+ $subPage = trim( $subPage );
 47+
 48+ $survey = Survey::newFromName( $subPage, null, true );
 49+
 50+ if ( $survey === false ) {
 51+ $survey = new Survey( array( 'name' => $subPage ), true );
 52+ }
 53+ else {
 54+ $this->displayNavigation( array(
 55+ wfMsgExt( 'survey-navigation-take', 'parseinline', $subPage ),
 56+ wfMsgExt( 'survey-navigation-stats', 'parseinline', $subPage ),
 57+ wfMsgExt( 'survey-navigation-list', 'parseinline' )
 58+ ) );
 59+ }
 60+
 61+ $this->showSurvey( $survey );
 62+ $this->addModules( 'ext.survey.special.survey' );
 63+ }
 64+ }
 65+ }
 66+
 67+ /**
 68+ * Handle submission of a survey.
 69+ * This conists of finding the posted survey data, constructing the
 70+ * corresponding objects, writing these to the db and then redirecting
 71+ * the user back to the surveys list.
 72+ *
 73+ * @since 0.1
 74+ */
 75+ protected function handleSubmission() {
 76+ global $wgRequest;
 77+
 78+ $values = $wgRequest->getValues();
 79+
 80+ if ( $wgRequest->getInt( 'survey-id' ) == 0 ) {
 81+ $survey = new Survey( null );
 82+ } else {
 83+ $survey = Survey::newFromId( $wgRequest->getInt( 'survey-id' ), null, false );
 84+ }
 85+
 86+ foreach ( array( 'name', 'title', 'header', 'footer', 'thanks' ) as $field ) {
 87+ $survey->setField( $field, $wgRequest->getText( 'survey-' . $field ) );
 88+ }
 89+
 90+ $survey->setField( 'enabled', $wgRequest->getCheck( 'survey-enabled' ) );
 91+
 92+ foreach ( array( 'user_type', 'ratio', 'min_pages', 'expiry' ) as $field ) {
 93+ $survey->setField( $field, $wgRequest->getInt( 'survey-' . $field ) );
 94+ }
 95+
 96+ $survey->setField( 'namespaces', array() );
 97+
 98+ $survey->setQuestions( $this->getSubmittedQuestions() );
 99+
 100+ $survey->writeToDB();
 101+
 102+ $this->getOutput()->redirect( SpecialPage::getTitleFor( 'Surveys' )->getLocalURL() );
 103+ }
 104+
 105+ /**
 106+ * Gets a list of submitted surveys.
 107+ *
 108+ * @return array of SurveyQuestion
 109+ */
 110+ protected function getSubmittedQuestions() {
 111+ $questions = array();
 112+
 113+ foreach ( $GLOBALS['wgRequest']->getValues() as $name => $value ) {
 114+ $matches = array();
 115+
 116+ if ( preg_match( '/survey-question-text-(\d+)/', $name, $matches ) ) {
 117+ $questions[] = $this->getSubmittedQuestion( $matches[1] );
 118+ } elseif ( preg_match( '/survey-question-text-new-(\d+)/', $name, $matches ) ) {
 119+ $questions[] = $this->getSubmittedQuestion( $matches[1], true );
 120+ }
 121+ }
 122+
 123+ return $questions;
 124+ }
 125+
 126+ /**
 127+ * Create and return a survey question object from the submitted data.
 128+ *
 129+ * @since 0.1
 130+ *
 131+ * @param integer|null $questionId
 132+ *
 133+ * @return SurveyQuestion
 134+ */
 135+ protected function getSubmittedQuestion( $questionId, $isNewQuestion = false ) {
 136+ global $wgRequest;
 137+
 138+ if ( $isNewQuestion ) {
 139+ $questionDbId = null;
 140+ $questionId = "new-$questionId";
 141+ } else {
 142+ $questionDbId = $questionId;
 143+ }
 144+
 145+ $answers = array_filter(
 146+ explode( "\n", $wgRequest->getText( "survey-question-answers-$questionId" ) ),
 147+ function( $line ) {
 148+ return trim( $line ) != '';
 149+ }
 150+ );
 151+
 152+ $question = new SurveyQuestion( array(
 153+ 'id' => $questionDbId,
 154+ 'removed' => 0,
 155+ 'text' => $wgRequest->getText( "survey-question-text-$questionId" ),
 156+ 'type' => $wgRequest->getInt( "survey-question-type-$questionId" ),
 157+ 'required' => 0, // $wgRequest->getCheck( "survey-question-required-$questionId" ),
 158+ 'answers' => $answers
 159+ ) );
 160+
 161+ return $question;
 162+ }
 163+
 164+ /**
 165+ * Show error when requesting a non-existing survey.
 166+ *
 167+ * @since 0.1
 168+ */
 169+ protected function showNameError() {
 170+ $this->getOutput()->addHTML(
 171+ '<p class="errorbox">' . wfMsgHtml( 'surveys-special-unknown-name' ) . '</p>'
 172+ );
 173+ }
 174+
 175+ /**
 176+ * Get an array of numbers with as keys the formatted version of the values.
 177+ *
 178+ * @since 0.1
 179+ *
 180+ * @param array $numbers
 181+ *
 182+ * @return array
 183+ */
 184+ protected function getNumericalOptions( array $numbers ) {
 185+ $lang = $this->getLang();
 186+
 187+ return array_flip( array_map(
 188+ function( $n ) use( $lang ) { return $lang->formatNum( $n ); },
 189+ array_combine( $numbers, $numbers )
 190+ ) );
 191+ }
 192+
 193+ /**
 194+ * Show the survey.
 195+ *
 196+ * @since 0.1
 197+ *
 198+ * @param Survey $survey
 199+ */
 200+ protected function showSurvey( Survey $survey ) {
 201+ $fields = array();
 202+
 203+ $fields[] = array(
 204+ 'type' => 'hidden',
 205+ 'default' => $survey->getId(),
 206+ 'name' => 'survey-id',
 207+ 'id' => 'survey-id',
 208+ );
 209+
 210+ $fields[] = array(
 211+ 'type' => 'hidden',
 212+ 'default' => $survey->getField( 'name' ),
 213+ 'name' => 'survey-name',
 214+ 'id' => 'survey-name',
 215+ );
 216+
 217+ $fields[] = array(
 218+ 'type' => 'hidden',
 219+ 'default' => $survey->getField( 'expiry' ),
 220+ 'name' => 'survey-expiry',
 221+ 'id' => 'survey-expiry',
 222+ );
 223+
 224+ $fields[] = array(
 225+ 'class' => 'SurveyNameField',
 226+ 'default' => $survey->getField( 'name' ),
 227+ 'label-message' => 'survey-special-label-name',
 228+ 'style' => 'font-weight: bold;'
 229+ );
 230+
 231+ $fields[] = array(
 232+ 'type' => 'text',
 233+ 'default' => $survey->getField( 'title' ),
 234+ 'label-message' => 'survey-special-label-title',
 235+ 'id' => 'survey-title',
 236+ 'name' => 'survey-title',
 237+ );
 238+
 239+ $fields[] = array(
 240+ 'type' => 'check',
 241+ 'default' => $survey->getField( 'enabled' ) ? '1' : '0',
 242+ 'label-message' => 'survey-special-label-enabled',
 243+ 'id' => 'survey-enabled',
 244+ 'name' => 'survey-enabled',
 245+ );
 246+
 247+ $fields[] = array(
 248+ 'type' => 'radio',
 249+ 'default' => $survey->getField( 'user_type' ),
 250+ 'label-message' => 'survey-special-label-usertype',
 251+ 'id' => 'survey-user_type',
 252+ 'name' => 'survey-user_type',
 253+ 'options' => array(
 254+ wfMsg( 'survey-user-type-all' ) => Survey::$USER_ALL,
 255+ wfMsg( 'survey-user-type-loggedin' ) => Survey::$USER_LOGGEDIN,
 256+ wfMsg( 'survey-user-type-confirmed' ) => Survey::$USER_CONFIRMED,
 257+ wfMsg( 'survey-user-type-editor' ) => Survey::$USER_EDITOR,
 258+ wfMsg( 'survey-user-type-anon' ) => Survey::$USER_ANON,
 259+ ),
 260+ );
 261+
 262+ $fields[] = array(
 263+ 'type' => 'select',
 264+ 'default' => $survey->getField( 'ratio' ),
 265+ 'label-message' => 'survey-special-label-ratio',
 266+ 'id' => 'survey-ratio',
 267+ 'name' => 'survey-ratio',
 268+ 'options' => $this->getNumericalOptions( array_merge( array( 0.01, 0.1 ), range( 1, 100 ) ) ),
 269+ );
 270+
 271+ $fields[] = array(
 272+ 'type' => 'select',
 273+ 'default' => $survey->getField( 'min_pages' ),
 274+ 'label-message' => 'survey-special-label-minpages',
 275+ 'id' => 'survey-min_pages',
 276+ 'name' => 'survey-min_pages',
 277+ 'options' => $this->getNumericalOptions( range( 0, 250 ) ),
 278+ );
 279+
 280+ $fields[] = array(
 281+ 'type' => 'text',
 282+ 'default' => $survey->getField( 'header' ),
 283+ 'label-message' => 'survey-special-label-header',
 284+ 'id' => 'survey-header',
 285+ 'name' => 'survey-header',
 286+ );
 287+
 288+ $fields[] = array(
 289+ 'type' => 'text',
 290+ 'default' => $survey->getField( 'footer' ),
 291+ 'label-message' => 'survey-special-label-footer',
 292+ 'id' => 'survey-footer',
 293+ 'name' => 'survey-footer',
 294+ );
 295+
 296+ $fields[] = array(
 297+ 'type' => 'text',
 298+ 'default' => $survey->getField( 'thanks' ),
 299+ 'label-message' => 'survey-special-label-thanks',
 300+ 'id' => 'survey-thanks',
 301+ 'name' => 'survey-thanks',
 302+ );
 303+
 304+ foreach ( $survey->getQuestions() as /* SurveyQuestion */ $question ) {
 305+ $fields[] = array(
 306+ 'class' => 'SurveyQuestionField',
 307+ 'options' => $question->toArray()
 308+ );
 309+ }
 310+
 311+ // getContext was added in 1.18 and since that version is
 312+ // the second argument for the HTMLForm constructor.
 313+ if ( version_compare( $GLOBALS['wgVersion'], '1.18', '>=' ) ) {
 314+ $form = new HTMLForm( $fields, $this->getContext() );
 315+ } else {
 316+ $form = new HTMLForm( $fields );
 317+ $form->setTitle( $this->getTitle() );
 318+ }
 319+
 320+ $form->setSubmitText( wfMsg( 'surveys-special-save' ) );
 321+
 322+ $form->addButton(
 323+ 'cancelEdit',
 324+ wfMsg( 'cancel' ),
 325+ 'cancelEdit',
 326+ array(
 327+ 'onclick' => 'window.location="' . SpecialPage::getTitleFor( 'Surveys' )->getFullURL() . '";return false;'
 328+ )
 329+ );
 330+
 331+ $form->show();
 332+ }
 333+
 334+}
 335+
 336+class SurveyQuestionField extends HTMLFormField {
 337+
 338+ public function getInputHTML( $value ) {
 339+ $attribs = array(
 340+ 'class' => 'survey-question-data'
 341+ );
 342+
 343+ foreach ( $this->mParams['options'] as $name => $value ) {
 344+ if ( is_bool( $value ) ) {
 345+ $value = $value ? '1' : '0';
 346+ } elseif( is_object( $value ) || is_array( $value ) ) {
 347+ $value = FormatJson::encode( $value );
 348+ }
 349+
 350+ $attribs['data-' . $name] = $value;
 351+ }
 352+
 353+ return Html::element(
 354+ 'div',
 355+ $attribs
 356+ );
 357+ }
 358+
 359+}
 360+
 361+class SurveyNameField extends HTMLFormField {
 362+
 363+ public function getInputHTML( $value ) {
 364+ return Html::element(
 365+ 'span',
 366+ array(
 367+ 'style' => $this->mParams['style']
 368+ ),
 369+ $value
 370+ );
 371+ }
 372+
 373+}
\ No newline at end of file
Property changes on: tags/extensions/Survey/REL_0_1/specials/SpecialSurvey.php
___________________________________________________________________
Added: svn:eol-style
1374 + native
Index: tags/extensions/Survey/REL_0_1/specials/SpecialSurveys.php
@@ -0,0 +1,183 @@
 2+<?php
 3+
 4+/**
 5+ * Administration interface for surveys.
 6+ *
 7+ * @since 0.1
 8+ *
 9+ * @file SpecialSurveys.php
 10+ * @ingroup Survey
 11+ *
 12+ * @licence GNU GPL v3 or later
 13+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
 14+ */
 15+class SpecialSurveys extends SpecialSurveyPage {
 16+
 17+ /**
 18+ * Constructor.
 19+ *
 20+ * @since 0.1
 21+ */
 22+ public function __construct() {
 23+ parent::__construct( 'Surveys', 'surveyadmin' );
 24+ }
 25+
 26+ /**
 27+ * Main method.
 28+ *
 29+ * @since 0.1
 30+ *
 31+ * @param string $arg
 32+ */
 33+ public function execute( $subPage ) {
 34+ if ( !parent::execute( $subPage ) ) {
 35+ return;
 36+ }
 37+
 38+ global $wgRequest, $wgUser;
 39+
 40+ if ( $wgRequest->wasPosted()
 41+ && $wgUser->matchEditToken( $wgRequest->getVal( 'wpEditToken' ) )
 42+ && $wgRequest->getCheck( 'newsurvey' ) ) {
 43+ $this->getOutput()->redirect( SpecialPage::getTitleFor( 'EditSurvey', $wgRequest->getVal( 'newsurvey' ) )->getLocalURL() );
 44+ } else {
 45+ $this->displaySurveys();
 46+ }
 47+ }
 48+
 49+ /**
 50+ * Displays surveys.
 51+ *
 52+ * @since 0.1
 53+ */
 54+ protected function displaySurveys() {
 55+ $this->displayAddNewControl();
 56+
 57+ $surveys = Survey::select( array( 'id', 'name', 'enabled', 'title' ) );
 58+
 59+ if ( count( $surveys ) > 0 ) {
 60+ $this->displaySurveysTable( $surveys );
 61+ }
 62+
 63+ $this->addModules( 'ext.survey.special.surveys' );
 64+ }
 65+
 66+ /**
 67+ * Displays a small form to add a new campaign.
 68+ *
 69+ * @since 0.1
 70+ */
 71+ protected function displayAddNewControl() {
 72+ $out = $this->getOutput();
 73+
 74+ $out->addHTML( Html::openElement(
 75+ 'form',
 76+ array(
 77+ 'method' => 'post',
 78+ 'action' => $this->getTitle()->getLocalURL(),
 79+ )
 80+ ) );
 81+
 82+ $out->addHTML( '<fieldset>' );
 83+
 84+ $out->addHTML( '<legend>' . htmlspecialchars( wfMsg( 'surveys-special-addnew' ) ) . '</legend>' );
 85+
 86+ $out->addHTML( Html::element( 'p', array(), wfMsg( 'surveys-special-namedoc' ) ) );
 87+
 88+ $out->addHTML( Html::element( 'label', array( 'for' => 'newcampaign' ), wfMsg( 'surveys-special-newname' ) ) );
 89+
 90+ $out->addHTML( '&#160;' . Html::input( 'newsurvey' ) . '&#160;' );
 91+
 92+ $out->addHTML( Html::input(
 93+ 'addnewsurvey',
 94+ wfMsg( 'surveys-special-add' ),
 95+ 'submit'
 96+ ) );
 97+
 98+ global $wgUser;
 99+ $out->addHTML( Html::hidden( 'wpEditToken', $wgUser->editToken() ) );
 100+
 101+ $out->addHTML( '</fieldset></form>' );
 102+ }
 103+
 104+ /**
 105+ * Displays a list of all survets.
 106+ *
 107+ * @since 0.1
 108+ *
 109+ * @param array $surveys
 110+ */
 111+ protected function displaySurveysTable( array /* of Survey */ $surveys ) {
 112+ $out = $this->getOutput();
 113+
 114+ $out->addHTML( Html::element( 'h2', array(), wfMsg( 'surveys-special-existing' ) ) );
 115+
 116+ $out->addHTML( Xml::openElement(
 117+ 'table',
 118+ array( 'class' => 'wikitable sortable', 'style' => 'width:400px' )
 119+ ) );
 120+
 121+ $out->addHTML(
 122+ '<thead><tr>' .
 123+ Html::element( 'th', array(), wfMsg( 'surveys-special-title' ) ) .
 124+ Html::element( 'th', array(), wfMsg( 'surveys-special-status' ) ) .
 125+ Html::element( 'th', array( 'class' => 'unsortable' ), wfMsg( 'surveys-special-stats' ) ) .
 126+ Html::element( 'th', array( 'class' => 'unsortable' ), wfMsg( 'surveys-special-edit' ) ) .
 127+ Html::element( 'th', array( 'class' => 'unsortable' ), wfMsg( 'surveys-special-delete' ) ) .
 128+ '</tr></thead>'
 129+ );
 130+
 131+ $out->addHTML( '<tbody>' );
 132+
 133+ foreach ( $surveys as $survey ) {
 134+ $out->addHTML(
 135+ '<tr>' .
 136+ '<td data-sort-value="' . htmlspecialchars( $survey->getField( 'title' ) ) . '">' .
 137+ Html::element(
 138+ 'a',
 139+ array(
 140+ 'href' => SpecialPage::getTitleFor( 'TakeSurvey', $survey->getField( 'name' ) )->getLocalURL()
 141+ ),
 142+ $survey->getField( 'title' )
 143+ ) .
 144+ '</td>' .
 145+ Html::element( 'td', array(), wfMsg( 'surveys-special-' . ( $survey->getField( 'enabled' ) ? 'enabled' : 'disabled' ) ) ) .
 146+ '<td>' .
 147+ Html::element(
 148+ 'a',
 149+ array(
 150+ 'href' => SpecialPage::getTitleFor( 'SurveyStats', $survey->getField( 'name' ) )->getLocalURL()
 151+ ),
 152+ wfMsg( 'surveys-special-stats' )
 153+ ) .
 154+ '</td>' .
 155+ '<td>' .
 156+ Html::element(
 157+ 'a',
 158+ array(
 159+ 'href' => SpecialPage::getTitleFor( 'EditSurvey', $survey->getField( 'name' ) )->getLocalURL()
 160+ ),
 161+ wfMsg( 'surveys-special-edit' )
 162+ ) .
 163+ '</td>' .
 164+ '<td>' .
 165+ Html::element(
 166+ 'a',
 167+ array(
 168+ 'href' => '#',
 169+ 'class' => 'survey-delete',
 170+ 'data-survey-id' => $survey->getId(),
 171+ 'data-survey-token' => $GLOBALS['wgUser']->editToken( 'deletesurvey' . $survey->getId() )
 172+ ),
 173+ wfMsg( 'surveys-special-delete' )
 174+ ) .
 175+ '</td>' .
 176+ '</tr>'
 177+ );
 178+ }
 179+
 180+ $out->addHTML( '</tbody>' );
 181+ $out->addHTML( '</table>' );
 182+ }
 183+
 184+}
Property changes on: tags/extensions/Survey/REL_0_1/specials/SpecialSurveys.php
___________________________________________________________________
Added: svn:eol-style
1185 + native
Index: tags/extensions/Survey/REL_0_1/specials/SpecialTakeSurvey.php
@@ -0,0 +1,84 @@
 2+<?php
 3+
 4+/**
 5+ * Page on which a survey is displayed.
 6+ *
 7+ * @since 0.1
 8+ *
 9+ * @file SpecialTakeSurvey.php
 10+ * @ingroup Survey
 11+ *
 12+ * @licence GNU GPL v3 or later
 13+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
 14+ */
 15+class SpecialTakeSurvey extends SpecialSurveyPage {
 16+
 17+ /**
 18+ * Constructor.
 19+ *
 20+ * @since 0.1
 21+ */
 22+ public function __construct() {
 23+ parent::__construct( 'TakeSurvey', 'surveysubmit' );
 24+ }
 25+
 26+ /**
 27+ * Main method.
 28+ *
 29+ * @since 0.1
 30+ *
 31+ * @param string $arg
 32+ */
 33+ public function execute( $subPage ) {
 34+ if ( !parent::execute( $subPage ) ) {
 35+ return;
 36+ }
 37+
 38+ $survey = Survey::selectRow(
 39+ array( 'enabled' ),
 40+ array( 'name' => $subPage )
 41+ );
 42+
 43+ if ( $survey === false ) {
 44+ $this->showError( 'surveys-takesurvey-nosuchsurvey' );
 45+ }
 46+ else if ( $survey->getField( 'enabled' ) ) {
 47+ $this->displaySurvey( $subPage );
 48+ }
 49+ else if ( $GLOBALS['wgUser']->isAllowed( 'surveyadmin' ) ) {
 50+ $this->showWarning( 'surveys-takesurvey-warn-notenabled' );
 51+ $this->getOutput()->addHTML( '<br /><br /><br /><br />' );
 52+ $this->displaySurvey( $subPage );
 53+ }
 54+ else {
 55+ $this->showError( 'surveys-takesurvey-surveynotenabled' );
 56+ }
 57+ }
 58+
 59+ /**
 60+ * Add the output for the actual survey.
 61+ * This is done by adding a survey tag as wikitext, which then get's rendered.
 62+ *
 63+ * @since 0.1
 64+ *
 65+ * @param string $subPage
 66+ */
 67+ protected function displaySurvey( $subPage ) {
 68+ $this->displayNavigation( array(
 69+ wfMsgExt( 'survey-navigation-edit', 'parseinline', $subPage ),
 70+ wfMsgExt( 'survey-navigation-stats', 'parseinline', $subPage ),
 71+ wfMsgExt( 'survey-navigation-list', 'parseinline' )
 72+ ) );
 73+
 74+ $this->getOutput()->addWikiText( Xml::element(
 75+ 'survey',
 76+ array(
 77+ 'name' => $subPage,
 78+ 'require-enabled' => $GLOBALS['wgUser']->isAllowed( 'surveyadmin' ) ? '0' : '1',
 79+ 'cookie' => 'no'
 80+ ),
 81+ wfMsg( 'surveys-takesurvey-loading' )
 82+ ) );
 83+ }
 84+
 85+}
Property changes on: tags/extensions/Survey/REL_0_1/specials/SpecialTakeSurvey.php
___________________________________________________________________
Added: svn:eol-style
186 + native
Index: tags/extensions/Survey/REL_0_1/Survey.hooks.php
@@ -0,0 +1,188 @@
 2+<?php
 3+
 4+/**
 5+ * Static class for hooks handled by the Survey extension.
 6+ *
 7+ * @since 0.1
 8+ *
 9+ * @file Survey.hooks.php
 10+ * @ingroup Survey
 11+ *
 12+ * @licence GNU GPL v3+
 13+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
 14+ */
 15+final class SurveyHooks {
 16+
 17+ /**
 18+ * Register the survey tag extension when the parser initializes.
 19+ *
 20+ * @since 0.1
 21+ *
 22+ * @param Parser $parser
 23+ *
 24+ * @return true
 25+ */
 26+ public static function onParserFirstCallInit( Parser &$parser ) {
 27+ $parser->setHook( 'survey', __CLASS__ . '::onSurveyRender' );
 28+ return true;
 29+ }
 30+
 31+ /**
 32+ * Render the survey tag.
 33+ *
 34+ * @since 0.1
 35+ *
 36+ * @param mixed $input
 37+ * @param array $args
 38+ * @param Parser $parser
 39+ * @param PPFrame $frame
 40+ */
 41+ public static function onSurveyRender( $input, array $args, Parser $parser, PPFrame $frame ) {
 42+ $tag = new SurveyTag( $args, $input );
 43+ return $tag->render( $parser );
 44+ }
 45+
 46+ /**
 47+ * Schema update to set up the needed database tables.
 48+ *
 49+ * @since 0.1
 50+ *
 51+ * @param DatabaseUpdater $updater
 52+ *
 53+ * @return true
 54+ */
 55+ public static function onSchemaUpdate( /* DatabaseUpdater */ $updater = null ) {
 56+ global $wgDBtype;
 57+
 58+ $updater->addExtensionUpdate( array(
 59+ 'addTable',
 60+ 'surveys',
 61+ dirname( __FILE__ ) . '/Survey.sql',
 62+ true
 63+ ) );
 64+ $updater->addExtensionUpdate( array(
 65+ 'addTable',
 66+ 'survey_questions',
 67+ dirname( __FILE__ ) . '/Survey.sql',
 68+ true
 69+ ) );
 70+ $updater->addExtensionUpdate( array(
 71+ 'addTable',
 72+ 'survey_submissions',
 73+ dirname( __FILE__ ) . '/Survey.sql',
 74+ true
 75+ ) );
 76+ $updater->addExtensionUpdate( array(
 77+ 'addTable',
 78+ 'survey_answers',
 79+ dirname( __FILE__ ) . '/Survey.sql',
 80+ true
 81+ ) );
 82+ $updater->addExtensionUpdate( array(
 83+ 'addIndex',
 84+ 'surveys',
 85+ 'surveys_survey_name',
 86+ dirname( __FILE__ ) . '/sql/Survey_indexSurveyName.sql',
 87+ true
 88+ ) );
 89+ $updater->addExtensionUpdate( array(
 90+ 'addIndex',
 91+ 'survey_answers',
 92+ 'answer_question_id',
 93+ dirname( __FILE__ ) . '/sql/Survey_indexQuestionId.sql',
 94+ true
 95+ ) );
 96+ $updater->addExtensionUpdate( array(
 97+ 'addIndex',
 98+ 'survey_answers',
 99+ 'answer_submission_id',
 100+ dirname( __FILE__ ) . '/sql/Survey_indexSubmissionId.sql',
 101+ true
 102+ ) );
 103+
 104+ return true;
 105+ }
 106+
 107+ /**
 108+ * Hook to add PHPUnit test cases.
 109+ *
 110+ * @since 0.1
 111+ *
 112+ * @param array $files
 113+ */
 114+ public static function registerUnitTests( array &$files ) {
 115+ $testDir = dirname( __FILE__ ) . '/test/';
 116+
 117+ $files[] = $testDir . 'SurveyQuestionTest.php';
 118+
 119+ return true;
 120+ }
 121+
 122+ /**
 123+ * Hook to insert things into article headers.
 124+ *
 125+ * @since 0.1
 126+ *
 127+ * @param Article &$article
 128+ * @param boolean $outputDone
 129+ * @param boolean $useParserCache
 130+ *
 131+ * @return true
 132+ */
 133+ public static function onArticleViewHeader( Article &$article, &$outputDone, &$useParserCache ) {
 134+ if ( !Survey::has( array( 'enabled' => 1 ) ) ) {
 135+ return true;
 136+ }
 137+
 138+ $surveys = Survey::select(
 139+ array(
 140+ 'id', 'namespaces', 'ratio', 'expiry', 'min_pages'
 141+ ),
 142+ array(
 143+ 'enabled' => 1,
 144+ 'user_type' => Survey::getTypesForUser( $GLOBALS['wgUser'] )
 145+ )
 146+ );
 147+
 148+ foreach ( $surveys as /* Survey */ $survey ) {
 149+
 150+ if ( count( $survey->getField( 'namespaces' ) ) == 0 ) {
 151+ $nsValid = true;
 152+ }
 153+ else {
 154+ $nsValid = in_array( $article->getTitle()->getNamespace(), $survey->getField( 'namespaces' ) );
 155+ }
 156+
 157+ if ( $nsValid ) {
 158+ $GLOBALS['wgOut']->addWikiText( Xml::element(
 159+ 'survey',
 160+ array(
 161+ 'id' => $survey->getId(),
 162+ 'ratio' => $survey->getField( 'ratio' ),
 163+ 'expiry' => $survey->getField( 'expiry' ),
 164+ 'min-pages' => $survey->getField( 'min_pages' ),
 165+ )
 166+ ) );
 167+ }
 168+ }
 169+
 170+ return true;
 171+ }
 172+
 173+ /**
 174+ * Adds a link to Admin Links page.
 175+ *
 176+ * @since 0.1
 177+ *
 178+ * @return true
 179+ */
 180+ public static function addToAdminLinks( &$admin_links_tree ) {
 181+ $section = new ALSection( 'Survey' );
 182+ $row = new ALRow( 'smw' );
 183+ $row->addItem( AlItem::newFromSpecialPage( 'Surveys' ) );
 184+ $section->addRow( $row );
 185+ $admin_links_tree->addSection( $section, 'Survey' );
 186+ return true;
 187+ }
 188+
 189+}
Property changes on: tags/extensions/Survey/REL_0_1/Survey.hooks.php
___________________________________________________________________
Added: svn:eol-style
1190 + native
Index: tags/extensions/Survey/REL_0_1/INSTALL
@@ -0,0 +1,85 @@
 2+These is the install file for the Survey extension.
 3+
 4+Extension page on mediawiki.org: http://www.mediawiki.org/wiki/Extension:Survey
 5+Latest version of the install file: http://svn.wikimedia.org/viewvc/mediawiki/trunk/extensions/Survey/INSTALL?view=co
 6+
 7+
 8+== Requirements ==
 9+
 10+Survey requires:
 11+
 12+* MediaWiki 1.17 or above
 13+* PHP 5.3 or above
 14+
 15+== Download ==
 16+
 17+You can find the current version of Survey on the [https://code.google.com/p/mwsuvey/downloads/list Google Code download page],
 18+as well as a [https://code.google.com/p/mwsuvey/downloads/list?can=1 list of legacy downloads].
 19+
 20+You can also get the code directly from SVN. Tags can be obtained via
 21+
 22+ svn checkout <nowiki>http://svn.wikimedia.org/svnroot/mediawiki/tags/extensions/Survey/REL_version</nowiki>
 23+
 24+Where 'version' is the version number of the tag, such as 0_1 (see the [http://svn.wikimedia.org/svnroot/mediawiki/tags/extensions/Survey/ available tags]).
 25+The latest code can be obtained from trunk:
 26+
 27+ svn checkout <nowiki>http://svn.wikimedia.org/svnroot/mediawiki/trunk/extensions/Survey/</nowiki>
 28+
 29+== Installation ==
 30+
 31+Once you have downloaded the code, place the ''Survey'' directory within your MediaWiki
 32+'extensions' directory. Then add the following code to your [[Manual:LocalSettings.php|LocalSettings.php]] file:
 33+
 34+# Survey
 35+require_once( "$IP/extensions/Survey/Survey.php" );
 36+
 37+== Configuration ==
 38+
 39+Configuration of Survey is done by assigning to $egSurveySettings in your
 40+[[Manual:LocalSettings.php|LocalSettings.php]] file, AFTER the inlcusion of the
 41+extension. The options are listed below and their default is set in the Survey settings file:
 42+http://svn.wikimedia.org/viewvc/mediawiki/trunk/extensions/Survey/Survey.settings.php?view=markup
 43+You should NOT modify the settings file, but can have a look at it to get an idea of
 44+how to use the settings, in case the below descriptions do not suffice.
 45+
 46+{| class="wikitable sortable"
 47+! Name
 48+! Type
 49+! Default
 50+! Description
 51+|-
 52+| defaultEnabled
 53+| boolean
 54+| false
 55+| If surveys should be enabled by default
 56+|-
 57+| defaultUserType
 58+| Survey::$USER_
 59+| Survey::$USER_ALL
 60+| The default type of users a survey is shown to
 61+|-
 62+| defaultNamespaces
 63+| array
 64+| array()
 65+| The default namespaces in which surveys should be shown. Empty list for no namespace restrictions
 66+|-
 67+| defaultRatio
 68+| integer
 69+| 100
 70+| The default percentage of users the surveys should be shown to
 71+|-
 72+| defaultExpiry
 73+| integer
 74+| 60 * 60 * 24 * 30
 75+| The default expiry of cookies used to track survey completion of users, in seconds
 76+|-
 77+| defaultMinPages
 78+| integer
 79+| 0
 80+| The default minimun amount of pages users should visit before getting a survey
 81+| -
 82+| JSDebug
 83+| boolean
 84+| false
 85+| Indicates if JavaScript debugging should be on or not. Should be false on production environments.
 86+|}
Property changes on: tags/extensions/Survey/REL_0_1/INSTALL
___________________________________________________________________
Added: svn:eol-style
187 + native
Index: tags/extensions/Survey/REL_0_1/RELEASE-NOTES
@@ -0,0 +1,19 @@
 2+These are the release notes for the Survey extension.
 3+
 4+Extension page on mediawiki.org: http://www.mediawiki.org/wiki/Extension:Survey
 5+Latest version of the release notes: http://svn.wikimedia.org/viewvc/mediawiki/trunk/extensions/Survey/RELEASE-NOTES?view=co
 6+
 7+
 8+=== Version 0.1 ===
 9+2011-09-13
 10+
 11+Initial release with these features:
 12+
 13+* Surveys get displayed to wiki users using a nice pop-up form.
 14+* Surveys can be created and modified via an admin panel (Special:Surveys).
 15+* Surveys can be shown to specific types of users (logged in, anonymouse, editor, confirmed, ...)
 16+* Surveys can be shown for a specified percentage of users, and only after a certain amount of page views.
 17+* Survey questions can have different types of inputs, of which some allow restricting answers.
 18+* Surveys can be tested by admins via Special:TakeSurvey without them being live on the wiki.
 19+* Summaries of survey submissions can be found on Special:SurveyStats.
 20+* The survey submission data (ie user answers) can be exported via an API.
Property changes on: tags/extensions/Survey/REL_0_1/RELEASE-NOTES
___________________________________________________________________
Added: svn:eol-style
121 + native
Index: tags/extensions/Survey/REL_0_1/includes/SurveyDBClass.php
@@ -0,0 +1,732 @@
 2+<?php
 3+
 4+/**
 5+ * Abstract base class for representing objects that are stored in some DB table.
 6+ *
 7+ * @since 0.1
 8+ *
 9+ * @file SurveyDBClass.php
 10+ * @ingroup Survey
 11+ *
 12+ * @licence GNU GPL v3 or later
 13+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
 14+ */
 15+abstract class SurveyDBClass {
 16+
 17+ /**
 18+ * The fields of the object.
 19+ * field name (w/o prefix) => value
 20+ *
 21+ * @since 0.1
 22+ * @var array
 23+ */
 24+ protected $fields = array();
 25+
 26+ /**
 27+ * Constructor.
 28+ *
 29+ * @since 0.1
 30+ *
 31+ * @param array|null $fields
 32+ * @param boolean $loadDefaults
 33+ */
 34+ public function __construct( $fields, $loadDefaults = false ) {
 35+ $this->setField( static::getIDField(), null );
 36+
 37+ if ( !is_array( $fields ) ) {
 38+ $fields = array();
 39+ }
 40+
 41+ if ( $loadDefaults ) {
 42+ $fields = array_merge( static::getDefaults(), $fields );
 43+ }
 44+
 45+ $this->setFields( $fields );
 46+ }
 47+
 48+ /**
 49+ * Returns an array with the fields and their types this object contains.
 50+ * This corresponds directly to the fields in the database, without prefix.
 51+ *
 52+ * field name => type
 53+ *
 54+ * Allowed types:
 55+ * * id
 56+ * * str
 57+ * * int
 58+ * * bool
 59+ * * array
 60+ *
 61+ * @since 0.1
 62+ *
 63+ * @return array
 64+ */
 65+ protected static function getFieldTypes() {
 66+ return array();
 67+ }
 68+
 69+ /**
 70+ * Returns an array with the fields and their descriptions.
 71+ *
 72+ * field name => field description
 73+ *
 74+ * @since 0.1
 75+ *
 76+ * @return array
 77+ */
 78+ public static function getFieldDescriptions() {
 79+ return array();
 80+ }
 81+
 82+ /**
 83+ * Returns the name of the database table objects of this type are stored in.
 84+ *
 85+ * @since 0.1
 86+ *
 87+ * @throws MWException
 88+ * @return string
 89+ */
 90+ public static function getDBTable() {
 91+ throw new MWException( 'Class did not implement getDBTable' );
 92+ }
 93+
 94+ /**
 95+ * Gets the db field prefix.
 96+ *
 97+ * @since 0.1
 98+ *
 99+ * @throws MWException
 100+ * @return string
 101+ */
 102+ protected static function getFieldPrefix() {
 103+ throw new MWException( 'Class did not implement getFieldPrefix' );
 104+ }
 105+
 106+ /**
 107+ * Returns the name of the id db field, without prefix.
 108+ *
 109+ * @since 0.1
 110+ *
 111+ * @return string
 112+ */
 113+ protected static function getIDField() {
 114+ return 'id';
 115+ }
 116+
 117+ /**
 118+ * Get a new instance of the class from a database result.
 119+ *
 120+ * @since 0.1
 121+ *
 122+ * @param object $result
 123+ *
 124+ * @return SurveyDBClass
 125+ */
 126+ public static function newFromDBResult( $result ) {
 127+ $result = (array)$result;
 128+ $data = array();
 129+ $idFieldLength = strlen( static::getFieldPrefix() );
 130+
 131+ foreach ( $result as $name => $value ) {
 132+ $data[substr( $name, $idFieldLength )] = $value;
 133+ }
 134+
 135+ return static::newFromArray( $data );
 136+ }
 137+
 138+ /**
 139+ * Get a new instance of the class from an array.
 140+ *
 141+ * @since 0.1
 142+ *
 143+ * @param array $data
 144+ * @param boolean $loadDefaults
 145+ *
 146+ * @return SurveyDBClass
 147+ */
 148+ public static function newFromArray( array $data, $loadDefaults = false ) {
 149+ return new static( $data, $loadDefaults );
 150+ }
 151+
 152+ /**
 153+ * Selects the the specified fields of the records matching the provided
 154+ * conditions. Field names get prefixed.
 155+ *
 156+ * @since 0.1
 157+ *
 158+ * @param array|null $fields
 159+ * @param array $conditions
 160+ * @param array $options
 161+ *
 162+ * @return array of self
 163+ */
 164+ public static function select( $fields = null, array $conditions = array(), array $options = array() ) {
 165+ if ( is_null( $fields ) ) {
 166+ $fields = array_keys( static::getFieldTypes() );
 167+ }
 168+
 169+ $result = static::rawSelect(
 170+ static::getPrefixedFields( $fields ),
 171+ static::getPrefixedValues( $conditions ),
 172+ $options
 173+ );
 174+
 175+ $objects = array();
 176+
 177+ foreach ( $result as $record ) {
 178+ $objects[] = static::newFromDBResult( $record );
 179+ }
 180+
 181+ return $objects;
 182+ }
 183+
 184+ /**
 185+ * Selects the the specified fields of the first matching record.
 186+ * Field names get prefixed.
 187+ *
 188+ * @since 0.1
 189+ *
 190+ * @param array|null $fields
 191+ * @param array $conditions
 192+ * @param array $options
 193+ *
 194+ * @return self|false
 195+ */
 196+ public static function selectRow( $fields = null, array $conditions = array(), array $options = array() ) {
 197+ $options['LIMIT'] = 1;
 198+
 199+ $objects = static::select( $fields, $conditions, $options );
 200+
 201+ return count( $objects ) > 0 ? $objects[0] : false;
 202+ }
 203+
 204+ /**
 205+ * Returns if there is at least one record matching the provided conditions.
 206+ * Condition field names get prefixed.
 207+ *
 208+ * @since 0.1
 209+ *
 210+ * @param array $conditions
 211+ *
 212+ * @return boolean
 213+ */
 214+ public static function has( array $conditions = array() ) {
 215+ return static::selectRow( array( static::getIDField() ), $conditions ) !== false;
 216+ }
 217+
 218+ /**
 219+ * Returns the amount of matching records.
 220+ * Condition field names get prefixed.
 221+ *
 222+ * @since 0.1
 223+ *
 224+ * @param array $conditions
 225+ * @param array $options
 226+ *
 227+ * @return integer
 228+ */
 229+ public static function count( array $conditions = array(), array $options = array() ) {
 230+ $res = static::rawSelect(
 231+ array( 'COUNT(*) AS rowcount' ),
 232+ static::getPrefixedValues( $conditions ),
 233+ $options
 234+ )->fetchObject();
 235+
 236+ return $res->rowcount;
 237+ }
 238+
 239+ /**
 240+ * Selects the the specified fields of the records matching the provided
 241+ * conditions. Field names do NOT get prefixed.
 242+ *
 243+ * @since 0.1
 244+ *
 245+ * @param array|null $fields
 246+ * @param array $conditions
 247+ * @param array $options
 248+ *
 249+ * @return ResultWrapper
 250+ */
 251+ public static function rawSelect( $fields = null, array $conditions = array(), array $options = array() ) {
 252+ $dbr = wfGetDB( DB_SLAVE );
 253+
 254+ return $dbr->select(
 255+ static::getDBTable(),
 256+ $fields,
 257+ count( $conditions ) == 0 ? '' : $conditions,
 258+ '',
 259+ $options
 260+ );
 261+ }
 262+
 263+ public static function update( array $values, array $conditions = array() ) {
 264+ $dbw = wfGetDB( DB_MASTER );
 265+
 266+ return $dbw->update(
 267+ static::getDBTable(),
 268+ static::getPrefixedValues( $values ),
 269+ static::getPrefixedValues( $conditions )
 270+ );
 271+ }
 272+
 273+ /**
 274+ * Writes the answer to the database, either updating it
 275+ * when it already exists, or inserting it when it doesn't.
 276+ *
 277+ * @since 0.1
 278+ *
 279+ * @return boolean Success indicator
 280+ */
 281+ public function writeToDB() {
 282+ if ( $this->hasIdField() ) {
 283+ return $this->updateInDB();
 284+ } else {
 285+ return $this->insertIntoDB();
 286+ }
 287+ }
 288+
 289+ /**
 290+ * Updates the object in the database.
 291+ *
 292+ * @since 0.1
 293+ *
 294+ * @return boolean Success indicator
 295+ */
 296+ protected function updateInDB() {
 297+ $dbw = wfGetDB( DB_MASTER );
 298+
 299+ return $dbw->update(
 300+ $this->getDBTable(),
 301+ $this->getWriteValues(),
 302+ array( static::getFieldPrefix() . static::getIDField() => $this->getId() )
 303+ );
 304+ }
 305+
 306+ /**
 307+ * Inserts the object into the database.
 308+ *
 309+ * @since 0.1
 310+ *
 311+ * @return boolean Success indicator
 312+ */
 313+ protected function insertIntoDB() {
 314+ $dbw = wfGetDB( DB_MASTER );
 315+
 316+ $result = $dbw->insert(
 317+ static::getDBTable(),
 318+ static::getWriteValues()
 319+ );
 320+
 321+ $this->setField( static::getIDField(), $dbw->insertId() );
 322+
 323+ return $result;
 324+ }
 325+
 326+ /**
 327+ * Removes the object from the database.
 328+ *
 329+ * @since 0.1
 330+ *
 331+ * @return boolean Success indicator
 332+ */
 333+ public function removeFromDB() {
 334+ $dbw = wfGetDB( DB_MASTER );
 335+
 336+ $sucecss = $dbw->delete(
 337+ static::getDBTable(),
 338+ array( static::getFieldPrefix() . static::getIDField() => $this->getId() )
 339+ );
 340+
 341+ if ( $sucecss ) {
 342+ $this->setField( static::getIDField(), null );
 343+ }
 344+
 345+ return $sucecss;
 346+ }
 347+
 348+ /**
 349+ * Return the names of the fields.
 350+ *
 351+ * @since 0.1
 352+ *
 353+ * @return array
 354+ */
 355+ public function getFields() {
 356+ return $this->fields;
 357+ }
 358+
 359+ /**
 360+ * Return the names of the fields.
 361+ *
 362+ * @since 0.1
 363+ *
 364+ * @return array
 365+ */
 366+ public static function getFieldNames() {
 367+ return array_keys( static::getFieldTypes() );
 368+ }
 369+
 370+ /**
 371+ * Return the names of the fields.
 372+ *
 373+ * @since 0.1
 374+ *
 375+ * @return array
 376+ */
 377+ public function getSetFieldNames() {
 378+ return array_keys( $this->fields );
 379+ }
 380+
 381+ /**
 382+ * Sets the value of a field.
 383+ * Strings can be provided for other types,
 384+ * so this method can be called from unserialization handlers.
 385+ *
 386+ * @since 0.1
 387+ *
 388+ * @param string $name
 389+ * @param mixed $value
 390+ *
 391+ * @throws MWException
 392+ */
 393+ public function setField( $name, $value ) {
 394+ $fields = static::getFieldTypes();
 395+
 396+ if ( array_key_exists( $name, $fields ) ) {
 397+ switch ( $fields[$name] ) {
 398+ case 'int':
 399+ $value = (int)$value;
 400+ break;
 401+ case 'bool':
 402+ if ( is_string( $value ) ) {
 403+ $value = $value !== '0';
 404+ } elseif ( is_int( $value ) ) {
 405+ $value = $value !== 0;
 406+ }
 407+ break;
 408+ case 'array':
 409+ if ( is_string( $value ) ) {
 410+ $value = unserialize( $value );
 411+ }
 412+ break;
 413+ case 'id':
 414+ if ( is_string( $value ) ) {
 415+ $value = (int)$value;
 416+ }
 417+ break;
 418+ }
 419+
 420+ $this->fields[$name] = $value;
 421+ } else {
 422+ throw new MWException( 'Attempted to set unknonw field ' . $name );
 423+ }
 424+ }
 425+
 426+ /**
 427+ * Gets the value of a field.
 428+ *
 429+ * @since 0.1
 430+ *
 431+ * @param string $name
 432+ *
 433+ * @throws MWException
 434+ * @return mixed
 435+ */
 436+ public function getField( $name ) {
 437+ if ( $this->hasField( $name ) ) {
 438+ return $this->fields[$name];
 439+ } else {
 440+ throw new MWException( 'Attempted to get not-set field ' . $name );
 441+ }
 442+ }
 443+
 444+ /**
 445+ * Remove a field.
 446+ *
 447+ * @since 0.1
 448+ *
 449+ * @param string $name
 450+ */
 451+ public function removeField( $name ) {
 452+ unset( $this->fields[$name] );
 453+ }
 454+
 455+ /**
 456+ * Returns the objects database id.
 457+ *
 458+ * @since 0.1
 459+ *
 460+ * @return integer|null
 461+ */
 462+ public function getId() {
 463+ return $this->getField( static::getIDField() );
 464+ }
 465+
 466+ /**
 467+ * Sets the objects database id.
 468+ *
 469+ * @since 0.1
 470+ *
 471+ * @param integere|null $id
 472+ */
 473+ public function setId( $id ) {
 474+ return $this->setField( static::getIDField(), $id );
 475+ }
 476+
 477+ /**
 478+ * Gets if a certain field is set.
 479+ *
 480+ * @since 0.1
 481+ *
 482+ * @param string $name
 483+ *
 484+ * @return boolean
 485+ */
 486+ public function hasField( $name ) {
 487+ return array_key_exists( $name, $this->fields );
 488+ }
 489+
 490+ /**
 491+ * Gets if the object can take a certain field.
 492+ *
 493+ * @since 0.1
 494+ *
 495+ * @param string $name
 496+ *
 497+ * @return boolean
 498+ */
 499+ public static function canHasField( $name ) {
 500+ return array_key_exists( $name, static::getFieldTypes() );
 501+ }
 502+
 503+ /**
 504+ * Gets if the id field is set.
 505+ *
 506+ * @since 0.1
 507+ *
 508+ * @return boolean
 509+ */
 510+ public function hasIdField() {
 511+ return $this->hasField( static::getIDField() )
 512+ && !is_null( $this->getField( static::getIDField() ) );
 513+ }
 514+
 515+ /**
 516+ * Sets multiple fields.
 517+ *
 518+ * @since 0.1
 519+ *
 520+ * @param array $fields The fields to set
 521+ * @param boolean $override Override already set fields with the provided values?
 522+ */
 523+ public function setFields( array $fields, $override = true ) {
 524+ foreach ( $fields as $name => $value ) {
 525+ if ( $override || !$this->hasField( $name ) ) {
 526+ $this->setField( $name, $value );
 527+ }
 528+ }
 529+ }
 530+
 531+ /**
 532+ * Gets the fields => values to write to the surveys table.
 533+ *
 534+ * @since 0.1
 535+ *
 536+ * @return array
 537+ */
 538+ protected function getWriteValues() {
 539+ $values = array();
 540+
 541+ foreach ( static::getFieldTypes() as $name => $type ) {
 542+ if ( array_key_exists( $name, $this->fields ) ) {
 543+ $value = $this->fields[$name];
 544+
 545+ switch ( $type ) {
 546+ case 'array':
 547+ $value = serialize( (array)$value );
 548+ }
 549+
 550+ $values[static::getFieldPrefix() . $name] = $value;
 551+ }
 552+ }
 553+
 554+ return $values;
 555+ }
 556+
 557+ /**
 558+ * Takes in a field or array of fields and returns an
 559+ * array with their prefixed versions, ready for db usage.
 560+ *
 561+ * @since 0.1
 562+ *
 563+ * @param array|string $fields
 564+ *
 565+ * @return array
 566+ */
 567+ public static function getPrefixedFields( $fields ) {
 568+ $fields = (array)$fields;
 569+
 570+ foreach ( $fields as &$field ) {
 571+ $field = static::getFieldPrefix() . $field;
 572+ }
 573+
 574+ return $fields;
 575+ }
 576+
 577+ /**
 578+ * Takes in a field and returns an it's prefixed version, ready for db usage.
 579+ *
 580+ * @since 0.1
 581+ *
 582+ * @param string $field
 583+ *
 584+ * @return string
 585+ */
 586+ public static function getPrefixedField( $field ) {
 587+ return static::getFieldPrefix() . $field;
 588+ }
 589+
 590+ /**
 591+ * Takes in an associative array with field names as keys and
 592+ * their values as value. The field names are prefixed with the
 593+ * db field prefix.
 594+ *
 595+ * @since 0.1
 596+ *
 597+ * @param array $values
 598+ *
 599+ * @return array
 600+ */
 601+ public static function getPrefixedValues( array $values ) {
 602+ $prefixedValues = array();
 603+
 604+ foreach ( $values as $field => $value ) {
 605+ $prefixedValues[static::getFieldPrefix() . $field] = $value;
 606+ }
 607+
 608+ return $prefixedValues;
 609+ }
 610+
 611+ /**
 612+ * Serializes the survey to an associative array which
 613+ * can then easily be converted into JSON or similar.
 614+ *
 615+ * @since 0.1
 616+ *
 617+ * @param null|array $props
 618+ *
 619+ * @return array
 620+ */
 621+ public function toArray( $fields = null ) {
 622+ $data = array();
 623+ $setFields = array();
 624+
 625+ if ( !is_array( $fields ) ) {
 626+ $setFields = $this->getSetFieldNames();
 627+ } else {
 628+ foreach ( $fields as $field ) {
 629+ if ( $this->hasField( $field ) ) {
 630+ $setFields[] = $field;
 631+ }
 632+ }
 633+ }
 634+
 635+ foreach ( $setFields as $field ) {
 636+ $data[$field] = $this->getField( $field );
 637+ }
 638+
 639+ return $data;
 640+ }
 641+
 642+ public function loadDefaults( $override = true ) {
 643+ $this->setFields( static::getDefaults(), $override );
 644+ }
 645+
 646+ /**
 647+ * Returns a list of default field values.
 648+ * field name => field value
 649+ *
 650+ * @since 0.1
 651+ *
 652+ * @return array
 653+ */
 654+ public static function getDefaults() {
 655+ return array();
 656+ }
 657+
 658+ /**
 659+ * Get API parameters for the fields supported by this object.
 660+ *
 661+ * @since 0.1
 662+ *
 663+ * @param boolean $requireParams
 664+ *
 665+ * @return array
 666+ */
 667+ public static function getAPIParams( $requireParams = true ) {
 668+ $typeMap = array(
 669+ 'id' => 'integer',
 670+ 'int' => 'integer',
 671+ 'str' => 'string',
 672+ 'bool' => 'integer',
 673+ 'array' => 'string'
 674+ );
 675+
 676+ $params = array();
 677+ $defaults = static::getDefaults();
 678+
 679+ foreach ( static::getFieldTypes() as $field => $type ) {
 680+ if ( $field == static::getIDField() ) {
 681+ continue;
 682+ }
 683+
 684+ $hasDefault = array_key_exists( $field, $defaults );
 685+
 686+ $params[$field] = array(
 687+ ApiBase::PARAM_TYPE => $typeMap[$type],
 688+ ApiBase::PARAM_REQUIRED => $requireParams && !$hasDefault
 689+ );
 690+
 691+ if ( $type == 'array' ) {
 692+ $params[$field][ApiBase::PARAM_ISMULTI] = true;
 693+ }
 694+
 695+ if ( $hasDefault ) {
 696+ $default = is_array( $defaults[$field] ) ? implode( '|', $defaults[$field] ) : $defaults[$field];
 697+ $params[$field][ApiBase::PARAM_DFLT] = $default;
 698+ }
 699+ }
 700+
 701+ return $params;
 702+ }
 703+
 704+ /**
 705+ * Takes an array of field name => field value and
 706+ * filters it on valid field names.
 707+ *
 708+ * @since 0.1
 709+ *
 710+ * @param array $conditions
 711+ * @param false|integer $id
 712+ *
 713+ * @return array
 714+ */
 715+ public static function getValidFields( array $conditions, $id = false ) {
 716+ $validFields = array();
 717+
 718+ $fields = static::getFieldTypes();
 719+
 720+ foreach ( $conditions as $name => $value ) {
 721+ if ( array_key_exists( $name, $fields ) ) {
 722+ $validFields[$name] = $value;
 723+ }
 724+ }
 725+
 726+ if ( $id !== false ) {
 727+ $validParams[static::getIDField()] = $id;
 728+ }
 729+
 730+ return $validFields;
 731+ }
 732+
 733+}
Property changes on: tags/extensions/Survey/REL_0_1/includes/SurveyDBClass.php
___________________________________________________________________
Added: svn:eol-style
1734 + native
Index: tags/extensions/Survey/REL_0_1/includes/SurveySubmission.php
@@ -0,0 +1,110 @@
 2+<?php
 3+
 4+/**
 5+ * Simple survey submission object class.
 6+ *
 7+ * @since 0.1
 8+ *
 9+ * @file SurveySubmission.php
 10+ * @ingroup Survey
 11+ *
 12+ * @licence GNU GPL v3 or later
 13+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
 14+ */
 15+class SurveySubmission extends SurveyDBClass {
 16+
 17+ /**
 18+ * @see SurveyDBClass::getDBTable()
 19+ */
 20+ public static function getDBTable() {
 21+ return 'survey_submissions';
 22+ }
 23+
 24+ /**
 25+ * Gets the db field prefix.
 26+ *
 27+ * @since 0.1
 28+ *
 29+ * @return string
 30+ */
 31+ protected static function getFieldPrefix() {
 32+ return 'submission_';
 33+ }
 34+
 35+ /**
 36+ * Returns an array with the fields and their types this object contains.
 37+ * This corresponds directly to the fields in the database, without prefix.
 38+ *
 39+ * survey_id:
 40+ * The ID of the survey this submission is for.
 41+ *
 42+ * page_id:
 43+ * The ID of the page this submission was made on.
 44+ *
 45+ * user_name:
 46+ * The name of the user that made the submission (username or ip).
 47+ *
 48+ * time:
 49+ * Timestamp idnicating when the submission was made.
 50+ *
 51+ * @since 0.1
 52+ *
 53+ * @return array
 54+ */
 55+ protected static function getFieldTypes() {
 56+ return array(
 57+ 'id' => 'id',
 58+ 'survey_id' => 'id',
 59+ 'page_id' => 'id',
 60+ 'user_name' => 'str',
 61+ 'time' => 'str',
 62+ );
 63+ }
 64+
 65+ /**
 66+ * List of answers.
 67+ *
 68+ * @since 0.1
 69+ * @var array of SurveyAnswer
 70+ */
 71+ protected $answers;
 72+
 73+
 74+ public function addAnswer( SurveyAnswer $answer ) {
 75+ $this->answers[] = $answer;
 76+ }
 77+
 78+ public function setAnswers( array $answers ) {
 79+ $this->answers = $answers;
 80+ }
 81+
 82+ public function getAnswers() {
 83+ return $this->answers;
 84+ }
 85+
 86+ /**
 87+ * Writes the answer to the database, either updating it
 88+ * when it already exists, or inserting it when it doesn't.
 89+ *
 90+ * @since 0.1
 91+ *
 92+ * @return boolean Success indicator
 93+ */
 94+ public function writeToDB() {
 95+ $success = parent::writeToDB();
 96+
 97+ if ( $success ) {
 98+ $this->writeAnswersToDB();
 99+ }
 100+
 101+ return $success;
 102+ }
 103+
 104+ public function writeAnswersToDB() {
 105+ foreach ( $this->answers as /* SurveyAnswer */ $answer ) {
 106+ $answer->setField( 'submission_id', $this->getId() );
 107+ $answer->writeToDB();
 108+ }
 109+ }
 110+
 111+}
Property changes on: tags/extensions/Survey/REL_0_1/includes/SurveySubmission.php
___________________________________________________________________
Added: svn:eol-style
1112 + native
Index: tags/extensions/Survey/REL_0_1/includes/SurveyTag.php
@@ -0,0 +1,108 @@
 2+<?php
 3+
 4+/**
 5+ * Class to render survey tags.
 6+ *
 7+ * @since 0.1
 8+ *
 9+ * @file SurveyTag.php
 10+ * @ingroup Survey
 11+ *
 12+ * @licence GNU GPL v3+
 13+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
 14+ */
 15+class SurveyTag {
 16+
 17+ /**
 18+ * List of survey parameters.
 19+ *
 20+ * @since 0.1
 21+ *
 22+ * @var array
 23+ */
 24+ protected $parameters;
 25+
 26+ protected $contents;
 27+
 28+ /**
 29+ * Constructor.
 30+ *
 31+ * @since 0.1
 32+ *
 33+ * @param array $args
 34+ * @param string|null $contents
 35+ */
 36+ public function __construct( array $args, $contents = null ) {
 37+ $this->parameters = $args;
 38+ $this->contents = $contents;
 39+
 40+ $args = filter_var_array( $args, $this->getSurveyParameters() );
 41+
 42+ if ( is_array( $args ) ) {
 43+ $this->parameters = array();
 44+
 45+ foreach ( $args as $name => $value ) {
 46+ if ( !is_null( $value ) && $value !== false ) {
 47+ $this->parameters['survey-data-' . $name] = $value;
 48+ }
 49+ }
 50+
 51+ $this->parameters['class'] = 'surveytag';
 52+ $this->parameters['survey-data-token'] =
 53+ $GLOBALS['wgUser']->editToken( serialize( array( 'submitsurvey', $GLOBALS['wgUser']->getName() ) ) );
 54+ } else {
 55+ throw new MWException( 'Invalid parameters for survey tag.' );
 56+ }
 57+ }
 58+
 59+ /**
 60+ * Renrder the survey div.
 61+ *
 62+ * @since 0.1
 63+ *
 64+ * @param Parser $parser
 65+ *
 66+ * @return string
 67+ */
 68+ public function render( Parser $parser ) {
 69+ static $loadedJs = false;
 70+
 71+ if ( !$loadedJs ) {
 72+ $parser->getOutput()->addModules( 'ext.survey.tag' );
 73+ $parser->getOutput()->addHeadItem(
 74+ Skin::makeVariablesScript( array(
 75+ 'wgSurveyDebug' => SurveySettings::get( 'JSDebug' )
 76+ ) )
 77+ );
 78+ }
 79+
 80+ return Html::element(
 81+ 'span',
 82+ $this->parameters,
 83+ $this->contents
 84+ );
 85+ }
 86+
 87+ /**
 88+ *
 89+ *
 90+ * @since 0.1
 91+ *
 92+ * @param array $args
 93+ *
 94+ * @return array
 95+ */
 96+ protected function getSurveyParameters() {
 97+ return array(
 98+ 'id' => array( 'filter' => FILTER_VALIDATE_INT, 'options' => array( 'min_range' => 1 ) ),
 99+ 'name' => array(),
 100+ 'cookie' => array(),
 101+ 'title' => array(),
 102+ 'require-enabled' => array( 'filter' => FILTER_VALIDATE_INT, 'options' => array( 'min_range' => 0, 'max_range' => 1 ) ),
 103+ 'expiry' => array( 'filter' => FILTER_VALIDATE_INT, 'options' => array( 'min_range' => 0 ) ),
 104+ 'min-pages' => array( 'filter' => FILTER_VALIDATE_INT, 'options' => array( 'min_range' => 0 ) ),
 105+ 'ratio' => array( 'filter' => FILTER_VALIDATE_INT, 'options' => array( 'min_range' => 0, 'max_range' => 100 ) ),
 106+ );
 107+ }
 108+
 109+}
Property changes on: tags/extensions/Survey/REL_0_1/includes/SurveyTag.php
___________________________________________________________________
Added: svn:eol-style
1110 + native
Index: tags/extensions/Survey/REL_0_1/includes/SurveyAnswer.php
@@ -0,0 +1,60 @@
 2+<?php
 3+
 4+/**
 5+ * Simple survey submission object class.
 6+ *
 7+ * @since 0.1
 8+ *
 9+ * @file SurveySubmission.php
 10+ * @ingroup Survey
 11+ *
 12+ * @licence GNU GPL v3 or later
 13+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
 14+ */
 15+class SurveyAnswer extends SurveyDBClass {
 16+
 17+ /**
 18+ * @see SurveyDBClass::getDBTable()
 19+ */
 20+ public static function getDBTable() {
 21+ return 'survey_answers';
 22+ }
 23+
 24+ /**
 25+ * Gets the db field prefix.
 26+ *
 27+ * @since 0.1
 28+ *
 29+ * @return string
 30+ */
 31+ protected static function getFieldPrefix() {
 32+ return 'answer_';
 33+ }
 34+
 35+ /**
 36+ * Returns an array with the fields and their types this object contains.
 37+ * This corresponds directly to the fields in the database, without prefix.
 38+ *
 39+ * text:
 40+ * The answer text.
 41+ *
 42+ * submission_id:
 43+ * The ID of the submission this answer is part of.
 44+ *
 45+ * question_id:
 46+ * The ID of the question this answer corresponds to.
 47+ *
 48+ * @since 0.1
 49+ *
 50+ * @return array
 51+ */
 52+ protected static function getFieldTypes() {
 53+ return array(
 54+ 'id' => 'id',
 55+ 'text' => 'str',
 56+ 'submission_id' => 'id',
 57+ 'question_id' => 'id',
 58+ );
 59+ }
 60+
 61+}
Property changes on: tags/extensions/Survey/REL_0_1/includes/SurveyAnswer.php
___________________________________________________________________
Added: svn:eol-style
162 + native
Index: tags/extensions/Survey/REL_0_1/includes/Survey.class.php
@@ -0,0 +1,338 @@
 2+<?php
 3+
 4+/**
 5+ * Simple Survey object class.
 6+ *
 7+ * @since 0.1
 8+ *
 9+ * @file Survey.class.php
 10+ * @ingroup Survey
 11+ *
 12+ * @licence GNU GPL v3 or later
 13+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
 14+ */
 15+class Survey extends SurveyDBClass {
 16+
 17+ public static $USER_ALL = 0;
 18+ public static $USER_LOGGEDIN = 1;
 19+ public static $USER_CONFIRMED = 2;
 20+ public static $USER_EDITOR = 3;
 21+ public static $USER_ANON = 4;
 22+
 23+ /**
 24+ * @see SurveyDBClass::getDBTable()
 25+ */
 26+ public static function getDBTable() {
 27+ return 'surveys';
 28+ }
 29+
 30+ /**
 31+ * Returns an array with the fields and their types this object contains.
 32+ * This corresponds directly to the fields in the database, without prefix.
 33+ *
 34+ * @since 0.1
 35+ *
 36+ * @return array
 37+ */
 38+ protected static function getFieldTypes() {
 39+ return array(
 40+ 'id' => 'id',
 41+ 'name' => 'str',
 42+ 'title' => 'str',
 43+ 'enabled' => 'bool',
 44+ 'header' => 'str',
 45+ 'footer' => 'str',
 46+ 'thanks' => 'str',
 47+ 'user_type' => 'int',
 48+ 'namespaces' => 'array',
 49+ 'ratio' => 'int',
 50+ 'expiry' => 'int',
 51+ 'min_pages' => 'int'
 52+ );
 53+ }
 54+
 55+ /**
 56+ * Returns a list of default field values.
 57+ * field name => field value
 58+ *
 59+ * @since 0.1
 60+ *
 61+ * @return array
 62+ */
 63+ public static function getDefaults() {
 64+ return array(
 65+ 'name' => '',
 66+ 'title' => '',
 67+ 'enabled' => SurveySettings::get( 'defaultEnabled' ) ? '1' : '0',
 68+ 'header' => 'Thank you for taking this short survey. Please fill out the following questions:',
 69+ 'footer' => '',
 70+ 'thanks' => 'Thank you for your responses.',
 71+ 'user_type' => SurveySettings::get( 'defaultUserType' ),
 72+ 'namespaces' => SurveySettings::get( 'defaultNamespaces' ),
 73+ 'ratio' => SurveySettings::get( 'defaultRatio' ),
 74+ 'expiry' => SurveySettings::get( 'defaultExpiry' ),
 75+ 'min_pages' => SurveySettings::get( 'defaultMinPages' ),
 76+ );
 77+ }
 78+
 79+ /**
 80+ * Gets the db field prefix.
 81+ *
 82+ * @since 0.1
 83+ *
 84+ * @return string
 85+ */
 86+ protected static function getFieldPrefix() {
 87+ return 'survey_';
 88+ }
 89+
 90+ /**
 91+ * Returns the Survey with specified name, or false if there is no such survey.
 92+ *
 93+ * @since 0.1
 94+ *
 95+ * @param string $surveyName
 96+ * @param array|null $fields
 97+ * @param boolean $loadQuestions
 98+ *
 99+ * @return Survey or false
 100+ */
 101+ public static function newFromName( $surveyName, $fields = null, $loadQuestions = true ) {
 102+ return self::newFromDB( array( 'name' => $surveyName ), $fields, $loadQuestions );
 103+ }
 104+
 105+ /**
 106+ * Returns the Survey with specified ID, or false if there is no such survey.
 107+ *
 108+ * @since 0.1
 109+ *
 110+ * @param integer surveyId
 111+ * @param array|null $fields
 112+ * @param boolean $loadQuestions
 113+ *
 114+ * @return Survey or false
 115+ */
 116+ public static function newFromId( $surveyId, $fields = null, $loadQuestions = true ) {
 117+ return self::newFromDB( array( 'id' => $surveyId ), $fields, $loadQuestions );
 118+ }
 119+
 120+ /**
 121+ * Returns a new instance of Survey build from a database result
 122+ * obtained by doing a select with the porvided conditions on the surveys table.
 123+ * If no survey matches the conditions, false will be returned.
 124+ *
 125+ * @since 0.1
 126+ *
 127+ * @param array $conditions
 128+ * @param array|null $fields
 129+ * @param boolean $loadQuestions
 130+ *
 131+ * @return Survey or false
 132+ */
 133+ public static function newFromDB( array $conditions, $fields = null, $loadQuestions = true ) {
 134+ $survey = self::selectRow( $fields, $conditions );
 135+
 136+ if ( $survey !== false && $loadQuestions ) {
 137+ $survey->loadQuestionsFromDB();
 138+ }
 139+
 140+ return $survey;
 141+ }
 142+
 143+ /**
 144+ * The questions that go with this survey.
 145+ *
 146+ * @since 0.1
 147+ * @var array of SurveyQuestion
 148+ */
 149+ protected $questions;
 150+
 151+ /**
 152+ * Constructor.
 153+ *
 154+ * @since 0.1
 155+ *
 156+ * @param array|null $fields
 157+ * @param boolean $loadDefaults
 158+ * @param array $questions
 159+ */
 160+ public function __construct( $fields, $loadDefaults = false, array $questions = array() ) {
 161+ parent::__construct( $fields, $loadDefaults );
 162+ $this->setQuestions( $questions );
 163+ }
 164+
 165+ /**
 166+ * Load the surveys questions from the database.
 167+ *
 168+ * @since 0.1
 169+ */
 170+ public function loadQuestionsFromDB() {
 171+ $this->questions = SurveyQuestion::getQuestionsForSurvey( $this->getId() );
 172+ }
 173+
 174+ /**
 175+ * Writes the surveyand it's questions to the database, either updating it
 176+ * when it already exists, or inserting it when it doesn't.
 177+ *
 178+ * @since 0.1
 179+ *
 180+ * @return boolean Success indicator
 181+ */
 182+ public function writeToDB() {
 183+ $success = parent::writeToDB();
 184+
 185+ if ( $success ) {
 186+ $success = $this->writeQuestionsToDB();
 187+ }
 188+
 189+ return $success;
 190+ }
 191+
 192+ /**
 193+ * Writes the surveys questions to the database.
 194+ *
 195+ * @since 0.1
 196+ *
 197+ * @return boolean Success indicator
 198+ */
 199+ public function writeQuestionsToDB() {
 200+ $success = true;
 201+
 202+ $dbw = wfGetDB( DB_MASTER );
 203+
 204+ $dbw->begin();
 205+
 206+ SurveyQuestion::update(
 207+ array( 'removed' => 1 ),
 208+ array( 'survey_id' => $this->getId() )
 209+ );
 210+
 211+ foreach ( $this->questions as /* SurveyQuestion */ $question ) {
 212+ $question->setField( 'survey_id', $this->getId() );
 213+ $success = $question->writeToDB() && $success;
 214+ }
 215+
 216+ $dbw->commit();
 217+
 218+ return $success;
 219+ }
 220+
 221+ /**
 222+ * Returns the surveys questions.
 223+ *
 224+ * @since 0.1
 225+ *
 226+ * @return array of SurveyQuestion
 227+ */
 228+ public function getQuestions() {
 229+ return $this->questions;
 230+ }
 231+
 232+ /**
 233+ * Sets the surveys questions.
 234+ *
 235+ * @since 0.1
 236+ *
 237+ * @param array $questions list of SurveyQuestion
 238+ */
 239+ public function setQuestions( array /* of SurveyQuestion */ $questions ) {
 240+ $this->questions = $questions;
 241+ }
 242+
 243+ /**
 244+ * Serializes the survey to an associative array which
 245+ * can then easily be converted into JSON or similar.
 246+ *
 247+ * @since 0.1
 248+ *
 249+ * @param null|array $fields
 250+ *
 251+ * @return array
 252+ */
 253+ public function toArray( $fields = null ) {
 254+ $data = parent::toArray( $fields );
 255+
 256+ $data['questions'] = array();
 257+
 258+ foreach ( $this->questions as /* SurveyQuestion */ $question ) {
 259+ $data['questions'][] = $question->toArray();
 260+ }
 261+
 262+ return $data;
 263+ }
 264+
 265+ /**
 266+ * Removes the object from the database.
 267+ *
 268+ * @since 0.1
 269+ *
 270+ * @return boolean Success indicator
 271+ */
 272+ public function removeFromDB() {
 273+ $dbr= wfgetDB( DB_SLAVE );
 274+
 275+ $submissionsForSurvey = $dbr->select(
 276+ 'survey_submissions',
 277+ array( 'submission_id' ),
 278+ array( 'submission_survey_id' => $this->getId() )
 279+ );
 280+
 281+ $dbw = wfGetDB( DB_MASTER );
 282+
 283+ $dbw->begin();
 284+
 285+ $sucecss = parent::removeFromDB();
 286+
 287+ $sucecss = $dbw->delete(
 288+ 'survey_questions',
 289+ array( 'question_survey_id' => $this->getId() )
 290+ ) && $sucecss;
 291+
 292+ $sucecss = $dbw->delete(
 293+ 'survey_submissions',
 294+ array( 'submission_survey_id' => $this->getId() )
 295+ ) && $sucecss;
 296+
 297+ foreach ( $submissionsForSurvey as $nr => $submission ) {
 298+ $sucecss = $dbw->delete(
 299+ 'survey_answers',
 300+ array( 'answer_submission_id' => $submission->id )
 301+ ) && $sucecss;
 302+
 303+ if ( $nr % 500 == 0 ) {
 304+ $dbw->commit();
 305+ $dbw->begin();
 306+ }
 307+ }
 308+
 309+ $dbw->commit();
 310+
 311+ return $sucecss;
 312+ }
 313+
 314+ /**
 315+ * Returns the survey user types the provided user has.
 316+ *
 317+ * @since 0.1
 318+ *
 319+ * @param User $user
 320+ *
 321+ * @return array of Survey::$USER_
 322+ */
 323+ public static function getTypesForUser( User $user ) {
 324+ $userTypes = array( Survey::$USER_ALL );
 325+
 326+ $userTypes[] = $user->isLoggedIn() ? Survey::$USER_LOGGEDIN : Survey::$USER_ANON;
 327+
 328+ if ( $user->isEmailConfirmed() ) {
 329+ $userTypes[] = Survey::$USER_CONFIRMED;
 330+ }
 331+
 332+ if ( $user->getEditCount() > 0 ) {
 333+ $userTypes[] = Survey::$USER_EDITOR;
 334+ }
 335+
 336+ return $userTypes;
 337+ }
 338+
 339+}
Property changes on: tags/extensions/Survey/REL_0_1/includes/Survey.class.php
___________________________________________________________________
Added: svn:eol-style
1340 + native
Index: tags/extensions/Survey/REL_0_1/includes/SurveyCompat.php
@@ -0,0 +1,20 @@
 2+<?php
 3+
 4+/**
 5+ * Compatibility methods needed for Survey to work with older
 6+ * versions of MediaWiki.
 7+ *
 8+ * @since 0.1
 9+ *
 10+ * @file SurveyCompat.php
 11+ * @ingroup Survey
 12+ *
 13+ * @licence GNU GPL v3 or later
 14+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
 15+ */
 16+
 17+class SurveyCompat {
 18+
 19+
 20+
 21+}
\ No newline at end of file
Property changes on: tags/extensions/Survey/REL_0_1/includes/SurveyCompat.php
___________________________________________________________________
Added: svn:eol-style
122 + native
Index: tags/extensions/Survey/REL_0_1/includes/SurveyQuestion.php
@@ -0,0 +1,189 @@
 2+<?php
 3+
 4+/**
 5+ * Simple survey question object class.
 6+ *
 7+ * @since 0.1
 8+ *
 9+ * @file SurveyQuestion.php
 10+ * @ingroup Survey
 11+ *
 12+ * @licence GNU GPL v3 or later
 13+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
 14+ */
 15+class SurveyQuestion extends SurveyDBClass {
 16+
 17+ public static $TYPE_TEXT = 0;
 18+ public static $TYPE_NUMBER = 1;
 19+ public static $TYPE_SELECT = 2;
 20+ public static $TYPE_RADIO = 3;
 21+ public static $TYPE_TEXTAREA = 4;
 22+ public static $TYPE_CHECK = 5;
 23+
 24+ /**
 25+ * @see SurveyDBClass::getDBTable()
 26+ */
 27+ public static function getDBTable() {
 28+ return 'survey_questions';
 29+ }
 30+
 31+ /**
 32+ * Gets the db field prefix.
 33+ *
 34+ * @since 0.1
 35+ *
 36+ * @return string
 37+ */
 38+ protected static function getFieldPrefix() {
 39+ return 'question_';
 40+ }
 41+
 42+ /**
 43+ * Returns an array with the fields and their types this object contains.
 44+ * This corresponds directly to the fields in the database, without prefix.
 45+ *
 46+ * survey_id:
 47+ * The ID of the survey this question belongs to.
 48+ * This can be null. When written to the db via Survey::writeToDB of
 49+ * a Survey holding this question, the survey ID will first be set.
 50+ *
 51+ * text:
 52+ * The question text.
 53+ *
 54+ * type:
 55+ * The question type.
 56+ *
 57+ * required:
 58+ * Indicated if the question is required,
 59+ * ie if the user can not submit the survey without answering it.
 60+ *
 61+ * answers:
 62+ * List of allowed values for the question.
 63+ * Empty list for no restrictions.
 64+ *
 65+ * removed:
 66+ * Indicated if the question was removed.
 67+ * Removed questions are kept in the db so their answers can
 68+ * still be used untill the survey itself gets removed.
 69+ *
 70+ * @since 0.1
 71+ *
 72+ * @return array
 73+ */
 74+ protected static function getFieldTypes() {
 75+ return array(
 76+ 'id' => 'id',
 77+ 'survey_id' => 'int',
 78+ 'text' => 'str',
 79+ 'type' => 'int',
 80+ 'required' => 'bool',
 81+ 'answers' => 'array',
 82+ 'removed' => 'bool',
 83+ );
 84+ }
 85+
 86+ /**
 87+ * Returns a list of default field values.
 88+ * field name => field value
 89+ *
 90+ * @since 0.1
 91+ *
 92+ * @return array
 93+ */
 94+ public static function getDefaults() {
 95+ return array(
 96+ 'text' => '',
 97+ 'type' => self::$TYPE_TEXT,
 98+ 'required' => false,
 99+ 'answers' => array(),
 100+ 'removed' => false,
 101+ );
 102+ }
 103+
 104+ /**
 105+ * Unserialization method for survey question data passed as a multi-value API parameter.
 106+ * Uses base64 and replaces padding = by !, so the values does not contain any = or |.
 107+ *
 108+ * @since 0.1
 109+ *
 110+ * @param string $args
 111+ *
 112+ * @return SurveyQuestion
 113+ */
 114+ public static function newFromUrlData( $args ) {
 115+ $args = (array)FormatJson::decode( base64_decode( str_replace( '!', '=', $args ) ) );
 116+ return self::newFromArray( $args );
 117+ }
 118+
 119+ /**
 120+ * Serialization method for survey questions that need to be passed via multi-value API parameter.
 121+ * Uses base64 and replaces padding = by !, so the values does not contain any = or |.
 122+ *
 123+ * @since 0.1
 124+ *
 125+ * @return string
 126+ */
 127+ public function toUrlData() {
 128+ return str_replace( '=', '!', base64_encode( FormatJson::encode( $this->toArray() ) ) );
 129+ }
 130+
 131+ /**
 132+ * Returns the questions for the specified survey.
 133+ *
 134+ * @since 0.1
 135+ *
 136+ * @param integer $surveyId
 137+ * @param boolean $incRemoved
 138+ *
 139+ * @return array of SurveyQuestion
 140+ */
 141+ public static function getQuestionsForSurvey( $surveyId, $incRemoved = false ) {
 142+ $conditions = array( 'survey_id' => $surveyId );
 143+
 144+ if ( $incRemoved === false ) {
 145+ $conditions['removed'] = 0;
 146+ }
 147+
 148+ return self::select( null, $conditions );
 149+ }
 150+
 151+ /**
 152+ * Gets the message for a question type.
 153+ * The message key, not the internationalized string.
 154+ *
 155+ * @since 0.1
 156+ *
 157+ * @param integer $type
 158+ *
 159+ * @return string
 160+ */
 161+ public static function getTypeMessage( $type ) {
 162+ static $messageMap = false;
 163+
 164+ if ( $messageMap === false ) {
 165+ $messageMap = array(
 166+ self::$TYPE_TEXT => 'text',
 167+ self::$TYPE_NUMBER => 'number',
 168+ self::$TYPE_SELECT => 'select',
 169+ self::$TYPE_RADIO => 'radio',
 170+ self::$TYPE_TEXTAREA => 'textarea',
 171+ self::$TYPE_CHECK => 'check',
 172+ );
 173+ }
 174+
 175+ return 'survey-question-type-' . $messageMap[$type];
 176+ }
 177+
 178+ /**
 179+ * Returns if the type of the question is restrictive,
 180+ * ie if the question input only allows certain answers.
 181+ *
 182+ * @since 0.1
 183+ *
 184+ * @return boolean
 185+ */
 186+ public function isRestrictiveType() {
 187+ return in_array( $this->getField( 'type' ), array( self::$TYPE_SELECT, self::$TYPE_RADIO, self::$TYPE_CHECK ) );
 188+ }
 189+
 190+}
Property changes on: tags/extensions/Survey/REL_0_1/includes/SurveyQuestion.php
___________________________________________________________________
Added: svn:eol-style
1191 + native
Index: tags/extensions/Survey/REL_0_1/COPYING
@@ -0,0 +1,682 @@
 2+The license text below "----" applies to all files within this distribution, other
 3+than those that are in a directory which contains files named "LICENSE" or
 4+"COPYING", or a subdirectory thereof. For those files, the license text contained in
 5+said file overrides any license information contained in directories of smaller depth.
 6+Alternative licenses are typically used for software that is provided by external
 7+parties, and merely packaged with this software for convenience.
 8+----
 9+
 10+ GNU GENERAL PUBLIC LICENSE
 11+ Version 3, 29 June 2007
 12+
 13+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
 14+ Everyone is permitted to copy and distribute verbatim copies
 15+ of this license document, but changing it is not allowed.
 16+
 17+ Preamble
 18+
 19+ The GNU General Public License is a free, copyleft license for
 20+software and other kinds of works.
 21+
 22+ The licenses for most software and other practical works are designed
 23+to take away your freedom to share and change the works. By contrast,
 24+the GNU General Public License is intended to guarantee your freedom to
 25+share and change all versions of a program--to make sure it remains free
 26+software for all its users. We, the Free Software Foundation, use the
 27+GNU General Public License for most of our software; it applies also to
 28+any other work released this way by its authors. You can apply it to
 29+your programs, too.
 30+
 31+ When we speak of free software, we are referring to freedom, not
 32+price. Our General Public Licenses are designed to make sure that you
 33+have the freedom to distribute copies of free software (and charge for
 34+them if you wish), that you receive source code or can get it if you
 35+want it, that you can change the software or use pieces of it in new
 36+free programs, and that you know you can do these things.
 37+
 38+ To protect your rights, we need to prevent others from denying you
 39+these rights or asking you to surrender the rights. Therefore, you have
 40+certain responsibilities if you distribute copies of the software, or if
 41+you modify it: responsibilities to respect the freedom of others.
 42+
 43+ For example, if you distribute copies of such a program, whether
 44+gratis or for a fee, you must pass on to the recipients the same
 45+freedoms that you received. You must make sure that they, too, receive
 46+or can get the source code. And you must show them these terms so they
 47+know their rights.
 48+
 49+ Developers that use the GNU GPL protect your rights with two steps:
 50+(1) assert copyright on the software, and (2) offer you this License
 51+giving you legal permission to copy, distribute and/or modify it.
 52+
 53+ For the developers' and authors' protection, the GPL clearly explains
 54+that there is no warranty for this free software. For both users' and
 55+authors' sake, the GPL requires that modified versions be marked as
 56+changed, so that their problems will not be attributed erroneously to
 57+authors of previous versions.
 58+
 59+ Some devices are designed to deny users access to install or run
 60+modified versions of the software inside them, although the manufacturer
 61+can do so. This is fundamentally incompatible with the aim of
 62+protecting users' freedom to change the software. The systematic
 63+pattern of such abuse occurs in the area of products for individuals to
 64+use, which is precisely where it is most unacceptable. Therefore, we
 65+have designed this version of the GPL to prohibit the practice for those
 66+products. If such problems arise substantially in other domains, we
 67+stand ready to extend this provision to those domains in future versions
 68+of the GPL, as needed to protect the freedom of users.
 69+
 70+ Finally, every program is threatened constantly by software patents.
 71+States should not allow patents to restrict development and use of
 72+software on general-purpose computers, but in those that do, we wish to
 73+avoid the special danger that patents applied to a free program could
 74+make it effectively proprietary. To prevent this, the GPL assures that
 75+patents cannot be used to render the program non-free.
 76+
 77+ The precise terms and conditions for copying, distribution and
 78+modification follow.
 79+
 80+ TERMS AND CONDITIONS
 81+
 82+ 0. Definitions.
 83+
 84+ "This License" refers to version 3 of the GNU General Public License.
 85+
 86+ "Copyright" also means copyright-like laws that apply to other kinds of
 87+works, such as semiconductor masks.
 88+
 89+ "The Program" refers to any copyrightable work licensed under this
 90+License. Each licensee is addressed as "you". "Licensees" and
 91+"recipients" may be individuals or organizations.
 92+
 93+ To "modify" a work means to copy from or adapt all or part of the work
 94+in a fashion requiring copyright permission, other than the making of an
 95+exact copy. The resulting work is called a "modified version" of the
 96+earlier work or a work "based on" the earlier work.
 97+
 98+ A "covered work" means either the unmodified Program or a work based
 99+on the Program.
 100+
 101+ To "propagate" a work means to do anything with it that, without
 102+permission, would make you directly or secondarily liable for
 103+infringement under applicable copyright law, except executing it on a
 104+computer or modifying a private copy. Propagation includes copying,
 105+distribution (with or without modification), making available to the
 106+public, and in some countries other activities as well.
 107+
 108+ To "convey" a work means any kind of propagation that enables other
 109+parties to make or receive copies. Mere interaction with a user through
 110+a computer network, with no transfer of a copy, is not conveying.
 111+
 112+ An interactive user interface displays "Appropriate Legal Notices"
 113+to the extent that it includes a convenient and prominently visible
 114+feature that (1) displays an appropriate copyright notice, and (2)
 115+tells the user that there is no warranty for the work (except to the
 116+extent that warranties are provided), that licensees may convey the
 117+work under this License, and how to view a copy of this License. If
 118+the interface presents a list of user commands or options, such as a
 119+menu, a prominent item in the list meets this criterion.
 120+
 121+ 1. Source Code.
 122+
 123+ The "source code" for a work means the preferred form of the work
 124+for making modifications to it. "Object code" means any non-source
 125+form of a work.
 126+
 127+ A "Standard Interface" means an interface that either is an official
 128+standard defined by a recognized standards body, or, in the case of
 129+interfaces specified for a particular programming language, one that
 130+is widely used among developers working in that language.
 131+
 132+ The "System Libraries" of an executable work include anything, other
 133+than the work as a whole, that (a) is included in the normal form of
 134+packaging a Major Component, but which is not part of that Major
 135+Component, and (b) serves only to enable use of the work with that
 136+Major Component, or to implement a Standard Interface for which an
 137+implementation is available to the public in source code form. A
 138+"Major Component", in this context, means a major essential component
 139+(kernel, window system, and so on) of the specific operating system
 140+(if any) on which the executable work runs, or a compiler used to
 141+produce the work, or an object code interpreter used to run it.
 142+
 143+ The "Corresponding Source" for a work in object code form means all
 144+the source code needed to generate, install, and (for an executable
 145+work) run the object code and to modify the work, including scripts to
 146+control those activities. However, it does not include the work's
 147+System Libraries, or general-purpose tools or generally available free
 148+programs which are used unmodified in performing those activities but
 149+which are not part of the work. For example, Corresponding Source
 150+includes interface definition files associated with source files for
 151+the work, and the source code for shared libraries and dynamically
 152+linked subprograms that the work is specifically designed to require,
 153+such as by intimate data communication or control flow between those
 154+subprograms and other parts of the work.
 155+
 156+ The Corresponding Source need not include anything that users
 157+can regenerate automatically from other parts of the Corresponding
 158+Source.
 159+
 160+ The Corresponding Source for a work in source code form is that
 161+same work.
 162+
 163+ 2. Basic Permissions.
 164+
 165+ All rights granted under this License are granted for the term of
 166+copyright on the Program, and are irrevocable provided the stated
 167+conditions are met. This License explicitly affirms your unlimited
 168+permission to run the unmodified Program. The output from running a
 169+covered work is covered by this License only if the output, given its
 170+content, constitutes a covered work. This License acknowledges your
 171+rights of fair use or other equivalent, as provided by copyright law.
 172+
 173+ You may make, run and propagate covered works that you do not
 174+convey, without conditions so long as your license otherwise remains
 175+in force. You may convey covered works to others for the sole purpose
 176+of having them make modifications exclusively for you, or provide you
 177+with facilities for running those works, provided that you comply with
 178+the terms of this License in conveying all material for which you do
 179+not control copyright. Those thus making or running the covered works
 180+for you must do so exclusively on your behalf, under your direction
 181+and control, on terms that prohibit them from making any copies of
 182+your copyrighted material outside their relationship with you.
 183+
 184+ Conveying under any other circumstances is permitted solely under
 185+the conditions stated below. Sublicensing is not allowed; section 10
 186+makes it unnecessary.
 187+
 188+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
 189+
 190+ No covered work shall be deemed part of an effective technological
 191+measure under any applicable law fulfilling obligations under article
 192+11 of the WIPO copyright treaty adopted on 20 December 1996, or
 193+similar laws prohibiting or restricting circumvention of such
 194+measures.
 195+
 196+ When you convey a covered work, you waive any legal power to forbid
 197+circumvention of technological measures to the extent such circumvention
 198+is effected by exercising rights under this License with respect to
 199+the covered work, and you disclaim any intention to limit operation or
 200+modification of the work as a means of enforcing, against the work's
 201+users, your or third parties' legal rights to forbid circumvention of
 202+technological measures.
 203+
 204+ 4. Conveying Verbatim Copies.
 205+
 206+ You may convey verbatim copies of the Program's source code as you
 207+receive it, in any medium, provided that you conspicuously and
 208+appropriately publish on each copy an appropriate copyright notice;
 209+keep intact all notices stating that this License and any
 210+non-permissive terms added in accord with section 7 apply to the code;
 211+keep intact all notices of the absence of any warranty; and give all
 212+recipients a copy of this License along with the Program.
 213+
 214+ You may charge any price or no price for each copy that you convey,
 215+and you may offer support or warranty protection for a fee.
 216+
 217+ 5. Conveying Modified Source Versions.
 218+
 219+ You may convey a work based on the Program, or the modifications to
 220+produce it from the Program, in the form of source code under the
 221+terms of section 4, provided that you also meet all of these conditions:
 222+
 223+ a) The work must carry prominent notices stating that you modified
 224+ it, and giving a relevant date.
 225+
 226+ b) The work must carry prominent notices stating that it is
 227+ released under this License and any conditions added under section
 228+ 7. This requirement modifies the requirement in section 4 to
 229+ "keep intact all notices".
 230+
 231+ c) You must license the entire work, as a whole, under this
 232+ License to anyone who comes into possession of a copy. This
 233+ License will therefore apply, along with any applicable section 7
 234+ additional terms, to the whole of the work, and all its parts,
 235+ regardless of how they are packaged. This License gives no
 236+ permission to license the work in any other way, but it does not
 237+ invalidate such permission if you have separately received it.
 238+
 239+ d) If the work has interactive user interfaces, each must display
 240+ Appropriate Legal Notices; however, if the Program has interactive
 241+ interfaces that do not display Appropriate Legal Notices, your
 242+ work need not make them do so.
 243+
 244+ A compilation of a covered work with other separate and independent
 245+works, which are not by their nature extensions of the covered work,
 246+and which are not combined with it such as to form a larger program,
 247+in or on a volume of a storage or distribution medium, is called an
 248+"aggregate" if the compilation and its resulting copyright are not
 249+used to limit the access or legal rights of the compilation's users
 250+beyond what the individual works permit. Inclusion of a covered work
 251+in an aggregate does not cause this License to apply to the other
 252+parts of the aggregate.
 253+
 254+ 6. Conveying Non-Source Forms.
 255+
 256+ You may convey a covered work in object code form under the terms
 257+of sections 4 and 5, provided that you also convey the
 258+machine-readable Corresponding Source under the terms of this License,
 259+in one of these ways:
 260+
 261+ a) Convey the object code in, or embodied in, a physical product
 262+ (including a physical distribution medium), accompanied by the
 263+ Corresponding Source fixed on a durable physical medium
 264+ customarily used for software interchange.
 265+
 266+ b) Convey the object code in, or embodied in, a physical product
 267+ (including a physical distribution medium), accompanied by a
 268+ written offer, valid for at least three years and valid for as
 269+ long as you offer spare parts or customer support for that product
 270+ model, to give anyone who possesses the object code either (1) a
 271+ copy of the Corresponding Source for all the software in the
 272+ product that is covered by this License, on a durable physical
 273+ medium customarily used for software interchange, for a price no
 274+ more than your reasonable cost of physically performing this
 275+ conveying of source, or (2) access to copy the
 276+ Corresponding Source from a network server at no charge.
 277+
 278+ c) Convey individual copies of the object code with a copy of the
 279+ written offer to provide the Corresponding Source. This
 280+ alternative is allowed only occasionally and noncommercially, and
 281+ only if you received the object code with such an offer, in accord
 282+ with subsection 6b.
 283+
 284+ d) Convey the object code by offering access from a designated
 285+ place (gratis or for a charge), and offer equivalent access to the
 286+ Corresponding Source in the same way through the same place at no
 287+ further charge. You need not require recipients to copy the
 288+ Corresponding Source along with the object code. If the place to
 289+ copy the object code is a network server, the Corresponding Source
 290+ may be on a different server (operated by you or a third party)
 291+ that supports equivalent copying facilities, provided you maintain
 292+ clear directions next to the object code saying where to find the
 293+ Corresponding Source. Regardless of what server hosts the
 294+ Corresponding Source, you remain obligated to ensure that it is
 295+ available for as long as needed to satisfy these requirements.
 296+
 297+ e) Convey the object code using peer-to-peer transmission, provided
 298+ you inform other peers where the object code and Corresponding
 299+ Source of the work are being offered to the general public at no
 300+ charge under subsection 6d.
 301+
 302+ A separable portion of the object code, whose source code is excluded
 303+from the Corresponding Source as a System Library, need not be
 304+included in conveying the object code work.
 305+
 306+ A "User Product" is either (1) a "consumer product", which means any
 307+tangible personal property which is normally used for personal, family,
 308+or household purposes, or (2) anything designed or sold for incorporation
 309+into a dwelling. In determining whether a product is a consumer product,
 310+doubtful cases shall be resolved in favor of coverage. For a particular
 311+product received by a particular user, "normally used" refers to a
 312+typical or common use of that class of product, regardless of the status
 313+of the particular user or of the way in which the particular user
 314+actually uses, or expects or is expected to use, the product. A product
 315+is a consumer product regardless of whether the product has substantial
 316+commercial, industrial or non-consumer uses, unless such uses represent
 317+the only significant mode of use of the product.
 318+
 319+ "Installation Information" for a User Product means any methods,
 320+procedures, authorization keys, or other information required to install
 321+and execute modified versions of a covered work in that User Product from
 322+a modified version of its Corresponding Source. The information must
 323+suffice to ensure that the continued functioning of the modified object
 324+code is in no case prevented or interfered with solely because
 325+modification has been made.
 326+
 327+ If you convey an object code work under this section in, or with, or
 328+specifically for use in, a User Product, and the conveying occurs as
 329+part of a transaction in which the right of possession and use of the
 330+User Product is transferred to the recipient in perpetuity or for a
 331+fixed term (regardless of how the transaction is characterized), the
 332+Corresponding Source conveyed under this section must be accompanied
 333+by the Installation Information. But this requirement does not apply
 334+if neither you nor any third party retains the ability to install
 335+modified object code on the User Product (for example, the work has
 336+been installed in ROM).
 337+
 338+ The requirement to provide Installation Information does not include a
 339+requirement to continue to provide support service, warranty, or updates
 340+for a work that has been modified or installed by the recipient, or for
 341+the User Product in which it has been modified or installed. Access to a
 342+network may be denied when the modification itself materially and
 343+adversely affects the operation of the network or violates the rules and
 344+protocols for communication across the network.
 345+
 346+ Corresponding Source conveyed, and Installation Information provided,
 347+in accord with this section must be in a format that is publicly
 348+documented (and with an implementation available to the public in
 349+source code form), and must require no special password or key for
 350+unpacking, reading or copying.
 351+
 352+ 7. Additional Terms.
 353+
 354+ "Additional permissions" are terms that supplement the terms of this
 355+License by making exceptions from one or more of its conditions.
 356+Additional permissions that are applicable to the entire Program shall
 357+be treated as though they were included in this License, to the extent
 358+that they are valid under applicable law. If additional permissions
 359+apply only to part of the Program, that part may be used separately
 360+under those permissions, but the entire Program remains governed by
 361+this License without regard to the additional permissions.
 362+
 363+ When you convey a copy of a covered work, you may at your option
 364+remove any additional permissions from that copy, or from any part of
 365+it. (Additional permissions may be written to require their own
 366+removal in certain cases when you modify the work.) You may place
 367+additional permissions on material, added by you to a covered work,
 368+for which you have or can give appropriate copyright permission.
 369+
 370+ Notwithstanding any other provision of this License, for material you
 371+add to a covered work, you may (if authorized by the copyright holders of
 372+that material) supplement the terms of this License with terms:
 373+
 374+ a) Disclaiming warranty or limiting liability differently from the
 375+ terms of sections 15 and 16 of this License; or
 376+
 377+ b) Requiring preservation of specified reasonable legal notices or
 378+ author attributions in that material or in the Appropriate Legal
 379+ Notices displayed by works containing it; or
 380+
 381+ c) Prohibiting misrepresentation of the origin of that material, or
 382+ requiring that modified versions of such material be marked in
 383+ reasonable ways as different from the original version; or
 384+
 385+ d) Limiting the use for publicity purposes of names of licensors or
 386+ authors of the material; or
 387+
 388+ e) Declining to grant rights under trademark law for use of some
 389+ trade names, trademarks, or service marks; or
 390+
 391+ f) Requiring indemnification of licensors and authors of that
 392+ material by anyone who conveys the material (or modified versions of
 393+ it) with contractual assumptions of liability to the recipient, for
 394+ any liability that these contractual assumptions directly impose on
 395+ those licensors and authors.
 396+
 397+ All other non-permissive additional terms are considered "further
 398+restrictions" within the meaning of section 10. If the Program as you
 399+received it, or any part of it, contains a notice stating that it is
 400+governed by this License along with a term that is a further
 401+restriction, you may remove that term. If a license document contains
 402+a further restriction but permits relicensing or conveying under this
 403+License, you may add to a covered work material governed by the terms
 404+of that license document, provided that the further restriction does
 405+not survive such relicensing or conveying.
 406+
 407+ If you add terms to a covered work in accord with this section, you
 408+must place, in the relevant source files, a statement of the
 409+additional terms that apply to those files, or a notice indicating
 410+where to find the applicable terms.
 411+
 412+ Additional terms, permissive or non-permissive, may be stated in the
 413+form of a separately written license, or stated as exceptions;
 414+the above requirements apply either way.
 415+
 416+ 8. Termination.
 417+
 418+ You may not propagate or modify a covered work except as expressly
 419+provided under this License. Any attempt otherwise to propagate or
 420+modify it is void, and will automatically terminate your rights under
 421+this License (including any patent licenses granted under the third
 422+paragraph of section 11).
 423+
 424+ However, if you cease all violation of this License, then your
 425+license from a particular copyright holder is reinstated (a)
 426+provisionally, unless and until the copyright holder explicitly and
 427+finally terminates your license, and (b) permanently, if the copyright
 428+holder fails to notify you of the violation by some reasonable means
 429+prior to 60 days after the cessation.
 430+
 431+ Moreover, your license from a particular copyright holder is
 432+reinstated permanently if the copyright holder notifies you of the
 433+violation by some reasonable means, this is the first time you have
 434+received notice of violation of this License (for any work) from that
 435+copyright holder, and you cure the violation prior to 30 days after
 436+your receipt of the notice.
 437+
 438+ Termination of your rights under this section does not terminate the
 439+licenses of parties who have received copies or rights from you under
 440+this License. If your rights have been terminated and not permanently
 441+reinstated, you do not qualify to receive new licenses for the same
 442+material under section 10.
 443+
 444+ 9. Acceptance Not Required for Having Copies.
 445+
 446+ You are not required to accept this License in order to receive or
 447+run a copy of the Program. Ancillary propagation of a covered work
 448+occurring solely as a consequence of using peer-to-peer transmission
 449+to receive a copy likewise does not require acceptance. However,
 450+nothing other than this License grants you permission to propagate or
 451+modify any covered work. These actions infringe copyright if you do
 452+not accept this License. Therefore, by modifying or propagating a
 453+covered work, you indicate your acceptance of this License to do so.
 454+
 455+ 10. Automatic Licensing of Downstream Recipients.
 456+
 457+ Each time you convey a covered work, the recipient automatically
 458+receives a license from the original licensors, to run, modify and
 459+propagate that work, subject to this License. You are not responsible
 460+for enforcing compliance by third parties with this License.
 461+
 462+ An "entity transaction" is a transaction transferring control of an
 463+organization, or substantially all assets of one, or subdividing an
 464+organization, or merging organizations. If propagation of a covered
 465+work results from an entity transaction, each party to that
 466+transaction who receives a copy of the work also receives whatever
 467+licenses to the work the party's predecessor in interest had or could
 468+give under the previous paragraph, plus a right to possession of the
 469+Corresponding Source of the work from the predecessor in interest, if
 470+the predecessor has it or can get it with reasonable efforts.
 471+
 472+ You may not impose any further restrictions on the exercise of the
 473+rights granted or affirmed under this License. For example, you may
 474+not impose a license fee, royalty, or other charge for exercise of
 475+rights granted under this License, and you may not initiate litigation
 476+(including a cross-claim or counterclaim in a lawsuit) alleging that
 477+any patent claim is infringed by making, using, selling, offering for
 478+sale, or importing the Program or any portion of it.
 479+
 480+ 11. Patents.
 481+
 482+ A "contributor" is a copyright holder who authorizes use under this
 483+License of the Program or a work on which the Program is based. The
 484+work thus licensed is called the contributor's "contributor version".
 485+
 486+ A contributor's "essential patent claims" are all patent claims
 487+owned or controlled by the contributor, whether already acquired or
 488+hereafter acquired, that would be infringed by some manner, permitted
 489+by this License, of making, using, or selling its contributor version,
 490+but do not include claims that would be infringed only as a
 491+consequence of further modification of the contributor version. For
 492+purposes of this definition, "control" includes the right to grant
 493+patent sublicenses in a manner consistent with the requirements of
 494+this License.
 495+
 496+ Each contributor grants you a non-exclusive, worldwide, royalty-free
 497+patent license under the contributor's essential patent claims, to
 498+make, use, sell, offer for sale, import and otherwise run, modify and
 499+propagate the contents of its contributor version.
 500+
 501+ In the following three paragraphs, a "patent license" is any express
 502+agreement or commitment, however denominated, not to enforce a patent
 503+(such as an express permission to practice a patent or covenant not to
 504+sue for patent infringement). To "grant" such a patent license to a
 505+party means to make such an agreement or commitment not to enforce a
 506+patent against the party.
 507+
 508+ If you convey a covered work, knowingly relying on a patent license,
 509+and the Corresponding Source of the work is not available for anyone
 510+to copy, free of charge and under the terms of this License, through a
 511+publicly available network server or other readily accessible means,
 512+then you must either (1) cause the Corresponding Source to be so
 513+available, or (2) arrange to deprive yourself of the benefit of the
 514+patent license for this particular work, or (3) arrange, in a manner
 515+consistent with the requirements of this License, to extend the patent
 516+license to downstream recipients. "Knowingly relying" means you have
 517+actual knowledge that, but for the patent license, your conveying the
 518+covered work in a country, or your recipient's use of the covered work
 519+in a country, would infringe one or more identifiable patents in that
 520+country that you have reason to believe are valid.
 521+
 522+ If, pursuant to or in connection with a single transaction or
 523+arrangement, you convey, or propagate by procuring conveyance of, a
 524+covered work, and grant a patent license to some of the parties
 525+receiving the covered work authorizing them to use, propagate, modify
 526+or convey a specific copy of the covered work, then the patent license
 527+you grant is automatically extended to all recipients of the covered
 528+work and works based on it.
 529+
 530+ A patent license is "discriminatory" if it does not include within
 531+the scope of its coverage, prohibits the exercise of, or is
 532+conditioned on the non-exercise of one or more of the rights that are
 533+specifically granted under this License. You may not convey a covered
 534+work if you are a party to an arrangement with a third party that is
 535+in the business of distributing software, under which you make payment
 536+to the third party based on the extent of your activity of conveying
 537+the work, and under which the third party grants, to any of the
 538+parties who would receive the covered work from you, a discriminatory
 539+patent license (a) in connection with copies of the covered work
 540+conveyed by you (or copies made from those copies), or (b) primarily
 541+for and in connection with specific products or compilations that
 542+contain the covered work, unless you entered into that arrangement,
 543+or that patent license was granted, prior to 28 March 2007.
 544+
 545+ Nothing in this License shall be construed as excluding or limiting
 546+any implied license or other defenses to infringement that may
 547+otherwise be available to you under applicable patent law.
 548+
 549+ 12. No Surrender of Others' Freedom.
 550+
 551+ If conditions are imposed on you (whether by court order, agreement or
 552+otherwise) that contradict the conditions of this License, they do not
 553+excuse you from the conditions of this License. If you cannot convey a
 554+covered work so as to satisfy simultaneously your obligations under this
 555+License and any other pertinent obligations, then as a consequence you may
 556+not convey it at all. For example, if you agree to terms that obligate you
 557+to collect a royalty for further conveying from those to whom you convey
 558+the Program, the only way you could satisfy both those terms and this
 559+License would be to refrain entirely from conveying the Program.
 560+
 561+ 13. Use with the GNU Affero General Public License.
 562+
 563+ Notwithstanding any other provision of this License, you have
 564+permission to link or combine any covered work with a work licensed
 565+under version 3 of the GNU Affero General Public License into a single
 566+combined work, and to convey the resulting work. The terms of this
 567+License will continue to apply to the part which is the covered work,
 568+but the special requirements of the GNU Affero General Public License,
 569+section 13, concerning interaction through a network will apply to the
 570+combination as such.
 571+
 572+ 14. Revised Versions of this License.
 573+
 574+ The Free Software Foundation may publish revised and/or new versions of
 575+the GNU General Public License from time to time. Such new versions will
 576+be similar in spirit to the present version, but may differ in detail to
 577+address new problems or concerns.
 578+
 579+ Each version is given a distinguishing version number. If the
 580+Program specifies that a certain numbered version of the GNU General
 581+Public License "or any later version" applies to it, you have the
 582+option of following the terms and conditions either of that numbered
 583+version or of any later version published by the Free Software
 584+Foundation. If the Program does not specify a version number of the
 585+GNU General Public License, you may choose any version ever published
 586+by the Free Software Foundation.
 587+
 588+ If the Program specifies that a proxy can decide which future
 589+versions of the GNU General Public License can be used, that proxy's
 590+public statement of acceptance of a version permanently authorizes you
 591+to choose that version for the Program.
 592+
 593+ Later license versions may give you additional or different
 594+permissions. However, no additional obligations are imposed on any
 595+author or copyright holder as a result of your choosing to follow a
 596+later version.
 597+
 598+ 15. Disclaimer of Warranty.
 599+
 600+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
 601+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
 602+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
 603+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
 604+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 605+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
 606+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
 607+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
 608+
 609+ 16. Limitation of Liability.
 610+
 611+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
 612+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
 613+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
 614+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
 615+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
 616+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
 617+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
 618+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
 619+SUCH DAMAGES.
 620+
 621+ 17. Interpretation of Sections 15 and 16.
 622+
 623+ If the disclaimer of warranty and limitation of liability provided
 624+above cannot be given local legal effect according to their terms,
 625+reviewing courts shall apply local law that most closely approximates
 626+an absolute waiver of all civil liability in connection with the
 627+Program, unless a warranty or assumption of liability accompanies a
 628+copy of the Program in return for a fee.
 629+
 630+ END OF TERMS AND CONDITIONS
 631+
 632+ How to Apply These Terms to Your New Programs
 633+
 634+ If you develop a new program, and you want it to be of the greatest
 635+possible use to the public, the best way to achieve this is to make it
 636+free software which everyone can redistribute and change under these terms.
 637+
 638+ To do so, attach the following notices to the program. It is safest
 639+to attach them to the start of each source file to most effectively
 640+state the exclusion of warranty; and each file should have at least
 641+the "copyright" line and a pointer to where the full notice is found.
 642+
 643+ <one line to give the program's name and a brief idea of what it does.>
 644+ Copyright (C) <year> <name of author>
 645+
 646+ This program is free software: you can redistribute it and/or modify
 647+ it under the terms of the GNU General Public License as published by
 648+ the Free Software Foundation, either version 3 of the License, or
 649+ (at your option) any later version.
 650+
 651+ This program is distributed in the hope that it will be useful,
 652+ but WITHOUT ANY WARRANTY; without even the implied warranty of
 653+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 654+ GNU General Public License for more details.
 655+
 656+ You should have received a copy of the GNU General Public License
 657+ along with this program. If not, see <http://www.gnu.org/licenses/>.
 658+
 659+Also add information on how to contact you by electronic and paper mail.
 660+
 661+ If the program does terminal interaction, make it output a short
 662+notice like this when it starts in an interactive mode:
 663+
 664+ <program> Copyright (C) <year> <name of author>
 665+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
 666+ This is free software, and you are welcome to redistribute it
 667+ under certain conditions; type `show c' for details.
 668+
 669+The hypothetical commands `show w' and `show c' should show the appropriate
 670+parts of the General Public License. Of course, your program's commands
 671+might be different; for a GUI interface, you would use an "about box".
 672+
 673+ You should also get your employer (if you work as a programmer) or school,
 674+if any, to sign a "copyright disclaimer" for the program, if necessary.
 675+For more information on this, and how to apply and follow the GNU GPL, see
 676+<http://www.gnu.org/licenses/>.
 677+
 678+ The GNU General Public License does not permit incorporating your program
 679+into proprietary programs. If your program is a subroutine library, you
 680+may consider it more useful to permit linking proprietary applications with
 681+the library. If this is what you want to do, use the GNU Lesser General
 682+Public License instead of this License. But first, please read
 683+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
\ No newline at end of file
Property changes on: tags/extensions/Survey/REL_0_1/COPYING
___________________________________________________________________
Added: svn:eol-style
1684 + native
Index: tags/extensions/Survey/REL_0_1/api/ApiDeleteSurvey.php
@@ -0,0 +1,98 @@
 2+<?php
 3+
 4+/**
 5+ * API module to delete surveys.
 6+ *
 7+ * @since 0.1
 8+ *
 9+ * @file ApiDeleteSurvey.php
 10+ * @ingroup Survey
 11+ * @ingroup API
 12+ *
 13+ * @licence GNU GPL v3+
 14+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
 15+ */
 16+class ApiDeleteSurvey extends ApiBase {
 17+
 18+ public function __construct( $main, $action ) {
 19+ parent::__construct( $main, $action );
 20+ }
 21+
 22+ public function execute() {
 23+ global $wgUser;
 24+
 25+ if ( !$wgUser->isAllowed( 'surveyadmin' ) || $wgUser->isBlocked() ) {
 26+ $this->dieUsageMsg( array( 'badaccess-groups' ) );
 27+ }
 28+
 29+ $params = $this->extractRequestParams();
 30+
 31+ $everythingOk = true;
 32+
 33+ foreach ( $params['ids'] as $id ) {
 34+ $surey = new Survey( array( 'id' => $id ) );
 35+ $everythingOk = $surey->removeFromDB() && $everythingOk;
 36+ }
 37+
 38+ $this->getResult()->addValue(
 39+ null,
 40+ 'success',
 41+ $everythingOk
 42+ );
 43+ }
 44+
 45+ public function needsToken() {
 46+ return true;
 47+ }
 48+
 49+ public function getTokenSalt() {
 50+ $params = $this->extractRequestParams();
 51+ return 'deletesurvey' . implode( '|', $params['ids'] );
 52+ }
 53+
 54+ public function mustBePosted() {
 55+ return true;
 56+ }
 57+
 58+ public function getAllowedParams() {
 59+ return array(
 60+ 'ids' => array(
 61+ ApiBase::PARAM_TYPE => 'integer',
 62+ ApiBase::PARAM_REQUIRED => true,
 63+ ApiBase::PARAM_ISMULTI => true,
 64+ ),
 65+ 'token' => null,
 66+ );
 67+ }
 68+
 69+ public function getParamDescription() {
 70+ return array(
 71+ 'ids' => 'The IDs of the surveys to delete',
 72+ 'token' => 'Edit token. You can get one of these through prop=info.',
 73+ );
 74+ }
 75+
 76+ public function getDescription() {
 77+ return array(
 78+ 'API module for deleting surveys.'
 79+ );
 80+ }
 81+
 82+ public function getPossibleErrors() {
 83+ return array_merge( parent::getPossibleErrors(), array(
 84+ array( 'missingparam', 'ids' ),
 85+ ) );
 86+ }
 87+
 88+ protected function getExamples() {
 89+ return array(
 90+ 'api.php?action=deletesurvey&ids=42',
 91+ 'api.php?action=deletesurvey&ids=4|2',
 92+ );
 93+ }
 94+
 95+ public function getVersion() {
 96+ return __CLASS__ . ': $Id$';
 97+ }
 98+
 99+}
Property changes on: tags/extensions/Survey/REL_0_1/api/ApiDeleteSurvey.php
___________________________________________________________________
Added: svn:keywords
1100 + Id
Added: svn:eol-style
2101 + native
Index: tags/extensions/Survey/REL_0_1/api/ApiSubmitSurvey.php
@@ -0,0 +1,118 @@
 2+<?php
 3+
 4+/**
 5+ * API module to submit surveys.
 6+ *
 7+ * @since 0.1
 8+ *
 9+ * @file ApiSubmitSurvey.php
 10+ * @ingroup Survey
 11+ * @ingroup API
 12+ *
 13+ * @licence GNU GPL v3+
 14+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
 15+ */
 16+class ApiSubmitSurvey extends ApiBase {
 17+
 18+ public function __construct( $main, $action ) {
 19+ parent::__construct( $main, $action );
 20+ }
 21+
 22+ public function execute() {
 23+ global $wgUser;
 24+
 25+ if ( !$wgUser->isAllowed( 'surveysubmit' ) || $wgUser->isBlocked() ) {
 26+ $this->dieUsageMsg( array( 'badaccess-groups' ) );
 27+ }
 28+
 29+ $params = $this->extractRequestParams();
 30+
 31+ if ( !( isset( $params['id'] ) XOR isset( $params['name'] ) ) ) {
 32+ $this->dieUsage( wfMsgExt( 'survey-err-id-xor-name' ), 'id-xor-name' );
 33+ }
 34+
 35+ if ( isset( $params['name'] ) ) {
 36+ $survey = Survey::newFromName( $params['name'], null, false );
 37+
 38+ if ( $survey === false ) {
 39+ $this->dieUsage( wfMsgExt( 'survey-err-survey-name-unknown', 'parsemag', $params['name'] ), 'survey-name-unknown' );
 40+ }
 41+ } else {
 42+ $survey = Survey::newFromId( $params['id'], null, false );
 43+
 44+ if ( $survey === false ) {
 45+ $this->dieUsage( wfMsgExt( 'survey-err-survey-id-unknown', 'parsemag', $params['id'] ), 'survey-id-unknown' );
 46+ }
 47+ }
 48+
 49+ $submission = new SurveySubmission( array(
 50+ 'survey_id' => $survey->getId(),
 51+ 'page_id' => 0, // TODO
 52+ 'user_name' => $GLOBALS['wgUser']->getName(),
 53+ 'time' => wfTimestampNow()
 54+ ) );
 55+
 56+ foreach ( FormatJson::decode( $params['answers'] ) as $answer ) {
 57+ $submission->addAnswer( SurveyAnswer::newFromArray( (array)$answer ) );
 58+ }
 59+
 60+ $submission->writeToDB();
 61+ }
 62+
 63+ public function needsToken() {
 64+ return true;
 65+ }
 66+
 67+ public function getTokenSalt() {
 68+ return serialize( array( 'submitsurvey', $GLOBALS['wgUser']->getName() ) );
 69+ }
 70+
 71+ public function mustBePosted() {
 72+ return true;
 73+ }
 74+
 75+ public function getAllowedParams() {
 76+ return array(
 77+ 'id' => array(
 78+ ApiBase::PARAM_TYPE => 'integer',
 79+ ),
 80+ 'name' => array(
 81+ ApiBase::PARAM_TYPE => 'string',
 82+ ),
 83+ 'answers' => array(
 84+ ApiBase::PARAM_TYPE => 'string',
 85+ ),
 86+ 'token' => null,
 87+ );
 88+ }
 89+
 90+ public function getParamDescription() {
 91+ return array(
 92+ 'id' => 'The ID of the survey being submitted.',
 93+ 'name' => 'The name of the survey being submitted.',
 94+ 'token' => 'Edit token. You can get one of these through prop=info.',
 95+ );
 96+ }
 97+
 98+ public function getDescription() {
 99+ return array(
 100+ ''
 101+ );
 102+ }
 103+
 104+ public function getPossibleErrors() {
 105+ return array_merge( parent::getPossibleErrors(), array(
 106+ ) );
 107+ }
 108+
 109+ protected function getExamples() {
 110+ return array(
 111+ 'api.php?action=submitsurvey&',
 112+ );
 113+ }
 114+
 115+ public function getVersion() {
 116+ return __CLASS__ . ': $Id$';
 117+ }
 118+
 119+}
Property changes on: tags/extensions/Survey/REL_0_1/api/ApiSubmitSurvey.php
___________________________________________________________________
Added: svn:keywords
1120 + Id
Added: svn:eol-style
2121 + native
Index: tags/extensions/Survey/REL_0_1/api/ApiQuerySurveySubmissions.php
@@ -0,0 +1,154 @@
 2+<?php
 3+
 4+/**
 5+ * API module to get a list of survey submissions.
 6+ *
 7+ * @since 0.1
 8+ *
 9+ * @file ApiQuerySurveySubmissions.php
 10+ * @ingroup Surveys
 11+ * @ingroup API
 12+ *
 13+ * @licence GNU GPL v3+
 14+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
 15+ */
 16+class ApiQuerySurveySubmissions extends ApiQueryBase {
 17+
 18+ public function __construct( $main, $action ) {
 19+ parent::__construct( $main, $action, 'qs' );
 20+ }
 21+
 22+ /**
 23+ * Retrieve the special words from the database.
 24+ */
 25+ public function execute() {
 26+ global $wgUser;
 27+
 28+ if ( $wgUser->isBlocked() ) {
 29+ $this->dieUsageMsg( array( 'badaccess-groups' ) );
 30+ }
 31+
 32+ // Get the requests parameters.
 33+ $params = $this->extractRequestParams();
 34+
 35+ $starPropPosition = array_search( '*', $params['props'] );
 36+
 37+ if ( $starPropPosition !== false ) {
 38+ unset( $params['props'][$starPropPosition] );
 39+ $params['props'] = array_merge( $params['props'], SurveySubmission::getFieldNames() );
 40+ }
 41+
 42+ $params = array_filter( $params, function( $param ) { return !is_null( $param ); } );
 43+
 44+ $results = SurveySubmission::select(
 45+ $params['props'],
 46+ SurveySubmission::getValidFields( $params ),
 47+ array(
 48+ 'LIMIT' => $params['limit'] + 1,
 49+ 'ORDER BY' => SurveySubmission::getPrefixedField( 'id' ) . ' ASC'
 50+ )
 51+ );
 52+
 53+ $serializedResults = array();
 54+ $count = 0;
 55+
 56+ foreach ( $results as $result ) {
 57+ if ( ++$count > $params['limit'] ) {
 58+ // We've reached the one extra which shows that
 59+ // there are additional pages to be had. Stop here...
 60+ $this->setContinueEnumParameter( 'continue', $result->getId() );
 61+ break;
 62+ }
 63+
 64+ $serializedResults[] = $result->toArray();
 65+ }
 66+
 67+ $this->getResult()->setIndexedTagName( $serializedResults, 'submission' );
 68+
 69+ $this->getResult()->addValue(
 70+ null,
 71+ 'submissions',
 72+ $serializedResults
 73+ );
 74+ }
 75+
 76+ public function needsToken() {
 77+ return true;
 78+ }
 79+
 80+ public function getTokenSalt() {
 81+ return 'querysurveysubmissions';
 82+ }
 83+
 84+ /**
 85+ * (non-PHPdoc)
 86+ * @see includes/api/ApiBase#getAllowedParams()
 87+ */
 88+ public function getAllowedParams() {
 89+ $params = array (
 90+ 'props' => array(
 91+ ApiBase::PARAM_TYPE => array_merge( SurveySubmission::getFieldNames(), array( '*' ) ),
 92+ ApiBase::PARAM_ISMULTI => true,
 93+ ApiBase::PARAM_DFLT => '*'
 94+ ),
 95+ 'limit' => array(
 96+ ApiBase::PARAM_DFLT => 20,
 97+ ApiBase::PARAM_TYPE => 'limit',
 98+ ApiBase::PARAM_MIN => 1,
 99+ ApiBase::PARAM_MAX => ApiBase::LIMIT_BIG1,
 100+ ApiBase::PARAM_MAX2 => ApiBase::LIMIT_BIG2
 101+ ),
 102+ 'continue' => null,
 103+ 'token' => null,
 104+ );
 105+
 106+ return array_merge( SurveySubmission::getAPIParams( false ), $params );
 107+ }
 108+
 109+ /**
 110+ * (non-PHPdoc)
 111+ * @see includes/api/ApiBase#getParamDescription()
 112+ */
 113+ public function getParamDescription() {
 114+ $descs = array (
 115+ 'props' => 'Survey data to query',
 116+ 'continue' => 'Offset number from where to continue the query',
 117+ 'limit' => 'Max amount of words to return',
 118+ 'token' => 'Edit token. You can get one of these through prop=info.',
 119+ );
 120+
 121+ return array_merge( SurveySubmission::getFieldDescriptions(), $descs );
 122+ }
 123+
 124+ /**
 125+ * (non-PHPdoc)
 126+ * @see includes/api/ApiBase#getDescription()
 127+ */
 128+ public function getDescription() {
 129+ return 'API module for obatining survey submissions';
 130+ }
 131+
 132+ /**
 133+ * (non-PHPdoc)
 134+ * @see includes/api/ApiBase#getPossibleErrors()
 135+ */
 136+ public function getPossibleErrors() {
 137+ return array_merge( parent::getPossibleErrors(), array(
 138+ ) );
 139+ }
 140+
 141+ /**
 142+ * (non-PHPdoc)
 143+ * @see includes/api/ApiBase#getExamples()
 144+ */
 145+ protected function getExamples() {
 146+ return array (
 147+ 'api.php?action=query&list=surveysubmissions&',
 148+ );
 149+ }
 150+
 151+ public function getVersion() {
 152+ return __CLASS__ . ': $Id$';
 153+ }
 154+
 155+}
Property changes on: tags/extensions/Survey/REL_0_1/api/ApiQuerySurveySubmissions.php
___________________________________________________________________
Added: svn:keywords
1156 + Id
Added: svn:eol-style
2157 + native
Index: tags/extensions/Survey/REL_0_1/api/ApiEditSurvey.php
@@ -0,0 +1,119 @@
 2+<?php
 3+
 4+/**
 5+ * API module to edit surveys.
 6+ *
 7+ * @since 0.1
 8+ *
 9+ * @file ApiEditSurvey.php
 10+ * @ingroup Survey
 11+ * @ingroup API
 12+ *
 13+ * @licence GNU GPL v3+
 14+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
 15+ */
 16+class ApiEditSurvey extends ApiBase {
 17+
 18+ public function __construct( $main, $action ) {
 19+ parent::__construct( $main, $action );
 20+ }
 21+
 22+ public function execute() {
 23+ global $wgUser;
 24+
 25+ if ( !$wgUser->isAllowed( 'surveyadmin' ) || $wgUser->isBlocked() ) {
 26+ $this->dieUsageMsg( array( 'badaccess-groups' ) );
 27+ }
 28+
 29+ $params = $this->extractRequestParams();
 30+
 31+ foreach ( $params['questions'] as &$question ) {
 32+ $question = SurveyQuestion::newFromUrlData( $question );
 33+ }
 34+
 35+ $survey = new Survey( Survey::getValidFields( $params, $params['id'] ) );
 36+
 37+ $this->getResult()->addValue(
 38+ null,
 39+ 'success',
 40+ $survey->writeToDB()
 41+ );
 42+
 43+ $this->getResult()->addValue(
 44+ 'survey',
 45+ 'id',
 46+ $survey->getId()
 47+ );
 48+
 49+ $this->getResult()->addValue(
 50+ 'survey',
 51+ 'name',
 52+ $survey->getField( 'name' )
 53+ );
 54+ }
 55+
 56+ public function needsToken() {
 57+ return true;
 58+ }
 59+
 60+ public function getTokenSalt() {
 61+ return 'editsurvey';
 62+ }
 63+
 64+ public function mustBePosted() {
 65+ return true;
 66+ }
 67+
 68+ public function getAllowedParams() {
 69+ $params = array(
 70+ 'id' => array(
 71+ ApiBase::PARAM_TYPE => 'integer',
 72+ ApiBase::PARAM_REQUIRED => true,
 73+ ),
 74+ 'questions' => array(
 75+ ApiBase::PARAM_TYPE => 'string',
 76+ ApiBase::PARAM_ISMULTI => true,
 77+ ApiBase::PARAM_REQUIRED => true,
 78+ ),
 79+ 'token' => null,
 80+ );
 81+
 82+ return array_merge( Survey::getAPIParams(), $params );
 83+ }
 84+
 85+ public function getParamDescription() {
 86+ return array(
 87+ 'id' => 'The ID of the survey to modify',
 88+ 'name' => 'The name of the survey',
 89+ 'enabled' => 'Enable the survey or not',
 90+ 'questions' => 'The questions that make up the survey',
 91+ 'token' => 'Edit token. You can get one of these through prop=info.',
 92+ );
 93+ }
 94+
 95+ public function getDescription() {
 96+ return array(
 97+ 'API module for editing a survey.'
 98+ );
 99+ }
 100+
 101+ public function getPossibleErrors() {
 102+ return array_merge( parent::getPossibleErrors(), array(
 103+ array( 'missingparam', 'id' ),
 104+ array( 'missingparam', 'name' ),
 105+ array( 'missingparam', 'enabled' ),
 106+ array( 'missingparam', 'questions' ),
 107+ ) );
 108+ }
 109+
 110+ protected function getExamples() {
 111+ return array(
 112+ 'api.php?action=editsurvey&',
 113+ );
 114+ }
 115+
 116+ public function getVersion() {
 117+ return __CLASS__ . ': $Id$';
 118+ }
 119+
 120+}
Property changes on: tags/extensions/Survey/REL_0_1/api/ApiEditSurvey.php
___________________________________________________________________
Added: svn:keywords
1121 + Id
Added: svn:eol-style
2122 + native
Index: tags/extensions/Survey/REL_0_1/api/ApiAddSurvey.php
@@ -0,0 +1,122 @@
 2+<?php
 3+
 4+/**
 5+ * API module to add surveys.
 6+ *
 7+ * @since 0.1
 8+ *
 9+ * @file ApiAddSurvey.php
 10+ * @ingroup Survey
 11+ * @ingroup API
 12+ *
 13+ * @licence GNU GPL v3+
 14+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
 15+ */
 16+class ApiAddSurvey extends ApiBase {
 17+
 18+ public function __construct( $main, $action ) {
 19+ parent::__construct( $main, $action );
 20+ }
 21+
 22+ public function execute() {
 23+ global $wgUser;
 24+
 25+ if ( !$wgUser->isAllowed( 'surveyadmin' ) || $wgUser->isBlocked() ) {
 26+ $this->dieUsageMsg( array( 'badaccess-groups' ) );
 27+ }
 28+
 29+ $params = $this->extractRequestParams();
 30+
 31+ foreach ( $params['questions'] as &$question ) {
 32+ $question = SurveyQuestion::newFromUrlData( $question );
 33+ }
 34+
 35+ try {
 36+ $survey = new Survey( Survey::getValidFields( $params ) );
 37+ $success = $survey->writeToDB();
 38+ }
 39+ catch ( DBQueryError $ex ) {
 40+ if ( $ex->errno == 1062 ) {
 41+ $this->dieUsage( wfMsgExt( 'survey-err-duplicate-name', 'parsemag', $params['name'] ), 'duplicate-survey-name' );
 42+ } else {
 43+ throw $ex;
 44+ }
 45+ }
 46+
 47+ $this->getResult()->addValue(
 48+ null,
 49+ 'success',
 50+ $success
 51+ );
 52+
 53+ $this->getResult()->addValue(
 54+ 'survey',
 55+ 'id',
 56+ $survey->getId()
 57+ );
 58+
 59+ $this->getResult()->addValue(
 60+ 'survey',
 61+ 'name',
 62+ $survey->getField( 'name' )
 63+ );
 64+ }
 65+
 66+ public function needsToken() {
 67+ return true;
 68+ }
 69+
 70+ public function getTokenSalt() {
 71+ return 'addsurvey';
 72+ }
 73+
 74+ public function mustBePosted() {
 75+ return true;
 76+ }
 77+
 78+ public function getAllowedParams() {
 79+ $params = array(
 80+ 'questions' => array(
 81+ ApiBase::PARAM_TYPE => 'string',
 82+ ApiBase::PARAM_ISMULTI => true,
 83+ ApiBase::PARAM_DFLT => '',
 84+ ),
 85+ 'token' => null,
 86+ );
 87+
 88+ return array_merge( Survey::getAPIParams(), $params );
 89+ }
 90+
 91+ public function getParamDescription() {
 92+ return array(
 93+ 'name' => 'The name of the survey',
 94+ 'enabled' => 'Enable the survey or not',
 95+ 'questions' => 'The questions that make up the survey',
 96+ 'token' => 'Edit token. You can get one of these through prop=info.',
 97+ );
 98+ }
 99+
 100+ public function getDescription() {
 101+ return array(
 102+ 'API module for adding surveys.'
 103+ );
 104+ }
 105+
 106+ public function getPossibleErrors() {
 107+ return array_merge( parent::getPossibleErrors(), array(
 108+ array( 'missingparam', 'name' ),
 109+ array( 'missingparam', 'enabled' ),
 110+ ) );
 111+ }
 112+
 113+ protected function getExamples() {
 114+ return array(
 115+ 'api.php?action=addsurvey&name=My awesome survey&enabled=1&questions=',
 116+ );
 117+ }
 118+
 119+ public function getVersion() {
 120+ return __CLASS__ . ': $Id$';
 121+ }
 122+
 123+}
Property changes on: tags/extensions/Survey/REL_0_1/api/ApiAddSurvey.php
___________________________________________________________________
Added: svn:keywords
1124 + Id
Added: svn:eol-style
2125 + native
Index: tags/extensions/Survey/REL_0_1/api/ApiQuerySurveyAnswers.php
@@ -0,0 +1,154 @@
 2+<?php
 3+
 4+/**
 5+ * API module to get a list of survey answers.
 6+ *
 7+ * @since 0.1
 8+ *
 9+ * @file ApiQuerySurveyAnswers.php
 10+ * @ingroup Surveys
 11+ * @ingroup API
 12+ *
 13+ * @licence GNU GPL v3+
 14+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
 15+ */
 16+class ApiQuerySurveyAnswers extends ApiQueryBase {
 17+
 18+ public function __construct( $main, $action ) {
 19+ parent::__construct( $main, $action, 'qa' );
 20+ }
 21+
 22+ /**
 23+ * Retrieve the special words from the database.
 24+ */
 25+ public function execute() {
 26+ global $wgUser;
 27+
 28+ if ( $wgUser->isBlocked() ) {
 29+ $this->dieUsageMsg( array( 'badaccess-groups' ) );
 30+ }
 31+
 32+ // Get the requests parameters.
 33+ $params = $this->extractRequestParams();
 34+
 35+ $starPropPosition = array_search( '*', $params['props'] );
 36+
 37+ if ( $starPropPosition !== false ) {
 38+ unset( $params['props'][$starPropPosition] );
 39+ $params['props'] = array_merge( $params['props'], SurveyAnswer::getFieldNames() );
 40+ }
 41+
 42+ $params = array_filter( $params, function( $param ) { return !is_null( $param ); } );
 43+
 44+ $answers = SurveyAnswer::select(
 45+ $params['props'],
 46+ SurveyAnswer::getValidFields( $params ),
 47+ array(
 48+ 'LIMIT' => $params['limit'] + 1,
 49+ 'ORDER BY' => SurveyAnswer::getPrefixedField( 'id' ) . ' ASC'
 50+ )
 51+ );
 52+
 53+ $serializedAnswers = array();
 54+ $count = 0;
 55+
 56+ foreach ( $answers as $answer ) {
 57+ if ( ++$count > $params['limit'] ) {
 58+ // We've reached the one extra which shows that
 59+ // there are additional pages to be had. Stop here...
 60+ $this->setContinueEnumParameter( 'continue', $answer->getId() );
 61+ break;
 62+ }
 63+
 64+ $serializedAnswers[] = $answer->toArray();
 65+ }
 66+
 67+ $this->getResult()->setIndexedTagName( $serializedAnswers, 'answer' );
 68+
 69+ $this->getResult()->addValue(
 70+ null,
 71+ 'answers',
 72+ $serializedAnswers
 73+ );
 74+ }
 75+
 76+ public function needsToken() {
 77+ return true;
 78+ }
 79+
 80+ public function getTokenSalt() {
 81+ return 'querysurveyanswers';
 82+ }
 83+
 84+ /**
 85+ * (non-PHPdoc)
 86+ * @see includes/api/ApiBase#getAllowedParams()
 87+ */
 88+ public function getAllowedParams() {
 89+ $params = array (
 90+ 'props' => array(
 91+ ApiBase::PARAM_TYPE => array_merge( SurveyAnswer::getFieldNames(), array( '*' ) ),
 92+ ApiBase::PARAM_ISMULTI => true,
 93+ ApiBase::PARAM_DFLT => '*'
 94+ ),
 95+ 'limit' => array(
 96+ ApiBase::PARAM_DFLT => 20,
 97+ ApiBase::PARAM_TYPE => 'limit',
 98+ ApiBase::PARAM_MIN => 1,
 99+ ApiBase::PARAM_MAX => ApiBase::LIMIT_BIG1,
 100+ ApiBase::PARAM_MAX2 => ApiBase::LIMIT_BIG2
 101+ ),
 102+ 'continue' => null,
 103+ 'token' => null,
 104+ );
 105+
 106+ return array_merge( SurveyAnswer::getAPIParams( false ), $params );
 107+ }
 108+
 109+ /**
 110+ * (non-PHPdoc)
 111+ * @see includes/api/ApiBase#getParamDescription()
 112+ */
 113+ public function getParamDescription() {
 114+ $descs = array (
 115+ 'props' => 'Survey data to query',
 116+ 'continue' => 'Offset number from where to continue the query',
 117+ 'limit' => 'Max amount of words to return',
 118+ 'token' => 'Edit token. You can get one of these through prop=info.',
 119+ );
 120+
 121+ return array_merge( SurveyAnswer::getFieldDescriptions(), $descs );
 122+ }
 123+
 124+ /**
 125+ * (non-PHPdoc)
 126+ * @see includes/api/ApiBase#getDescription()
 127+ */
 128+ public function getDescription() {
 129+ return 'API module for obatining survey answers';
 130+ }
 131+
 132+ /**
 133+ * (non-PHPdoc)
 134+ * @see includes/api/ApiBase#getPossibleErrors()
 135+ */
 136+ public function getPossibleErrors() {
 137+ return array_merge( parent::getPossibleErrors(), array(
 138+ ) );
 139+ }
 140+
 141+ /**
 142+ * (non-PHPdoc)
 143+ * @see includes/api/ApiBase#getExamples()
 144+ */
 145+ protected function getExamples() {
 146+ return array (
 147+ 'api.php?action=query&list=surveyanswers&',
 148+ );
 149+ }
 150+
 151+ public function getVersion() {
 152+ return __CLASS__ . ': $Id$';
 153+ }
 154+
 155+}
Property changes on: tags/extensions/Survey/REL_0_1/api/ApiQuerySurveyAnswers.php
___________________________________________________________________
Added: svn:keywords
1156 + Id
Added: svn:eol-style
2157 + native
Index: tags/extensions/Survey/REL_0_1/api/ApiQuerySurveys.php
@@ -0,0 +1,215 @@
 2+<?php
 3+
 4+/**
 5+ * API module to get a list of surveys.
 6+ *
 7+ * @since 0.1
 8+ *
 9+ * @file ApiQuerySurveys.php
 10+ * @ingroup Surveys
 11+ * @ingroup API
 12+ *
 13+ * @licence GNU GPL v3+
 14+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
 15+ */
 16+class ApiQuerySurveys extends ApiQueryBase {
 17+
 18+ public function __construct( $main, $action ) {
 19+ parent::__construct( $main, $action, 'su' );
 20+ }
 21+
 22+ /**
 23+ * Retrieve the special words from the database.
 24+ */
 25+ public function execute() {
 26+ global $wgUser;
 27+
 28+ if ( $wgUser->isBlocked() ) {
 29+ $this->dieUsageMsg( array( 'badaccess-groups' ) );
 30+ }
 31+
 32+ // Get the requests parameters.
 33+ $params = $this->extractRequestParams();
 34+
 35+ if ( !( ( isset( $params['ids'] ) && count( $params['ids'] ) > 0 )
 36+ XOR ( isset( $params['names'] ) && count( $params['names'] ) > 0 )
 37+ ) ) {
 38+ $this->dieUsage( wfMsgExt( 'survey-err-ids-xor-names' ), 'ids-xor-names' );
 39+ }
 40+
 41+ $this->addTables( 'surveys' );
 42+
 43+ $starPropPosition = array_search( '*', $params['props'] );
 44+
 45+ if ( $starPropPosition !== false ) {
 46+ unset( $params['props'][$starPropPosition] );
 47+ $params['props'] = array_merge( $params['props'], Survey::getFieldNames() );
 48+ }
 49+
 50+ $fields = array_merge( array( 'id' ), $params['props'] );
 51+
 52+ $this->addFields( Survey::getPrefixedFields( $fields ) );
 53+
 54+ if ( isset( $params['ids'] ) ) {
 55+ $this->addWhere( array( 'survey_id' => $params['ids'] ) );
 56+ } else {
 57+ $this->addWhere( array( 'survey_name' => $params['names'] ) );
 58+ }
 59+
 60+ if ( isset( $params['enabled'] ) ) {
 61+ $this->addWhere( array( 'survey_enabled' => $params['enabled'] ) );
 62+ }
 63+
 64+ if ( isset( $params['continue'] ) ) {
 65+ $this->addWhere( 'survey_id >= ' . wfGetDB( DB_SLAVE )->addQuotes( $params['continue'] ) );
 66+ }
 67+
 68+ $this->addOption( 'LIMIT', $params['limit'] + 1 );
 69+ $this->addOption( 'ORDER BY', 'survey_id ASC' );
 70+
 71+ $surveys = $this->select( __METHOD__ );
 72+ $count = 0;
 73+ $resultSurveys = array();
 74+
 75+ foreach ( $surveys as $survey ) {
 76+ if ( ++$count > $params['limit'] ) {
 77+ // We've reached the one extra which shows that
 78+ // there are additional pages to be had. Stop here...
 79+ $this->setContinueEnumParameter( 'continue', $survey->survey_id );
 80+ break;
 81+ }
 82+
 83+ $surveyObject = Survey::newFromDBResult( $survey );
 84+
 85+ if ( $params['incquestions'] ) {
 86+ $surveyObject->loadQuestionsFromDB();
 87+ }
 88+
 89+ $resultSurveys[] = $this->getSurveyData( $surveyObject->toArray( $fields ) );
 90+ }
 91+
 92+ $this->getResult()->setIndexedTagName( $resultSurveys, 'survey' );
 93+
 94+ $this->getResult()->addValue(
 95+ null,
 96+ 'surveys',
 97+ $resultSurveys
 98+ );
 99+ }
 100+
 101+ /**
 102+ *
 103+ *
 104+ * @since 0.1
 105+ *
 106+ * @param array $survey
 107+ *
 108+ * @return $survey
 109+ */
 110+ protected function getSurveyData( array $survey ) {
 111+ foreach ( $survey['questions'] as $nr => $question ) {
 112+ $this->getResult()->setIndexedTagName( $survey['questions'][$nr], 'answer' );
 113+ }
 114+
 115+ $this->getResult()->setIndexedTagName( $survey['questions'], 'question' );
 116+
 117+ return $survey;
 118+ }
 119+
 120+ public function needsToken() {
 121+ return true;
 122+ }
 123+
 124+ public function getTokenSalt() {
 125+ return 'querysurveys';
 126+ }
 127+
 128+ /**
 129+ * (non-PHPdoc)
 130+ * @see includes/api/ApiBase#getAllowedParams()
 131+ */
 132+ public function getAllowedParams() {
 133+ return array (
 134+ 'ids' => array(
 135+ ApiBase::PARAM_TYPE => 'integer',
 136+ ApiBase::PARAM_ISMULTI => true,
 137+ ),
 138+ 'names' => array(
 139+ ApiBase::PARAM_TYPE => 'string',
 140+ ApiBase::PARAM_ISMULTI => true,
 141+ ),
 142+ 'props' => array(
 143+ ApiBase::PARAM_TYPE => array_merge( Survey::getFieldNames(), array( '*' ) ),
 144+ ApiBase::PARAM_ISMULTI => true,
 145+ ApiBase::PARAM_DFLT => 'id|name|enabled'
 146+ ),
 147+ 'incquestions' => array(
 148+ ApiBase::PARAM_TYPE => 'integer',
 149+ ApiBase::PARAM_DFLT => '0',
 150+ ),
 151+ 'enabled' => array(
 152+ ApiBase::PARAM_TYPE => 'integer',
 153+ ),
 154+ 'limit' => array(
 155+ ApiBase::PARAM_DFLT => 20,
 156+ ApiBase::PARAM_TYPE => 'limit',
 157+ ApiBase::PARAM_MIN => 1,
 158+ ApiBase::PARAM_MAX => ApiBase::LIMIT_BIG1,
 159+ ApiBase::PARAM_MAX2 => ApiBase::LIMIT_BIG2
 160+ ),
 161+ 'continue' => null,
 162+ 'token' => null,
 163+ );
 164+
 165+ }
 166+
 167+ /**
 168+ * (non-PHPdoc)
 169+ * @see includes/api/ApiBase#getParamDescription()
 170+ */
 171+ public function getParamDescription() {
 172+ return array (
 173+ 'ids' => 'The IDs of the surveys to return',
 174+ 'names' => 'The names of the surveys to return',
 175+ 'incquestions' => 'Include the questions of the surveys or not',
 176+ 'enabled' => 'Enabled state to filter on',
 177+ 'props' => 'Survey data to query',
 178+ 'continue' => 'Offset number from where to continue the query',
 179+ 'limit' => 'Max amount of words to return',
 180+ 'token' => 'Edit token. You can get one of these through prop=info.',
 181+ );
 182+ }
 183+
 184+ /**
 185+ * (non-PHPdoc)
 186+ * @see includes/api/ApiBase#getDescription()
 187+ */
 188+ public function getDescription() {
 189+ return 'API module for obatining surveys and optionaly their questions';
 190+ }
 191+
 192+ /**
 193+ * (non-PHPdoc)
 194+ * @see includes/api/ApiBase#getPossibleErrors()
 195+ */
 196+ public function getPossibleErrors() {
 197+ return array_merge( parent::getPossibleErrors(), array(
 198+ array( 'surveyids', 'name' ),
 199+ ) );
 200+ }
 201+
 202+ /**
 203+ * (non-PHPdoc)
 204+ * @see includes/api/ApiBase#getExamples()
 205+ */
 206+ protected function getExamples() {
 207+ return array (
 208+ 'api.php?action=query&list=surveys&',
 209+ );
 210+ }
 211+
 212+ public function getVersion() {
 213+ return __CLASS__ . ': $Id$';
 214+ }
 215+
 216+}
Property changes on: tags/extensions/Survey/REL_0_1/api/ApiQuerySurveys.php
___________________________________________________________________
Added: svn:keywords
1217 + Id
Added: svn:eol-style
2218 + native
Index: tags/extensions/Survey/REL_0_1/resources/ext.survey.tag.js
@@ -0,0 +1,98 @@
 2+/**
 3+ * JavasSript for the Survey MediaWiki extension.
 4+ * @see https://secure.wikimedia.org/wikipedia/mediawiki/wiki/Extension:Survey
 5+ *
 6+ * @licence GNU GPL v3 or later
 7+ * @author Jeroen De Dauw <jeroendedauw at gmail dot com>
 8+ */
 9+
 10+(function( $, survey ) {
 11+
 12+ function getCookieName( options ) {
 13+ return ( typeof options.id !== 'undefined' ) ?
 14+ 'survey-id-' + options.id
 15+ : 'survey-name-' + options.name
 16+ }
 17+
 18+ function getCookie( options ) {
 19+ var cookie = $.cookie( getCookieName( options ) );
 20+ survey.log( 'read "' + cookie + '" from cookie ' + getCookieName( options ) );
 21+ return cookie;
 22+ }
 23+
 24+ function setCookie( options, cookieValue ) {
 25+ var date = new Date();
 26+ date.setTime( date.getTime() + options.expiry * 1000 );
 27+ $.cookie( getCookieName( options ), cookieValue, { 'expires': date, 'path': '/' } );
 28+ survey.log( 'wrote "' + cookieValue + '" to cookie ' + getCookieName( options ) );
 29+ }
 30+
 31+ function hasCookie( options ) {
 32+ return getCookie( options ) !== null;
 33+ }
 34+
 35+ function winsLottery( options ) {
 36+ var rand = Math.random();
 37+ survey.log( 'doLottery: ' + rand + ' < ' + options.ratio );
 38+ return rand < options.ratio;
 39+ }
 40+
 41+ function initCookieSurvey( options, $tag ) {
 42+ if ( hasCookie( options ) || options.ratio === 1 || winsLottery( options ) ) {
 43+ var cookie = getCookie( options );
 44+
 45+ if ( cookie !== 'done' ) {
 46+ if ( ( options.pages === 0 || parseInt( cookie ) >= options.pages ) ) {
 47+ $tag.mwSurvey( options );
 48+ setCookie( options, 'done' );
 49+ }
 50+ else if ( options.pages !== 0 ) {
 51+ var nr = parseInt( getCookie( options ) );
 52+ setCookie( options, ( isNaN( nr ) ? 0 : nr ) + 1 )
 53+ }
 54+ }
 55+ }
 56+ else {
 57+ setCookie( options, 'done' );
 58+ }
 59+ }
 60+
 61+ function initTag( $tag ) {
 62+ var ratioAttr = $tag.attr( 'survey-data-ratio' );
 63+ var expiryAttr = $tag.attr( 'survey-data-expiry' );
 64+ var pagesAttr = $tag.attr( 'survey-data-min-pages' );
 65+
 66+ var options = {
 67+ 'ratio': typeof ratioAttr === 'undefined' ? 1 : parseFloat( ratioAttr ) / 100,
 68+ 'cookie': $tag.attr( 'survey-data-cookie' ) !== 'no',
 69+ 'expiry': typeof expiryAttr === 'undefined' ? 60 * 60 * 24 * 30 : parseInt( expiryAttr ),
 70+ 'pages': typeof pagesAttr === 'undefined' ? 0 : parseInt( pagesAttr )
 71+ };
 72+
 73+ if ( $tag.attr( 'survey-data-id' ) ) {
 74+ options.id = $tag.attr( 'survey-data-id' );
 75+ } else if ( $tag.attr( 'survey-data-name' ) ) {
 76+ options.name = $tag.attr( 'survey-data-name' );
 77+ }
 78+ else {
 79+ // TODO
 80+ return;
 81+ }
 82+
 83+ if ( options.cookie ) {
 84+ initCookieSurvey( options, $tag );
 85+ }
 86+ else {
 87+ $tag.mwSurvey( options );
 88+ }
 89+ }
 90+
 91+ $( document ).ready( function() {
 92+
 93+ $( '.surveytag' ).each( function( index, domElement ) {
 94+ initTag( $( domElement ) );
 95+ } );
 96+
 97+ } );
 98+
 99+})( jQuery, window.survey );
\ No newline at end of file
Property changes on: tags/extensions/Survey/REL_0_1/resources/ext.survey.tag.js
___________________________________________________________________
Added: svn:eol-style
1100 + native
Index: tags/extensions/Survey/REL_0_1/resources/ext.survey.special.survey.js
@@ -0,0 +1,186 @@
 2+/**
 3+ * JavasSript for the Survey MediaWiki extension.
 4+ * @see https://secure.wikimedia.org/wikipedia/mediawiki/wiki/Extension:Survey
 5+ *
 6+ * @licence GNU GPL v3 or later
 7+ * @author Jeroen De Dauw <jeroendedauw at gmail dot com>
 8+ */
 9+
 10+(function( $, mw, survey ) { $( document ).ready( function() {
 11+
 12+ var _this = this;
 13+
 14+ var $table = null;
 15+ var newQuestionNr = 0;
 16+ var questionNr = 0;
 17+
 18+ function addAddQuestionRow() {
 19+ var $tr = $( '<tr />' ).attr( {
 20+ 'class': 'add-question'
 21+ } );
 22+
 23+ $table.append( $tr );
 24+
 25+ $tr.append( $( '<td />' ).attr( { 'class': 'mw-label question-label' } ).html(
 26+ '' //$( '<label />' ).text( mw.msg( 'survey-special-label-addquestion' ) )
 27+ ) );
 28+
 29+ $tr.append( $( '<td />' ).attr( { 'class': 'mw-input' } ).html(
 30+ '' //getQuestionInput( { 'id': 'new', 'answers': [], 'type': 0 } )
 31+ ).append( $( '<button />' ).button( { 'label': mw.msg( 'survey-special-label-add-first' ) } )
 32+ .click( function() {
 33+ $( this ).button( { 'label': mw.msg( 'survey-special-label-add-another' ) } );
 34+ onAddQuestionRequest();
 35+ return false;
 36+ } )
 37+ ) );
 38+//
 39+// $( '#survey-question-text-new' ).keypress( function( event ) {
 40+// if ( event.which == '13' ) {
 41+// event.preventDefault();
 42+// onAddQuestionRequest();
 43+// }
 44+// } );
 45+ };
 46+
 47+ function addQuestion( question ) {
 48+ var $tr = $( '<tr />' ).attr( {
 49+ 'class': 'mw-htmlform-field-SurveyQuestionField'
 50+ } );
 51+
 52+ $tr.append( $( '<td />' ).attr( { 'class': 'mw-label question-label' } ).html(
 53+ $( '<label />' ).text( mw.msg( 'survey-question-label-nr', ++questionNr ) )
 54+ ) );
 55+
 56+ $tr.append( $( '<td />' ).attr( { 'class': 'mw-input' } ).html(
 57+ getQuestionInput( question )
 58+ .append( '<br />' )
 59+ .append( $( '<button />' ).button( { 'label': mw.msg( 'survey-special-remove' ) } )
 60+ .click( function() {
 61+ if ( confirm( mw.msg( 'survey-special-remove-confirm' ) ) ) {
 62+ removeQuestion( question );
 63+ }
 64+
 65+ return false;
 66+ } )
 67+ )
 68+ ) );
 69+
 70+ $table.find( '.add-question' ).before( $tr );
 71+ };
 72+
 73+ function getQuestionInput( question ) {
 74+ var $input = $( '<div />' ).attr( {
 75+ 'border': '1px solid black',
 76+ 'id': 'survey-question-div-' + question.id
 77+ } );
 78+
 79+ var answerSelector = new survey.answerSelector( {
 80+ 'visible': survey.question.typeHasAnswers( parseInt( question.type ) ),
 81+ 'attr': {
 82+ 'rows': 2,
 83+ 'cols': 80,
 84+ 'id': 'survey-question-answers-' + question.id,
 85+ 'name': 'survey-question-answers-' + question.id
 86+ },
 87+ 'answers': question.answers
 88+ } );
 89+
 90+ $input.append( $( '<label />' ).attr( {
 91+ 'for': 'survey-question-text-' + question.id
 92+ } ).text( mw.msg( 'survey-special-label-text' ) ) );
 93+
 94+ $input.append( '<br />' );
 95+
 96+ $input.append( $( '<textarea />' ).attr( {
 97+ 'rows': 2,
 98+ 'cols': 80,
 99+ 'id': 'survey-question-text-' + question.id,
 100+ 'name': 'survey-question-text-' + question.id
 101+ } ).val( question.text ) );
 102+
 103+ $input.append( '<br />' );
 104+
 105+ $input.append( $( '<label />' ).attr( {
 106+ 'for': 'survey-question-type-' + question.id
 107+ } ).text( mw.msg( 'survey-special-label-type' ) ) );
 108+
 109+ $input.append( survey.question.getTypeSelector(
 110+ question.type,
 111+ {
 112+ 'id': 'survey-question-type-' + question.id,
 113+ 'name': 'survey-question-type-' + question.id
 114+ },
 115+ function( newValue ) {
 116+ answerSelector.setVisible( survey.question.typeHasAnswers( parseInt( newValue ) ) );
 117+ }
 118+ ) );
 119+
 120+ // Not implemented in actual survey yet, so don't show for now.
 121+// $required = $( '<input />' ).attr( {
 122+// 'id': 'survey-question-required-' + question.id,
 123+// 'name': 'survey-question-required-' + question.id,
 124+// 'type': 'checkbox',
 125+// } );
 126+//
 127+// if ( question.required ) {
 128+// $required.attr( 'checked', 'checked' );
 129+// }
 130+//
 131+// $input.append( $required );
 132+//
 133+// $input.append( $( '<label />' ).attr( {
 134+// 'for': 'survey-question-required-' + question.id
 135+// } ).text( mw.msg( 'survey-special-label-required' ) ) );
 136+
 137+ $input.append( answerSelector.getHtml() );
 138+
 139+ return $input;
 140+ };
 141+
 142+ function removeQuestion( question ) {
 143+ $( '#survey-question-div-' + question.id ).closest( 'tr' ).slideUp( 'fast', function() { $( this ).remove(); } )
 144+ };
 145+
 146+ function onAddQuestionRequest() {
 147+ addQuestion( {
 148+ 'text': '', // $( '#survey-question-text-new' ).val(),
 149+ 'required': false, //!!$( '#survey-question-required-new' ).attr( 'checked' ),
 150+ 'type': 0, // $( '#survey-question-type-new' ).val(),
 151+ 'id': 'new-' + ++newQuestionNr,
 152+ 'answers': [] //$( '#survey-question-answers-new' ).val().split( '\n' )
 153+ } );
 154+ $( '#survey-question-text-new-' + newQuestionNr ).focus().select();
 155+ $( 'html' ).animate( { scrollTop: $( document ).height() }, 'fast' );
 156+ };
 157+
 158+ function setup() {
 159+ $table = $( '#survey-title' ).closest( 'tbody' );
 160+
 161+ $table.append( '<tr><td colspan="2"><hr /></td></tr>' );
 162+
 163+ addAddQuestionRow();
 164+
 165+ $table.append( '<tr><td colspan="2"><hr /></td></tr>' );
 166+
 167+ $( '.survey-question-data' ).each( function( index, domElement ) {
 168+ $this = $( domElement );
 169+
 170+ addQuestion( {
 171+ 'text': $this.attr( 'data-text' ),
 172+ 'default': $this.attr( 'data-default' ),
 173+ 'required': $this.attr( 'data-required' ) == '1',
 174+ 'id': $this.attr( 'data-id' ),
 175+ 'type': $this.attr( 'data-type' ),
 176+ 'answers': eval( $this.attr( 'data-answers' ) ),
 177+ } );
 178+ } );
 179+
 180+ $( '.mw-htmlform-submit' ).button();
 181+ $( '#cancelEdit' ).button();
 182+
 183+ };
 184+
 185+ setup();
 186+
 187+} ); })( jQuery, window.mediaWiki, window.survey );
\ No newline at end of file
Property changes on: tags/extensions/Survey/REL_0_1/resources/ext.survey.special.survey.js
___________________________________________________________________
Added: svn:eol-style
1188 + native
Index: tags/extensions/Survey/REL_0_1/resources/jquery.survey.css
@@ -0,0 +1,12 @@
 2+@CHARSET "UTF-8";
 3+
 4+.survey-textarea {
 5+ width: 80%
 6+}
 7+
 8+div.survey-question {
 9+ border-top: 1px solid #ddd;
 10+ padding-top: 10px;
 11+ padding-bottom: 10px;
 12+ font-size: smaller;
 13+}
Property changes on: tags/extensions/Survey/REL_0_1/resources/jquery.survey.css
___________________________________________________________________
Added: svn:eol-style
114 + native
Index: tags/extensions/Survey/REL_0_1/resources/JSON.js
@@ -0,0 +1,480 @@
 2+/*
 3+ http://www.JSON.org/json2.js
 4+ 2011-02-23
 5+
 6+ Public Domain.
 7+
 8+ NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
 9+
 10+ See http://www.JSON.org/js.html
 11+
 12+
 13+ This code should be minified before deployment.
 14+ See http://javascript.crockford.com/jsmin.html
 15+
 16+ USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
 17+ NOT CONTROL.
 18+
 19+
 20+ This file creates a global JSON object containing two methods: stringify
 21+ and parse.
 22+
 23+ JSON.stringify(value, replacer, space)
 24+ value any JavaScript value, usually an object or array.
 25+
 26+ replacer an optional parameter that determines how object
 27+ values are stringified for objects. It can be a
 28+ function or an array of strings.
 29+
 30+ space an optional parameter that specifies the indentation
 31+ of nested structures. If it is omitted, the text will
 32+ be packed without extra whitespace. If it is a number,
 33+ it will specify the number of spaces to indent at each
 34+ level. If it is a string (such as '\t' or '&nbsp;'),
 35+ it contains the characters used to indent at each level.
 36+
 37+ This method produces a JSON text from a JavaScript value.
 38+
 39+ When an object value is found, if the object contains a toJSON
 40+ method, its toJSON method will be called and the result will be
 41+ stringified. A toJSON method does not serialize: it returns the
 42+ value represented by the name/value pair that should be serialized,
 43+ or undefined if nothing should be serialized. The toJSON method
 44+ will be passed the key associated with the value, and this will be
 45+ bound to the value
 46+
 47+ For example, this would serialize Dates as ISO strings.
 48+
 49+ Date.prototype.toJSON = function (key) {
 50+ function f(n) {
 51+ // Format integers to have at least two digits.
 52+ return n < 10 ? '0' + n : n;
 53+ }
 54+
 55+ return this.getUTCFullYear() + '-' +
 56+ f(this.getUTCMonth() + 1) + '-' +
 57+ f(this.getUTCDate()) + 'T' +
 58+ f(this.getUTCHours()) + ':' +
 59+ f(this.getUTCMinutes()) + ':' +
 60+ f(this.getUTCSeconds()) + 'Z';
 61+ };
 62+
 63+ You can provide an optional replacer method. It will be passed the
 64+ key and value of each member, with this bound to the containing
 65+ object. The value that is returned from your method will be
 66+ serialized. If your method returns undefined, then the member will
 67+ be excluded from the serialization.
 68+
 69+ If the replacer parameter is an array of strings, then it will be
 70+ used to select the members to be serialized. It filters the results
 71+ such that only members with keys listed in the replacer array are
 72+ stringified.
 73+
 74+ Values that do not have JSON representations, such as undefined or
 75+ functions, will not be serialized. Such values in objects will be
 76+ dropped; in arrays they will be replaced with null. You can use
 77+ a replacer function to replace those with JSON values.
 78+ JSON.stringify(undefined) returns undefined.
 79+
 80+ The optional space parameter produces a stringification of the
 81+ value that is filled with line breaks and indentation to make it
 82+ easier to read.
 83+
 84+ If the space parameter is a non-empty string, then that string will
 85+ be used for indentation. If the space parameter is a number, then
 86+ the indentation will be that many spaces.
 87+
 88+ Example:
 89+
 90+ text = JSON.stringify(['e', {pluribus: 'unum'}]);
 91+ // text is '["e",{"pluribus":"unum"}]'
 92+
 93+
 94+ text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
 95+ // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
 96+
 97+ text = JSON.stringify([new Date()], function (key, value) {
 98+ return this[key] instanceof Date ?
 99+ 'Date(' + this[key] + ')' : value;
 100+ });
 101+ // text is '["Date(---current time---)"]'
 102+
 103+
 104+ JSON.parse(text, reviver)
 105+ This method parses a JSON text to produce an object or array.
 106+ It can throw a SyntaxError exception.
 107+
 108+ The optional reviver parameter is a function that can filter and
 109+ transform the results. It receives each of the keys and values,
 110+ and its return value is used instead of the original value.
 111+ If it returns what it received, then the structure is not modified.
 112+ If it returns undefined then the member is deleted.
 113+
 114+ Example:
 115+
 116+ // Parse the text. Values that look like ISO date strings will
 117+ // be converted to Date objects.
 118+
 119+ myData = JSON.parse(text, function (key, value) {
 120+ var a;
 121+ if (typeof value === 'string') {
 122+ a =
 123+/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
 124+ if (a) {
 125+ return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
 126+ +a[5], +a[6]));
 127+ }
 128+ }
 129+ return value;
 130+ });
 131+
 132+ myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
 133+ var d;
 134+ if (typeof value === 'string' &&
 135+ value.slice(0, 5) === 'Date(' &&
 136+ value.slice(-1) === ')') {
 137+ d = new Date(value.slice(5, -1));
 138+ if (d) {
 139+ return d;
 140+ }
 141+ }
 142+ return value;
 143+ });
 144+
 145+
 146+ This is a reference implementation. You are free to copy, modify, or
 147+ redistribute.
 148+*/
 149+
 150+/*jslint evil: true, strict: false, regexp: false */
 151+
 152+/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
 153+ call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
 154+ getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
 155+ lastIndex, length, parse, prototype, push, replace, slice, stringify,
 156+ test, toJSON, toString, valueOf
 157+*/
 158+
 159+
 160+// Create a JSON object only if one does not already exist. We create the
 161+// methods in a closure to avoid creating global variables.
 162+
 163+var JSON;
 164+if (!JSON) {
 165+ JSON = {};
 166+}
 167+
 168+(function () {
 169+ "use strict";
 170+
 171+ function f(n) {
 172+ // Format integers to have at least two digits.
 173+ return n < 10 ? '0' + n : n;
 174+ }
 175+
 176+ if (typeof Date.prototype.toJSON !== 'function') {
 177+
 178+ Date.prototype.toJSON = function (key) {
 179+
 180+ return isFinite(this.valueOf()) ?
 181+ this.getUTCFullYear() + '-' +
 182+ f(this.getUTCMonth() + 1) + '-' +
 183+ f(this.getUTCDate()) + 'T' +
 184+ f(this.getUTCHours()) + ':' +
 185+ f(this.getUTCMinutes()) + ':' +
 186+ f(this.getUTCSeconds()) + 'Z' : null;
 187+ };
 188+
 189+ String.prototype.toJSON =
 190+ Number.prototype.toJSON =
 191+ Boolean.prototype.toJSON = function (key) {
 192+ return this.valueOf();
 193+ };
 194+ }
 195+
 196+ var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
 197+ escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
 198+ gap,
 199+ indent,
 200+ meta = { // table of character substitutions
 201+ '\b': '\\b',
 202+ '\t': '\\t',
 203+ '\n': '\\n',
 204+ '\f': '\\f',
 205+ '\r': '\\r',
 206+ '"' : '\\"',
 207+ '\\': '\\\\'
 208+ },
 209+ rep;
 210+
 211+
 212+ function quote(string) {
 213+
 214+// If the string contains no control characters, no quote characters, and no
 215+// backslash characters, then we can safely slap some quotes around it.
 216+// Otherwise we must also replace the offending characters with safe escape
 217+// sequences.
 218+
 219+ escapable.lastIndex = 0;
 220+ return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
 221+ var c = meta[a];
 222+ return typeof c === 'string' ? c :
 223+ '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
 224+ }) + '"' : '"' + string + '"';
 225+ }
 226+
 227+
 228+ function str(key, holder) {
 229+
 230+// Produce a string from holder[key].
 231+
 232+ var i, // The loop counter.
 233+ k, // The member key.
 234+ v, // The member value.
 235+ length,
 236+ mind = gap,
 237+ partial,
 238+ value = holder[key];
 239+
 240+// If the value has a toJSON method, call it to obtain a replacement value.
 241+
 242+ if (value && typeof value === 'object' &&
 243+ typeof value.toJSON === 'function') {
 244+ value = value.toJSON(key);
 245+ }
 246+
 247+// If we were called with a replacer function, then call the replacer to
 248+// obtain a replacement value.
 249+
 250+ if (typeof rep === 'function') {
 251+ value = rep.call(holder, key, value);
 252+ }
 253+
 254+// What happens next depends on the value's type.
 255+
 256+ switch (typeof value) {
 257+ case 'string':
 258+ return quote(value);
 259+
 260+ case 'number':
 261+
 262+// JSON numbers must be finite. Encode non-finite numbers as null.
 263+
 264+ return isFinite(value) ? String(value) : 'null';
 265+
 266+ case 'boolean':
 267+ case 'null':
 268+
 269+// If the value is a boolean or null, convert it to a string. Note:
 270+// typeof null does not produce 'null'. The case is included here in
 271+// the remote chance that this gets fixed someday.
 272+
 273+ return String(value);
 274+
 275+// If the type is 'object', we might be dealing with an object or an array or
 276+// null.
 277+
 278+ case 'object':
 279+
 280+// Due to a specification blunder in ECMAScript, typeof null is 'object',
 281+// so watch out for that case.
 282+
 283+ if (!value) {
 284+ return 'null';
 285+ }
 286+
 287+// Make an array to hold the partial results of stringifying this object value.
 288+
 289+ gap += indent;
 290+ partial = [];
 291+
 292+// Is the value an array?
 293+
 294+ if (Object.prototype.toString.apply(value) === '[object Array]') {
 295+
 296+// The value is an array. Stringify every element. Use null as a placeholder
 297+// for non-JSON values.
 298+
 299+ length = value.length;
 300+ for (i = 0; i < length; i += 1) {
 301+ partial[i] = str(i, value) || 'null';
 302+ }
 303+
 304+// Join all of the elements together, separated with commas, and wrap them in
 305+// brackets.
 306+
 307+ v = partial.length === 0 ? '[]' : gap ?
 308+ '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' :
 309+ '[' + partial.join(',') + ']';
 310+ gap = mind;
 311+ return v;
 312+ }
 313+
 314+// If the replacer is an array, use it to select the members to be stringified.
 315+
 316+ if (rep && typeof rep === 'object') {
 317+ length = rep.length;
 318+ for (i = 0; i < length; i += 1) {
 319+ if (typeof rep[i] === 'string') {
 320+ k = rep[i];
 321+ v = str(k, value);
 322+ if (v) {
 323+ partial.push(quote(k) + (gap ? ': ' : ':') + v);
 324+ }
 325+ }
 326+ }
 327+ } else {
 328+
 329+// Otherwise, iterate through all of the keys in the object.
 330+
 331+ for (k in value) {
 332+ if (Object.prototype.hasOwnProperty.call(value, k)) {
 333+ v = str(k, value);
 334+ if (v) {
 335+ partial.push(quote(k) + (gap ? ': ' : ':') + v);
 336+ }
 337+ }
 338+ }
 339+ }
 340+
 341+// Join all of the member texts together, separated with commas,
 342+// and wrap them in braces.
 343+
 344+ v = partial.length === 0 ? '{}' : gap ?
 345+ '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' :
 346+ '{' + partial.join(',') + '}';
 347+ gap = mind;
 348+ return v;
 349+ }
 350+ }
 351+
 352+// If the JSON object does not yet have a stringify method, give it one.
 353+
 354+ if (typeof JSON.stringify !== 'function') {
 355+ JSON.stringify = function (value, replacer, space) {
 356+
 357+// The stringify method takes a value and an optional replacer, and an optional
 358+// space parameter, and returns a JSON text. The replacer can be a function
 359+// that can replace values, or an array of strings that will select the keys.
 360+// A default replacer method can be provided. Use of the space parameter can
 361+// produce text that is more easily readable.
 362+
 363+ var i;
 364+ gap = '';
 365+ indent = '';
 366+
 367+// If the space parameter is a number, make an indent string containing that
 368+// many spaces.
 369+
 370+ if (typeof space === 'number') {
 371+ for (i = 0; i < space; i += 1) {
 372+ indent += ' ';
 373+ }
 374+
 375+// If the space parameter is a string, it will be used as the indent string.
 376+
 377+ } else if (typeof space === 'string') {
 378+ indent = space;
 379+ }
 380+
 381+// If there is a replacer, it must be a function or an array.
 382+// Otherwise, throw an error.
 383+
 384+ rep = replacer;
 385+ if (replacer && typeof replacer !== 'function' &&
 386+ (typeof replacer !== 'object' ||
 387+ typeof replacer.length !== 'number')) {
 388+ throw new Error('JSON.stringify');
 389+ }
 390+
 391+// Make a fake root object containing our value under the key of ''.
 392+// Return the result of stringifying the value.
 393+
 394+ return str('', {'': value});
 395+ };
 396+ }
 397+
 398+
 399+// If the JSON object does not yet have a parse method, give it one.
 400+
 401+ if (typeof JSON.parse !== 'function') {
 402+ JSON.parse = function (text, reviver) {
 403+
 404+// The parse method takes a text and an optional reviver function, and returns
 405+// a JavaScript value if the text is a valid JSON text.
 406+
 407+ var j;
 408+
 409+ function walk(holder, key) {
 410+
 411+// The walk method is used to recursively walk the resulting structure so
 412+// that modifications can be made.
 413+
 414+ var k, v, value = holder[key];
 415+ if (value && typeof value === 'object') {
 416+ for (k in value) {
 417+ if (Object.prototype.hasOwnProperty.call(value, k)) {
 418+ v = walk(value, k);
 419+ if (v !== undefined) {
 420+ value[k] = v;
 421+ } else {
 422+ delete value[k];
 423+ }
 424+ }
 425+ }
 426+ }
 427+ return reviver.call(holder, key, value);
 428+ }
 429+
 430+
 431+// Parsing happens in four stages. In the first stage, we replace certain
 432+// Unicode characters with escape sequences. JavaScript handles many characters
 433+// incorrectly, either silently deleting them, or treating them as line endings.
 434+
 435+ text = String(text);
 436+ cx.lastIndex = 0;
 437+ if (cx.test(text)) {
 438+ text = text.replace(cx, function (a) {
 439+ return '\\u' +
 440+ ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
 441+ });
 442+ }
 443+
 444+// In the second stage, we run the text against regular expressions that look
 445+// for non-JSON patterns. We are especially concerned with '()' and 'new'
 446+// because they can cause invocation, and '=' because it can cause mutation.
 447+// But just to be safe, we want to reject all unexpected forms.
 448+
 449+// We split the second stage into 4 regexp operations in order to work around
 450+// crippling inefficiencies in IE's and Safari's regexp engines. First we
 451+// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
 452+// replace all simple value tokens with ']' characters. Third, we delete all
 453+// open brackets that follow a colon or comma or that begin the text. Finally,
 454+// we look to see that the remaining characters are only whitespace or ']' or
 455+// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
 456+
 457+ if (/^[\],:{}\s]*$/
 458+ .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
 459+ .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
 460+ .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
 461+
 462+// In the third stage we use the eval function to compile the text into a
 463+// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
 464+// in JavaScript: it can begin a block or an object literal. We wrap the text
 465+// in parens to eliminate the ambiguity.
 466+
 467+ j = eval('(' + text + ')');
 468+
 469+// In the optional fourth stage, we recursively walk the new structure, passing
 470+// each name/value pair to a reviver function for possible transformation.
 471+
 472+ return typeof reviver === 'function' ?
 473+ walk({'': j}, '') : j;
 474+ }
 475+
 476+// If the text is not JSON parseable, then a SyntaxError is thrown.
 477+
 478+ throw new SyntaxError('JSON.parse');
 479+ };
 480+ }
 481+}());
Property changes on: tags/extensions/Survey/REL_0_1/resources/JSON.js
___________________________________________________________________
Added: svn:eol-style
1482 + native
Index: tags/extensions/Survey/REL_0_1/resources/ext.survey.special.surveys.js
@@ -0,0 +1,50 @@
 2+/**
 3+ * JavasSript for the Survey MediaWiki extension.
 4+ * @see https://secure.wikimedia.org/wikipedia/mediawiki/wiki/Extension:Survey
 5+ *
 6+ * @licence GNU GPL v3 or later
 7+ * @author Jeroen De Dauw <jeroendedauw at gmail dot com>
 8+ */
 9+
 10+(function( $ ) { $( document ).ready( function() {
 11+
 12+ function deleteSurvey( options, successCallback, failCallback ) {
 13+ $.post(
 14+ wgScriptPath + '/api.php',
 15+ {
 16+ 'action': 'deletesurvey',
 17+ 'format': 'json',
 18+ 'ids': options.id,
 19+ 'token': options.token
 20+ },
 21+ function( data ) {
 22+ if ( data.success ) {
 23+ successCallback();
 24+ } else {
 25+ failCallback( mw.msg( 'surveys-special-delete-failed' ) );
 26+ }
 27+ }
 28+ );
 29+ }
 30+
 31+ $( '.survey-delete' ).click( function() {
 32+ $this = $( this );
 33+
 34+ if ( confirm( mw.msg( 'surveys-special-confirm-delete' ) ) ) {
 35+ deleteSurvey(
 36+ {
 37+ id: $this.attr( 'data-survey-id' ),
 38+ token: $this.attr( 'data-survey-token' )
 39+ },
 40+ function() {
 41+ $this.closest( 'tr' ).slideUp( 'slow', function() { $( this ).remove(); } );
 42+ },
 43+ function( error ) {
 44+ alert( error );
 45+ }
 46+ );
 47+ }
 48+ return false;
 49+ } );
 50+
 51+} ); })( jQuery );
\ No newline at end of file
Property changes on: tags/extensions/Survey/REL_0_1/resources/ext.survey.special.surveys.js
___________________________________________________________________
Added: svn:eol-style
152 + native
Index: tags/extensions/Survey/REL_0_1/resources/ext.survey.answerSelector.js
@@ -0,0 +1,55 @@
 2+/**
 3+ * JavasSript for the Survey MediaWiki extension.
 4+ * @see https://secure.wikimedia.org/wikipedia/mediawiki/wiki/Extension:Survey
 5+ *
 6+ * @licence GNU GPL v3 or later
 7+ * @author Jeroen De Dauw <jeroendedauw at gmail dot com>
 8+ */
 9+
 10+(function( $, mw, survey ) {
 11+
 12+ survey.answerSelector = function( options ) {
 13+ var _this = this;
 14+
 15+ var defaults = {
 16+ 'visible': true,
 17+ 'answers': []
 18+ };
 19+
 20+ options = $.extend( defaults, options );
 21+
 22+ this.$div = $( '<div />' ).html( '' );
 23+
 24+ this.$div.append( $( '<p />' ).text( mw.msg( 'survey-special-label-answers' ) ) );
 25+
 26+ this.$div.append( $( '<textarea />' ).attr( options.attr ).val( options.answers.join( '\n' ) ) );
 27+
 28+ this.setVisible( options.visible );
 29+ };
 30+
 31+ survey.answerSelector.prototype = {
 32+
 33+ getHtml: function() {
 34+ return this.$div;
 35+ },
 36+
 37+ show: function() {
 38+ this.$div.show();
 39+ },
 40+
 41+ hide: function() {
 42+ this.$div.hide();
 43+ },
 44+
 45+ setVisible: function( visible ) {
 46+ if ( visible ) {
 47+ this.show();
 48+ }
 49+ else {
 50+ this.hide();
 51+ }
 52+ }
 53+
 54+ };
 55+
 56+} )( jQuery, window.mediaWiki, window.survey );
Property changes on: tags/extensions/Survey/REL_0_1/resources/ext.survey.answerSelector.js
___________________________________________________________________
Added: svn:eol-style
157 + native
Index: tags/extensions/Survey/REL_0_1/resources/jquery.survey.js
@@ -0,0 +1,313 @@
 2+/**
 3+ * JavasSript for the Survey MediaWiki extension.
 4+ * @see https://secure.wikimedia.org/wikipedia/mediawiki/wiki/Extension:Survey
 5+ *
 6+ * @licence GNU GPL v3 or later
 7+ * @author Jeroen De Dauw <jeroendedauw at gmail dot com>
 8+ */
 9+
 10+( function ( $ ) { $.fn.mwSurvey = function( options ) {
 11+
 12+ var _this = this;
 13+ this.options = options;
 14+
 15+ this.inputs = [];
 16+
 17+ this.identifier = null;
 18+ this.identifierType = null;
 19+
 20+ this.getSurveyData = function( options, callback ) {
 21+ var requestArgs = {
 22+ 'action': 'query',
 23+ 'list': 'surveys',
 24+ 'format': 'json',
 25+ 'suincquestions': 1,
 26+ 'suprops': '*'
 27+ };
 28+
 29+ if ( options.requireEnabled ) {
 30+ requestArgs['suenabled'] = 1;
 31+ }
 32+
 33+ requestArgs[ 'su' + this.identifierType + 's' ] = this.identifier;
 34+
 35+ $.getJSON(
 36+ wgScriptPath + '/api.php',
 37+ requestArgs,
 38+ function( data ) {
 39+ if ( data.surveys ) {
 40+ callback( data.surveys );
 41+ } else if ( data.error ) {
 42+ debugger;
 43+ // TODO
 44+ } else {
 45+ debugger;
 46+ // TODO
 47+ }
 48+ }
 49+ );
 50+ };
 51+
 52+ this.getQuestionInput = function( question ) {
 53+ survey.log( 'getQuestionInput: ' + question.id );
 54+
 55+ var type = survey.question.type;
 56+
 57+ var $input;
 58+ var id = 'question-input-' + question.id;
 59+
 60+ switch ( question.type ) {
 61+ case type.TEXT: default:
 62+ $input = $( '<input />' ).attr( {
 63+ 'id': id,
 64+ 'class': 'question-input survey-text'
 65+ } );
 66+ break;
 67+ case type.NUMBER:
 68+ $input = $( '<input />' ).numeric().attr( {
 69+ 'id': id,
 70+ 'class': 'question-input survey-number',
 71+ 'size': 7
 72+ } );
 73+ break;
 74+ case type.SELECT:
 75+ var answers = {};
 76+
 77+ for ( i in question.answers ) {
 78+ answers[question.answers[i]] = question.answers[i];
 79+ }
 80+
 81+ $input = survey.htmlSelect( answers, 0, {
 82+ 'id': id,
 83+ 'class': 'question-input survey-select'
 84+ } );
 85+ break;
 86+ case type.RADIO:
 87+ var answers = {};
 88+
 89+ for ( i in question.answers ) {
 90+ answers[question.answers[i]] = question.answers[i];
 91+ }
 92+
 93+ $input = survey.htmlRadio(
 94+ answers,
 95+ null,
 96+ id,
 97+ {
 98+ 'id': id,
 99+ 'class': 'question-input survey-radio'
 100+ }
 101+ );
 102+ break;
 103+ case type.TEXTAREA:
 104+ $input = $( '<textarea />' ).attr( {
 105+ 'id': id,
 106+ 'class': 'question-input survey-textarea',
 107+ 'cols': 80,
 108+ 'rows': 2
 109+ } );
 110+ break;
 111+ case type.CHECK:
 112+ $input = $( '<input />' ).attr( {
 113+ 'id': id,
 114+ 'type': 'checkbox',
 115+ 'class': 'question-input survey-check',
 116+ } );
 117+ break;
 118+ }
 119+
 120+ $input.data( 'question-id', question.id );
 121+
 122+ this.inputs.push( { 'input': $input, 'type': question.type } );
 123+
 124+ $q = $( '<div />' ).attr( 'class', 'survey-question' ).html( $input );
 125+
 126+ if ( question.type === type.CHECK ) {
 127+ $q.prepend( $( '<label />' ).text( question.text ).attr( 'for', id ) );
 128+ }
 129+ else {
 130+ $q.prepend( $( '<p />' ).text( question.text ).attr( 'class', 'question-text' ) );
 131+ }
 132+
 133+ return $q;
 134+ };
 135+
 136+ this.getSurveyQuestion = function( question ) {
 137+ if ( survey.question.typeHasAnswers( question.type )
 138+ && question.answers.length == 0 ) {
 139+ survey.log( 'getSurveyQuestion: no answers for: ' + question.id );
 140+ return '';
 141+ }
 142+ else {
 143+ return this.getQuestionInput( question );
 144+ }
 145+ };
 146+
 147+ this.getSurveyQuestions = function( questions ) {
 148+ $questions = $( '<div />' );
 149+
 150+ for ( i in questions ) {
 151+ $questions.append( this.getSurveyQuestion( questions[i] ) );
 152+ }
 153+
 154+ return $questions;
 155+ };
 156+
 157+ this.getAnswers = function( surveyId ) {
 158+ var answers = [];
 159+
 160+ for ( i in this.inputs ) {
 161+ var $input = this.inputs[i].input;
 162+ var id = $input.data( 'question-id' );
 163+
 164+ if ( this.inputs[i].type === survey.question.type.RADIO ) {
 165+ var value = $( 'input:radio[name=question-input-' + id + ']:checked' ).val();
 166+ }
 167+ else {
 168+ var value = $input.val();
 169+ }
 170+
 171+ answers.push( {
 172+ 'text': value,
 173+ 'question_id': id
 174+ } );
 175+ }
 176+
 177+ return JSON.stringify( answers );
 178+ };
 179+
 180+ this.submitSurvey = function( surveyId, callback ) {
 181+ var requestArgs = {
 182+ 'action': 'submitsurvey',
 183+ 'format': 'json',
 184+ 'token': $( this ).attr( 'survey-data-token' ),
 185+ 'answers': this.getAnswers( surveyId )
 186+ };
 187+
 188+ requestArgs[this.identifierType] = this.identifier;
 189+
 190+ $.post(
 191+ wgScriptPath + '/api.php',
 192+ requestArgs,
 193+ function( data ) {
 194+ callback();
 195+ // TODO
 196+ }
 197+ );
 198+ };
 199+
 200+ this.doCompletion = function() {
 201+ $.fancybox.close();
 202+ };
 203+
 204+ this.showCompletion = function( surveyData ) {
 205+ $div = $( '#survey-' + surveyData.id );
 206+
 207+ $div.html( $( '<p />' ).text( surveyData.thanks ) );
 208+
 209+ $div.append( $( '<button />' )
 210+ .button( { label: mw.msg( 'survey-jquery-finish' ) } )
 211+ .click( this.doCompletion )
 212+ );
 213+ };
 214+
 215+ this.getSurveyBody = function( surveyData ) {
 216+ $survey = $( '<div />' );
 217+
 218+ $survey.append( $( '<h1 />' ).text( surveyData.title ) );
 219+
 220+ $survey.append( $( '<p />' ).text( surveyData.header ) );
 221+
 222+ $survey.append( this.getSurveyQuestions( surveyData.questions ) );
 223+
 224+ var submissionButton = $( '<button />' )
 225+ .button( { label: mw.msg( 'survey-jquery-submit' ) } )
 226+ .click( function() {
 227+ var $this = $( this );
 228+ $this.button( 'disable' );
 229+
 230+ if ( true /* isValid */ ) {
 231+ _this.submitSurvey(
 232+ surveyData.id,
 233+ function() {
 234+ if ( surveyData.thanks == '' ) {
 235+ _this.doCompletion();
 236+ } else {
 237+ _this.showCompletion( surveyData );
 238+ }
 239+ }
 240+ );
 241+ } else {
 242+ // TODO
 243+
 244+ $this.button( 'enable' );
 245+ }
 246+ } );
 247+
 248+ $survey.append( submissionButton );
 249+
 250+ $survey.append( $( '<p />' ).text( surveyData.footer ) );
 251+
 252+ return $survey;
 253+ };
 254+
 255+ this.initSurvey = function( surveyData ) {
 256+ $div = $( '<div />' ).attr( {
 257+ 'style': 'display:none'
 258+ } ).html( $( '<div />' ).attr( { 'id': 'survey-' + surveyData.id } ).html( this.getSurveyBody( surveyData ) ) );
 259+
 260+ $link = $( '<a />' ).attr( {
 261+ 'href': '#survey-' + surveyData.id,
 262+ } ).html( $div );
 263+
 264+ $( this ).html( $link );
 265+
 266+ $link.fancybox( {
 267+// 'width' : '75%',
 268+// 'height' : '75%',
 269+ 'autoScale' : false,
 270+ 'transitionIn' : 'none',
 271+ 'transitionOut' : 'none',
 272+ 'type' : 'inline',
 273+ 'hideOnOverlayClick': false,
 274+ 'autoDimensions': true
 275+ } );
 276+
 277+ $link.click();
 278+
 279+ if ( typeof this.options.onShow === 'function' ) {
 280+ this.options.onShow( { 'id': surveyData.id } );
 281+ }
 282+ };
 283+
 284+ this.init = function() {
 285+ var $this = $( this );
 286+
 287+ if ( $this.attr( 'survey-data-id' ) ) {
 288+ this.identifier = $this.attr( 'survey-data-id' );
 289+ this.identifierType = 'id';
 290+ } else if ( $this.attr( 'survey-data-name' ) ) {
 291+ this.identifier = $this.attr( 'survey-data-name' );
 292+ this.identifierType = 'name';
 293+ }
 294+
 295+ if ( this.identifier !== null ) {
 296+ this.getSurveyData(
 297+ {
 298+ 'requireEnabled': $this.attr( 'survey-data-require-enabled' ) !== '0'
 299+ },
 300+ function( surveyData ) {
 301+ if ( 0 in surveyData ) {
 302+ _this.initSurvey( surveyData[0] );
 303+ }
 304+ else {
 305+ $this.text( mw.msg( 'survey-jquery-load-failed' ) );
 306+ }
 307+ }
 308+ );
 309+ }
 310+ };
 311+
 312+ this.init();
 313+
 314+}; } )( jQuery );
Property changes on: tags/extensions/Survey/REL_0_1/resources/jquery.survey.js
___________________________________________________________________
Added: svn:eol-style
1315 + native
Index: tags/extensions/Survey/REL_0_1/resources/ext.survey.js
@@ -0,0 +1,126 @@
 2+/**
 3+ * JavasSript for the Survey MediaWiki extension.
 4+ * @see https://secure.wikimedia.org/wikipedia/mediawiki/wiki/Extension:Survey
 5+ *
 6+ * @licence GNU GPL v3 or later
 7+ * @author Jeroen De Dauw <jeroendedauw at gmail dot com>
 8+ */
 9+
 10+window.survey = new( function() {
 11+
 12+ this.log = function( message ) {
 13+ if ( mediaWiki.config.get( 'wgSurveyDebug' ) ) {
 14+ if ( typeof mediaWiki === 'undefined' ) {
 15+ if ( typeof console !== 'undefined' ) {
 16+ console.log( 'Survey: ' + message );
 17+ }
 18+ } else {
 19+ return mediaWiki.log.call( mediaWiki.log, 'Survey: ' + message );
 20+ }
 21+ }
 22+ };
 23+
 24+ this.msg = function() {
 25+ if ( typeof mediaWiki === 'undefined' ) {
 26+ message = window.wgSurveyMessages[arguments[0]];
 27+
 28+ for ( var i = arguments.length - 1; i > 0; i-- ) {
 29+ message = message.replace( '$' + i, arguments[i] );
 30+ }
 31+
 32+ return message;
 33+ } else {
 34+ return mediaWiki.msg.apply( mediaWiki.msg, arguments );
 35+ }
 36+ };
 37+
 38+ this.htmlSelect = function( options, value, attributes, onChangeCallback ) {
 39+ $select = $( '<select />' ).attr( attributes );
 40+
 41+ for ( message in options ) {
 42+ var attribs = { 'value': options[message] };
 43+
 44+ if ( value === options[message] ) {
 45+ attribs.selected = 'selected';
 46+ }
 47+
 48+ $select.append( $( '<option />' ).text( message ).attr( attribs ) );
 49+ }
 50+
 51+ if ( typeof onChangeCallback !== 'undefined' ) {
 52+ $select.change( function() { onChangeCallback( $( this ).val() ) } );
 53+ }
 54+
 55+ return $select;
 56+ };
 57+
 58+ this.htmlRadio = function( options, value, name, attributes ) {
 59+ var $radio = $( '<div />' ).attr( attributes );
 60+ $radio.html( '' );
 61+
 62+ for ( message in options ) {
 63+ var itemValue = options[message];
 64+ var id = name + itemValue;
 65+
 66+// if ( value === null ) {
 67+// value = itemValue;
 68+// }
 69+
 70+ $input = $( '<input />' ).attr( {
 71+ 'id': id,
 72+ 'type': 'radio',
 73+ 'name': name,
 74+ 'value': itemValue
 75+ } );
 76+
 77+ if ( value === options[message] ) {
 78+ $input.attr( 'checked', 'checked' );
 79+ }
 80+
 81+ $radio.append( $input );
 82+ $radio.append( $( '<label />' ).attr( 'for', id ).text( message ) );
 83+ $radio.append( $( '<br />' ) );
 84+ }
 85+
 86+ return $radio;
 87+ };
 88+
 89+ this.question = new( function() {
 90+
 91+ this.type = new( function() {
 92+ this.TEXT = 0;
 93+ this.NUMBER = 1;
 94+ this.SELECT = 2;
 95+ this.RADIO = 3;
 96+ this.TEXTAREA = 4;
 97+ this.CHECK = 5;
 98+ } );
 99+
 100+ this.typeHasAnswers = function( t ) {
 101+ return $.inArray( t, [ survey.question.type.RADIO, survey.question.type.SELECT ] ) !== -1;
 102+ };
 103+
 104+ this.getTypeSelector = function( value, attributes, onChangeCallback ) {
 105+ var options = [];
 106+
 107+ var types = {
 108+ 'text': survey.question.type.TEXT,
 109+ 'number': survey.question.type.NUMBER,
 110+ 'select': survey.question.type.SELECT,
 111+ 'radio': survey.question.type.RADIO,
 112+ 'textarea': survey.question.type.TEXTAREA,
 113+ 'check': survey.question.type.CHECK
 114+ };
 115+
 116+ for ( msg in types ) {
 117+ options[survey.msg( 'survey-question-type-' + msg )] = types[msg];
 118+ }
 119+
 120+ return survey.htmlSelect( options, parseInt( value ), attributes, onChangeCallback );
 121+ };
 122+
 123+ } );
 124+
 125+} )();
 126+
 127+
Property changes on: tags/extensions/Survey/REL_0_1/resources/ext.survey.js
___________________________________________________________________
Added: svn:eol-style
1128 + native
Index: tags/extensions/Survey/REL_0_1/resources/fancybox/jquery.fancybox-1.3.4.css
@@ -0,0 +1,359 @@
 2+/*
 3+ * FancyBox - jQuery Plugin
 4+ * Simple and fancy lightbox alternative
 5+ *
 6+ * Examples and documentation at: http://fancybox.net
 7+ *
 8+ * Copyright (c) 2008 - 2010 Janis Skarnelis
 9+ * That said, it is hardly a one-person project. Many people have submitted bugs, code, and offered their advice freely. Their support is greatly appreciated.
 10+ *
 11+ * Version: 1.3.4 (11/11/2010)
 12+ * Requires: jQuery v1.3+
 13+ *
 14+ * Dual licensed under the MIT and GPL licenses:
 15+ * http://www.opensource.org/licenses/mit-license.php
 16+ * http://www.gnu.org/licenses/gpl.html
 17+ */
 18+
 19+#fancybox-loading {
 20+ position: fixed;
 21+ top: 50%;
 22+ left: 50%;
 23+ width: 40px;
 24+ height: 40px;
 25+ margin-top: -20px;
 26+ margin-left: -20px;
 27+ cursor: pointer;
 28+ overflow: hidden;
 29+ z-index: 1104;
 30+ display: none;
 31+}
 32+
 33+#fancybox-loading div {
 34+ position: absolute;
 35+ top: 0;
 36+ left: 0;
 37+ width: 40px;
 38+ height: 480px;
 39+ background-image: url('fancybox.png');
 40+}
 41+
 42+#fancybox-overlay {
 43+ position: absolute;
 44+ top: 0;
 45+ left: 0;
 46+ width: 100%;
 47+ z-index: 1100;
 48+ display: none;
 49+}
 50+
 51+#fancybox-tmp {
 52+ padding: 0;
 53+ margin: 0;
 54+ border: 0;
 55+ overflow: auto;
 56+ display: none;
 57+}
 58+
 59+#fancybox-wrap {
 60+ position: absolute;
 61+ top: 0;
 62+ left: 0;
 63+ padding: 20px;
 64+ z-index: 1101;
 65+ outline: none;
 66+ display: none;
 67+}
 68+
 69+#fancybox-outer {
 70+ position: relative;
 71+ width: 100%;
 72+ height: 100%;
 73+ background: #fff;
 74+}
 75+
 76+#fancybox-content {
 77+ width: 0;
 78+ height: 0;
 79+ padding: 0;
 80+ outline: none;
 81+ position: relative;
 82+ overflow: hidden;
 83+ z-index: 1102;
 84+ border: 0px solid #fff;
 85+}
 86+
 87+#fancybox-hide-sel-frame {
 88+ position: absolute;
 89+ top: 0;
 90+ left: 0;
 91+ width: 100%;
 92+ height: 100%;
 93+ background: transparent;
 94+ z-index: 1101;
 95+}
 96+
 97+#fancybox-close {
 98+ position: absolute;
 99+ top: -15px;
 100+ right: -15px;
 101+ width: 30px;
 102+ height: 30px;
 103+ background: transparent url('fancybox.png') -40px 0px;
 104+ cursor: pointer;
 105+ z-index: 1103;
 106+ display: none;
 107+}
 108+
 109+#fancybox-error {
 110+ color: #444;
 111+ font: normal 12px/20px Arial;
 112+ padding: 14px;
 113+ margin: 0;
 114+}
 115+
 116+#fancybox-img {
 117+ width: 100%;
 118+ height: 100%;
 119+ padding: 0;
 120+ margin: 0;
 121+ border: none;
 122+ outline: none;
 123+ line-height: 0;
 124+ vertical-align: top;
 125+}
 126+
 127+#fancybox-frame {
 128+ width: 100%;
 129+ height: 100%;
 130+ border: none;
 131+ display: block;
 132+}
 133+
 134+#fancybox-left, #fancybox-right {
 135+ position: absolute;
 136+ bottom: 0px;
 137+ height: 100%;
 138+ width: 35%;
 139+ cursor: pointer;
 140+ outline: none;
 141+ background: transparent url('blank.gif');
 142+ z-index: 1102;
 143+ display: none;
 144+}
 145+
 146+#fancybox-left {
 147+ left: 0px;
 148+}
 149+
 150+#fancybox-right {
 151+ right: 0px;
 152+}
 153+
 154+#fancybox-left-ico, #fancybox-right-ico {
 155+ position: absolute;
 156+ top: 50%;
 157+ left: -9999px;
 158+ width: 30px;
 159+ height: 30px;
 160+ margin-top: -15px;
 161+ cursor: pointer;
 162+ z-index: 1102;
 163+ display: block;
 164+}
 165+
 166+#fancybox-left-ico {
 167+ background-image: url('fancybox.png');
 168+ background-position: -40px -30px;
 169+}
 170+
 171+#fancybox-right-ico {
 172+ background-image: url('fancybox.png');
 173+ background-position: -40px -60px;
 174+}
 175+
 176+#fancybox-left:hover, #fancybox-right:hover {
 177+ visibility: visible; /* IE6 */
 178+}
 179+
 180+#fancybox-left:hover span {
 181+ left: 20px;
 182+}
 183+
 184+#fancybox-right:hover span {
 185+ left: auto;
 186+ right: 20px;
 187+}
 188+
 189+.fancybox-bg {
 190+ position: absolute;
 191+ padding: 0;
 192+ margin: 0;
 193+ border: 0;
 194+ width: 20px;
 195+ height: 20px;
 196+ z-index: 1001;
 197+}
 198+
 199+#fancybox-bg-n {
 200+ top: -20px;
 201+ left: 0;
 202+ width: 100%;
 203+ background-image: url('fancybox-x.png');
 204+}
 205+
 206+#fancybox-bg-ne {
 207+ top: -20px;
 208+ right: -20px;
 209+ background-image: url('fancybox.png');
 210+ background-position: -40px -162px;
 211+}
 212+
 213+#fancybox-bg-e {
 214+ top: 0;
 215+ right: -20px;
 216+ height: 100%;
 217+ background-image: url('fancybox-y.png');
 218+ background-position: -20px 0px;
 219+}
 220+
 221+#fancybox-bg-se {
 222+ bottom: -20px;
 223+ right: -20px;
 224+ background-image: url('fancybox.png');
 225+ background-position: -40px -182px;
 226+}
 227+
 228+#fancybox-bg-s {
 229+ bottom: -20px;
 230+ left: 0;
 231+ width: 100%;
 232+ background-image: url('fancybox-x.png');
 233+ background-position: 0px -20px;
 234+}
 235+
 236+#fancybox-bg-sw {
 237+ bottom: -20px;
 238+ left: -20px;
 239+ background-image: url('fancybox.png');
 240+ background-position: -40px -142px;
 241+}
 242+
 243+#fancybox-bg-w {
 244+ top: 0;
 245+ left: -20px;
 246+ height: 100%;
 247+ background-image: url('fancybox-y.png');
 248+}
 249+
 250+#fancybox-bg-nw {
 251+ top: -20px;
 252+ left: -20px;
 253+ background-image: url('fancybox.png');
 254+ background-position: -40px -122px;
 255+}
 256+
 257+#fancybox-title {
 258+ font-family: Helvetica;
 259+ font-size: 12px;
 260+ z-index: 1102;
 261+}
 262+
 263+.fancybox-title-inside {
 264+ padding-bottom: 10px;
 265+ text-align: center;
 266+ color: #333;
 267+ background: #fff;
 268+ position: relative;
 269+}
 270+
 271+.fancybox-title-outside {
 272+ padding-top: 10px;
 273+ color: #fff;
 274+}
 275+
 276+.fancybox-title-over {
 277+ position: absolute;
 278+ bottom: 0;
 279+ left: 0;
 280+ color: #FFF;
 281+ text-align: left;
 282+}
 283+
 284+#fancybox-title-over {
 285+ padding: 10px;
 286+ background-image: url('fancy_title_over.png');
 287+ display: block;
 288+}
 289+
 290+.fancybox-title-float {
 291+ position: absolute;
 292+ left: 0;
 293+ bottom: -20px;
 294+ height: 32px;
 295+}
 296+
 297+#fancybox-title-float-wrap {
 298+ border: none;
 299+ border-collapse: collapse;
 300+ width: auto;
 301+}
 302+
 303+#fancybox-title-float-wrap td {
 304+ border: none;
 305+ white-space: nowrap;
 306+}
 307+
 308+#fancybox-title-float-left {
 309+ padding: 0 0 0 15px;
 310+ background: url('fancybox.png') -40px -90px no-repeat;
 311+}
 312+
 313+#fancybox-title-float-main {
 314+ color: #FFF;
 315+ line-height: 29px;
 316+ font-weight: bold;
 317+ padding: 0 0 3px 0;
 318+ background: url('fancybox-x.png') 0px -40px;
 319+}
 320+
 321+#fancybox-title-float-right {
 322+ padding: 0 0 0 15px;
 323+ background: url('fancybox.png') -55px -90px no-repeat;
 324+}
 325+
 326+/* IE6 */
 327+
 328+.fancybox-ie6 #fancybox-close { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_close.png', sizingMethod='scale'); }
 329+
 330+.fancybox-ie6 #fancybox-left-ico { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_nav_left.png', sizingMethod='scale'); }
 331+.fancybox-ie6 #fancybox-right-ico { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_nav_right.png', sizingMethod='scale'); }
 332+
 333+.fancybox-ie6 #fancybox-title-over { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_over.png', sizingMethod='scale'); zoom: 1; }
 334+.fancybox-ie6 #fancybox-title-float-left { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_left.png', sizingMethod='scale'); }
 335+.fancybox-ie6 #fancybox-title-float-main { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_main.png', sizingMethod='scale'); }
 336+.fancybox-ie6 #fancybox-title-float-right { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_right.png', sizingMethod='scale'); }
 337+
 338+.fancybox-ie6 #fancybox-bg-w, .fancybox-ie6 #fancybox-bg-e, .fancybox-ie6 #fancybox-left, .fancybox-ie6 #fancybox-right, #fancybox-hide-sel-frame {
 339+ height: expression(this.parentNode.clientHeight + "px");
 340+}
 341+
 342+#fancybox-loading.fancybox-ie6 {
 343+ position: absolute; margin-top: 0;
 344+ top: expression( (-20 + (document.documentElement.clientHeight ? document.documentElement.clientHeight/2 : document.body.clientHeight/2 ) + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop )) + 'px');
 345+}
 346+
 347+#fancybox-loading.fancybox-ie6 div { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_loading.png', sizingMethod='scale'); }
 348+
 349+/* IE6, IE7, IE8 */
 350+
 351+.fancybox-ie .fancybox-bg { background: transparent !important; }
 352+
 353+.fancybox-ie #fancybox-bg-n { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_n.png', sizingMethod='scale'); }
 354+.fancybox-ie #fancybox-bg-ne { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_ne.png', sizingMethod='scale'); }
 355+.fancybox-ie #fancybox-bg-e { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_e.png', sizingMethod='scale'); }
 356+.fancybox-ie #fancybox-bg-se { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_se.png', sizingMethod='scale'); }
 357+.fancybox-ie #fancybox-bg-s { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_s.png', sizingMethod='scale'); }
 358+.fancybox-ie #fancybox-bg-sw { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_sw.png', sizingMethod='scale'); }
 359+.fancybox-ie #fancybox-bg-w { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_w.png', sizingMethod='scale'); }
 360+.fancybox-ie #fancybox-bg-nw { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_nw.png', sizingMethod='scale'); }
\ No newline at end of file
Property changes on: tags/extensions/Survey/REL_0_1/resources/fancybox/jquery.fancybox-1.3.4.css
___________________________________________________________________
Added: svn:eol-style
1361 + native
Index: tags/extensions/Survey/REL_0_1/resources/fancybox/fancy_shadow_se.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: tags/extensions/Survey/REL_0_1/resources/fancybox/fancy_shadow_se.png
___________________________________________________________________
Added: svn:mime-type
2362 + image/png
Index: tags/extensions/Survey/REL_0_1/resources/fancybox/fancy_title_over.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: tags/extensions/Survey/REL_0_1/resources/fancybox/fancy_title_over.png
___________________________________________________________________
Added: svn:mime-type
3363 + image/png
Index: tags/extensions/Survey/REL_0_1/resources/fancybox/jquery.fancybox-1.3.4.pack.js
@@ -0,0 +1,46 @@
 2+/*
 3+ * FancyBox - jQuery Plugin
 4+ * Simple and fancy lightbox alternative
 5+ *
 6+ * Examples and documentation at: http://fancybox.net
 7+ *
 8+ * Copyright (c) 2008 - 2010 Janis Skarnelis
 9+ * That said, it is hardly a one-person project. Many people have submitted bugs, code, and offered their advice freely. Their support is greatly appreciated.
 10+ *
 11+ * Version: 1.3.4 (11/11/2010)
 12+ * Requires: jQuery v1.3+
 13+ *
 14+ * Dual licensed under the MIT and GPL licenses:
 15+ * http://www.opensource.org/licenses/mit-license.php
 16+ * http://www.gnu.org/licenses/gpl.html
 17+ */
 18+
 19+;(function(b){var m,t,u,f,D,j,E,n,z,A,q=0,e={},o=[],p=0,d={},l=[],G=null,v=new Image,J=/\.(jpg|gif|png|bmp|jpeg)(.*)?$/i,W=/[^\.]\.(swf)\s*$/i,K,L=1,y=0,s="",r,i,h=false,B=b.extend(b("<div/>")[0],{prop:0}),M=b.browser.msie&&b.browser.version<7&&!window.XMLHttpRequest,N=function(){t.hide();v.onerror=v.onload=null;G&&G.abort();m.empty()},O=function(){if(false===e.onError(o,q,e)){t.hide();h=false}else{e.titleShow=false;e.width="auto";e.height="auto";m.html('<p id="fancybox-error">The requested content cannot be loaded.<br />Please try again later.</p>');
 20+F()}},I=function(){var a=o[q],c,g,k,C,P,w;N();e=b.extend({},b.fn.fancybox.defaults,typeof b(a).data("fancybox")=="undefined"?e:b(a).data("fancybox"));w=e.onStart(o,q,e);if(w===false)h=false;else{if(typeof w=="object")e=b.extend(e,w);k=e.title||(a.nodeName?b(a).attr("title"):a.title)||"";if(a.nodeName&&!e.orig)e.orig=b(a).children("img:first").length?b(a).children("img:first"):b(a);if(k===""&&e.orig&&e.titleFromAlt)k=e.orig.attr("alt");c=e.href||(a.nodeName?b(a).attr("href"):a.href)||null;if(/^(?:javascript)/i.test(c)||
 21+c=="#")c=null;if(e.type){g=e.type;if(!c)c=e.content}else if(e.content)g="html";else if(c)g=c.match(J)?"image":c.match(W)?"swf":b(a).hasClass("iframe")?"iframe":c.indexOf("#")===0?"inline":"ajax";if(g){if(g=="inline"){a=c.substr(c.indexOf("#"));g=b(a).length>0?"inline":"ajax"}e.type=g;e.href=c;e.title=k;if(e.autoDimensions)if(e.type=="html"||e.type=="inline"||e.type=="ajax"){e.width="auto";e.height="auto"}else e.autoDimensions=false;if(e.modal){e.overlayShow=true;e.hideOnOverlayClick=false;e.hideOnContentClick=
 22+false;e.enableEscapeButton=false;e.showCloseButton=false}e.padding=parseInt(e.padding,10);e.margin=parseInt(e.margin,10);m.css("padding",e.padding+e.margin);b(".fancybox-inline-tmp").unbind("fancybox-cancel").bind("fancybox-change",function(){b(this).replaceWith(j.children())});switch(g){case "html":m.html(e.content);F();break;case "inline":if(b(a).parent().is("#fancybox-content")===true){h=false;break}b('<div class="fancybox-inline-tmp" />').hide().insertBefore(b(a)).bind("fancybox-cleanup",function(){b(this).replaceWith(j.children())}).bind("fancybox-cancel",
 23+function(){b(this).replaceWith(m.children())});b(a).appendTo(m);F();break;case "image":h=false;b.fancybox.showActivity();v=new Image;v.onerror=function(){O()};v.onload=function(){h=true;v.onerror=v.onload=null;e.width=v.width;e.height=v.height;b("<img />").attr({id:"fancybox-img",src:v.src,alt:e.title}).appendTo(m);Q()};v.src=c;break;case "swf":e.scrolling="no";C='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="'+e.width+'" height="'+e.height+'"><param name="movie" value="'+c+
 24+'"></param>';P="";b.each(e.swf,function(x,H){C+='<param name="'+x+'" value="'+H+'"></param>';P+=" "+x+'="'+H+'"'});C+='<embed src="'+c+'" type="application/x-shockwave-flash" width="'+e.width+'" height="'+e.height+'"'+P+"></embed></object>";m.html(C);F();break;case "ajax":h=false;b.fancybox.showActivity();e.ajax.win=e.ajax.success;G=b.ajax(b.extend({},e.ajax,{url:c,data:e.ajax.data||{},error:function(x){x.status>0&&O()},success:function(x,H,R){if((typeof R=="object"?R:G).status==200){if(typeof e.ajax.win==
 25+"function"){w=e.ajax.win(c,x,H,R);if(w===false){t.hide();return}else if(typeof w=="string"||typeof w=="object")x=w}m.html(x);F()}}}));break;case "iframe":Q()}}else O()}},F=function(){var a=e.width,c=e.height;a=a.toString().indexOf("%")>-1?parseInt((b(window).width()-e.margin*2)*parseFloat(a)/100,10)+"px":a=="auto"?"auto":a+"px";c=c.toString().indexOf("%")>-1?parseInt((b(window).height()-e.margin*2)*parseFloat(c)/100,10)+"px":c=="auto"?"auto":c+"px";m.wrapInner('<div style="width:'+a+";height:"+c+
 26+";overflow: "+(e.scrolling=="auto"?"auto":e.scrolling=="yes"?"scroll":"hidden")+';position:relative;"></div>');e.width=m.width();e.height=m.height();Q()},Q=function(){var a,c;t.hide();if(f.is(":visible")&&false===d.onCleanup(l,p,d)){b.event.trigger("fancybox-cancel");h=false}else{h=true;b(j.add(u)).unbind();b(window).unbind("resize.fb scroll.fb");b(document).unbind("keydown.fb");f.is(":visible")&&d.titlePosition!=="outside"&&f.css("height",f.height());l=o;p=q;d=e;if(d.overlayShow){u.css({"background-color":d.overlayColor,
 27+opacity:d.overlayOpacity,cursor:d.hideOnOverlayClick?"pointer":"auto",height:b(document).height()});if(!u.is(":visible")){M&&b("select:not(#fancybox-tmp select)").filter(function(){return this.style.visibility!=="hidden"}).css({visibility:"hidden"}).one("fancybox-cleanup",function(){this.style.visibility="inherit"});u.show()}}else u.hide();i=X();s=d.title||"";y=0;n.empty().removeAttr("style").removeClass();if(d.titleShow!==false){if(b.isFunction(d.titleFormat))a=d.titleFormat(s,l,p,d);else a=s&&s.length?
 28+d.titlePosition=="float"?'<table id="fancybox-title-float-wrap" cellpadding="0" cellspacing="0"><tr><td id="fancybox-title-float-left"></td><td id="fancybox-title-float-main">'+s+'</td><td id="fancybox-title-float-right"></td></tr></table>':'<div id="fancybox-title-'+d.titlePosition+'">'+s+"</div>":false;s=a;if(!(!s||s==="")){n.addClass("fancybox-title-"+d.titlePosition).html(s).appendTo("body").show();switch(d.titlePosition){case "inside":n.css({width:i.width-d.padding*2,marginLeft:d.padding,marginRight:d.padding});
 29+y=n.outerHeight(true);n.appendTo(D);i.height+=y;break;case "over":n.css({marginLeft:d.padding,width:i.width-d.padding*2,bottom:d.padding}).appendTo(D);break;case "float":n.css("left",parseInt((n.width()-i.width-40)/2,10)*-1).appendTo(f);break;default:n.css({width:i.width-d.padding*2,paddingLeft:d.padding,paddingRight:d.padding}).appendTo(f)}}}n.hide();if(f.is(":visible")){b(E.add(z).add(A)).hide();a=f.position();r={top:a.top,left:a.left,width:f.width(),height:f.height()};c=r.width==i.width&&r.height==
 30+i.height;j.fadeTo(d.changeFade,0.3,function(){var g=function(){j.html(m.contents()).fadeTo(d.changeFade,1,S)};b.event.trigger("fancybox-change");j.empty().removeAttr("filter").css({"border-width":d.padding,width:i.width-d.padding*2,height:e.autoDimensions?"auto":i.height-y-d.padding*2});if(c)g();else{B.prop=0;b(B).animate({prop:1},{duration:d.changeSpeed,easing:d.easingChange,step:T,complete:g})}})}else{f.removeAttr("style");j.css("border-width",d.padding);if(d.transitionIn=="elastic"){r=V();j.html(m.contents());
 31+f.show();if(d.opacity)i.opacity=0;B.prop=0;b(B).animate({prop:1},{duration:d.speedIn,easing:d.easingIn,step:T,complete:S})}else{d.titlePosition=="inside"&&y>0&&n.show();j.css({width:i.width-d.padding*2,height:e.autoDimensions?"auto":i.height-y-d.padding*2}).html(m.contents());f.css(i).fadeIn(d.transitionIn=="none"?0:d.speedIn,S)}}}},Y=function(){if(d.enableEscapeButton||d.enableKeyboardNav)b(document).bind("keydown.fb",function(a){if(a.keyCode==27&&d.enableEscapeButton){a.preventDefault();b.fancybox.close()}else if((a.keyCode==
 32+37||a.keyCode==39)&&d.enableKeyboardNav&&a.target.tagName!=="INPUT"&&a.target.tagName!=="TEXTAREA"&&a.target.tagName!=="SELECT"){a.preventDefault();b.fancybox[a.keyCode==37?"prev":"next"]()}});if(d.showNavArrows){if(d.cyclic&&l.length>1||p!==0)z.show();if(d.cyclic&&l.length>1||p!=l.length-1)A.show()}else{z.hide();A.hide()}},S=function(){if(!b.support.opacity){j.get(0).style.removeAttribute("filter");f.get(0).style.removeAttribute("filter")}e.autoDimensions&&j.css("height","auto");f.css("height","auto");
 33+s&&s.length&&n.show();d.showCloseButton&&E.show();Y();d.hideOnContentClick&&j.bind("click",b.fancybox.close);d.hideOnOverlayClick&&u.bind("click",b.fancybox.close);b(window).bind("resize.fb",b.fancybox.resize);d.centerOnScroll&&b(window).bind("scroll.fb",b.fancybox.center);if(d.type=="iframe")b('<iframe id="fancybox-frame" name="fancybox-frame'+(new Date).getTime()+'" frameborder="0" hspace="0" '+(b.browser.msie?'allowtransparency="true""':"")+' scrolling="'+e.scrolling+'" src="'+d.href+'"></iframe>').appendTo(j);
 34+f.show();h=false;b.fancybox.center();d.onComplete(l,p,d);var a,c;if(l.length-1>p){a=l[p+1].href;if(typeof a!=="undefined"&&a.match(J)){c=new Image;c.src=a}}if(p>0){a=l[p-1].href;if(typeof a!=="undefined"&&a.match(J)){c=new Image;c.src=a}}},T=function(a){var c={width:parseInt(r.width+(i.width-r.width)*a,10),height:parseInt(r.height+(i.height-r.height)*a,10),top:parseInt(r.top+(i.top-r.top)*a,10),left:parseInt(r.left+(i.left-r.left)*a,10)};if(typeof i.opacity!=="undefined")c.opacity=a<0.5?0.5:a;f.css(c);
 35+j.css({width:c.width-d.padding*2,height:c.height-y*a-d.padding*2})},U=function(){return[b(window).width()-d.margin*2,b(window).height()-d.margin*2,b(document).scrollLeft()+d.margin,b(document).scrollTop()+d.margin]},X=function(){var a=U(),c={},g=d.autoScale,k=d.padding*2;c.width=d.width.toString().indexOf("%")>-1?parseInt(a[0]*parseFloat(d.width)/100,10):d.width+k;c.height=d.height.toString().indexOf("%")>-1?parseInt(a[1]*parseFloat(d.height)/100,10):d.height+k;if(g&&(c.width>a[0]||c.height>a[1]))if(e.type==
 36+"image"||e.type=="swf"){g=d.width/d.height;if(c.width>a[0]){c.width=a[0];c.height=parseInt((c.width-k)/g+k,10)}if(c.height>a[1]){c.height=a[1];c.width=parseInt((c.height-k)*g+k,10)}}else{c.width=Math.min(c.width,a[0]);c.height=Math.min(c.height,a[1])}c.top=parseInt(Math.max(a[3]-20,a[3]+(a[1]-c.height-40)*0.5),10);c.left=parseInt(Math.max(a[2]-20,a[2]+(a[0]-c.width-40)*0.5),10);return c},V=function(){var a=e.orig?b(e.orig):false,c={};if(a&&a.length){c=a.offset();c.top+=parseInt(a.css("paddingTop"),
 37+10)||0;c.left+=parseInt(a.css("paddingLeft"),10)||0;c.top+=parseInt(a.css("border-top-width"),10)||0;c.left+=parseInt(a.css("border-left-width"),10)||0;c.width=a.width();c.height=a.height();c={width:c.width+d.padding*2,height:c.height+d.padding*2,top:c.top-d.padding-20,left:c.left-d.padding-20}}else{a=U();c={width:d.padding*2,height:d.padding*2,top:parseInt(a[3]+a[1]*0.5,10),left:parseInt(a[2]+a[0]*0.5,10)}}return c},Z=function(){if(t.is(":visible")){b("div",t).css("top",L*-40+"px");L=(L+1)%12}else clearInterval(K)};
 38+b.fn.fancybox=function(a){if(!b(this).length)return this;b(this).data("fancybox",b.extend({},a,b.metadata?b(this).metadata():{})).unbind("click.fb").bind("click.fb",function(c){c.preventDefault();if(!h){h=true;b(this).blur();o=[];q=0;c=b(this).attr("rel")||"";if(!c||c==""||c==="nofollow")o.push(this);else{o=b("a[rel="+c+"], area[rel="+c+"]");q=o.index(this)}I()}});return this};b.fancybox=function(a,c){var g;if(!h){h=true;g=typeof c!=="undefined"?c:{};o=[];q=parseInt(g.index,10)||0;if(b.isArray(a)){for(var k=
 39+0,C=a.length;k<C;k++)if(typeof a[k]=="object")b(a[k]).data("fancybox",b.extend({},g,a[k]));else a[k]=b({}).data("fancybox",b.extend({content:a[k]},g));o=jQuery.merge(o,a)}else{if(typeof a=="object")b(a).data("fancybox",b.extend({},g,a));else a=b({}).data("fancybox",b.extend({content:a},g));o.push(a)}if(q>o.length||q<0)q=0;I()}};b.fancybox.showActivity=function(){clearInterval(K);t.show();K=setInterval(Z,66)};b.fancybox.hideActivity=function(){t.hide()};b.fancybox.next=function(){return b.fancybox.pos(p+
 40+1)};b.fancybox.prev=function(){return b.fancybox.pos(p-1)};b.fancybox.pos=function(a){if(!h){a=parseInt(a);o=l;if(a>-1&&a<l.length){q=a;I()}else if(d.cyclic&&l.length>1){q=a>=l.length?0:l.length-1;I()}}};b.fancybox.cancel=function(){if(!h){h=true;b.event.trigger("fancybox-cancel");N();e.onCancel(o,q,e);h=false}};b.fancybox.close=function(){function a(){u.fadeOut("fast");n.empty().hide();f.hide();b.event.trigger("fancybox-cleanup");j.empty();d.onClosed(l,p,d);l=e=[];p=q=0;d=e={};h=false}if(!(h||f.is(":hidden"))){h=
 41+true;if(d&&false===d.onCleanup(l,p,d))h=false;else{N();b(E.add(z).add(A)).hide();b(j.add(u)).unbind();b(window).unbind("resize.fb scroll.fb");b(document).unbind("keydown.fb");j.find("iframe").attr("src",M&&/^https/i.test(window.location.href||"")?"javascript:void(false)":"about:blank");d.titlePosition!=="inside"&&n.empty();f.stop();if(d.transitionOut=="elastic"){r=V();var c=f.position();i={top:c.top,left:c.left,width:f.width(),height:f.height()};if(d.opacity)i.opacity=1;n.empty().hide();B.prop=1;
 42+b(B).animate({prop:0},{duration:d.speedOut,easing:d.easingOut,step:T,complete:a})}else f.fadeOut(d.transitionOut=="none"?0:d.speedOut,a)}}};b.fancybox.resize=function(){u.is(":visible")&&u.css("height",b(document).height());b.fancybox.center(true)};b.fancybox.center=function(a){var c,g;if(!h){g=a===true?1:0;c=U();!g&&(f.width()>c[0]||f.height()>c[1])||f.stop().animate({top:parseInt(Math.max(c[3]-20,c[3]+(c[1]-j.height()-40)*0.5-d.padding)),left:parseInt(Math.max(c[2]-20,c[2]+(c[0]-j.width()-40)*0.5-
 43+d.padding))},typeof a=="number"?a:200)}};b.fancybox.init=function(){if(!b("#fancybox-wrap").length){b("body").append(m=b('<div id="fancybox-tmp"></div>'),t=b('<div id="fancybox-loading"><div></div></div>'),u=b('<div id="fancybox-overlay"></div>'),f=b('<div id="fancybox-wrap"></div>'));D=b('<div id="fancybox-outer"></div>').append('<div class="fancybox-bg" id="fancybox-bg-n"></div><div class="fancybox-bg" id="fancybox-bg-ne"></div><div class="fancybox-bg" id="fancybox-bg-e"></div><div class="fancybox-bg" id="fancybox-bg-se"></div><div class="fancybox-bg" id="fancybox-bg-s"></div><div class="fancybox-bg" id="fancybox-bg-sw"></div><div class="fancybox-bg" id="fancybox-bg-w"></div><div class="fancybox-bg" id="fancybox-bg-nw"></div>').appendTo(f);
 44+D.append(j=b('<div id="fancybox-content"></div>'),E=b('<a id="fancybox-close"></a>'),n=b('<div id="fancybox-title"></div>'),z=b('<a href="javascript:;" id="fancybox-left"><span class="fancy-ico" id="fancybox-left-ico"></span></a>'),A=b('<a href="javascript:;" id="fancybox-right"><span class="fancy-ico" id="fancybox-right-ico"></span></a>'));E.click(b.fancybox.close);t.click(b.fancybox.cancel);z.click(function(a){a.preventDefault();b.fancybox.prev()});A.click(function(a){a.preventDefault();b.fancybox.next()});
 45+b.fn.mousewheel&&f.bind("mousewheel.fb",function(a,c){if(h)a.preventDefault();else if(b(a.target).get(0).clientHeight==0||b(a.target).get(0).scrollHeight===b(a.target).get(0).clientHeight){a.preventDefault();b.fancybox[c>0?"prev":"next"]()}});b.support.opacity||f.addClass("fancybox-ie");if(M){t.addClass("fancybox-ie6");f.addClass("fancybox-ie6");b('<iframe id="fancybox-hide-sel-frame" src="'+(/^https/i.test(window.location.href||"")?"javascript:void(false)":"about:blank")+'" scrolling="no" border="0" frameborder="0" tabindex="-1"></iframe>').prependTo(D)}}};
 46+b.fn.fancybox.defaults={padding:10,margin:40,opacity:false,modal:false,cyclic:false,scrolling:"auto",width:560,height:340,autoScale:true,autoDimensions:true,centerOnScroll:false,ajax:{},swf:{wmode:"transparent"},hideOnOverlayClick:true,hideOnContentClick:false,overlayShow:true,overlayOpacity:0.7,overlayColor:"#777",titleShow:true,titlePosition:"float",titleFormat:null,titleFromAlt:false,transitionIn:"fade",transitionOut:"fade",speedIn:300,speedOut:300,changeSpeed:300,changeFade:"fast",easingIn:"swing",
 47+easingOut:"swing",showCloseButton:true,showNavArrows:true,enableEscapeButton:true,enableKeyboardNav:true,onStart:function(){},onCancel:function(){},onComplete:function(){},onCleanup:function(){},onClosed:function(){},onError:function(){}};b(document).ready(function(){b.fancybox.init()})})(jQuery);
\ No newline at end of file
Property changes on: tags/extensions/Survey/REL_0_1/resources/fancybox/jquery.fancybox-1.3.4.pack.js
___________________________________________________________________
Added: svn:eol-style
148 + native
Index: tags/extensions/Survey/REL_0_1/resources/fancybox/fancy_loading.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: tags/extensions/Survey/REL_0_1/resources/fancybox/fancy_loading.png
___________________________________________________________________
Added: svn:mime-type
249 + image/png
Index: tags/extensions/Survey/REL_0_1/resources/fancybox/fancy_title_right.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: tags/extensions/Survey/REL_0_1/resources/fancybox/fancy_title_right.png
___________________________________________________________________
Added: svn:mime-type
350 + image/png
Index: tags/extensions/Survey/REL_0_1/resources/fancybox/jquery.mousewheel-3.0.4.pack.js
@@ -0,0 +1,14 @@
 2+/*! Copyright (c) 2010 Brandon Aaron (http://brandonaaron.net)
 3+* Licensed under the MIT License (LICENSE.txt).
 4+*
 5+* Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
 6+* Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
 7+* Thanks to: Seamus Leahy for adding deltaX and deltaY
 8+*
 9+* Version: 3.0.4
 10+*
 11+* Requires: 1.2.2+
 12+*/
 13+
 14+(function(d){function g(a){var b=a||window.event,i=[].slice.call(arguments,1),c=0,h=0,e=0;a=d.event.fix(b);a.type="mousewheel";if(a.wheelDelta)c=a.wheelDelta/120;if(a.detail)c=-a.detail/3;e=c;if(b.axis!==undefined&&b.axis===b.HORIZONTAL_AXIS){e=0;h=-1*c}if(b.wheelDeltaY!==undefined)e=b.wheelDeltaY/120;if(b.wheelDeltaX!==undefined)h=-1*b.wheelDeltaX/120;i.unshift(a,c,h,e);return d.event.handle.apply(this,i)}var f=["DOMMouseScroll","mousewheel"];d.event.special.mousewheel={setup:function(){if(this.addEventListener)for(var a=
 15+f.length;a;)this.addEventListener(f[--a],g,false);else this.onmousewheel=g},teardown:function(){if(this.removeEventListener)for(var a=f.length;a;)this.removeEventListener(f[--a],g,false);else this.onmousewheel=null}};d.fn.extend({mousewheel:function(a){return a?this.bind("mousewheel",a):this.trigger("mousewheel")},unmousewheel:function(a){return this.unbind("mousewheel",a)}})})(jQuery);
\ No newline at end of file
Property changes on: tags/extensions/Survey/REL_0_1/resources/fancybox/jquery.mousewheel-3.0.4.pack.js
___________________________________________________________________
Added: svn:eol-style
116 + native
Index: tags/extensions/Survey/REL_0_1/resources/fancybox/fancy_nav_right.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: tags/extensions/Survey/REL_0_1/resources/fancybox/fancy_nav_right.png
___________________________________________________________________
Added: svn:mime-type
217 + image/png
Index: tags/extensions/Survey/REL_0_1/resources/fancybox/fancy_title_main.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: tags/extensions/Survey/REL_0_1/resources/fancybox/fancy_title_main.png
___________________________________________________________________
Added: svn:mime-type
318 + image/png
Index: tags/extensions/Survey/REL_0_1/resources/fancybox/blank.gif
Cannot display: file marked as a binary type.
svn:mime-type = image/gif
Property changes on: tags/extensions/Survey/REL_0_1/resources/fancybox/blank.gif
___________________________________________________________________
Added: svn:mime-type
419 + image/gif
Index: tags/extensions/Survey/REL_0_1/resources/fancybox/fancybox.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: tags/extensions/Survey/REL_0_1/resources/fancybox/fancybox.png
___________________________________________________________________
Added: svn:mime-type
520 + image/png
Index: tags/extensions/Survey/REL_0_1/resources/fancybox/fancy_shadow_e.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: tags/extensions/Survey/REL_0_1/resources/fancybox/fancy_shadow_e.png
___________________________________________________________________
Added: svn:mime-type
621 + image/png
Index: tags/extensions/Survey/REL_0_1/resources/fancybox/fancy_shadow_nw.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: tags/extensions/Survey/REL_0_1/resources/fancybox/fancy_shadow_nw.png
___________________________________________________________________
Added: svn:mime-type
722 + image/png
Index: tags/extensions/Survey/REL_0_1/resources/fancybox/fancy_title_left.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: tags/extensions/Survey/REL_0_1/resources/fancybox/fancy_title_left.png
___________________________________________________________________
Added: svn:mime-type
823 + image/png
Index: tags/extensions/Survey/REL_0_1/resources/fancybox/fancy_nav_left.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: tags/extensions/Survey/REL_0_1/resources/fancybox/fancy_nav_left.png
___________________________________________________________________
Added: svn:mime-type
924 + image/png
Index: tags/extensions/Survey/REL_0_1/resources/fancybox/fancy_shadow_sw.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: tags/extensions/Survey/REL_0_1/resources/fancybox/fancy_shadow_sw.png
___________________________________________________________________
Added: svn:mime-type
1025 + image/png
Index: tags/extensions/Survey/REL_0_1/resources/fancybox/fancybox-x.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: tags/extensions/Survey/REL_0_1/resources/fancybox/fancybox-x.png
___________________________________________________________________
Added: svn:mime-type
1126 + image/png
Index: tags/extensions/Survey/REL_0_1/resources/fancybox/fancybox-y.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: tags/extensions/Survey/REL_0_1/resources/fancybox/fancybox-y.png
___________________________________________________________________
Added: svn:mime-type
1227 + image/png
Index: tags/extensions/Survey/REL_0_1/resources/fancybox/jquery.fancybox-1.3.4.js
@@ -0,0 +1,1156 @@
 2+/*
 3+ * FancyBox - jQuery Plugin
 4+ * Simple and fancy lightbox alternative
 5+ *
 6+ * Examples and documentation at: http://fancybox.net
 7+ *
 8+ * Copyright (c) 2008 - 2010 Janis Skarnelis
 9+ * That said, it is hardly a one-person project. Many people have submitted bugs, code, and offered their advice freely. Their support is greatly appreciated.
 10+ *
 11+ * Version: 1.3.4 (11/11/2010)
 12+ * Requires: jQuery v1.3+
 13+ *
 14+ * Dual licensed under the MIT and GPL licenses:
 15+ * http://www.opensource.org/licenses/mit-license.php
 16+ * http://www.gnu.org/licenses/gpl.html
 17+ */
 18+
 19+;(function($) {
 20+ var tmp, loading, overlay, wrap, outer, content, close, title, nav_left, nav_right,
 21+
 22+ selectedIndex = 0, selectedOpts = {}, selectedArray = [], currentIndex = 0, currentOpts = {}, currentArray = [],
 23+
 24+ ajaxLoader = null, imgPreloader = new Image(), imgRegExp = /\.(jpg|gif|png|bmp|jpeg)(.*)?$/i, swfRegExp = /[^\.]\.(swf)\s*$/i,
 25+
 26+ loadingTimer, loadingFrame = 1,
 27+
 28+ titleHeight = 0, titleStr = '', start_pos, final_pos, busy = false, fx = $.extend($('<div/>')[0], { prop: 0 }),
 29+
 30+ isIE6 = $.browser.msie && $.browser.version < 7 && !window.XMLHttpRequest,
 31+
 32+ /*
 33+ * Private methods
 34+ */
 35+
 36+ _abort = function() {
 37+ loading.hide();
 38+
 39+ imgPreloader.onerror = imgPreloader.onload = null;
 40+
 41+ if (ajaxLoader) {
 42+ ajaxLoader.abort();
 43+ }
 44+
 45+ tmp.empty();
 46+ },
 47+
 48+ _error = function() {
 49+ if (false === selectedOpts.onError(selectedArray, selectedIndex, selectedOpts)) {
 50+ loading.hide();
 51+ busy = false;
 52+ return;
 53+ }
 54+
 55+ selectedOpts.titleShow = false;
 56+
 57+ selectedOpts.width = 'auto';
 58+ selectedOpts.height = 'auto';
 59+
 60+ tmp.html( '<p id="fancybox-error">The requested content cannot be loaded.<br />Please try again later.</p>' );
 61+
 62+ _process_inline();
 63+ },
 64+
 65+ _start = function() {
 66+ var obj = selectedArray[ selectedIndex ],
 67+ href,
 68+ type,
 69+ title,
 70+ str,
 71+ emb,
 72+ ret;
 73+
 74+ _abort();
 75+
 76+ selectedOpts = $.extend({}, $.fn.fancybox.defaults, (typeof $(obj).data('fancybox') == 'undefined' ? selectedOpts : $(obj).data('fancybox')));
 77+
 78+ ret = selectedOpts.onStart(selectedArray, selectedIndex, selectedOpts);
 79+
 80+ if (ret === false) {
 81+ busy = false;
 82+ return;
 83+ } else if (typeof ret == 'object') {
 84+ selectedOpts = $.extend(selectedOpts, ret);
 85+ }
 86+
 87+ title = selectedOpts.title || (obj.nodeName ? $(obj).attr('title') : obj.title) || '';
 88+
 89+ if (obj.nodeName && !selectedOpts.orig) {
 90+ selectedOpts.orig = $(obj).children("img:first").length ? $(obj).children("img:first") : $(obj);
 91+ }
 92+
 93+ if (title === '' && selectedOpts.orig && selectedOpts.titleFromAlt) {
 94+ title = selectedOpts.orig.attr('alt');
 95+ }
 96+
 97+ href = selectedOpts.href || (obj.nodeName ? $(obj).attr('href') : obj.href) || null;
 98+
 99+ if ((/^(?:javascript)/i).test(href) || href == '#') {
 100+ href = null;
 101+ }
 102+
 103+ if (selectedOpts.type) {
 104+ type = selectedOpts.type;
 105+
 106+ if (!href) {
 107+ href = selectedOpts.content;
 108+ }
 109+
 110+ } else if (selectedOpts.content) {
 111+ type = 'html';
 112+
 113+ } else if (href) {
 114+ if (href.match(imgRegExp)) {
 115+ type = 'image';
 116+
 117+ } else if (href.match(swfRegExp)) {
 118+ type = 'swf';
 119+
 120+ } else if ($(obj).hasClass("iframe")) {
 121+ type = 'iframe';
 122+
 123+ } else if (href.indexOf("#") === 0) {
 124+ type = 'inline';
 125+
 126+ } else {
 127+ type = 'ajax';
 128+ }
 129+ }
 130+
 131+ if (!type) {
 132+ _error();
 133+ return;
 134+ }
 135+
 136+ if (type == 'inline') {
 137+ obj = href.substr(href.indexOf("#"));
 138+ type = $(obj).length > 0 ? 'inline' : 'ajax';
 139+ }
 140+
 141+ selectedOpts.type = type;
 142+ selectedOpts.href = href;
 143+ selectedOpts.title = title;
 144+
 145+ if (selectedOpts.autoDimensions) {
 146+ if (selectedOpts.type == 'html' || selectedOpts.type == 'inline' || selectedOpts.type == 'ajax') {
 147+ selectedOpts.width = 'auto';
 148+ selectedOpts.height = 'auto';
 149+ } else {
 150+ selectedOpts.autoDimensions = false;
 151+ }
 152+ }
 153+
 154+ if (selectedOpts.modal) {
 155+ selectedOpts.overlayShow = true;
 156+ selectedOpts.hideOnOverlayClick = false;
 157+ selectedOpts.hideOnContentClick = false;
 158+ selectedOpts.enableEscapeButton = false;
 159+ selectedOpts.showCloseButton = false;
 160+ }
 161+
 162+ selectedOpts.padding = parseInt(selectedOpts.padding, 10);
 163+ selectedOpts.margin = parseInt(selectedOpts.margin, 10);
 164+
 165+ tmp.css('padding', (selectedOpts.padding + selectedOpts.margin));
 166+
 167+ $('.fancybox-inline-tmp').unbind('fancybox-cancel').bind('fancybox-change', function() {
 168+ $(this).replaceWith(content.children());
 169+ });
 170+
 171+ switch (type) {
 172+ case 'html' :
 173+ tmp.html( selectedOpts.content );
 174+ _process_inline();
 175+ break;
 176+
 177+ case 'inline' :
 178+ if ( $(obj).parent().is('#fancybox-content') === true) {
 179+ busy = false;
 180+ return;
 181+ }
 182+
 183+ $('<div class="fancybox-inline-tmp" />')
 184+ .hide()
 185+ .insertBefore( $(obj) )
 186+ .bind('fancybox-cleanup', function() {
 187+ $(this).replaceWith(content.children());
 188+ }).bind('fancybox-cancel', function() {
 189+ $(this).replaceWith(tmp.children());
 190+ });
 191+
 192+ $(obj).appendTo(tmp);
 193+
 194+ _process_inline();
 195+ break;
 196+
 197+ case 'image':
 198+ busy = false;
 199+
 200+ $.fancybox.showActivity();
 201+
 202+ imgPreloader = new Image();
 203+
 204+ imgPreloader.onerror = function() {
 205+ _error();
 206+ };
 207+
 208+ imgPreloader.onload = function() {
 209+ busy = true;
 210+
 211+ imgPreloader.onerror = imgPreloader.onload = null;
 212+
 213+ _process_image();
 214+ };
 215+
 216+ imgPreloader.src = href;
 217+ break;
 218+
 219+ case 'swf':
 220+ selectedOpts.scrolling = 'no';
 221+
 222+ str = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="' + selectedOpts.width + '" height="' + selectedOpts.height + '"><param name="movie" value="' + href + '"></param>';
 223+ emb = '';
 224+
 225+ $.each(selectedOpts.swf, function(name, val) {
 226+ str += '<param name="' + name + '" value="' + val + '"></param>';
 227+ emb += ' ' + name + '="' + val + '"';
 228+ });
 229+
 230+ str += '<embed src="' + href + '" type="application/x-shockwave-flash" width="' + selectedOpts.width + '" height="' + selectedOpts.height + '"' + emb + '></embed></object>';
 231+
 232+ tmp.html(str);
 233+
 234+ _process_inline();
 235+ break;
 236+
 237+ case 'ajax':
 238+ busy = false;
 239+
 240+ $.fancybox.showActivity();
 241+
 242+ selectedOpts.ajax.win = selectedOpts.ajax.success;
 243+
 244+ ajaxLoader = $.ajax($.extend({}, selectedOpts.ajax, {
 245+ url : href,
 246+ data : selectedOpts.ajax.data || {},
 247+ error : function(XMLHttpRequest, textStatus, errorThrown) {
 248+ if ( XMLHttpRequest.status > 0 ) {
 249+ _error();
 250+ }
 251+ },
 252+ success : function(data, textStatus, XMLHttpRequest) {
 253+ var o = typeof XMLHttpRequest == 'object' ? XMLHttpRequest : ajaxLoader;
 254+ if (o.status == 200) {
 255+ if ( typeof selectedOpts.ajax.win == 'function' ) {
 256+ ret = selectedOpts.ajax.win(href, data, textStatus, XMLHttpRequest);
 257+
 258+ if (ret === false) {
 259+ loading.hide();
 260+ return;
 261+ } else if (typeof ret == 'string' || typeof ret == 'object') {
 262+ data = ret;
 263+ }
 264+ }
 265+
 266+ tmp.html( data );
 267+ _process_inline();
 268+ }
 269+ }
 270+ }));
 271+
 272+ break;
 273+
 274+ case 'iframe':
 275+ _show();
 276+ break;
 277+ }
 278+ },
 279+
 280+ _process_inline = function() {
 281+ var
 282+ w = selectedOpts.width,
 283+ h = selectedOpts.height;
 284+
 285+ if (w.toString().indexOf('%') > -1) {
 286+ w = parseInt( ($(window).width() - (selectedOpts.margin * 2)) * parseFloat(w) / 100, 10) + 'px';
 287+
 288+ } else {
 289+ w = w == 'auto' ? 'auto' : w + 'px';
 290+ }
 291+
 292+ if (h.toString().indexOf('%') > -1) {
 293+ h = parseInt( ($(window).height() - (selectedOpts.margin * 2)) * parseFloat(h) / 100, 10) + 'px';
 294+
 295+ } else {
 296+ h = h == 'auto' ? 'auto' : h + 'px';
 297+ }
 298+
 299+ tmp.wrapInner('<div style="width:' + w + ';height:' + h + ';overflow: ' + (selectedOpts.scrolling == 'auto' ? 'auto' : (selectedOpts.scrolling == 'yes' ? 'scroll' : 'hidden')) + ';position:relative;"></div>');
 300+
 301+ selectedOpts.width = tmp.width();
 302+ selectedOpts.height = tmp.height();
 303+
 304+ _show();
 305+ },
 306+
 307+ _process_image = function() {
 308+ selectedOpts.width = imgPreloader.width;
 309+ selectedOpts.height = imgPreloader.height;
 310+
 311+ $("<img />").attr({
 312+ 'id' : 'fancybox-img',
 313+ 'src' : imgPreloader.src,
 314+ 'alt' : selectedOpts.title
 315+ }).appendTo( tmp );
 316+
 317+ _show();
 318+ },
 319+
 320+ _show = function() {
 321+ var pos, equal;
 322+
 323+ loading.hide();
 324+
 325+ if (wrap.is(":visible") && false === currentOpts.onCleanup(currentArray, currentIndex, currentOpts)) {
 326+ $.event.trigger('fancybox-cancel');
 327+
 328+ busy = false;
 329+ return;
 330+ }
 331+
 332+ busy = true;
 333+
 334+ $(content.add( overlay )).unbind();
 335+
 336+ $(window).unbind("resize.fb scroll.fb");
 337+ $(document).unbind('keydown.fb');
 338+
 339+ if (wrap.is(":visible") && currentOpts.titlePosition !== 'outside') {
 340+ wrap.css('height', wrap.height());
 341+ }
 342+
 343+ currentArray = selectedArray;
 344+ currentIndex = selectedIndex;
 345+ currentOpts = selectedOpts;
 346+
 347+ if (currentOpts.overlayShow) {
 348+ overlay.css({
 349+ 'background-color' : currentOpts.overlayColor,
 350+ 'opacity' : currentOpts.overlayOpacity,
 351+ 'cursor' : currentOpts.hideOnOverlayClick ? 'pointer' : 'auto',
 352+ 'height' : $(document).height()
 353+ });
 354+
 355+ if (!overlay.is(':visible')) {
 356+ if (isIE6) {
 357+ $('select:not(#fancybox-tmp select)').filter(function() {
 358+ return this.style.visibility !== 'hidden';
 359+ }).css({'visibility' : 'hidden'}).one('fancybox-cleanup', function() {
 360+ this.style.visibility = 'inherit';
 361+ });
 362+ }
 363+
 364+ overlay.show();
 365+ }
 366+ } else {
 367+ overlay.hide();
 368+ }
 369+
 370+ final_pos = _get_zoom_to();
 371+
 372+ _process_title();
 373+
 374+ if (wrap.is(":visible")) {
 375+ $( close.add( nav_left ).add( nav_right ) ).hide();
 376+
 377+ pos = wrap.position(),
 378+
 379+ start_pos = {
 380+ top : pos.top,
 381+ left : pos.left,
 382+ width : wrap.width(),
 383+ height : wrap.height()
 384+ };
 385+
 386+ equal = (start_pos.width == final_pos.width && start_pos.height == final_pos.height);
 387+
 388+ content.fadeTo(currentOpts.changeFade, 0.3, function() {
 389+ var finish_resizing = function() {
 390+ content.html( tmp.contents() ).fadeTo(currentOpts.changeFade, 1, _finish);
 391+ };
 392+
 393+ $.event.trigger('fancybox-change');
 394+
 395+ content
 396+ .empty()
 397+ .removeAttr('filter')
 398+ .css({
 399+ 'border-width' : currentOpts.padding,
 400+ 'width' : final_pos.width - currentOpts.padding * 2,
 401+ 'height' : selectedOpts.autoDimensions ? 'auto' : final_pos.height - titleHeight - currentOpts.padding * 2
 402+ });
 403+
 404+ if (equal) {
 405+ finish_resizing();
 406+
 407+ } else {
 408+ fx.prop = 0;
 409+
 410+ $(fx).animate({prop: 1}, {
 411+ duration : currentOpts.changeSpeed,
 412+ easing : currentOpts.easingChange,
 413+ step : _draw,
 414+ complete : finish_resizing
 415+ });
 416+ }
 417+ });
 418+
 419+ return;
 420+ }
 421+
 422+ wrap.removeAttr("style");
 423+
 424+ content.css('border-width', currentOpts.padding);
 425+
 426+ if (currentOpts.transitionIn == 'elastic') {
 427+ start_pos = _get_zoom_from();
 428+
 429+ content.html( tmp.contents() );
 430+
 431+ wrap.show();
 432+
 433+ if (currentOpts.opacity) {
 434+ final_pos.opacity = 0;
 435+ }
 436+
 437+ fx.prop = 0;
 438+
 439+ $(fx).animate({prop: 1}, {
 440+ duration : currentOpts.speedIn,
 441+ easing : currentOpts.easingIn,
 442+ step : _draw,
 443+ complete : _finish
 444+ });
 445+
 446+ return;
 447+ }
 448+
 449+ if (currentOpts.titlePosition == 'inside' && titleHeight > 0) {
 450+ title.show();
 451+ }
 452+
 453+ content
 454+ .css({
 455+ 'width' : final_pos.width - currentOpts.padding * 2,
 456+ 'height' : selectedOpts.autoDimensions ? 'auto' : final_pos.height - titleHeight - currentOpts.padding * 2
 457+ })
 458+ .html( tmp.contents() );
 459+
 460+ wrap
 461+ .css(final_pos)
 462+ .fadeIn( currentOpts.transitionIn == 'none' ? 0 : currentOpts.speedIn, _finish );
 463+ },
 464+
 465+ _format_title = function(title) {
 466+ if (title && title.length) {
 467+ if (currentOpts.titlePosition == 'float') {
 468+ return '<table id="fancybox-title-float-wrap" cellpadding="0" cellspacing="0"><tr><td id="fancybox-title-float-left"></td><td id="fancybox-title-float-main">' + title + '</td><td id="fancybox-title-float-right"></td></tr></table>';
 469+ }
 470+
 471+ return '<div id="fancybox-title-' + currentOpts.titlePosition + '">' + title + '</div>';
 472+ }
 473+
 474+ return false;
 475+ },
 476+
 477+ _process_title = function() {
 478+ titleStr = currentOpts.title || '';
 479+ titleHeight = 0;
 480+
 481+ title
 482+ .empty()
 483+ .removeAttr('style')
 484+ .removeClass();
 485+
 486+ if (currentOpts.titleShow === false) {
 487+ title.hide();
 488+ return;
 489+ }
 490+
 491+ titleStr = $.isFunction(currentOpts.titleFormat) ? currentOpts.titleFormat(titleStr, currentArray, currentIndex, currentOpts) : _format_title(titleStr);
 492+
 493+ if (!titleStr || titleStr === '') {
 494+ title.hide();
 495+ return;
 496+ }
 497+
 498+ title
 499+ .addClass('fancybox-title-' + currentOpts.titlePosition)
 500+ .html( titleStr )
 501+ .appendTo( 'body' )
 502+ .show();
 503+
 504+ switch (currentOpts.titlePosition) {
 505+ case 'inside':
 506+ title
 507+ .css({
 508+ 'width' : final_pos.width - (currentOpts.padding * 2),
 509+ 'marginLeft' : currentOpts.padding,
 510+ 'marginRight' : currentOpts.padding
 511+ });
 512+
 513+ titleHeight = title.outerHeight(true);
 514+
 515+ title.appendTo( outer );
 516+
 517+ final_pos.height += titleHeight;
 518+ break;
 519+
 520+ case 'over':
 521+ title
 522+ .css({
 523+ 'marginLeft' : currentOpts.padding,
 524+ 'width' : final_pos.width - (currentOpts.padding * 2),
 525+ 'bottom' : currentOpts.padding
 526+ })
 527+ .appendTo( outer );
 528+ break;
 529+
 530+ case 'float':
 531+ title
 532+ .css('left', parseInt((title.width() - final_pos.width - 40)/ 2, 10) * -1)
 533+ .appendTo( wrap );
 534+ break;
 535+
 536+ default:
 537+ title
 538+ .css({
 539+ 'width' : final_pos.width - (currentOpts.padding * 2),
 540+ 'paddingLeft' : currentOpts.padding,
 541+ 'paddingRight' : currentOpts.padding
 542+ })
 543+ .appendTo( wrap );
 544+ break;
 545+ }
 546+
 547+ title.hide();
 548+ },
 549+
 550+ _set_navigation = function() {
 551+ if (currentOpts.enableEscapeButton || currentOpts.enableKeyboardNav) {
 552+ $(document).bind('keydown.fb', function(e) {
 553+ if (e.keyCode == 27 && currentOpts.enableEscapeButton) {
 554+ e.preventDefault();
 555+ $.fancybox.close();
 556+
 557+ } else if ((e.keyCode == 37 || e.keyCode == 39) && currentOpts.enableKeyboardNav && e.target.tagName !== 'INPUT' && e.target.tagName !== 'TEXTAREA' && e.target.tagName !== 'SELECT') {
 558+ e.preventDefault();
 559+ $.fancybox[ e.keyCode == 37 ? 'prev' : 'next']();
 560+ }
 561+ });
 562+ }
 563+
 564+ if (!currentOpts.showNavArrows) {
 565+ nav_left.hide();
 566+ nav_right.hide();
 567+ return;
 568+ }
 569+
 570+ if ((currentOpts.cyclic && currentArray.length > 1) || currentIndex !== 0) {
 571+ nav_left.show();
 572+ }
 573+
 574+ if ((currentOpts.cyclic && currentArray.length > 1) || currentIndex != (currentArray.length -1)) {
 575+ nav_right.show();
 576+ }
 577+ },
 578+
 579+ _finish = function () {
 580+ if (!$.support.opacity) {
 581+ content.get(0).style.removeAttribute('filter');
 582+ wrap.get(0).style.removeAttribute('filter');
 583+ }
 584+
 585+ if (selectedOpts.autoDimensions) {
 586+ content.css('height', 'auto');
 587+ }
 588+
 589+ wrap.css('height', 'auto');
 590+
 591+ if (titleStr && titleStr.length) {
 592+ title.show();
 593+ }
 594+
 595+ if (currentOpts.showCloseButton) {
 596+ close.show();
 597+ }
 598+
 599+ _set_navigation();
 600+
 601+ if (currentOpts.hideOnContentClick) {
 602+ content.bind('click', $.fancybox.close);
 603+ }
 604+
 605+ if (currentOpts.hideOnOverlayClick) {
 606+ overlay.bind('click', $.fancybox.close);
 607+ }
 608+
 609+ $(window).bind("resize.fb", $.fancybox.resize);
 610+
 611+ if (currentOpts.centerOnScroll) {
 612+ $(window).bind("scroll.fb", $.fancybox.center);
 613+ }
 614+
 615+ if (currentOpts.type == 'iframe') {
 616+ $('<iframe id="fancybox-frame" name="fancybox-frame' + new Date().getTime() + '" frameborder="0" hspace="0" ' + ($.browser.msie ? 'allowtransparency="true""' : '') + ' scrolling="' + selectedOpts.scrolling + '" src="' + currentOpts.href + '"></iframe>').appendTo(content);
 617+ }
 618+
 619+ wrap.show();
 620+
 621+ busy = false;
 622+
 623+ $.fancybox.center();
 624+
 625+ currentOpts.onComplete(currentArray, currentIndex, currentOpts);
 626+
 627+ _preload_images();
 628+ },
 629+
 630+ _preload_images = function() {
 631+ var href,
 632+ objNext;
 633+
 634+ if ((currentArray.length -1) > currentIndex) {
 635+ href = currentArray[ currentIndex + 1 ].href;
 636+
 637+ if (typeof href !== 'undefined' && href.match(imgRegExp)) {
 638+ objNext = new Image();
 639+ objNext.src = href;
 640+ }
 641+ }
 642+
 643+ if (currentIndex > 0) {
 644+ href = currentArray[ currentIndex - 1 ].href;
 645+
 646+ if (typeof href !== 'undefined' && href.match(imgRegExp)) {
 647+ objNext = new Image();
 648+ objNext.src = href;
 649+ }
 650+ }
 651+ },
 652+
 653+ _draw = function(pos) {
 654+ var dim = {
 655+ width : parseInt(start_pos.width + (final_pos.width - start_pos.width) * pos, 10),
 656+ height : parseInt(start_pos.height + (final_pos.height - start_pos.height) * pos, 10),
 657+
 658+ top : parseInt(start_pos.top + (final_pos.top - start_pos.top) * pos, 10),
 659+ left : parseInt(start_pos.left + (final_pos.left - start_pos.left) * pos, 10)
 660+ };
 661+
 662+ if (typeof final_pos.opacity !== 'undefined') {
 663+ dim.opacity = pos < 0.5 ? 0.5 : pos;
 664+ }
 665+
 666+ wrap.css(dim);
 667+
 668+ content.css({
 669+ 'width' : dim.width - currentOpts.padding * 2,
 670+ 'height' : dim.height - (titleHeight * pos) - currentOpts.padding * 2
 671+ });
 672+ },
 673+
 674+ _get_viewport = function() {
 675+ return [
 676+ $(window).width() - (currentOpts.margin * 2),
 677+ $(window).height() - (currentOpts.margin * 2),
 678+ $(document).scrollLeft() + currentOpts.margin,
 679+ $(document).scrollTop() + currentOpts.margin
 680+ ];
 681+ },
 682+
 683+ _get_zoom_to = function () {
 684+ var view = _get_viewport(),
 685+ to = {},
 686+ resize = currentOpts.autoScale,
 687+ double_padding = currentOpts.padding * 2,
 688+ ratio;
 689+
 690+ if (currentOpts.width.toString().indexOf('%') > -1) {
 691+ to.width = parseInt((view[0] * parseFloat(currentOpts.width)) / 100, 10);
 692+ } else {
 693+ to.width = currentOpts.width + double_padding;
 694+ }
 695+
 696+ if (currentOpts.height.toString().indexOf('%') > -1) {
 697+ to.height = parseInt((view[1] * parseFloat(currentOpts.height)) / 100, 10);
 698+ } else {
 699+ to.height = currentOpts.height + double_padding;
 700+ }
 701+
 702+ if (resize && (to.width > view[0] || to.height > view[1])) {
 703+ if (selectedOpts.type == 'image' || selectedOpts.type == 'swf') {
 704+ ratio = (currentOpts.width ) / (currentOpts.height );
 705+
 706+ if ((to.width ) > view[0]) {
 707+ to.width = view[0];
 708+ to.height = parseInt(((to.width - double_padding) / ratio) + double_padding, 10);
 709+ }
 710+
 711+ if ((to.height) > view[1]) {
 712+ to.height = view[1];
 713+ to.width = parseInt(((to.height - double_padding) * ratio) + double_padding, 10);
 714+ }
 715+
 716+ } else {
 717+ to.width = Math.min(to.width, view[0]);
 718+ to.height = Math.min(to.height, view[1]);
 719+ }
 720+ }
 721+
 722+ to.top = parseInt(Math.max(view[3] - 20, view[3] + ((view[1] - to.height - 40) * 0.5)), 10);
 723+ to.left = parseInt(Math.max(view[2] - 20, view[2] + ((view[0] - to.width - 40) * 0.5)), 10);
 724+
 725+ return to;
 726+ },
 727+
 728+ _get_obj_pos = function(obj) {
 729+ var pos = obj.offset();
 730+
 731+ pos.top += parseInt( obj.css('paddingTop'), 10 ) || 0;
 732+ pos.left += parseInt( obj.css('paddingLeft'), 10 ) || 0;
 733+
 734+ pos.top += parseInt( obj.css('border-top-width'), 10 ) || 0;
 735+ pos.left += parseInt( obj.css('border-left-width'), 10 ) || 0;
 736+
 737+ pos.width = obj.width();
 738+ pos.height = obj.height();
 739+
 740+ return pos;
 741+ },
 742+
 743+ _get_zoom_from = function() {
 744+ var orig = selectedOpts.orig ? $(selectedOpts.orig) : false,
 745+ from = {},
 746+ pos,
 747+ view;
 748+
 749+ if (orig && orig.length) {
 750+ pos = _get_obj_pos(orig);
 751+
 752+ from = {
 753+ width : pos.width + (currentOpts.padding * 2),
 754+ height : pos.height + (currentOpts.padding * 2),
 755+ top : pos.top - currentOpts.padding - 20,
 756+ left : pos.left - currentOpts.padding - 20
 757+ };
 758+
 759+ } else {
 760+ view = _get_viewport();
 761+
 762+ from = {
 763+ width : currentOpts.padding * 2,
 764+ height : currentOpts.padding * 2,
 765+ top : parseInt(view[3] + view[1] * 0.5, 10),
 766+ left : parseInt(view[2] + view[0] * 0.5, 10)
 767+ };
 768+ }
 769+
 770+ return from;
 771+ },
 772+
 773+ _animate_loading = function() {
 774+ if (!loading.is(':visible')){
 775+ clearInterval(loadingTimer);
 776+ return;
 777+ }
 778+
 779+ $('div', loading).css('top', (loadingFrame * -40) + 'px');
 780+
 781+ loadingFrame = (loadingFrame + 1) % 12;
 782+ };
 783+
 784+ /*
 785+ * Public methods
 786+ */
 787+
 788+ $.fn.fancybox = function(options) {
 789+ if (!$(this).length) {
 790+ return this;
 791+ }
 792+
 793+ $(this)
 794+ .data('fancybox', $.extend({}, options, ($.metadata ? $(this).metadata() : {})))
 795+ .unbind('click.fb')
 796+ .bind('click.fb', function(e) {
 797+ e.preventDefault();
 798+
 799+ if (busy) {
 800+ return;
 801+ }
 802+
 803+ busy = true;
 804+
 805+ $(this).blur();
 806+
 807+ selectedArray = [];
 808+ selectedIndex = 0;
 809+
 810+ var rel = $(this).attr('rel') || '';
 811+
 812+ if (!rel || rel == '' || rel === 'nofollow') {
 813+ selectedArray.push(this);
 814+
 815+ } else {
 816+ selectedArray = $("a[rel=" + rel + "], area[rel=" + rel + "]");
 817+ selectedIndex = selectedArray.index( this );
 818+ }
 819+
 820+ _start();
 821+
 822+ return;
 823+ });
 824+
 825+ return this;
 826+ };
 827+
 828+ $.fancybox = function(obj) {
 829+ var opts;
 830+
 831+ if (busy) {
 832+ return;
 833+ }
 834+
 835+ busy = true;
 836+ opts = typeof arguments[1] !== 'undefined' ? arguments[1] : {};
 837+
 838+ selectedArray = [];
 839+ selectedIndex = parseInt(opts.index, 10) || 0;
 840+
 841+ if ($.isArray(obj)) {
 842+ for (var i = 0, j = obj.length; i < j; i++) {
 843+ if (typeof obj[i] == 'object') {
 844+ $(obj[i]).data('fancybox', $.extend({}, opts, obj[i]));
 845+ } else {
 846+ obj[i] = $({}).data('fancybox', $.extend({content : obj[i]}, opts));
 847+ }
 848+ }
 849+
 850+ selectedArray = jQuery.merge(selectedArray, obj);
 851+
 852+ } else {
 853+ if (typeof obj == 'object') {
 854+ $(obj).data('fancybox', $.extend({}, opts, obj));
 855+ } else {
 856+ obj = $({}).data('fancybox', $.extend({content : obj}, opts));
 857+ }
 858+
 859+ selectedArray.push(obj);
 860+ }
 861+
 862+ if (selectedIndex > selectedArray.length || selectedIndex < 0) {
 863+ selectedIndex = 0;
 864+ }
 865+
 866+ _start();
 867+ };
 868+
 869+ $.fancybox.showActivity = function() {
 870+ clearInterval(loadingTimer);
 871+
 872+ loading.show();
 873+ loadingTimer = setInterval(_animate_loading, 66);
 874+ };
 875+
 876+ $.fancybox.hideActivity = function() {
 877+ loading.hide();
 878+ };
 879+
 880+ $.fancybox.next = function() {
 881+ return $.fancybox.pos( currentIndex + 1);
 882+ };
 883+
 884+ $.fancybox.prev = function() {
 885+ return $.fancybox.pos( currentIndex - 1);
 886+ };
 887+
 888+ $.fancybox.pos = function(pos) {
 889+ if (busy) {
 890+ return;
 891+ }
 892+
 893+ pos = parseInt(pos);
 894+
 895+ selectedArray = currentArray;
 896+
 897+ if (pos > -1 && pos < currentArray.length) {
 898+ selectedIndex = pos;
 899+ _start();
 900+
 901+ } else if (currentOpts.cyclic && currentArray.length > 1) {
 902+ selectedIndex = pos >= currentArray.length ? 0 : currentArray.length - 1;
 903+ _start();
 904+ }
 905+
 906+ return;
 907+ };
 908+
 909+ $.fancybox.cancel = function() {
 910+ if (busy) {
 911+ return;
 912+ }
 913+
 914+ busy = true;
 915+
 916+ $.event.trigger('fancybox-cancel');
 917+
 918+ _abort();
 919+
 920+ selectedOpts.onCancel(selectedArray, selectedIndex, selectedOpts);
 921+
 922+ busy = false;
 923+ };
 924+
 925+ // Note: within an iframe use - parent.$.fancybox.close();
 926+ $.fancybox.close = function() {
 927+ if (busy || wrap.is(':hidden')) {
 928+ return;
 929+ }
 930+
 931+ busy = true;
 932+
 933+ if (currentOpts && false === currentOpts.onCleanup(currentArray, currentIndex, currentOpts)) {
 934+ busy = false;
 935+ return;
 936+ }
 937+
 938+ _abort();
 939+
 940+ $(close.add( nav_left ).add( nav_right )).hide();
 941+
 942+ $(content.add( overlay )).unbind();
 943+
 944+ $(window).unbind("resize.fb scroll.fb");
 945+ $(document).unbind('keydown.fb');
 946+
 947+ content.find('iframe').attr('src', isIE6 && /^https/i.test(window.location.href || '') ? 'javascript:void(false)' : 'about:blank');
 948+
 949+ if (currentOpts.titlePosition !== 'inside') {
 950+ title.empty();
 951+ }
 952+
 953+ wrap.stop();
 954+
 955+ function _cleanup() {
 956+ overlay.fadeOut('fast');
 957+
 958+ title.empty().hide();
 959+ wrap.hide();
 960+
 961+ $.event.trigger('fancybox-cleanup');
 962+
 963+ content.empty();
 964+
 965+ currentOpts.onClosed(currentArray, currentIndex, currentOpts);
 966+
 967+ currentArray = selectedOpts = [];
 968+ currentIndex = selectedIndex = 0;
 969+ currentOpts = selectedOpts = {};
 970+
 971+ busy = false;
 972+ }
 973+
 974+ if (currentOpts.transitionOut == 'elastic') {
 975+ start_pos = _get_zoom_from();
 976+
 977+ var pos = wrap.position();
 978+
 979+ final_pos = {
 980+ top : pos.top ,
 981+ left : pos.left,
 982+ width : wrap.width(),
 983+ height : wrap.height()
 984+ };
 985+
 986+ if (currentOpts.opacity) {
 987+ final_pos.opacity = 1;
 988+ }
 989+
 990+ title.empty().hide();
 991+
 992+ fx.prop = 1;
 993+
 994+ $(fx).animate({ prop: 0 }, {
 995+ duration : currentOpts.speedOut,
 996+ easing : currentOpts.easingOut,
 997+ step : _draw,
 998+ complete : _cleanup
 999+ });
 1000+
 1001+ } else {
 1002+ wrap.fadeOut( currentOpts.transitionOut == 'none' ? 0 : currentOpts.speedOut, _cleanup);
 1003+ }
 1004+ };
 1005+
 1006+ $.fancybox.resize = function() {
 1007+ if (overlay.is(':visible')) {
 1008+ overlay.css('height', $(document).height());
 1009+ }
 1010+
 1011+ $.fancybox.center(true);
 1012+ };
 1013+
 1014+ $.fancybox.center = function() {
 1015+ var view, align;
 1016+
 1017+ if (busy) {
 1018+ return;
 1019+ }
 1020+
 1021+ align = arguments[0] === true ? 1 : 0;
 1022+ view = _get_viewport();
 1023+
 1024+ if (!align && (wrap.width() > view[0] || wrap.height() > view[1])) {
 1025+ return;
 1026+ }
 1027+
 1028+ wrap
 1029+ .stop()
 1030+ .animate({
 1031+ 'top' : parseInt(Math.max(view[3] - 20, view[3] + ((view[1] - content.height() - 40) * 0.5) - currentOpts.padding)),
 1032+ 'left' : parseInt(Math.max(view[2] - 20, view[2] + ((view[0] - content.width() - 40) * 0.5) - currentOpts.padding))
 1033+ }, typeof arguments[0] == 'number' ? arguments[0] : 200);
 1034+ };
 1035+
 1036+ $.fancybox.init = function() {
 1037+ if ($("#fancybox-wrap").length) {
 1038+ return;
 1039+ }
 1040+
 1041+ $('body').append(
 1042+ tmp = $('<div id="fancybox-tmp"></div>'),
 1043+ loading = $('<div id="fancybox-loading"><div></div></div>'),
 1044+ overlay = $('<div id="fancybox-overlay"></div>'),
 1045+ wrap = $('<div id="fancybox-wrap"></div>')
 1046+ );
 1047+
 1048+ outer = $('<div id="fancybox-outer"></div>')
 1049+ .append('<div class="fancybox-bg" id="fancybox-bg-n"></div><div class="fancybox-bg" id="fancybox-bg-ne"></div><div class="fancybox-bg" id="fancybox-bg-e"></div><div class="fancybox-bg" id="fancybox-bg-se"></div><div class="fancybox-bg" id="fancybox-bg-s"></div><div class="fancybox-bg" id="fancybox-bg-sw"></div><div class="fancybox-bg" id="fancybox-bg-w"></div><div class="fancybox-bg" id="fancybox-bg-nw"></div>')
 1050+ .appendTo( wrap );
 1051+
 1052+ outer.append(
 1053+ content = $('<div id="fancybox-content"></div>'),
 1054+ close = $('<a id="fancybox-close"></a>'),
 1055+ title = $('<div id="fancybox-title"></div>'),
 1056+
 1057+ nav_left = $('<a href="javascript:;" id="fancybox-left"><span class="fancy-ico" id="fancybox-left-ico"></span></a>'),
 1058+ nav_right = $('<a href="javascript:;" id="fancybox-right"><span class="fancy-ico" id="fancybox-right-ico"></span></a>')
 1059+ );
 1060+
 1061+ close.click($.fancybox.close);
 1062+ loading.click($.fancybox.cancel);
 1063+
 1064+ nav_left.click(function(e) {
 1065+ e.preventDefault();
 1066+ $.fancybox.prev();
 1067+ });
 1068+
 1069+ nav_right.click(function(e) {
 1070+ e.preventDefault();
 1071+ $.fancybox.next();
 1072+ });
 1073+
 1074+ if ($.fn.mousewheel) {
 1075+ wrap.bind('mousewheel.fb', function(e, delta) {
 1076+ if (busy) {
 1077+ e.preventDefault();
 1078+
 1079+ } else if ($(e.target).get(0).clientHeight == 0 || $(e.target).get(0).scrollHeight === $(e.target).get(0).clientHeight) {
 1080+ e.preventDefault();
 1081+ $.fancybox[ delta > 0 ? 'prev' : 'next']();
 1082+ }
 1083+ });
 1084+ }
 1085+
 1086+ if (!$.support.opacity) {
 1087+ wrap.addClass('fancybox-ie');
 1088+ }
 1089+
 1090+ if (isIE6) {
 1091+ loading.addClass('fancybox-ie6');
 1092+ wrap.addClass('fancybox-ie6');
 1093+
 1094+ $('<iframe id="fancybox-hide-sel-frame" src="' + (/^https/i.test(window.location.href || '') ? 'javascript:void(false)' : 'about:blank' ) + '" scrolling="no" border="0" frameborder="0" tabindex="-1"></iframe>').prependTo(outer);
 1095+ }
 1096+ };
 1097+
 1098+ $.fn.fancybox.defaults = {
 1099+ padding : 10,
 1100+ margin : 40,
 1101+ opacity : false,
 1102+ modal : false,
 1103+ cyclic : false,
 1104+ scrolling : 'auto', // 'auto', 'yes' or 'no'
 1105+
 1106+ width : 560,
 1107+ height : 340,
 1108+
 1109+ autoScale : true,
 1110+ autoDimensions : true,
 1111+ centerOnScroll : false,
 1112+
 1113+ ajax : {},
 1114+ swf : { wmode: 'transparent' },
 1115+
 1116+ hideOnOverlayClick : true,
 1117+ hideOnContentClick : false,
 1118+
 1119+ overlayShow : true,
 1120+ overlayOpacity : 0.7,
 1121+ overlayColor : '#777',
 1122+
 1123+ titleShow : true,
 1124+ titlePosition : 'float', // 'float', 'outside', 'inside' or 'over'
 1125+ titleFormat : null,
 1126+ titleFromAlt : false,
 1127+
 1128+ transitionIn : 'fade', // 'elastic', 'fade' or 'none'
 1129+ transitionOut : 'fade', // 'elastic', 'fade' or 'none'
 1130+
 1131+ speedIn : 300,
 1132+ speedOut : 300,
 1133+
 1134+ changeSpeed : 300,
 1135+ changeFade : 'fast',
 1136+
 1137+ easingIn : 'swing',
 1138+ easingOut : 'swing',
 1139+
 1140+ showCloseButton : true,
 1141+ showNavArrows : true,
 1142+ enableEscapeButton : true,
 1143+ enableKeyboardNav : true,
 1144+
 1145+ onStart : function(){},
 1146+ onCancel : function(){},
 1147+ onComplete : function(){},
 1148+ onCleanup : function(){},
 1149+ onClosed : function(){},
 1150+ onError : function(){}
 1151+ };
 1152+
 1153+ $(document).ready(function() {
 1154+ $.fancybox.init();
 1155+ });
 1156+
 1157+})(jQuery);
\ No newline at end of file
Property changes on: tags/extensions/Survey/REL_0_1/resources/fancybox/jquery.fancybox-1.3.4.js
___________________________________________________________________
Added: svn:eol-style
11158 + native
Index: tags/extensions/Survey/REL_0_1/resources/fancybox/fancy_shadow_n.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: tags/extensions/Survey/REL_0_1/resources/fancybox/fancy_shadow_n.png
___________________________________________________________________
Added: svn:mime-type
21159 + image/png
Index: tags/extensions/Survey/REL_0_1/resources/fancybox/fancy_close.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: tags/extensions/Survey/REL_0_1/resources/fancybox/fancy_close.png
___________________________________________________________________
Added: svn:mime-type
31160 + image/png
Index: tags/extensions/Survey/REL_0_1/resources/fancybox/fancy_shadow_s.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: tags/extensions/Survey/REL_0_1/resources/fancybox/fancy_shadow_s.png
___________________________________________________________________
Added: svn:mime-type
41161 + image/png
Index: tags/extensions/Survey/REL_0_1/resources/fancybox/fancy_shadow_ne.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: tags/extensions/Survey/REL_0_1/resources/fancybox/fancy_shadow_ne.png
___________________________________________________________________
Added: svn:mime-type
51162 + image/png
Index: tags/extensions/Survey/REL_0_1/resources/fancybox/jquery.easing-1.3.pack.js
@@ -0,0 +1,72 @@
 2+/*
 3+ * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/
 4+ *
 5+ * Uses the built in easing capabilities added In jQuery 1.1
 6+ * to offer multiple easing options
 7+ *
 8+ * TERMS OF USE - jQuery Easing
 9+ *
 10+ * Open source under the BSD License.
 11+ *
 12+ * Copyright © 2008 George McGinley Smith
 13+ * All rights reserved.
 14+ *
 15+ * Redistribution and use in source and binary forms, with or without modification,
 16+ * are permitted provided that the following conditions are met:
 17+ *
 18+ * Redistributions of source code must retain the above copyright notice, this list of
 19+ * conditions and the following disclaimer.
 20+ * Redistributions in binary form must reproduce the above copyright notice, this list
 21+ * of conditions and the following disclaimer in the documentation and/or other materials
 22+ * provided with the distribution.
 23+ *
 24+ * Neither the name of the author nor the names of contributors may be used to endorse
 25+ * or promote products derived from this software without specific prior written permission.
 26+ *
 27+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
 28+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 29+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 30+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 31+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 32+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 33+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 34+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 35+ * OF THE POSSIBILITY OF SUCH DAMAGE.
 36+ *
 37+*/
 38+
 39+// t: current time, b: begInnIng value, c: change In value, d: duration
 40+eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('h.i[\'1a\']=h.i[\'z\'];h.O(h.i,{y:\'D\',z:9(x,t,b,c,d){6 h.i[h.i.y](x,t,b,c,d)},17:9(x,t,b,c,d){6 c*(t/=d)*t+b},D:9(x,t,b,c,d){6-c*(t/=d)*(t-2)+b},13:9(x,t,b,c,d){e((t/=d/2)<1)6 c/2*t*t+b;6-c/2*((--t)*(t-2)-1)+b},X:9(x,t,b,c,d){6 c*(t/=d)*t*t+b},U:9(x,t,b,c,d){6 c*((t=t/d-1)*t*t+1)+b},R:9(x,t,b,c,d){e((t/=d/2)<1)6 c/2*t*t*t+b;6 c/2*((t-=2)*t*t+2)+b},N:9(x,t,b,c,d){6 c*(t/=d)*t*t*t+b},M:9(x,t,b,c,d){6-c*((t=t/d-1)*t*t*t-1)+b},L:9(x,t,b,c,d){e((t/=d/2)<1)6 c/2*t*t*t*t+b;6-c/2*((t-=2)*t*t*t-2)+b},K:9(x,t,b,c,d){6 c*(t/=d)*t*t*t*t+b},J:9(x,t,b,c,d){6 c*((t=t/d-1)*t*t*t*t+1)+b},I:9(x,t,b,c,d){e((t/=d/2)<1)6 c/2*t*t*t*t*t+b;6 c/2*((t-=2)*t*t*t*t+2)+b},G:9(x,t,b,c,d){6-c*8.C(t/d*(8.g/2))+c+b},15:9(x,t,b,c,d){6 c*8.n(t/d*(8.g/2))+b},12:9(x,t,b,c,d){6-c/2*(8.C(8.g*t/d)-1)+b},Z:9(x,t,b,c,d){6(t==0)?b:c*8.j(2,10*(t/d-1))+b},Y:9(x,t,b,c,d){6(t==d)?b+c:c*(-8.j(2,-10*t/d)+1)+b},W:9(x,t,b,c,d){e(t==0)6 b;e(t==d)6 b+c;e((t/=d/2)<1)6 c/2*8.j(2,10*(t-1))+b;6 c/2*(-8.j(2,-10*--t)+2)+b},V:9(x,t,b,c,d){6-c*(8.o(1-(t/=d)*t)-1)+b},S:9(x,t,b,c,d){6 c*8.o(1-(t=t/d-1)*t)+b},Q:9(x,t,b,c,d){e((t/=d/2)<1)6-c/2*(8.o(1-t*t)-1)+b;6 c/2*(8.o(1-(t-=2)*t)+1)+b},P:9(x,t,b,c,d){f s=1.l;f p=0;f a=c;e(t==0)6 b;e((t/=d)==1)6 b+c;e(!p)p=d*.3;e(a<8.w(c)){a=c;f s=p/4}m f s=p/(2*8.g)*8.r(c/a);6-(a*8.j(2,10*(t-=1))*8.n((t*d-s)*(2*8.g)/p))+b},H:9(x,t,b,c,d){f s=1.l;f p=0;f a=c;e(t==0)6 b;e((t/=d)==1)6 b+c;e(!p)p=d*.3;e(a<8.w(c)){a=c;f s=p/4}m f s=p/(2*8.g)*8.r(c/a);6 a*8.j(2,-10*t)*8.n((t*d-s)*(2*8.g)/p)+c+b},T:9(x,t,b,c,d){f s=1.l;f p=0;f a=c;e(t==0)6 b;e((t/=d/2)==2)6 b+c;e(!p)p=d*(.3*1.5);e(a<8.w(c)){a=c;f s=p/4}m f s=p/(2*8.g)*8.r(c/a);e(t<1)6-.5*(a*8.j(2,10*(t-=1))*8.n((t*d-s)*(2*8.g)/p))+b;6 a*8.j(2,-10*(t-=1))*8.n((t*d-s)*(2*8.g)/p)*.5+c+b},F:9(x,t,b,c,d,s){e(s==u)s=1.l;6 c*(t/=d)*t*((s+1)*t-s)+b},E:9(x,t,b,c,d,s){e(s==u)s=1.l;6 c*((t=t/d-1)*t*((s+1)*t+s)+1)+b},16:9(x,t,b,c,d,s){e(s==u)s=1.l;e((t/=d/2)<1)6 c/2*(t*t*(((s*=(1.B))+1)*t-s))+b;6 c/2*((t-=2)*t*(((s*=(1.B))+1)*t+s)+2)+b},A:9(x,t,b,c,d){6 c-h.i.v(x,d-t,0,c,d)+b},v:9(x,t,b,c,d){e((t/=d)<(1/2.k)){6 c*(7.q*t*t)+b}m e(t<(2/2.k)){6 c*(7.q*(t-=(1.5/2.k))*t+.k)+b}m e(t<(2.5/2.k)){6 c*(7.q*(t-=(2.14/2.k))*t+.11)+b}m{6 c*(7.q*(t-=(2.18/2.k))*t+.19)+b}},1b:9(x,t,b,c,d){e(t<d/2)6 h.i.A(x,t*2,0,c,d)*.5+b;6 h.i.v(x,t*2-d,0,c,d)*.5+c*.5+b}});',62,74,'||||||return||Math|function|||||if|var|PI|jQuery|easing|pow|75|70158|else|sin|sqrt||5625|asin|||undefined|easeOutBounce|abs||def|swing|easeInBounce|525|cos|easeOutQuad|easeOutBack|easeInBack|easeInSine|easeOutElastic|easeInOutQuint|easeOutQuint|easeInQuint|easeInOutQuart|easeOutQuart|easeInQuart|extend|easeInElastic|easeInOutCirc|easeInOutCubic|easeOutCirc|easeInOutElastic|easeOutCubic|easeInCirc|easeInOutExpo|easeInCubic|easeOutExpo|easeInExpo||9375|easeInOutSine|easeInOutQuad|25|easeOutSine|easeInOutBack|easeInQuad|625|984375|jswing|easeInOutBounce'.split('|'),0,{}))
 41+
 42+/*
 43+ *
 44+ * TERMS OF USE - EASING EQUATIONS
 45+ *
 46+ * Open source under the BSD License.
 47+ *
 48+ * Copyright © 2001 Robert Penner
 49+ * All rights reserved.
 50+ *
 51+ * Redistribution and use in source and binary forms, with or without modification,
 52+ * are permitted provided that the following conditions are met:
 53+ *
 54+ * Redistributions of source code must retain the above copyright notice, this list of
 55+ * conditions and the following disclaimer.
 56+ * Redistributions in binary form must reproduce the above copyright notice, this list
 57+ * of conditions and the following disclaimer in the documentation and/or other materials
 58+ * provided with the distribution.
 59+ *
 60+ * Neither the name of the author nor the names of contributors may be used to endorse
 61+ * or promote products derived from this software without specific prior written permission.
 62+ *
 63+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
 64+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 65+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 66+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 67+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 68+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 69+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 70+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 71+ * OF THE POSSIBILITY OF SUCH DAMAGE.
 72+ *
 73+ */
Property changes on: tags/extensions/Survey/REL_0_1/resources/fancybox/jquery.easing-1.3.pack.js
___________________________________________________________________
Added: svn:eol-style
174 + native
Index: tags/extensions/Survey/REL_0_1/resources/fancybox/fancy_shadow_w.png
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Property changes on: tags/extensions/Survey/REL_0_1/resources/fancybox/fancy_shadow_w.png
___________________________________________________________________
Added: svn:mime-type
275 + image/png
Index: tags/extensions/Survey/REL_0_1/resources/jquery.numeric.js
@@ -0,0 +1,279 @@
 2+/*
 3+ *
 4+ * Copyright (c) 2006-2011 Sam Collett (http://www.texotela.co.uk)
 5+ * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
 6+ * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
 7+ *
 8+ * Version 1.3
 9+ * Demo: http://www.texotela.co.uk/code/jquery/numeric/
 10+ *
 11+ */
 12+(function($) {
 13+/*
 14+ * Allows only valid characters to be entered into input boxes.
 15+ * Note: fixes value when pasting via Ctrl+V, but not when using the mouse to paste
 16+ * side-effect: Ctrl+A does not work, though you can still use the mouse to select (or double-click to select all)
 17+ *
 18+ * @name numeric
 19+ * @param config { decimal : "." , negative : true }
 20+ * @param callback A function that runs if the number is not valid (fires onblur)
 21+ * @author Sam Collett (http://www.texotela.co.uk)
 22+ * @example $(".numeric").numeric();
 23+ * @example $(".numeric").numeric(","); // use , as separater
 24+ * @example $(".numeric").numeric({ decimal : "," }); // use , as separator
 25+ * @example $(".numeric").numeric({ negative : false }); // do not allow negative values
 26+ * @example $(".numeric").numeric(null, callback); // use default values, pass on the 'callback' function
 27+ *
 28+ */
 29+$.fn.numeric = function(config, callback)
 30+{
 31+ if(typeof config === 'boolean')
 32+ {
 33+ config = { decimal: config };
 34+ }
 35+ config = config || {};
 36+ // if config.negative undefined, set to true (default is to allow negative numbers)
 37+ if(typeof config.negative == "undefined") config.negative = true;
 38+ // set decimal point
 39+ var decimal = (config.decimal === false) ? "" : config.decimal || ".";
 40+ // allow negatives
 41+ var negative = (config.negative === true) ? true : false;
 42+ // callback function
 43+ var callback = typeof callback == "function" ? callback : function(){};
 44+ // set data and methods
 45+ return this.data("numeric.decimal", decimal).data("numeric.negative", negative).data("numeric.callback", callback).keypress($.fn.numeric.keypress).keyup($.fn.numeric.keyup).blur($.fn.numeric.blur);
 46+}
 47+
 48+$.fn.numeric.keypress = function(e)
 49+{
 50+ // get decimal character and determine if negatives are allowed
 51+ var decimal = $.data(this, "numeric.decimal");
 52+ var negative = $.data(this, "numeric.negative");
 53+ // get the key that was pressed
 54+ var key = e.charCode ? e.charCode : e.keyCode ? e.keyCode : 0;
 55+ // allow enter/return key (only when in an input box)
 56+ if(key == 13 && this.nodeName.toLowerCase() == "input")
 57+ {
 58+ return true;
 59+ }
 60+ else if(key == 13)
 61+ {
 62+ return false;
 63+ }
 64+ var allow = false;
 65+ // allow Ctrl+A
 66+ if((e.ctrlKey && key == 97 /* firefox */) || (e.ctrlKey && key == 65) /* opera */) return true;
 67+ // allow Ctrl+X (cut)
 68+ if((e.ctrlKey && key == 120 /* firefox */) || (e.ctrlKey && key == 88) /* opera */) return true;
 69+ // allow Ctrl+C (copy)
 70+ if((e.ctrlKey && key == 99 /* firefox */) || (e.ctrlKey && key == 67) /* opera */) return true;
 71+ // allow Ctrl+Z (undo)
 72+ if((e.ctrlKey && key == 122 /* firefox */) || (e.ctrlKey && key == 90) /* opera */) return true;
 73+ // allow or deny Ctrl+V (paste), Shift+Ins
 74+ if((e.ctrlKey && key == 118 /* firefox */) || (e.ctrlKey && key == 86) /* opera */
 75+ || (e.shiftKey && key == 45)) return true;
 76+ // if a number was not pressed
 77+ if(key < 48 || key > 57)
 78+ {
 79+ /* '-' only allowed at start and if negative numbers allowed */
 80+ if(this.value.indexOf("-") != 0 && negative && key == 45 && (this.value.length == 0 || ($.fn.getSelectionStart(this)) == 0)) return true;
 81+ /* only one decimal separator allowed */
 82+ if(decimal && key == decimal.charCodeAt(0) && this.value.indexOf(decimal) != -1)
 83+ {
 84+ allow = false;
 85+ }
 86+ // check for other keys that have special purposes
 87+ if(
 88+ key != 8 /* backspace */ &&
 89+ key != 9 /* tab */ &&
 90+ key != 13 /* enter */ &&
 91+ key != 35 /* end */ &&
 92+ key != 36 /* home */ &&
 93+ key != 37 /* left */ &&
 94+ key != 39 /* right */ &&
 95+ key != 46 /* del */
 96+ )
 97+ {
 98+ allow = false;
 99+ }
 100+ else
 101+ {
 102+ // for detecting special keys (listed above)
 103+ // IE does not support 'charCode' and ignores them in keypress anyway
 104+ if(typeof e.charCode != "undefined")
 105+ {
 106+ // special keys have 'keyCode' and 'which' the same (e.g. backspace)
 107+ if(e.keyCode == e.which && e.which != 0)
 108+ {
 109+ allow = true;
 110+ // . and delete share the same code, don't allow . (will be set to true later if it is the decimal point)
 111+ if(e.which == 46) allow = false;
 112+ }
 113+ // or keyCode != 0 and 'charCode'/'which' = 0
 114+ else if(e.keyCode != 0 && e.charCode == 0 && e.which == 0)
 115+ {
 116+ allow = true;
 117+ }
 118+ }
 119+ }
 120+ // if key pressed is the decimal and it is not already in the field
 121+ if(decimal && key == decimal.charCodeAt(0))
 122+ {
 123+ if(this.value.indexOf(decimal) == -1)
 124+ {
 125+ allow = true;
 126+ }
 127+ else
 128+ {
 129+ allow = false;
 130+ }
 131+ }
 132+ }
 133+ else
 134+ {
 135+ allow = true;
 136+ }
 137+ return allow;
 138+}
 139+
 140+$.fn.numeric.keyup = function(e)
 141+{
 142+ var val = this.value;
 143+ if(val.length > 0)
 144+ {
 145+ // get carat (cursor) position
 146+ var carat = $.fn.getSelectionStart(this);
 147+ // get decimal character and determine if negatives are allowed
 148+ var decimal = $.data(this, "numeric.decimal");
 149+ var negative = $.data(this, "numeric.negative");
 150+
 151+ // prepend a 0 if necessary
 152+ if(decimal != "")
 153+ {
 154+ // find decimal point
 155+ var dot = val.indexOf(decimal);
 156+ // if dot at start, add 0 before
 157+ if(dot == 0)
 158+ {
 159+ this.value = "0" + val;
 160+ }
 161+ // if dot at position 1, check if there is a - symbol before it
 162+ if(dot == 1 && val.charAt(0) == "-")
 163+ {
 164+ this.value = "-0" + val.substring(1);
 165+ }
 166+ val = this.value;
 167+ }
 168+
 169+ // if pasted in, only allow the following characters
 170+ var validChars = [0,1,2,3,4,5,6,7,8,9,'-',decimal];
 171+ // get length of the value (to loop through)
 172+ var length = val.length;
 173+ // loop backwards (to prevent going out of bounds)
 174+ for(var i = length - 1; i >= 0; i--)
 175+ {
 176+ var ch = val.charAt(i);
 177+ // remove '-' if it is in the wrong place
 178+ if(i != 0 && ch == "-")
 179+ {
 180+ val = val.substring(0, i) + val.substring(i + 1);
 181+ }
 182+ // remove character if it is at the start, a '-' and negatives aren't allowed
 183+ else if(i == 0 && !negative && ch == "-")
 184+ {
 185+ val = val.substring(1);
 186+ }
 187+ var validChar = false;
 188+ // loop through validChars
 189+ for(var j = 0; j < validChars.length; j++)
 190+ {
 191+ // if it is valid, break out the loop
 192+ if(ch == validChars[j])
 193+ {
 194+ validChar = true;
 195+ break;
 196+ }
 197+ }
 198+ // if not a valid character, or a space, remove
 199+ if(!validChar || ch == " ")
 200+ {
 201+ val = val.substring(0, i) + val.substring(i + 1);
 202+ }
 203+ }
 204+ // remove extra decimal characters
 205+ var firstDecimal = val.indexOf(decimal);
 206+ if(firstDecimal > 0)
 207+ {
 208+ for(var i = length - 1; i > firstDecimal; i--)
 209+ {
 210+ var ch = val.charAt(i);
 211+ // remove decimal character
 212+ if(ch == decimal)
 213+ {
 214+ val = val.substring(0, i) + val.substring(i + 1);
 215+ }
 216+ }
 217+ }
 218+ // set the value and prevent the cursor moving to the end
 219+ this.value = val;
 220+ $.fn.setSelection(this, carat);
 221+ }
 222+}
 223+
 224+$.fn.numeric.blur = function()
 225+{
 226+ var decimal = $.data(this, "numeric.decimal");
 227+ var callback = $.data(this, "numeric.callback");
 228+ var val = this.value;
 229+ if(val != "")
 230+ {
 231+ var re = new RegExp("^\\d+$|\\d*" + decimal + "\\d+");
 232+ if(!re.exec(val))
 233+ {
 234+ callback.apply(this);
 235+ }
 236+ }
 237+}
 238+
 239+$.fn.removeNumeric = function()
 240+{
 241+ return this.data("numeric.decimal", null).data("numeric.negative", null).data("numeric.callback", null).unbind("keypress", $.fn.numeric.keypress).unbind("blur", $.fn.numeric.blur);
 242+}
 243+
 244+// Based on code from http://javascript.nwbox.com/cursor_position/ (Diego Perini <dperini@nwbox.com>)
 245+$.fn.getSelectionStart = function(o)
 246+{
 247+ if (o.createTextRange)
 248+ {
 249+ var r = document.selection.createRange().duplicate();
 250+ r.moveEnd('character', o.value.length);
 251+ if (r.text == '') return o.value.length;
 252+ return o.value.lastIndexOf(r.text);
 253+ } else return o.selectionStart;
 254+}
 255+
 256+// set the selection, o is the object (input), p is the position ([start, end] or just start)
 257+$.fn.setSelection = function(o, p)
 258+{
 259+ // if p is number, start and end are the same
 260+ if(typeof p == "number") p = [p, p];
 261+ // only set if p is an array of length 2
 262+ if(p && p.constructor == Array && p.length == 2)
 263+ {
 264+ if (o.createTextRange)
 265+ {
 266+ var r = o.createTextRange();
 267+ r.collapse(true);
 268+ r.moveStart('character', p[0]);
 269+ r.moveEnd('character', p[1]);
 270+ r.select();
 271+ }
 272+ else if(o.setSelectionRange)
 273+ {
 274+ o.focus();
 275+ o.setSelectionRange(p[0], p[1]);
 276+ }
 277+ }
 278+}
 279+
 280+})(jQuery);
\ No newline at end of file
Property changes on: tags/extensions/Survey/REL_0_1/resources/jquery.numeric.js
___________________________________________________________________
Added: svn:eol-style
1281 + native
Index: tags/extensions/Survey/REL_0_1/resources/ext.survey.special.survey.css
@@ -0,0 +1,5 @@
 2+@CHARSET "UTF-8";
 3+
 4+td .question-label {
 5+ vertical-align: middle;
 6+}
Property changes on: tags/extensions/Survey/REL_0_1/resources/ext.survey.special.survey.css
___________________________________________________________________
Added: svn:eol-style
17 + native
Index: tags/extensions/Survey/REL_0_1/Survey.alias.php
@@ -0,0 +1,23 @@
 2+<?php
 3+
 4+/**
 5+ * Aliases for the special pages of the Survey extension.
 6+ *
 7+ * @since 0.1
 8+ *
 9+ * @file Survey.alias.php
 10+ * @ingroup Survey
 11+ *
 12+ * @licence GNU GPL v3+
 13+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
 14+ */
 15+
 16+$specialPageAliases = array();
 17+
 18+/** English (English) */
 19+$specialPageAliases['en'] = array(
 20+ 'EditSurvey' => array( 'EditSurvey', 'Survey' ),
 21+ 'Surveys' => array( 'Surveys' ),
 22+ 'SurveyStats' => array( 'SurveyStats', 'SurveyStatistics' ),
 23+ 'TakeSurvey' => array( 'TakeSurvey' ),
 24+);
Property changes on: tags/extensions/Survey/REL_0_1/Survey.alias.php
___________________________________________________________________
Added: svn:eol-style
125 + native

Status & tagging log