2004-02-18 02:15:00 +00:00
|
|
|
<?php
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
2007-04-04 05:22:37 +00:00
|
|
|
* Contains the EditPage class
|
WARNING: HUGE COMMIT
Doxygen documentation update:
* Changed alls @addtogroup to @ingroup. @addtogroup adds the comment to the group description, but doesn't add the file, class, function, ... to the group like @ingroup does. See for example http://svn.wikimedia.org/doc/group__SpecialPage.html where it's impossible to see related files, classes, ... that should belong to that group.
* Added @file to file description, it seems that it should be explicitely decalred for file descriptions, otherwise doxygen will think that the comment document the first class, variabled, function, ... that is in that file.
* Removed some empty comments
* Removed some ?>
Added following groups:
* ExternalStorage
* JobQueue
* MaintenanceLanguage
One more thing: there are still a lot of warnings when generating the doc.
2008-05-20 17:13:28 +00:00
|
|
|
* @file
|
2004-09-02 23:28:24 +00:00
|
|
|
*/
|
2003-08-02 20:43:11 +00:00
|
|
|
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
2007-04-04 05:22:37 +00:00
|
|
|
* The edit page/HTML interface (split from Article)
|
2004-09-02 23:28:24 +00:00
|
|
|
* The actual database and text munging is still in Article,
|
|
|
|
|
* but it should get easier to call those from alternate
|
|
|
|
|
* interfaces.
|
2007-11-03 03:20:12 +00:00
|
|
|
*
|
|
|
|
|
* EditPage cares about two distinct titles:
|
2011-02-10 17:08:37 +00:00
|
|
|
* $this->mContextTitle is the page that forms submit to, links point to,
|
2007-11-03 03:20:12 +00:00
|
|
|
* redirects go to, etc. $this->mTitle (as well as $mArticle) is the
|
|
|
|
|
* page in the database that is actually being edited. These are
|
|
|
|
|
* usually the same, but they are now allowed to be different.
|
2011-08-27 01:24:31 +00:00
|
|
|
*
|
2011-08-29 15:45:54 +00:00
|
|
|
* Surgeon General's Warning: prolonged exposure to this class is known to cause
|
2011-08-27 01:24:31 +00:00
|
|
|
* headaches, which may be fatal.
|
2004-09-02 23:28:24 +00:00
|
|
|
*/
|
2003-08-02 20:43:11 +00:00
|
|
|
class EditPage {
|
2012-01-19 01:51:27 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Status: Article successfully updated
|
|
|
|
|
*/
|
2010-07-20 15:12:29 +00:00
|
|
|
const AS_SUCCESS_UPDATE = 200;
|
2012-01-19 01:51:27 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Status: Article successfully created
|
|
|
|
|
*/
|
2010-07-20 15:12:29 +00:00
|
|
|
const AS_SUCCESS_NEW_ARTICLE = 201;
|
2012-01-19 01:51:27 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Status: Article update aborted by a hook function
|
|
|
|
|
*/
|
2010-07-20 15:12:29 +00:00
|
|
|
const AS_HOOK_ERROR = 210;
|
2012-01-19 01:51:27 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Status: A hook function returned an error
|
|
|
|
|
*/
|
2010-07-20 15:12:29 +00:00
|
|
|
const AS_HOOK_ERROR_EXPECTED = 212;
|
2012-01-19 01:51:27 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Status: User is blocked from editting this page
|
|
|
|
|
*/
|
2010-07-20 15:12:29 +00:00
|
|
|
const AS_BLOCKED_PAGE_FOR_USER = 215;
|
2012-01-19 01:51:27 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Status: Content too big (> $wgMaxArticleSize)
|
|
|
|
|
*/
|
2010-07-20 15:12:29 +00:00
|
|
|
const AS_CONTENT_TOO_BIG = 216;
|
2012-01-19 01:51:27 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Status: User cannot edit? (not used)
|
|
|
|
|
*/
|
2010-07-20 15:12:29 +00:00
|
|
|
const AS_USER_CANNOT_EDIT = 217;
|
2012-01-19 01:51:27 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Status: this anonymous user is not allowed to edit this page
|
|
|
|
|
*/
|
2010-07-20 15:12:29 +00:00
|
|
|
const AS_READ_ONLY_PAGE_ANON = 218;
|
2012-01-19 01:51:27 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Status: this logged in user is not allowed to edit this page
|
|
|
|
|
*/
|
2010-07-20 15:12:29 +00:00
|
|
|
const AS_READ_ONLY_PAGE_LOGGED = 219;
|
2012-01-19 01:51:27 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Status: wiki is in readonly mode (wfReadOnly() == true)
|
|
|
|
|
*/
|
2010-07-20 15:12:29 +00:00
|
|
|
const AS_READ_ONLY_PAGE = 220;
|
2012-01-19 01:51:27 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Status: rate limiter for action 'edit' was tripped
|
|
|
|
|
*/
|
2010-07-20 15:12:29 +00:00
|
|
|
const AS_RATE_LIMITED = 221;
|
2012-01-19 01:51:27 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Status: article was deleted while editting and param wpRecreate == false or form
|
|
|
|
|
* was not posted
|
|
|
|
|
*/
|
2010-07-20 15:12:29 +00:00
|
|
|
const AS_ARTICLE_WAS_DELETED = 222;
|
2012-01-19 01:51:27 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Status: user tried to create this page, but is not allowed to do that
|
|
|
|
|
* ( Title->usercan('create') == false )
|
|
|
|
|
*/
|
2010-07-20 15:12:29 +00:00
|
|
|
const AS_NO_CREATE_PERMISSION = 223;
|
2012-01-19 01:51:27 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Status: user tried to create a blank page
|
|
|
|
|
*/
|
2010-07-20 15:12:29 +00:00
|
|
|
const AS_BLANK_ARTICLE = 224;
|
2012-01-19 01:51:27 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Status: (non-resolvable) edit conflict
|
|
|
|
|
*/
|
2010-07-20 15:12:29 +00:00
|
|
|
const AS_CONFLICT_DETECTED = 225;
|
2012-01-19 01:51:27 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Status: no edit summary given and the user has forceeditsummary set and the user is not
|
|
|
|
|
* editting in his own userspace or talkspace and wpIgnoreBlankSummary == false
|
|
|
|
|
*/
|
2010-07-20 15:12:29 +00:00
|
|
|
const AS_SUMMARY_NEEDED = 226;
|
2012-01-19 01:51:27 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Status: user tried to create a new section without content
|
|
|
|
|
*/
|
2010-07-20 15:12:29 +00:00
|
|
|
const AS_TEXTBOX_EMPTY = 228;
|
2012-01-19 01:51:27 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Status: article is too big (> $wgMaxArticleSize), after merging in the new section
|
|
|
|
|
*/
|
2009-12-04 15:45:02 +00:00
|
|
|
const AS_MAX_ARTICLE_SIZE_EXCEEDED = 229;
|
2012-01-19 01:51:27 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* not used
|
|
|
|
|
*/
|
2010-07-20 15:12:29 +00:00
|
|
|
const AS_OK = 230;
|
2012-01-19 01:51:27 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Status: WikiPage::doEdit() was unsuccessfull
|
|
|
|
|
*/
|
2010-07-20 15:12:29 +00:00
|
|
|
const AS_END = 231;
|
2012-01-19 01:51:27 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Status: summary contained spam according to one of the regexes in $wgSummarySpamRegex
|
|
|
|
|
*/
|
2010-07-20 15:12:29 +00:00
|
|
|
const AS_SPAM_ERROR = 232;
|
2012-01-19 01:51:27 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Status: anonymous user is not allowed to upload (User::isAllowed('upload') == false)
|
|
|
|
|
*/
|
2010-07-20 15:12:29 +00:00
|
|
|
const AS_IMAGE_REDIRECT_ANON = 233;
|
2012-01-19 01:51:27 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Status: logged in user is not allowed to upload (User::isAllowed('upload') == false)
|
|
|
|
|
*/
|
2010-07-20 15:12:29 +00:00
|
|
|
const AS_IMAGE_REDIRECT_LOGGED = 234;
|
2007-10-30 05:42:19 +00:00
|
|
|
|
2012-04-16 19:39:50 +00:00
|
|
|
/**
|
|
|
|
|
* HTML id and name for the beginning of the edit form.
|
|
|
|
|
*/
|
|
|
|
|
const EDITFORM_ID = 'editform';
|
|
|
|
|
|
2011-02-24 17:04:49 +00:00
|
|
|
/**
|
|
|
|
|
* @var Article
|
|
|
|
|
*/
|
2006-05-11 22:40:38 +00:00
|
|
|
var $mArticle;
|
2011-02-24 17:04:49 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @var Title
|
|
|
|
|
*/
|
2007-11-01 17:56:19 +00:00
|
|
|
var $mTitle;
|
2011-02-10 17:08:37 +00:00
|
|
|
private $mContextTitle = null;
|
2011-11-03 09:21:45 +00:00
|
|
|
var $action = 'submit';
|
2006-05-11 22:40:38 +00:00
|
|
|
var $isConflict = false;
|
|
|
|
|
var $isCssJsSubpage = false;
|
2009-08-01 07:41:57 +00:00
|
|
|
var $isCssSubpage = false;
|
|
|
|
|
var $isJsSubpage = false;
|
2011-06-05 14:46:55 +00:00
|
|
|
var $isWrongCaseCssJsPage = false;
|
2011-04-23 18:58:03 +00:00
|
|
|
var $isNew = false; // new page or new section
|
2011-01-20 07:38:30 +00:00
|
|
|
var $deletedSinceEdit;
|
2006-05-11 22:40:38 +00:00
|
|
|
var $formtype;
|
|
|
|
|
var $firsttime;
|
|
|
|
|
var $lastDelete;
|
2006-06-06 06:21:50 +00:00
|
|
|
var $mTokenOk = false;
|
2007-07-01 22:22:16 +00:00
|
|
|
var $mTokenOkExceptSuffix = false;
|
2006-06-07 08:28:43 +00:00
|
|
|
var $mTriedSave = false;
|
2011-02-14 03:10:08 +00:00
|
|
|
var $incompleteForm = false;
|
2006-05-11 22:40:38 +00:00
|
|
|
var $tooBig = false;
|
|
|
|
|
var $kblength = false;
|
|
|
|
|
var $missingComment = false;
|
|
|
|
|
var $missingSummary = false;
|
|
|
|
|
var $allowBlankSummary = false;
|
|
|
|
|
var $autoSumm = '';
|
|
|
|
|
var $hookError = '';
|
2008-08-27 05:56:34 +00:00
|
|
|
#var $mPreviewTemplates;
|
2011-05-26 19:52:56 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @var ParserOutput
|
|
|
|
|
*/
|
2008-08-27 05:56:34 +00:00
|
|
|
var $mParserOutput;
|
2012-02-16 16:09:08 +00:00
|
|
|
|
2012-02-09 21:06:19 +00:00
|
|
|
/**
|
|
|
|
|
* Has a summary been preset using GET parameter &summary= ?
|
|
|
|
|
* @var Bool
|
|
|
|
|
*/
|
|
|
|
|
var $hasPresetSummary = false;
|
2011-05-26 19:52:56 +00:00
|
|
|
|
2008-07-15 08:43:40 +00:00
|
|
|
var $mBaseRevision = false;
|
2009-11-23 13:27:34 +00:00
|
|
|
var $mShowSummaryField = true;
|
2005-08-02 13:35:19 +00:00
|
|
|
|
2004-03-08 09:09:35 +00:00
|
|
|
# Form values
|
2006-05-11 22:40:38 +00:00
|
|
|
var $save = false, $preview = false, $diff = false;
|
|
|
|
|
var $minoredit = false, $watchthis = false, $recreate = false;
|
2009-12-08 17:17:24 +00:00
|
|
|
var $textbox1 = '', $textbox2 = '', $summary = '', $nosummary = false;
|
2011-12-20 04:15:21 +00:00
|
|
|
var $edittime = '', $section = '', $sectiontitle = '', $starttime = '';
|
2009-12-08 17:17:24 +00:00
|
|
|
var $oldid = 0, $editintro = '', $scrolltop = null, $bot = true;
|
2005-08-02 13:35:19 +00:00
|
|
|
|
2006-11-22 20:53:11 +00:00
|
|
|
# Placeholders for text injection by hooks (must be HTML)
|
|
|
|
|
# extensions should take care to _append_ to the present value
|
2011-11-03 09:21:45 +00:00
|
|
|
public $editFormPageTop = ''; // Before even the preview
|
|
|
|
|
public $editFormTextTop = '';
|
|
|
|
|
public $editFormTextBeforeContent = '';
|
|
|
|
|
public $editFormTextAfterWarn = '';
|
|
|
|
|
public $editFormTextAfterTools = '';
|
|
|
|
|
public $editFormTextBottom = '';
|
|
|
|
|
public $editFormTextAfterContent = '';
|
|
|
|
|
public $previewTextAfterContent = '';
|
|
|
|
|
public $mPreloadText = '';
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2007-11-03 03:20:12 +00:00
|
|
|
/* $didSave should be set to true whenever an article was succesfully altered. */
|
|
|
|
|
public $didSave = false;
|
2009-01-17 00:53:23 +00:00
|
|
|
public $undidRev = 0;
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2007-11-03 03:20:12 +00:00
|
|
|
public $suppressIntro = false;
|
2006-11-22 20:53:11 +00:00
|
|
|
|
2004-09-03 16:51:45 +00:00
|
|
|
/**
|
2011-05-26 20:26:51 +00:00
|
|
|
* @param $article Article
|
2004-09-03 16:51:45 +00:00
|
|
|
*/
|
2012-01-04 06:52:59 +00:00
|
|
|
public function __construct( Article $article ) {
|
2011-11-03 09:21:45 +00:00
|
|
|
$this->mArticle = $article;
|
2007-11-03 03:20:12 +00:00
|
|
|
$this->mTitle = $article->getTitle();
|
2003-08-02 20:43:11 +00:00
|
|
|
}
|
2009-10-23 11:08:08 +00:00
|
|
|
|
2011-05-26 20:26:51 +00:00
|
|
|
/**
|
|
|
|
|
* @return Article
|
|
|
|
|
*/
|
2011-11-03 09:21:45 +00:00
|
|
|
public function getArticle() {
|
2008-12-20 01:15:40 +00:00
|
|
|
return $this->mArticle;
|
|
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2011-11-03 09:21:45 +00:00
|
|
|
/**
|
|
|
|
|
* @since 1.19
|
|
|
|
|
* @return Title
|
|
|
|
|
*/
|
|
|
|
|
public function getTitle() {
|
|
|
|
|
return $this->mTitle;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-10 17:08:37 +00:00
|
|
|
/**
|
|
|
|
|
* Set the context Title object
|
|
|
|
|
*
|
|
|
|
|
* @param $title Title object or null
|
|
|
|
|
*/
|
|
|
|
|
public function setContextTitle( $title ) {
|
|
|
|
|
$this->mContextTitle = $title;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the context title object.
|
|
|
|
|
* If not set, $wgTitle will be returned. This behavior might changed in
|
|
|
|
|
* the future to return $this->mTitle instead.
|
|
|
|
|
*
|
|
|
|
|
* @return Title object
|
|
|
|
|
*/
|
|
|
|
|
public function getContextTitle() {
|
|
|
|
|
if ( is_null( $this->mContextTitle ) ) {
|
|
|
|
|
global $wgTitle;
|
|
|
|
|
return $wgTitle;
|
|
|
|
|
} else {
|
|
|
|
|
return $this->mContextTitle;
|
|
|
|
|
}
|
|
|
|
|
}
|
here it is ... the upload-api, script-server, js2 (javascript phase2) branch merge 1st attempt.
Here is a short overview of changes and associated default configuration variables (most everything is off by default) also see ~soon to be updated~: http://www.mediawiki.org/wiki/Media_Projects_Overview
= Upload Improvements =
==Upload API ==
* Based on the early work of Bryan Tong and others it adds the upload option to the api.
* We rewrite Special:Upload page to include use the new refactoring
* Added in token checks in both the SpecialUpload.php page so avoids DOS / xss copy-by-url JavaScript based cross site POST file submissions
== Copy by URL==
$wgAllowCopyUploads = false;
* http class rewrite includes a new http background download see: includes/HttpFunctions.php
* spins off a php process that calls: maintenance/http_session_download.php
* pushes updates to the session and gives the user a progress bar on http copy uploads from other server progress (using js2 upload interface) (if not using the js2 upload interface it does the request in-place but the download is limited to the php ini timeout time)
== Firefogg ==
* Firefogg enables resumable upload by chunks
* progress indicators and conditional invokation (js2 system)
* and of-course client side transcoding.
= Script Server =
$wgEnableScriptLoader = false;
* off by default if $wgEnableScriptLoader is turned on script files are grouped, gziped, cached etc.
for more info see: http://www.mediawiki.org/wiki/Extension:ScriptLoader
* Includes some early skin js include fixes (skin/script system still lots of love)
* Includes a "javascript class autoloader" this is packaged into mwEmbed so that the mwEmbed library can work in stand alone mode (while retaining localization and script serving) (one such application is the make page for firefogg.org : http://www.firefogg.org/make/index.html )
* The file that contains the autojavascript loading classes is: js2/php/jsAutoloadLocalClasses.php
* One can use this auto class loading dependency system with extensions and add-ons but I need to better document that.
= js2 system / mwEmbed=
$wgEnableJS2system = false
* includes initial rewrite towards more jquery based javascript code
* especially for the Special:Upload page.
* Also the edit page include support for the "add-media-wizard"
* includes dependency loader for javascript that optionally takes advantage of the script-loader
* remote embedding of javascript interfaces (like embedding video, or commons media searching)
* $wgDebugJavaScript = false; .. .this variable lets you always get "always fresh javascript". When used with the script-loader it does not minify the script-loader output.
= mwEmbed =
* Will commit a separate patch to oggHandler that conditionally outputs <video tag> to use the new javascript video player.
** mv_embed player includes: play-head, volume control, remote embedding, oggz-chop support across plugins.
* add-media-wizard adds easy inserts of media to pages (with import)
== jQuery==
* we include a base install of jQuery, jQuery ui and some plugins.
* all the javascript classes are in the scriptloader so its easy to load any set of jquery ui components that you may need using the script-server. You get a callback so you can then execute js with dependencies loaded.
== other stuff ==
there is a bit more code in js2 that pertains to sequence editing, timed text display and basic image editing. We include a base import of pixastic-lib & pixastic-editor... will work with the pixastic developer to try and ensure upstream compatibility on our usage of the library for in-browser photo and sequence manipulation.
2009-07-14 23:52:14 +00:00
|
|
|
|
2005-08-20 06:57:21 +00:00
|
|
|
function submit() {
|
|
|
|
|
$this->edit();
|
|
|
|
|
}
|
|
|
|
|
|
2004-09-03 16:51:45 +00:00
|
|
|
/**
|
2006-01-07 13:09:30 +00:00
|
|
|
* This is the function that gets called for "action=edit". It
|
|
|
|
|
* sets up various member variables, then passes execution to
|
2005-08-20 06:57:21 +00:00
|
|
|
* another function, usually showEditForm()
|
2006-01-07 13:09:30 +00:00
|
|
|
*
|
2005-08-20 06:57:21 +00:00
|
|
|
* The edit form is self-submitting, so that when things like
|
|
|
|
|
* preview and edit conflicts occur, we get the same form back
|
2010-07-20 15:12:29 +00:00
|
|
|
* with the extra stuff added. Only when the final submission
|
2005-08-20 06:57:21 +00:00
|
|
|
* is made and all is well do we actually save and redirect to
|
|
|
|
|
* the newly-edited page.
|
2004-09-03 16:51:45 +00:00
|
|
|
*/
|
|
|
|
|
function edit() {
|
2010-02-09 07:39:09 +00:00
|
|
|
global $wgOut, $wgRequest, $wgUser;
|
2008-09-04 20:14:12 +00:00
|
|
|
// Allow extensions to modify/prevent this form or submission
|
2009-08-21 21:51:29 +00:00
|
|
|
if ( !wfRunHooks( 'AlternateEdit', array( $this ) ) ) {
|
2005-11-10 10:30:25 +00:00
|
|
|
return;
|
2008-09-04 20:14:12 +00:00
|
|
|
}
|
2006-01-07 13:31:29 +00:00
|
|
|
|
2008-01-11 20:51:53 +00:00
|
|
|
wfProfileIn( __METHOD__ );
|
2012-02-16 16:09:08 +00:00
|
|
|
wfDebug( __METHOD__ . ": enter\n" );
|
2005-08-21 04:45:28 +00:00
|
|
|
|
2011-11-02 20:18:43 +00:00
|
|
|
// If they used redlink=1 and the page exists, redirect to the main article
|
|
|
|
|
if ( $wgRequest->getBool( 'redlink' ) && $this->mTitle->exists() ) {
|
|
|
|
|
$wgOut->redirect( $this->mTitle->getFullURL() );
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2004-03-08 09:09:35 +00:00
|
|
|
$this->importFormData( $wgRequest );
|
2005-08-20 06:57:21 +00:00
|
|
|
$this->firsttime = false;
|
2005-08-02 13:35:19 +00:00
|
|
|
|
2008-09-16 04:59:49 +00:00
|
|
|
if ( $this->live ) {
|
2004-12-19 02:36:04 +00:00
|
|
|
$this->livePreview();
|
2008-01-11 20:51:53 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2004-12-19 02:36:04 +00:00
|
|
|
return;
|
|
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2008-10-13 22:39:53 +00:00
|
|
|
if ( wfReadOnly() && $this->save ) {
|
2009-09-10 06:43:01 +00:00
|
|
|
// Force preview
|
|
|
|
|
$this->save = false;
|
|
|
|
|
$this->preview = true;
|
2008-01-15 01:55:48 +00:00
|
|
|
}
|
2003-08-02 20:43:11 +00:00
|
|
|
|
2011-11-02 20:18:43 +00:00
|
|
|
if ( $this->save ) {
|
|
|
|
|
$this->formtype = 'save';
|
|
|
|
|
} elseif ( $this->preview ) {
|
|
|
|
|
$this->formtype = 'preview';
|
|
|
|
|
} elseif ( $this->diff ) {
|
|
|
|
|
$this->formtype = 'diff';
|
|
|
|
|
} else { # First time through
|
|
|
|
|
$this->firsttime = true;
|
|
|
|
|
if ( $this->previewOnOpen() ) {
|
2005-08-20 06:57:21 +00:00
|
|
|
$this->formtype = 'preview';
|
2011-11-02 20:18:43 +00:00
|
|
|
} else {
|
|
|
|
|
$this->formtype = 'initial';
|
2003-08-02 20:43:11 +00:00
|
|
|
}
|
|
|
|
|
}
|
2009-10-23 11:08:08 +00:00
|
|
|
|
2011-11-04 18:35:25 +00:00
|
|
|
$permErrors = $this->getEditPermissionErrors();
|
|
|
|
|
if ( $permErrors ) {
|
|
|
|
|
wfDebug( __METHOD__ . ": User can't edit\n" );
|
|
|
|
|
// Auto-block user's IP if the account was "hard" blocked
|
|
|
|
|
$wgUser->spreadAnyEditBlock();
|
|
|
|
|
|
|
|
|
|
$this->displayPermissionsError( $permErrors );
|
|
|
|
|
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2012-02-16 16:09:08 +00:00
|
|
|
wfProfileIn( __METHOD__ . "-business-end" );
|
2006-01-07 13:31:29 +00:00
|
|
|
|
2005-08-20 06:57:21 +00:00
|
|
|
$this->isConflict = false;
|
|
|
|
|
// css / js subpages of user pages get a special treatment
|
2011-04-23 18:58:03 +00:00
|
|
|
$this->isCssJsSubpage = $this->mTitle->isCssJsSubpage();
|
|
|
|
|
$this->isCssSubpage = $this->mTitle->isCssSubpage();
|
|
|
|
|
$this->isJsSubpage = $this->mTitle->isJsSubpage();
|
2010-11-25 23:12:05 +00:00
|
|
|
$this->isWrongCaseCssJsPage = $this->isWrongCaseCssJsPage();
|
2011-04-23 18:58:03 +00:00
|
|
|
$this->isNew = !$this->mTitle->exists() || $this->section == 'new';
|
2006-01-07 13:31:29 +00:00
|
|
|
|
2007-06-11 11:57:20 +00:00
|
|
|
# Show applicable editing introductions
|
2012-01-11 10:33:31 +00:00
|
|
|
if ( $this->formtype == 'initial' || $this->firsttime ) {
|
2005-08-20 06:57:21 +00:00
|
|
|
$this->showIntro();
|
2008-08-11 08:30:29 +00:00
|
|
|
}
|
|
|
|
|
|
2010-07-20 15:12:29 +00:00
|
|
|
# Attempt submission here. This will check for edit conflicts,
|
2005-08-20 06:57:21 +00:00
|
|
|
# and redundantly check for locked database, blocked IPs, etc.
|
|
|
|
|
# that edit() already checked just in case someone tries to sneak
|
|
|
|
|
# in the back door with a hand-edited submission URL.
|
2008-12-23 21:19:31 +00:00
|
|
|
|
2008-09-16 04:59:49 +00:00
|
|
|
if ( 'save' == $this->formtype ) {
|
|
|
|
|
if ( !$this->attemptSave() ) {
|
2012-02-16 16:09:08 +00:00
|
|
|
wfProfileOut( __METHOD__ . "-business-end" );
|
2008-01-11 20:51:53 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2005-08-20 06:57:21 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2006-01-07 13:31:29 +00:00
|
|
|
|
2005-08-20 06:57:21 +00:00
|
|
|
# First time through: get contents, set time for conflict
|
|
|
|
|
# checking, etc.
|
2008-09-16 04:59:49 +00:00
|
|
|
if ( 'initial' == $this->formtype || $this->firsttime ) {
|
2009-10-25 15:02:33 +00:00
|
|
|
if ( $this->initialiseForm() === false ) {
|
2007-03-14 18:20:21 +00:00
|
|
|
$this->noSuchSectionPage();
|
2012-02-16 16:09:08 +00:00
|
|
|
wfProfileOut( __METHOD__ . "-business-end" );
|
2008-01-11 20:51:53 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2007-03-14 18:20:21 +00:00
|
|
|
return;
|
|
|
|
|
}
|
2012-03-11 22:05:54 +00:00
|
|
|
if ( !$this->mTitle->getArticleID() )
|
2007-11-01 17:56:19 +00:00
|
|
|
wfRunHooks( 'EditFormPreloadText', array( &$this->textbox1, &$this->mTitle ) );
|
2010-02-20 17:05:56 +00:00
|
|
|
else
|
|
|
|
|
wfRunHooks( 'EditFormInitialText', array( $this ) );
|
2005-08-20 06:57:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->showEditForm();
|
2012-02-16 16:09:08 +00:00
|
|
|
wfProfileOut( __METHOD__ . "-business-end" );
|
2008-01-11 20:51:53 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2003-08-02 20:43:11 +00:00
|
|
|
}
|
2009-10-23 11:08:08 +00:00
|
|
|
|
2011-06-05 14:46:55 +00:00
|
|
|
/**
|
|
|
|
|
* @return array
|
|
|
|
|
*/
|
2008-09-04 20:14:12 +00:00
|
|
|
protected function getEditPermissionErrors() {
|
|
|
|
|
global $wgUser;
|
|
|
|
|
$permErrors = $this->mTitle->getUserPermissionsErrors( 'edit', $wgUser );
|
|
|
|
|
# Can this title be created?
|
2008-09-16 04:59:49 +00:00
|
|
|
if ( !$this->mTitle->exists() ) {
|
2008-09-04 20:14:12 +00:00
|
|
|
$permErrors = array_merge( $permErrors,
|
|
|
|
|
wfArrayDiff2( $this->mTitle->getUserPermissionsErrors( 'create', $wgUser ), $permErrors ) );
|
|
|
|
|
}
|
|
|
|
|
# Ignore some permissions errors when a user is just previewing/viewing diffs
|
|
|
|
|
$remove = array();
|
2012-02-16 16:09:08 +00:00
|
|
|
foreach ( $permErrors as $error ) {
|
2009-10-25 15:02:33 +00:00
|
|
|
if ( ( $this->preview || $this->diff ) &&
|
|
|
|
|
( $error[0] == 'blockedtext' || $error[0] == 'autoblockedtext' ) )
|
2008-09-04 20:14:12 +00:00
|
|
|
{
|
|
|
|
|
$remove[] = $error;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$permErrors = wfArrayDiff2( $permErrors, $remove );
|
|
|
|
|
return $permErrors;
|
|
|
|
|
}
|
2005-08-02 13:35:19 +00:00
|
|
|
|
2011-11-04 18:35:25 +00:00
|
|
|
/**
|
|
|
|
|
* Display a permissions error page, like OutputPage::showPermissionsErrorPage(),
|
|
|
|
|
* but with the following differences:
|
2012-01-04 06:52:59 +00:00
|
|
|
* - If redlink=1, the user will be redirected to the page
|
2011-11-04 18:35:25 +00:00
|
|
|
* - If there is content to display or the error occurs while either saving,
|
|
|
|
|
* previewing or showing the difference, it will be a
|
|
|
|
|
* "View source for ..." page displaying the source code after the error message.
|
|
|
|
|
*
|
|
|
|
|
* @since 1.19
|
|
|
|
|
* @param $permErrors Array of permissions errors, as returned by
|
|
|
|
|
* Title::getUserPermissionsErrors().
|
|
|
|
|
*/
|
|
|
|
|
protected function displayPermissionsError( array $permErrors ) {
|
|
|
|
|
global $wgRequest, $wgOut;
|
|
|
|
|
|
|
|
|
|
if ( $wgRequest->getBool( 'redlink' ) ) {
|
|
|
|
|
// The edit page was reached via a red link.
|
|
|
|
|
// Redirect to the article page and let them click the edit tab if
|
|
|
|
|
// they really want a permission error.
|
|
|
|
|
$wgOut->redirect( $this->mTitle->getFullUrl() );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$content = $this->getContent();
|
|
|
|
|
|
|
|
|
|
# Use the normal message if there's nothing to display
|
|
|
|
|
if ( $this->firsttime && $content === '' ) {
|
|
|
|
|
$action = $this->mTitle->exists() ? 'edit' :
|
2011-12-24 15:32:35 +00:00
|
|
|
( $this->mTitle->isTalkPage() ? 'createtalk' : 'createpage' );
|
2011-11-04 18:35:25 +00:00
|
|
|
throw new PermissionsError( $action, $permErrors );
|
|
|
|
|
}
|
|
|
|
|
|
2011-11-08 18:01:22 +00:00
|
|
|
$wgOut->setPageTitle( wfMessage( 'viewsource-title', $this->getContextTitle()->getPrefixedText() ) );
|
|
|
|
|
$wgOut->addBacklinkSubtitle( $this->getContextTitle() );
|
2011-11-04 18:35:25 +00:00
|
|
|
$wgOut->addWikiText( $wgOut->formatPermissionsErrorMessage( $permErrors, 'edit' ) );
|
|
|
|
|
$wgOut->addHTML( "<hr />\n" );
|
|
|
|
|
|
|
|
|
|
# If the user made changes, preserve them when showing the markup
|
|
|
|
|
# (This happens when a user is blocked during edit, for instance)
|
|
|
|
|
if ( !$this->firsttime ) {
|
|
|
|
|
$content = $this->textbox1;
|
|
|
|
|
$wgOut->addWikiMsg( 'viewyourtext' );
|
|
|
|
|
} else {
|
|
|
|
|
$wgOut->addWikiMsg( 'viewsourcetext' );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->showTextbox( $content, 'wpTextbox1', array( 'readonly' ) );
|
|
|
|
|
|
|
|
|
|
$wgOut->addHTML( Html::rawElement( 'div', array( 'class' => 'templatesUsed' ),
|
|
|
|
|
Linker::formatTemplates( $this->getTemplates() ) ) );
|
|
|
|
|
|
|
|
|
|
if ( $this->mTitle->exists() ) {
|
|
|
|
|
$wgOut->returnToMain( null, $this->mTitle );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-02-21 09:32:59 +00:00
|
|
|
/**
|
|
|
|
|
* Show a read-only error
|
|
|
|
|
* Parameters are the same as OutputPage:readOnlyPage()
|
2008-02-26 06:10:24 +00:00
|
|
|
* Redirect to the article page if redlink=1
|
2011-11-04 18:35:25 +00:00
|
|
|
* @deprecated in 1.19; use displayPermissionsError() instead
|
2008-02-21 09:32:59 +00:00
|
|
|
*/
|
2008-05-23 10:34:11 +00:00
|
|
|
function readOnlyPage( $source = null, $protected = false, $reasons = array(), $action = null ) {
|
2011-12-13 05:19:05 +00:00
|
|
|
wfDeprecated( __METHOD__, '1.19' );
|
2012-02-16 16:09:08 +00:00
|
|
|
|
2008-02-21 09:32:59 +00:00
|
|
|
global $wgRequest, $wgOut;
|
2008-09-16 04:59:49 +00:00
|
|
|
if ( $wgRequest->getBool( 'redlink' ) ) {
|
2008-02-21 09:32:59 +00:00
|
|
|
// The edit page was reached via a red link.
|
2008-04-14 07:45:50 +00:00
|
|
|
// Redirect to the article page and let them click the edit tab if
|
2008-02-21 09:32:59 +00:00
|
|
|
// they really want a permission error.
|
|
|
|
|
$wgOut->redirect( $this->mTitle->getFullUrl() );
|
|
|
|
|
} else {
|
2008-05-23 10:34:11 +00:00
|
|
|
$wgOut->readOnlyPage( $source, $protected, $reasons, $action );
|
2008-02-21 09:32:59 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2005-06-30 06:51:43 +00:00
|
|
|
/**
|
2007-07-10 19:23:01 +00:00
|
|
|
* Should we show a preview when the edit form is first shown?
|
|
|
|
|
*
|
2005-06-30 06:51:43 +00:00
|
|
|
* @return bool
|
|
|
|
|
*/
|
2008-07-17 04:37:59 +00:00
|
|
|
protected function previewOnOpen() {
|
2009-12-08 17:17:24 +00:00
|
|
|
global $wgRequest, $wgUser, $wgPreviewOnOpenNamespaces;
|
2008-09-16 04:59:49 +00:00
|
|
|
if ( $wgRequest->getVal( 'preview' ) == 'yes' ) {
|
2007-07-10 19:23:01 +00:00
|
|
|
// Explicit override from request
|
|
|
|
|
return true;
|
2008-09-16 04:59:49 +00:00
|
|
|
} elseif ( $wgRequest->getVal( 'preview' ) == 'no' ) {
|
2007-07-10 19:23:01 +00:00
|
|
|
// Explicit override from request
|
|
|
|
|
return false;
|
2011-06-17 16:03:52 +00:00
|
|
|
} elseif ( $this->section == 'new' ) {
|
2007-07-10 19:23:01 +00:00
|
|
|
// Nothing *to* preview for new sections
|
|
|
|
|
return false;
|
2009-02-22 13:58:42 +00:00
|
|
|
} elseif ( ( $wgRequest->getVal( 'preload' ) !== null || $this->mTitle->exists() ) && $wgUser->getOption( 'previewonfirst' ) ) {
|
2007-07-10 19:23:01 +00:00
|
|
|
// Standard preference behaviour
|
|
|
|
|
return true;
|
2009-12-08 17:17:24 +00:00
|
|
|
} elseif ( !$this->mTitle->exists() &&
|
2012-02-16 16:09:08 +00:00
|
|
|
isset( $wgPreviewOnOpenNamespaces[$this->mTitle->getNamespace()] ) &&
|
2009-12-08 17:17:24 +00:00
|
|
|
$wgPreviewOnOpenNamespaces[$this->mTitle->getNamespace()] )
|
|
|
|
|
{
|
2007-07-10 19:23:01 +00:00
|
|
|
// Categories are special
|
|
|
|
|
return true;
|
|
|
|
|
} else {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2005-06-30 06:51:43 +00:00
|
|
|
}
|
2003-08-02 20:43:11 +00:00
|
|
|
|
2009-12-02 07:22:29 +00:00
|
|
|
/**
|
2011-11-12 13:47:17 +00:00
|
|
|
* Checks whether the user entered a skin name in uppercase,
|
|
|
|
|
* e.g. "User:Example/Monobook.css" instead of "monobook.css"
|
2010-07-20 15:50:25 +00:00
|
|
|
*
|
2009-12-02 07:22:29 +00:00
|
|
|
* @return bool
|
|
|
|
|
*/
|
2011-11-12 13:47:17 +00:00
|
|
|
protected function isWrongCaseCssJsPage() {
|
2012-02-16 16:09:08 +00:00
|
|
|
if ( $this->mTitle->isCssJsSubpage() ) {
|
2011-11-12 13:47:17 +00:00
|
|
|
$name = $this->mTitle->getSkinFromCssJsSubpage();
|
|
|
|
|
$skins = array_merge(
|
|
|
|
|
array_keys( Skin::getSkinNames() ),
|
|
|
|
|
array( 'common' )
|
|
|
|
|
);
|
|
|
|
|
return !in_array( $name, $skins )
|
|
|
|
|
&& in_array( strtolower( $name ), $skins );
|
|
|
|
|
} else {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2009-12-02 07:22:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2011-11-12 13:47:17 +00:00
|
|
|
* Does this EditPage class support section editing?
|
|
|
|
|
* This is used by EditPage subclasses to indicate their ui cannot handle section edits
|
2010-07-20 15:50:25 +00:00
|
|
|
*
|
2011-11-12 13:47:17 +00:00
|
|
|
* @return bool
|
2009-12-02 07:22:29 +00:00
|
|
|
*/
|
2011-11-12 13:47:17 +00:00
|
|
|
protected function isSectionEditSupported() {
|
|
|
|
|
return true;
|
2009-12-02 07:22:29 +00:00
|
|
|
}
|
|
|
|
|
|
2004-09-03 16:51:45 +00:00
|
|
|
/**
|
2011-12-20 04:15:21 +00:00
|
|
|
* This function collects the form data and uses it to populate various member variables.
|
2011-06-05 14:46:55 +00:00
|
|
|
* @param $request WebRequest
|
2004-09-03 16:51:45 +00:00
|
|
|
*/
|
2004-03-08 09:09:35 +00:00
|
|
|
function importFormData( &$request ) {
|
2006-04-12 02:49:14 +00:00
|
|
|
global $wgLang, $wgUser;
|
2009-10-25 15:02:33 +00:00
|
|
|
|
|
|
|
|
wfProfileIn( __METHOD__ );
|
2005-08-21 04:45:28 +00:00
|
|
|
|
2008-02-26 22:40:59 +00:00
|
|
|
# Section edit can come from either the form or a link
|
|
|
|
|
$this->section = $request->getVal( 'wpSection', $request->getVal( 'section' ) );
|
|
|
|
|
|
2008-09-16 04:59:49 +00:00
|
|
|
if ( $request->wasPosted() ) {
|
2005-02-15 00:24:49 +00:00
|
|
|
# These fields need to be checked for encoding.
|
|
|
|
|
# Also remove trailing whitespace, but don't remove _initial_
|
|
|
|
|
# whitespace from the text boxes. This may be significant formatting.
|
2005-07-29 10:08:41 +00:00
|
|
|
$this->textbox1 = $this->safeUnicodeInput( $request, 'wpTextbox1' );
|
2012-02-16 16:09:08 +00:00
|
|
|
if ( !$request->getCheck( 'wpTextbox2' ) ) {
|
2009-12-02 07:22:29 +00:00
|
|
|
// Skip this if wpTextbox2 has input, it indicates that we came
|
|
|
|
|
// from a conflict page with raw page text, not a custom form
|
|
|
|
|
// modified by subclasses
|
2012-02-16 16:09:08 +00:00
|
|
|
wfProfileIn( get_class( $this ) . "::importContentFormData" );
|
2009-12-02 07:22:29 +00:00
|
|
|
$textbox1 = $this->importContentFormData( $request );
|
2012-02-16 16:09:08 +00:00
|
|
|
if ( isset( $textbox1 ) )
|
2009-12-02 07:22:29 +00:00
|
|
|
$this->textbox1 = $textbox1;
|
2012-02-16 16:09:08 +00:00
|
|
|
wfProfileOut( get_class( $this ) . "::importContentFormData" );
|
2009-12-02 07:22:29 +00:00
|
|
|
}
|
2010-02-20 17:05:56 +00:00
|
|
|
|
2005-10-08 22:33:46 +00:00
|
|
|
# Truncate for whole multibyte characters. +5 bytes for ellipsis
|
2011-01-07 00:17:52 +00:00
|
|
|
$this->summary = $wgLang->truncate( $request->getText( 'wpSummary' ), 250 );
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2011-12-20 04:15:21 +00:00
|
|
|
# If the summary consists of a heading, e.g. '==Foobar==', extract the title from the
|
|
|
|
|
# header syntax, e.g. 'Foobar'. This is mainly an issue when we are using wpSummary for
|
|
|
|
|
# section titles.
|
|
|
|
|
$this->summary = preg_replace( '/^\s*=+\s*(.*?)\s*=+\s*$/', '$1', $this->summary );
|
2012-02-16 16:09:08 +00:00
|
|
|
|
2011-12-20 04:15:21 +00:00
|
|
|
# Treat sectiontitle the same way as summary.
|
|
|
|
|
# Note that wpSectionTitle is not yet a part of the actual edit form, as wpSummary is
|
|
|
|
|
# currently doing double duty as both edit summary and section title. Right now this
|
|
|
|
|
# is just to allow API edits to work around this limitation, but this should be
|
|
|
|
|
# incorporated into the actual edit form when EditPage is rewritten (Bugs 18654, 26312).
|
|
|
|
|
$this->sectiontitle = $wgLang->truncate( $request->getText( 'wpSectionTitle' ), 250 );
|
|
|
|
|
$this->sectiontitle = preg_replace( '/^\s*=+\s*(.*?)\s*=+\s*$/', '$1', $this->sectiontitle );
|
2005-08-02 13:35:19 +00:00
|
|
|
|
2005-02-15 00:24:49 +00:00
|
|
|
$this->edittime = $request->getVal( 'wpEdittime' );
|
2005-08-02 20:17:23 +00:00
|
|
|
$this->starttime = $request->getVal( 'wpStarttime' );
|
2005-10-26 10:59:44 +00:00
|
|
|
|
2005-10-26 20:37:10 +00:00
|
|
|
$this->scrolltop = $request->getIntOrNull( 'wpScrolltop' );
|
2005-10-26 10:59:44 +00:00
|
|
|
|
2011-12-20 04:15:21 +00:00
|
|
|
if ( $this->textbox1 === '' && $request->getVal( 'wpTextbox1' ) === null ) {
|
2011-02-14 03:10:08 +00:00
|
|
|
// wpTextbox1 field is missing, possibly due to being "too big"
|
|
|
|
|
// according to some filter rules such as Suhosin's setting for
|
|
|
|
|
// suhosin.request.max_value_length (d'oh)
|
|
|
|
|
$this->incompleteForm = true;
|
|
|
|
|
} else {
|
|
|
|
|
// edittime should be one of our last fields; if it's missing,
|
|
|
|
|
// the submission probably broke somewhere in the middle.
|
|
|
|
|
$this->incompleteForm = is_null( $this->edittime );
|
|
|
|
|
}
|
|
|
|
|
if ( $this->incompleteForm ) {
|
2005-02-15 00:24:49 +00:00
|
|
|
# If the form is incomplete, force to preview.
|
2009-10-25 15:02:33 +00:00
|
|
|
wfDebug( __METHOD__ . ": Form data appears to be incomplete\n" );
|
2005-10-22 20:52:30 +00:00
|
|
|
wfDebug( "POST DATA: " . var_export( $_POST, true ) . "\n" );
|
2009-01-13 18:05:43 +00:00
|
|
|
$this->preview = true;
|
2005-02-15 00:24:49 +00:00
|
|
|
} else {
|
2006-02-20 21:18:11 +00:00
|
|
|
/* Fallback for live preview */
|
|
|
|
|
$this->preview = $request->getCheck( 'wpPreview' ) || $request->getCheck( 'wpLivePreview' );
|
2005-10-31 22:36:35 +00:00
|
|
|
$this->diff = $request->getCheck( 'wpDiff' );
|
2006-01-07 13:31:29 +00:00
|
|
|
|
2006-06-07 08:28:43 +00:00
|
|
|
// Remember whether a save was requested, so we can indicate
|
|
|
|
|
// if we forced preview due to session failure.
|
|
|
|
|
$this->mTriedSave = !$this->preview;
|
2007-01-13 19:58:40 +00:00
|
|
|
|
2008-09-16 04:59:49 +00:00
|
|
|
if ( $this->tokenOk( $request ) ) {
|
2006-06-06 06:21:50 +00:00
|
|
|
# Some browsers will not report any submit button
|
|
|
|
|
# if the user hits enter in the comment box.
|
|
|
|
|
# The unmarked state will be assumed to be a save,
|
|
|
|
|
# if the form seems otherwise complete.
|
2009-10-25 15:02:33 +00:00
|
|
|
wfDebug( __METHOD__ . ": Passed token check.\n" );
|
2011-06-17 16:03:52 +00:00
|
|
|
} elseif ( $this->diff ) {
|
2006-10-25 08:31:44 +00:00
|
|
|
# Failed token check, but only requested "Show Changes".
|
2009-10-25 15:02:33 +00:00
|
|
|
wfDebug( __METHOD__ . ": Failed token check; Show Changes requested.\n" );
|
2006-06-06 06:21:50 +00:00
|
|
|
} else {
|
|
|
|
|
# Page might be a hack attempt posted from
|
|
|
|
|
# an external site. Preview instead of saving.
|
2009-10-25 15:02:33 +00:00
|
|
|
wfDebug( __METHOD__ . ": Failed token check; forcing preview\n" );
|
2006-06-06 06:21:50 +00:00
|
|
|
$this->preview = true;
|
2005-02-15 00:24:49 +00:00
|
|
|
}
|
|
|
|
|
}
|
2008-04-06 17:52:55 +00:00
|
|
|
$this->save = !$this->preview && !$this->diff;
|
2009-10-25 15:02:33 +00:00
|
|
|
if ( !preg_match( '/^\d{14}$/', $this->edittime ) ) {
|
2005-02-15 00:24:49 +00:00
|
|
|
$this->edittime = null;
|
|
|
|
|
}
|
2005-08-02 13:35:19 +00:00
|
|
|
|
2009-10-25 15:02:33 +00:00
|
|
|
if ( !preg_match( '/^\d{14}$/', $this->starttime ) ) {
|
2005-08-02 20:17:23 +00:00
|
|
|
$this->starttime = null;
|
|
|
|
|
}
|
2006-01-07 13:31:29 +00:00
|
|
|
|
2010-07-20 15:12:29 +00:00
|
|
|
$this->recreate = $request->getCheck( 'wpRecreate' );
|
2005-08-02 20:17:23 +00:00
|
|
|
|
2005-02-15 00:24:49 +00:00
|
|
|
$this->minoredit = $request->getCheck( 'wpMinoredit' );
|
|
|
|
|
$this->watchthis = $request->getCheck( 'wpWatchthis' );
|
2006-04-12 02:49:14 +00:00
|
|
|
|
|
|
|
|
# Don't force edit summaries when a user is editing their own user or talk page
|
2009-10-23 11:08:08 +00:00
|
|
|
if ( ( $this->mTitle->mNamespace == NS_USER || $this->mTitle->mNamespace == NS_USER_TALK ) &&
|
|
|
|
|
$this->mTitle->getText() == $wgUser->getName() )
|
2008-09-16 16:55:49 +00:00
|
|
|
{
|
2006-04-12 02:49:14 +00:00
|
|
|
$this->allowBlankSummary = true;
|
|
|
|
|
} else {
|
2012-02-16 16:09:08 +00:00
|
|
|
$this->allowBlankSummary = $request->getBool( 'wpIgnoreBlankSummary' ) || !$wgUser->getOption( 'forceeditsummary' );
|
2006-04-12 02:49:14 +00:00
|
|
|
}
|
2007-01-13 19:58:40 +00:00
|
|
|
|
2008-04-14 07:45:50 +00:00
|
|
|
$this->autoSumm = $request->getText( 'wpAutoSummary' );
|
2005-02-15 00:24:49 +00:00
|
|
|
} else {
|
|
|
|
|
# Not a posted form? Start with nothing.
|
2009-10-25 15:02:33 +00:00
|
|
|
wfDebug( __METHOD__ . ": Not a posted form.\n" );
|
2011-12-20 04:15:21 +00:00
|
|
|
$this->textbox1 = '';
|
|
|
|
|
$this->summary = '';
|
|
|
|
|
$this->sectiontitle = '';
|
|
|
|
|
$this->edittime = '';
|
|
|
|
|
$this->starttime = wfTimestampNow();
|
|
|
|
|
$this->edit = false;
|
|
|
|
|
$this->preview = false;
|
|
|
|
|
$this->save = false;
|
|
|
|
|
$this->diff = false;
|
|
|
|
|
$this->minoredit = false;
|
|
|
|
|
$this->watchthis = $request->getBool( 'watchthis', false ); // Watch may be overriden by request parameters
|
|
|
|
|
$this->recreate = false;
|
2012-02-16 16:09:08 +00:00
|
|
|
|
2011-12-20 04:15:21 +00:00
|
|
|
// When creating a new section, we can preload a section title by passing it as the
|
|
|
|
|
// preloadtitle parameter in the URL (Bug 13100)
|
2011-04-25 03:20:17 +00:00
|
|
|
if ( $this->section == 'new' && $request->getVal( 'preloadtitle' ) ) {
|
2011-12-20 04:15:21 +00:00
|
|
|
$this->sectiontitle = $request->getVal( 'preloadtitle' );
|
|
|
|
|
// Once wpSummary isn't being use for setting section titles, we should delete this.
|
2008-02-26 22:40:59 +00:00
|
|
|
$this->summary = $request->getVal( 'preloadtitle' );
|
|
|
|
|
}
|
2011-04-25 03:20:17 +00:00
|
|
|
elseif ( $this->section != 'new' && $request->getVal( 'summary' ) ) {
|
2009-01-13 02:10:17 +00:00
|
|
|
$this->summary = $request->getText( 'summary' );
|
2012-02-09 21:06:19 +00:00
|
|
|
if ( $this->summary !== '' ) {
|
|
|
|
|
$this->hasPresetSummary = true;
|
|
|
|
|
}
|
2009-01-13 02:10:17 +00:00
|
|
|
}
|
2009-10-23 11:08:08 +00:00
|
|
|
|
2009-01-13 02:10:17 +00:00
|
|
|
if ( $request->getVal( 'minor' ) ) {
|
|
|
|
|
$this->minoredit = true;
|
|
|
|
|
}
|
2005-02-15 00:24:49 +00:00
|
|
|
}
|
2004-03-18 06:56:14 +00:00
|
|
|
|
2009-12-08 17:17:24 +00:00
|
|
|
$this->bot = $request->getBool( 'bot', true );
|
|
|
|
|
$this->nosummary = $request->getBool( 'nosummary' );
|
|
|
|
|
|
2004-03-08 09:09:35 +00:00
|
|
|
$this->oldid = $request->getInt( 'oldid' );
|
2004-03-18 06:56:14 +00:00
|
|
|
|
2004-12-19 02:36:04 +00:00
|
|
|
$this->live = $request->getCheck( 'live' );
|
2010-01-11 11:47:50 +00:00
|
|
|
$this->editintro = $request->getText( 'editintro',
|
|
|
|
|
// Custom edit intro for new sections
|
2011-04-25 03:20:17 +00:00
|
|
|
$this->section === 'new' ? 'MediaWiki:addsection-editintro' : '' );
|
2006-01-07 13:31:29 +00:00
|
|
|
|
2009-07-07 15:55:56 +00:00
|
|
|
// Allow extensions to modify form data
|
2009-08-21 21:51:29 +00:00
|
|
|
wfRunHooks( 'EditPage::importFormData', array( $this, $request ) );
|
2011-02-10 16:04:19 +00:00
|
|
|
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
2004-03-08 09:09:35 +00:00
|
|
|
}
|
2004-03-18 06:56:14 +00:00
|
|
|
|
2009-12-02 07:22:29 +00:00
|
|
|
/**
|
|
|
|
|
* Subpage overridable method for extracting the page content data from the
|
|
|
|
|
* posted form to be placed in $this->textbox1, if using customized input
|
|
|
|
|
* this method should be overrided and return the page text that will be used
|
|
|
|
|
* for saving, preview parsing and so on...
|
2010-07-20 15:50:25 +00:00
|
|
|
*
|
2010-03-17 22:02:43 +00:00
|
|
|
* @param $request WebRequest
|
2009-12-02 07:22:29 +00:00
|
|
|
*/
|
|
|
|
|
protected function importContentFormData( &$request ) {
|
|
|
|
|
return; // Don't do anything, EditPage already extracted wpTextbox1
|
|
|
|
|
}
|
|
|
|
|
|
2005-02-04 06:19:37 +00:00
|
|
|
/**
|
2011-11-12 13:47:17 +00:00
|
|
|
* Initialise form fields in the object
|
|
|
|
|
* Called on the first invocation, e.g. when a user clicks an edit link
|
|
|
|
|
* @return bool -- if the requested section is valid
|
2005-02-04 06:19:37 +00:00
|
|
|
*/
|
2011-11-12 13:47:17 +00:00
|
|
|
function initialiseForm() {
|
2005-02-15 00:24:49 +00:00
|
|
|
global $wgUser;
|
2011-11-12 13:47:17 +00:00
|
|
|
$this->edittime = $this->mArticle->getTimestamp();
|
|
|
|
|
$this->textbox1 = $this->getContent( false );
|
|
|
|
|
// activate checkboxes if user wants them to be always active
|
|
|
|
|
# Sort out the "watch" checkbox
|
|
|
|
|
if ( $wgUser->getOption( 'watchdefault' ) ) {
|
|
|
|
|
# Watch all edits
|
|
|
|
|
$this->watchthis = true;
|
|
|
|
|
} elseif ( $wgUser->getOption( 'watchcreations' ) && !$this->mTitle->exists() ) {
|
|
|
|
|
# Watch creations
|
|
|
|
|
$this->watchthis = true;
|
|
|
|
|
} elseif ( $this->mTitle->userIsWatching() ) {
|
|
|
|
|
# Already watched
|
|
|
|
|
$this->watchthis = true;
|
2009-02-22 13:58:42 +00:00
|
|
|
}
|
2011-11-12 13:47:17 +00:00
|
|
|
if ( $wgUser->getOption( 'minordefault' ) && !$this->isNew ) {
|
|
|
|
|
$this->minoredit = true;
|
2007-11-27 18:04:24 +00:00
|
|
|
}
|
2011-11-12 13:47:17 +00:00
|
|
|
if ( $this->textbox1 === false ) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
wfProxyCheck();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Fetch initial editing page content.
|
|
|
|
|
*
|
|
|
|
|
* @param $def_text string
|
|
|
|
|
* @return mixed string on success, $def_text for invalid sections
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
|
|
|
|
function getContent( $def_text = '' ) {
|
|
|
|
|
global $wgOut, $wgRequest, $wgParser;
|
|
|
|
|
|
|
|
|
|
wfProfileIn( __METHOD__ );
|
|
|
|
|
|
2011-12-30 20:43:08 +00:00
|
|
|
$text = false;
|
2011-11-12 13:47:17 +00:00
|
|
|
|
|
|
|
|
// For message page not locally set, use the i18n message.
|
|
|
|
|
// For other non-existent articles, use preload text if any.
|
2011-12-30 21:34:19 +00:00
|
|
|
if ( !$this->mTitle->exists() || $this->section == 'new' ) {
|
|
|
|
|
if ( $this->mTitle->getNamespace() == NS_MEDIAWIKI && $this->section != 'new' ) {
|
2011-11-12 13:47:17 +00:00
|
|
|
# If this is a system message, get the default text.
|
|
|
|
|
$text = $this->mTitle->getDefaultMessageText();
|
2011-12-30 20:43:08 +00:00
|
|
|
}
|
|
|
|
|
if ( $text === false ) {
|
2011-11-12 13:47:17 +00:00
|
|
|
# If requested, preload some text.
|
2011-12-30 20:43:08 +00:00
|
|
|
$preload = $wgRequest->getVal( 'preload',
|
|
|
|
|
// Custom preload text for new sections
|
|
|
|
|
$this->section === 'new' ? 'MediaWiki:addsection-preload' : '' );
|
2011-11-12 13:47:17 +00:00
|
|
|
$text = $this->getPreloadedText( $preload );
|
|
|
|
|
}
|
|
|
|
|
// For existing pages, get text based on "undo" or section parameters.
|
|
|
|
|
} else {
|
2011-12-30 20:43:08 +00:00
|
|
|
if ( $this->section != '' ) {
|
|
|
|
|
// Get section edit text (returns $def_text for invalid sections)
|
|
|
|
|
$text = $wgParser->getSection( $this->getOriginalContent(), $this->section, $def_text );
|
|
|
|
|
} else {
|
|
|
|
|
$undoafter = $wgRequest->getInt( 'undoafter' );
|
|
|
|
|
$undo = $wgRequest->getInt( 'undo' );
|
|
|
|
|
|
|
|
|
|
if ( $undo > 0 && $undoafter > 0 ) {
|
|
|
|
|
if ( $undo < $undoafter ) {
|
|
|
|
|
# If they got undoafter and undo round the wrong way, switch them
|
|
|
|
|
list( $undo, $undoafter ) = array( $undoafter, $undo );
|
|
|
|
|
}
|
|
|
|
|
|
2011-11-12 13:47:17 +00:00
|
|
|
$undorev = Revision::newFromId( $undo );
|
|
|
|
|
$oldrev = Revision::newFromId( $undoafter );
|
|
|
|
|
|
2011-12-30 20:43:08 +00:00
|
|
|
# Sanity check, make sure it's the right page,
|
|
|
|
|
# the revisions exist and they were not deleted.
|
|
|
|
|
# Otherwise, $text will be left as-is.
|
|
|
|
|
if ( !is_null( $undorev ) && !is_null( $oldrev ) &&
|
|
|
|
|
$undorev->getPage() == $oldrev->getPage() &&
|
2012-03-11 22:05:54 +00:00
|
|
|
$undorev->getPage() == $this->mTitle->getArticleID() &&
|
2011-12-30 20:43:08 +00:00
|
|
|
!$undorev->isDeleted( Revision::DELETED_TEXT ) &&
|
|
|
|
|
!$oldrev->isDeleted( Revision::DELETED_TEXT ) ) {
|
|
|
|
|
|
|
|
|
|
$text = $this->mArticle->getUndoText( $undorev, $oldrev );
|
|
|
|
|
if ( $text === false ) {
|
|
|
|
|
# Warn the user that something went wrong
|
|
|
|
|
$undoMsg = 'failure';
|
|
|
|
|
} else {
|
|
|
|
|
# Inform the user of our success and set an automatic edit summary
|
|
|
|
|
$undoMsg = 'success';
|
|
|
|
|
|
|
|
|
|
# If we just undid one rev, use an autosummary
|
|
|
|
|
$firstrev = $oldrev->getNext();
|
2012-04-28 21:39:00 +00:00
|
|
|
if ( $firstrev && $firstrev->getId() == $undo ) {
|
2011-12-30 20:43:08 +00:00
|
|
|
$undoSummary = wfMsgForContent( 'undo-summary', $undo, $undorev->getUserText() );
|
|
|
|
|
if ( $this->summary === '' ) {
|
|
|
|
|
$this->summary = $undoSummary;
|
|
|
|
|
} else {
|
|
|
|
|
$this->summary = $undoSummary . wfMsgForContent( 'colon-separator' ) . $this->summary;
|
|
|
|
|
}
|
|
|
|
|
$this->undidRev = $undo;
|
2011-11-12 13:47:17 +00:00
|
|
|
}
|
2011-12-30 20:43:08 +00:00
|
|
|
$this->formtype = 'diff';
|
2011-11-12 13:47:17 +00:00
|
|
|
}
|
2011-12-30 20:43:08 +00:00
|
|
|
} else {
|
|
|
|
|
// Failed basic sanity checks.
|
|
|
|
|
// Older revisions may have been removed since the link
|
|
|
|
|
// was created, or we may simply have got bogus input.
|
|
|
|
|
$undoMsg = 'norev';
|
2011-11-12 13:47:17 +00:00
|
|
|
}
|
2011-12-30 20:43:08 +00:00
|
|
|
|
2012-03-02 19:35:06 +00:00
|
|
|
$class = ( $undoMsg == 'success' ? '' : 'error ' ) . "mw-undo-{$undoMsg}";
|
|
|
|
|
$this->editFormPageTop .= $wgOut->parse( "<div class=\"{$class}\">" .
|
2011-12-30 20:43:08 +00:00
|
|
|
wfMsgNoTrans( 'undo-' . $undoMsg ) . '</div>', true, /* interface */true );
|
2011-11-12 13:47:17 +00:00
|
|
|
}
|
2011-12-30 20:43:08 +00:00
|
|
|
|
|
|
|
|
if ( $text === false ) {
|
|
|
|
|
$text = $this->getOriginalContent();
|
2011-11-12 13:47:17 +00:00
|
|
|
}
|
2007-06-11 11:57:20 +00:00
|
|
|
}
|
|
|
|
|
}
|
2011-11-12 13:47:17 +00:00
|
|
|
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
|
|
|
|
return $text;
|
|
|
|
|
}
|
|
|
|
|
|
2011-12-30 20:43:08 +00:00
|
|
|
/**
|
|
|
|
|
* Get the content of the wanted revision, without section extraction.
|
|
|
|
|
*
|
|
|
|
|
* The result of this function can be used to compare user's input with
|
|
|
|
|
* section replaced in its context (using WikiPage::replaceSection())
|
|
|
|
|
* to the original text of the edit.
|
|
|
|
|
*
|
|
|
|
|
* This difers from Article::getContent() that when a missing revision is
|
|
|
|
|
* encountered the result will be an empty string and not the
|
|
|
|
|
* 'missing-article' message.
|
|
|
|
|
*
|
|
|
|
|
* @since 1.19
|
|
|
|
|
* @return string
|
|
|
|
|
*/
|
|
|
|
|
private function getOriginalContent() {
|
|
|
|
|
if ( $this->section == 'new' ) {
|
|
|
|
|
return $this->getCurrentText();
|
|
|
|
|
}
|
|
|
|
|
$revision = $this->mArticle->getRevisionFetched();
|
|
|
|
|
if ( $revision === null ) {
|
|
|
|
|
return '';
|
|
|
|
|
}
|
|
|
|
|
return $this->mArticle->getContent();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the actual text of the page. This is basically similar to
|
|
|
|
|
* WikiPage::getRawText() except that when the page doesn't exist an empty
|
|
|
|
|
* string is returned instead of false.
|
|
|
|
|
*
|
|
|
|
|
* @since 1.19
|
|
|
|
|
* @return string
|
|
|
|
|
*/
|
|
|
|
|
private function getCurrentText() {
|
|
|
|
|
$text = $this->mArticle->getRawText();
|
|
|
|
|
if ( $text === false ) {
|
|
|
|
|
return '';
|
|
|
|
|
} else {
|
|
|
|
|
return $text;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-11-12 13:47:17 +00:00
|
|
|
/**
|
|
|
|
|
* Use this method before edit() to preload some text into the edit box
|
|
|
|
|
*
|
|
|
|
|
* @param $text string
|
|
|
|
|
*/
|
|
|
|
|
public function setPreloadedText( $text ) {
|
|
|
|
|
$this->mPreloadText = $text;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the contents to be preloaded into the box, either set by
|
|
|
|
|
* an earlier setPreloadText() or by loading the given page.
|
|
|
|
|
*
|
|
|
|
|
* @param $preload String: representing the title to preload from.
|
|
|
|
|
* @return String
|
|
|
|
|
*/
|
|
|
|
|
protected function getPreloadedText( $preload ) {
|
|
|
|
|
global $wgUser, $wgParser;
|
2011-11-13 09:12:03 +00:00
|
|
|
|
2011-11-12 13:47:17 +00:00
|
|
|
if ( !empty( $this->mPreloadText ) ) {
|
|
|
|
|
return $this->mPreloadText;
|
2011-11-13 09:12:03 +00:00
|
|
|
}
|
2012-02-16 16:09:08 +00:00
|
|
|
|
2011-11-13 09:12:03 +00:00
|
|
|
if ( $preload === '' ) {
|
|
|
|
|
return '';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$title = Title::newFromText( $preload );
|
|
|
|
|
# Check for existence to avoid getting MediaWiki:Noarticletext
|
|
|
|
|
if ( $title === null || !$title->exists() || !$title->userCan( 'read' ) ) {
|
|
|
|
|
return '';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$page = WikiPage::factory( $title );
|
|
|
|
|
if ( $page->isRedirect() ) {
|
|
|
|
|
$title = $page->getRedirectTarget();
|
|
|
|
|
# Same as before
|
|
|
|
|
if ( $title === null || !$title->exists() || !$title->userCan( 'read' ) ) {
|
|
|
|
|
return '';
|
2011-11-12 13:47:17 +00:00
|
|
|
}
|
2011-11-13 09:12:03 +00:00
|
|
|
$page = WikiPage::factory( $title );
|
2008-09-16 04:59:49 +00:00
|
|
|
}
|
2011-11-13 09:12:03 +00:00
|
|
|
|
|
|
|
|
$parserOptions = ParserOptions::newFromUser( $wgUser );
|
|
|
|
|
return $wgParser->getPreloadText( $page->getRawText(), $title, $parserOptions );
|
2011-11-12 13:47:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Make sure the form isn't faking a user's credentials.
|
|
|
|
|
*
|
|
|
|
|
* @param $request WebRequest
|
|
|
|
|
* @return bool
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
|
|
|
|
function tokenOk( &$request ) {
|
|
|
|
|
global $wgUser;
|
|
|
|
|
$token = $request->getVal( 'wpEditToken' );
|
|
|
|
|
$this->mTokenOk = $wgUser->matchEditToken( $token );
|
|
|
|
|
$this->mTokenOkExceptSuffix = $wgUser->matchEditTokenNoSuffix( $token );
|
|
|
|
|
return $this->mTokenOk;
|
2007-06-11 11:57:20 +00:00
|
|
|
}
|
2007-11-27 18:04:24 +00:00
|
|
|
|
2011-11-12 13:47:17 +00:00
|
|
|
/**
|
|
|
|
|
* Attempt submission
|
|
|
|
|
* @return bool false if output is done, true if the rest of the form should be displayed
|
|
|
|
|
*/
|
|
|
|
|
function attemptSave() {
|
|
|
|
|
global $wgUser, $wgOut;
|
|
|
|
|
|
|
|
|
|
$resultDetails = false;
|
|
|
|
|
# Allow bots to exempt some edits from bot flagging
|
|
|
|
|
$bot = $wgUser->isAllowed( 'bot' ) && $this->bot;
|
|
|
|
|
$status = $this->internalAttemptSave( $resultDetails, $bot );
|
|
|
|
|
// FIXME: once the interface for internalAttemptSave() is made nicer, this should use the message in $status
|
|
|
|
|
if ( $status->value == self::AS_SUCCESS_UPDATE || $status->value == self::AS_SUCCESS_NEW_ARTICLE ) {
|
|
|
|
|
$this->didSave = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch ( $status->value ) {
|
|
|
|
|
case self::AS_HOOK_ERROR_EXPECTED:
|
|
|
|
|
case self::AS_CONTENT_TOO_BIG:
|
|
|
|
|
case self::AS_ARTICLE_WAS_DELETED:
|
|
|
|
|
case self::AS_CONFLICT_DETECTED:
|
|
|
|
|
case self::AS_SUMMARY_NEEDED:
|
|
|
|
|
case self::AS_TEXTBOX_EMPTY:
|
|
|
|
|
case self::AS_MAX_ARTICLE_SIZE_EXCEEDED:
|
|
|
|
|
case self::AS_END:
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
case self::AS_HOOK_ERROR:
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
case self::AS_SUCCESS_NEW_ARTICLE:
|
|
|
|
|
$query = $resultDetails['redirect'] ? 'redirect=no' : '';
|
2011-11-30 22:48:10 +00:00
|
|
|
$anchor = isset ( $resultDetails['sectionanchor'] ) ? $resultDetails['sectionanchor'] : '';
|
|
|
|
|
$wgOut->redirect( $this->mTitle->getFullURL( $query ) . $anchor );
|
2011-11-12 13:47:17 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
case self::AS_SUCCESS_UPDATE:
|
|
|
|
|
$extraQuery = '';
|
|
|
|
|
$sectionanchor = $resultDetails['sectionanchor'];
|
|
|
|
|
|
|
|
|
|
// Give extensions a chance to modify URL query on update
|
|
|
|
|
wfRunHooks( 'ArticleUpdateBeforeRedirect', array( $this->mArticle, &$sectionanchor, &$extraQuery ) );
|
|
|
|
|
|
|
|
|
|
if ( $resultDetails['redirect'] ) {
|
|
|
|
|
if ( $extraQuery == '' ) {
|
|
|
|
|
$extraQuery = 'redirect=no';
|
|
|
|
|
} else {
|
|
|
|
|
$extraQuery = 'redirect=no&' . $extraQuery;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$wgOut->redirect( $this->mTitle->getFullURL( $extraQuery ) . $sectionanchor );
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
case self::AS_BLANK_ARTICLE:
|
|
|
|
|
$wgOut->redirect( $this->getContextTitle()->getFullURL() );
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
case self::AS_SPAM_ERROR:
|
|
|
|
|
$this->spamPageWithContent( $resultDetails['spam'] );
|
2007-06-11 11:57:20 +00:00
|
|
|
return false;
|
2011-11-12 13:47:17 +00:00
|
|
|
|
|
|
|
|
case self::AS_BLOCKED_PAGE_FOR_USER:
|
2012-02-16 00:54:34 +00:00
|
|
|
throw new UserBlockedError( $wgUser->getBlock() );
|
2011-11-12 13:47:17 +00:00
|
|
|
|
|
|
|
|
case self::AS_IMAGE_REDIRECT_ANON:
|
|
|
|
|
case self::AS_IMAGE_REDIRECT_LOGGED:
|
|
|
|
|
throw new PermissionsError( 'upload' );
|
|
|
|
|
|
|
|
|
|
case self::AS_READ_ONLY_PAGE_ANON:
|
|
|
|
|
case self::AS_READ_ONLY_PAGE_LOGGED:
|
|
|
|
|
throw new PermissionsError( 'edit' );
|
|
|
|
|
|
|
|
|
|
case self::AS_READ_ONLY_PAGE:
|
|
|
|
|
throw new ReadOnlyError;
|
|
|
|
|
|
|
|
|
|
case self::AS_RATE_LIMITED:
|
|
|
|
|
throw new ThrottledError();
|
|
|
|
|
|
|
|
|
|
case self::AS_NO_CREATE_PERMISSION:
|
|
|
|
|
$permission = $this->mTitle->isTalkPage() ? 'createtalk' : 'createpage';
|
|
|
|
|
throw new PermissionsError( $permission );
|
|
|
|
|
|
2012-05-10 04:48:16 +00:00
|
|
|
default:
|
|
|
|
|
// We don't recognize $status->value. The only way that can happen
|
|
|
|
|
// is if an extension hook aborted from inside ArticleSave.
|
|
|
|
|
// Render the status object into $this->hookError
|
|
|
|
|
// FIXME this sucks, we should just use the Status object throughout
|
|
|
|
|
$this->hookError = '<div class="error">' . $status->getWikitext() .
|
|
|
|
|
'</div>';
|
|
|
|
|
return true;
|
2005-08-20 06:57:21 +00:00
|
|
|
}
|
2011-11-12 13:47:17 +00:00
|
|
|
return false;
|
2003-08-02 20:43:11 +00:00
|
|
|
}
|
|
|
|
|
|
2004-09-03 16:51:45 +00:00
|
|
|
/**
|
2007-10-30 05:42:19 +00:00
|
|
|
* Attempt submission (no UI)
|
2011-06-05 14:46:55 +00:00
|
|
|
*
|
|
|
|
|
* @param $result
|
|
|
|
|
* @param $bot bool
|
|
|
|
|
*
|
2011-08-26 16:26:17 +00:00
|
|
|
* @return Status object, possibly with a message, but always with one of the AS_* constants in $status->value,
|
|
|
|
|
*
|
|
|
|
|
* FIXME: This interface is TERRIBLE, but hard to get rid of due to various error display idiosyncrasies. There are
|
|
|
|
|
* also lots of cases where error metadata is set in the object and retrieved later instead of being returned, e.g.
|
|
|
|
|
* AS_CONTENT_TOO_BIG and AS_BLOCKED_PAGE_FOR_USER. All that stuff needs to be cleaned up some time.
|
2004-09-03 16:51:45 +00:00
|
|
|
*/
|
2008-01-10 13:33:23 +00:00
|
|
|
function internalAttemptSave( &$result, $bot = false ) {
|
2012-04-08 20:20:05 +00:00
|
|
|
global $wgUser, $wgRequest, $wgParser, $wgMaxArticleSize;
|
2011-09-04 21:40:17 +00:00
|
|
|
|
2011-08-26 16:26:17 +00:00
|
|
|
$status = Status::newGood();
|
2006-01-07 13:31:29 +00:00
|
|
|
|
2010-07-20 15:12:29 +00:00
|
|
|
wfProfileIn( __METHOD__ );
|
2009-10-25 15:02:33 +00:00
|
|
|
wfProfileIn( __METHOD__ . '-checks' );
|
2005-08-21 04:45:28 +00:00
|
|
|
|
2010-02-20 17:05:56 +00:00
|
|
|
if ( !wfRunHooks( 'EditPage::attemptSave', array( $this ) ) ) {
|
2009-01-13 20:28:54 +00:00
|
|
|
wfDebug( "Hook 'EditPage::attemptSave' aborted article saving\n" );
|
2011-08-26 16:26:17 +00:00
|
|
|
$status->fatal( 'hookaborted' );
|
|
|
|
|
$status->value = self::AS_HOOK_ERROR;
|
2011-02-10 15:53:54 +00:00
|
|
|
wfProfileOut( __METHOD__ . '-checks' );
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
2011-08-26 16:26:17 +00:00
|
|
|
return $status;
|
2006-12-01 21:18:40 +00:00
|
|
|
}
|
|
|
|
|
|
2008-01-20 07:05:59 +00:00
|
|
|
# Check image redirect
|
2008-12-01 17:14:30 +00:00
|
|
|
if ( $this->mTitle->getNamespace() == NS_FILE &&
|
2008-01-20 07:05:59 +00:00
|
|
|
Title::newFromRedirect( $this->textbox1 ) instanceof Title &&
|
|
|
|
|
!$wgUser->isAllowed( 'upload' ) ) {
|
2011-08-26 16:26:17 +00:00
|
|
|
$code = $wgUser->isAnon() ? self::AS_IMAGE_REDIRECT_ANON : self::AS_IMAGE_REDIRECT_LOGGED;
|
|
|
|
|
$status->setResult( false, $code );
|
2011-02-10 15:53:54 +00:00
|
|
|
|
|
|
|
|
wfProfileOut( __METHOD__ . '-checks' );
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
|
|
|
|
|
2011-08-26 16:26:17 +00:00
|
|
|
return $status;
|
2008-01-20 07:05:59 +00:00
|
|
|
}
|
|
|
|
|
|
2005-08-20 06:57:21 +00:00
|
|
|
# Check for spam
|
2009-02-27 20:50:25 +00:00
|
|
|
$match = self::matchSummarySpamRegex( $this->summary );
|
2008-09-16 04:59:49 +00:00
|
|
|
if ( $match === false ) {
|
2008-08-19 20:32:30 +00:00
|
|
|
$match = self::matchSpamRegex( $this->textbox1 );
|
|
|
|
|
}
|
2008-09-16 04:59:49 +00:00
|
|
|
if ( $match !== false ) {
|
2008-08-19 20:32:30 +00:00
|
|
|
$result['spam'] = $match;
|
2011-08-18 20:03:30 +00:00
|
|
|
$ip = $wgRequest->getIP();
|
2008-06-19 23:33:45 +00:00
|
|
|
$pdbk = $this->mTitle->getPrefixedDBkey();
|
2008-08-19 20:32:30 +00:00
|
|
|
$match = str_replace( "\n", '', $match );
|
2008-06-19 23:33:45 +00:00
|
|
|
wfDebugLog( 'SpamRegex', "$ip spam regex hit [[$pdbk]]: \"$match\"" );
|
2011-08-26 16:26:17 +00:00
|
|
|
$status->fatal( 'spamprotectionmatch', $match );
|
|
|
|
|
$status->value = self::AS_SPAM_ERROR;
|
2009-10-25 15:02:33 +00:00
|
|
|
wfProfileOut( __METHOD__ . '-checks' );
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
2011-08-26 16:26:17 +00:00
|
|
|
return $status;
|
2005-08-02 20:17:23 +00:00
|
|
|
}
|
2008-09-16 04:59:49 +00:00
|
|
|
if ( !wfRunHooks( 'EditFilter', array( $this, $this->textbox1, $this->section, &$this->hookError, $this->summary ) ) ) {
|
2006-05-06 21:41:53 +00:00
|
|
|
# Error messages etc. could be handled within the hook...
|
2011-08-26 16:26:17 +00:00
|
|
|
$status->fatal( 'hookaborted' );
|
|
|
|
|
$status->value = self::AS_HOOK_ERROR;
|
2009-10-25 15:02:33 +00:00
|
|
|
wfProfileOut( __METHOD__ . '-checks' );
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
2011-08-26 16:26:17 +00:00
|
|
|
return $status;
|
2008-09-16 04:59:49 +00:00
|
|
|
} elseif ( $this->hookError != '' ) {
|
2006-05-06 21:41:53 +00:00
|
|
|
# ...or the hook could be expecting us to produce an error
|
2011-08-26 16:26:17 +00:00
|
|
|
$status->fatal( 'hookaborted' );
|
|
|
|
|
$status->value = self::AS_HOOK_ERROR_EXPECTED;
|
2009-10-25 15:02:33 +00:00
|
|
|
wfProfileOut( __METHOD__ . '-checks' );
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
2011-08-26 16:26:17 +00:00
|
|
|
return $status;
|
2005-09-29 23:35:31 +00:00
|
|
|
}
|
2011-09-04 21:40:17 +00:00
|
|
|
|
2008-09-16 04:59:49 +00:00
|
|
|
if ( $wgUser->isBlockedFrom( $this->mTitle, false ) ) {
|
2011-10-09 12:30:13 +00:00
|
|
|
// Auto-block user's IP if the account was "hard" blocked
|
|
|
|
|
$wgUser->spreadAnyEditBlock();
|
2005-08-20 06:57:21 +00:00
|
|
|
# Check block state against master, thus 'false'.
|
2011-08-26 16:26:17 +00:00
|
|
|
$status->setResult( false, self::AS_BLOCKED_PAGE_FOR_USER );
|
2009-10-25 15:02:33 +00:00
|
|
|
wfProfileOut( __METHOD__ . '-checks' );
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
2011-08-26 16:26:17 +00:00
|
|
|
return $status;
|
2003-08-02 20:43:11 +00:00
|
|
|
}
|
2011-09-04 21:40:17 +00:00
|
|
|
|
2009-10-25 15:02:33 +00:00
|
|
|
$this->kblength = (int)( strlen( $this->textbox1 ) / 1024 );
|
2008-09-16 04:59:49 +00:00
|
|
|
if ( $this->kblength > $wgMaxArticleSize ) {
|
2006-02-22 00:55:25 +00:00
|
|
|
// Error will be displayed by showEditForm()
|
|
|
|
|
$this->tooBig = true;
|
2011-08-26 16:26:17 +00:00
|
|
|
$status->setResult( false, self::AS_CONTENT_TOO_BIG );
|
2009-10-25 15:02:33 +00:00
|
|
|
wfProfileOut( __METHOD__ . '-checks' );
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
2011-08-26 16:26:17 +00:00
|
|
|
return $status;
|
2006-02-22 00:55:25 +00:00
|
|
|
}
|
2007-01-13 19:58:40 +00:00
|
|
|
|
2009-10-25 15:02:33 +00:00
|
|
|
if ( !$wgUser->isAllowed( 'edit' ) ) {
|
2008-09-16 04:59:49 +00:00
|
|
|
if ( $wgUser->isAnon() ) {
|
2011-08-26 16:26:17 +00:00
|
|
|
$status->setResult( false, self::AS_READ_ONLY_PAGE_ANON );
|
2009-10-25 15:02:33 +00:00
|
|
|
wfProfileOut( __METHOD__ . '-checks' );
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
2011-08-26 16:26:17 +00:00
|
|
|
return $status;
|
2009-10-25 15:02:33 +00:00
|
|
|
} else {
|
2011-08-26 16:26:17 +00:00
|
|
|
$status->fatal( 'readonlytext' );
|
|
|
|
|
$status->value = self::AS_READ_ONLY_PAGE_LOGGED;
|
2009-10-25 15:02:33 +00:00
|
|
|
wfProfileOut( __METHOD__ . '-checks' );
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
2011-08-26 16:26:17 +00:00
|
|
|
return $status;
|
2005-05-27 11:03:37 +00:00
|
|
|
}
|
2005-08-20 06:57:21 +00:00
|
|
|
}
|
New edit toolbar for bold, italic, links, headlines, math, images, media,
sigs, horizontal lines (more can be added easily). Select text and click
to apply, or just click to see an example. Mouseover should show speedtips.
Also, access keys for the edit window (ALT+P=Preview, ALT+S=Save) -> Moz+IE
2004-01-11 04:11:43 +00:00
|
|
|
|
2008-09-16 04:59:49 +00:00
|
|
|
if ( wfReadOnly() ) {
|
2011-08-26 16:26:17 +00:00
|
|
|
$status->fatal( 'readonlytext' );
|
|
|
|
|
$status->value = self::AS_READ_ONLY_PAGE;
|
2009-10-25 15:02:33 +00:00
|
|
|
wfProfileOut( __METHOD__ . '-checks' );
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
2011-08-26 16:26:17 +00:00
|
|
|
return $status;
|
2005-08-20 06:57:21 +00:00
|
|
|
}
|
2008-09-16 04:59:49 +00:00
|
|
|
if ( $wgUser->pingLimiter() ) {
|
2011-08-26 16:26:17 +00:00
|
|
|
$status->fatal( 'actionthrottledtext' );
|
|
|
|
|
$status->value = self::AS_RATE_LIMITED;
|
2009-10-25 15:02:33 +00:00
|
|
|
wfProfileOut( __METHOD__ . '-checks' );
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
2011-08-26 16:26:17 +00:00
|
|
|
return $status;
|
2005-08-20 06:57:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# If the article has been deleted while editing, don't save it without
|
|
|
|
|
# confirmation
|
2008-09-16 04:59:49 +00:00
|
|
|
if ( $this->wasDeletedSinceLastEdit() && !$this->recreate ) {
|
2011-08-26 16:26:17 +00:00
|
|
|
$status->setResult( false, self::AS_ARTICLE_WAS_DELETED );
|
2009-10-25 15:02:33 +00:00
|
|
|
wfProfileOut( __METHOD__ . '-checks' );
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
2011-08-26 16:26:17 +00:00
|
|
|
return $status;
|
2005-08-20 06:57:21 +00:00
|
|
|
}
|
2006-01-07 13:31:29 +00:00
|
|
|
|
2009-10-25 15:02:33 +00:00
|
|
|
wfProfileOut( __METHOD__ . '-checks' );
|
2006-01-07 13:31:29 +00:00
|
|
|
|
2012-04-26 20:59:19 +00:00
|
|
|
// Use SELECT FOR UPDATE here to avoid transaction collision in
|
|
|
|
|
// WikiPage::updateRevisionOn() and ending in the self::AS_END case.
|
|
|
|
|
$this->mArticle->loadPageData( 'forupdate' );
|
|
|
|
|
$new = !$this->mArticle->exists();
|
2011-01-15 15:21:36 +00:00
|
|
|
|
|
|
|
|
if ( $new ) {
|
2005-12-05 05:37:10 +00:00
|
|
|
// Late check for create permission, just in case *PARANOIA*
|
2008-09-16 04:59:49 +00:00
|
|
|
if ( !$this->mTitle->userCan( 'create' ) ) {
|
2011-08-26 16:26:17 +00:00
|
|
|
$status->fatal( 'nocreatetext' );
|
|
|
|
|
$status->value = self::AS_NO_CREATE_PERMISSION;
|
2009-10-25 15:02:33 +00:00
|
|
|
wfDebug( __METHOD__ . ": no create permission\n" );
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
2011-08-26 16:26:17 +00:00
|
|
|
return $status;
|
2005-12-05 05:37:10 +00:00
|
|
|
}
|
2006-01-07 13:31:29 +00:00
|
|
|
|
2005-08-20 06:57:21 +00:00
|
|
|
# Don't save a new article if it's blank.
|
2010-01-06 19:59:42 +00:00
|
|
|
if ( $this->textbox1 == '' ) {
|
2011-08-26 16:26:17 +00:00
|
|
|
$status->setResult( false, self::AS_BLANK_ARTICLE );
|
2009-10-25 15:02:33 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2011-08-26 16:26:17 +00:00
|
|
|
return $status;
|
2005-09-04 17:41:44 +00:00
|
|
|
}
|
2005-08-23 08:15:14 +00:00
|
|
|
|
2007-11-12 07:30:40 +00:00
|
|
|
// Run post-section-merge edit filter
|
2009-08-21 21:51:29 +00:00
|
|
|
if ( !wfRunHooks( 'EditFilterMerged', array( $this, $this->textbox1, &$this->hookError, $this->summary ) ) ) {
|
2007-11-12 07:30:40 +00:00
|
|
|
# Error messages etc. could be handled within the hook...
|
2011-08-26 16:26:17 +00:00
|
|
|
$status->fatal( 'hookaborted' );
|
|
|
|
|
$status->value = self::AS_HOOK_ERROR;
|
2009-10-25 15:02:33 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2011-08-26 16:26:17 +00:00
|
|
|
return $status;
|
2009-08-30 05:55:47 +00:00
|
|
|
} elseif ( $this->hookError != '' ) {
|
|
|
|
|
# ...or the hook could be expecting us to produce an error
|
2011-08-26 16:26:17 +00:00
|
|
|
$status->fatal( 'hookaborted' );
|
|
|
|
|
$status->value = self::AS_HOOK_ERROR_EXPECTED;
|
2009-10-25 15:02:33 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2011-08-26 16:26:17 +00:00
|
|
|
return $status;
|
2007-11-12 07:30:40 +00:00
|
|
|
}
|
2009-10-23 11:08:08 +00:00
|
|
|
|
2011-01-15 15:21:36 +00:00
|
|
|
$text = $this->textbox1;
|
2011-12-20 12:36:34 +00:00
|
|
|
$result['sectionanchor'] = '';
|
2011-12-20 04:15:21 +00:00
|
|
|
if ( $this->section == 'new' ) {
|
2011-12-20 23:50:15 +00:00
|
|
|
if ( $this->sectiontitle !== '' ) {
|
2011-12-20 04:15:21 +00:00
|
|
|
// Insert the section title above the content.
|
|
|
|
|
$text = wfMsgForContent( 'newsectionheaderdefaultlevel', $this->sectiontitle ) . "\n\n" . $text;
|
2012-02-16 16:09:08 +00:00
|
|
|
|
2011-12-20 04:15:21 +00:00
|
|
|
// Jump to the new section
|
|
|
|
|
$result['sectionanchor'] = $wgParser->guessLegacySectionNameFromWikiText( $this->sectiontitle );
|
2012-02-16 16:09:08 +00:00
|
|
|
|
2011-12-20 04:15:21 +00:00
|
|
|
// If no edit summary was specified, create one automatically from the section
|
|
|
|
|
// title and have it link to the new section. Otherwise, respect the summary as
|
|
|
|
|
// passed.
|
2011-12-20 23:50:15 +00:00
|
|
|
if ( $this->summary === '' ) {
|
2011-12-20 04:15:21 +00:00
|
|
|
$cleanSectionTitle = $wgParser->stripSectionName( $this->sectiontitle );
|
|
|
|
|
$this->summary = wfMsgForContent( 'newsectionsummary', $cleanSectionTitle );
|
|
|
|
|
}
|
2011-12-20 23:50:15 +00:00
|
|
|
} elseif ( $this->summary !== '' ) {
|
2011-12-20 04:15:21 +00:00
|
|
|
// Insert the section title above the content.
|
|
|
|
|
$text = wfMsgForContent( 'newsectionheaderdefaultlevel', $this->summary ) . "\n\n" . $text;
|
2012-02-16 16:09:08 +00:00
|
|
|
|
2011-12-20 04:15:21 +00:00
|
|
|
// Jump to the new section
|
|
|
|
|
$result['sectionanchor'] = $wgParser->guessLegacySectionNameFromWikiText( $this->summary );
|
|
|
|
|
|
|
|
|
|
// Create a link to the new section from the edit summary.
|
|
|
|
|
$cleanSummary = $wgParser->stripSectionName( $this->summary );
|
|
|
|
|
$this->summary = wfMsgForContent( 'newsectionsummary', $cleanSummary );
|
|
|
|
|
}
|
2011-01-15 15:21:36 +00:00
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2011-08-26 16:26:17 +00:00
|
|
|
$status->value = self::AS_SUCCESS_NEW_ARTICLE;
|
2006-01-07 13:31:29 +00:00
|
|
|
|
2011-01-15 15:21:36 +00:00
|
|
|
} else {
|
2004-03-18 15:02:56 +00:00
|
|
|
|
2011-01-15 15:21:36 +00:00
|
|
|
# Article exists. Check for edit conflict.
|
2011-12-30 16:12:46 +00:00
|
|
|
$timestamp = $this->mArticle->getTimestamp();
|
|
|
|
|
wfDebug( "timestamp: {$timestamp}, edittime: {$this->edittime}\n" );
|
2007-03-11 03:59:37 +00:00
|
|
|
|
2011-12-30 16:12:46 +00:00
|
|
|
if ( $timestamp != $this->edittime ) {
|
2011-01-15 15:21:36 +00:00
|
|
|
$this->isConflict = true;
|
2011-04-25 03:20:17 +00:00
|
|
|
if ( $this->section == 'new' ) {
|
2011-01-15 15:21:36 +00:00
|
|
|
if ( $this->mArticle->getUserText() == $wgUser->getName() &&
|
|
|
|
|
$this->mArticle->getComment() == $this->summary ) {
|
|
|
|
|
// Probably a duplicate submission of a new comment.
|
|
|
|
|
// This can happen when squid resends a request after
|
|
|
|
|
// a timeout but the first one actually went through.
|
|
|
|
|
wfDebug( __METHOD__ . ": duplicate new section submission; trigger edit conflict!\n" );
|
|
|
|
|
} else {
|
|
|
|
|
// New comment; suppress conflict.
|
|
|
|
|
$this->isConflict = false;
|
2012-02-16 16:09:08 +00:00
|
|
|
wfDebug( __METHOD__ . ": conflict suppressed; new section\n" );
|
2011-01-15 15:21:36 +00:00
|
|
|
}
|
2011-08-06 20:39:15 +00:00
|
|
|
} elseif ( $this->section == '' && $this->userWasLastToEdit( $wgUser->getId(), $this->edittime ) ) {
|
|
|
|
|
# Suppress edit conflict with self, except for section edits where merging is required.
|
|
|
|
|
wfDebug( __METHOD__ . ": Suppressing edit conflict, same user.\n" );
|
|
|
|
|
$this->isConflict = false;
|
2005-12-11 12:07:18 +00:00
|
|
|
}
|
|
|
|
|
}
|
2012-02-16 16:09:08 +00:00
|
|
|
|
2011-12-20 23:50:15 +00:00
|
|
|
// If sectiontitle is set, use it, otherwise use the summary as the section title (for
|
|
|
|
|
// backwards compatibility with old forms/bots).
|
|
|
|
|
if ( $this->sectiontitle !== '' ) {
|
|
|
|
|
$sectionTitle = $this->sectiontitle;
|
|
|
|
|
} else {
|
|
|
|
|
$sectionTitle = $this->summary;
|
|
|
|
|
}
|
2012-02-16 16:09:08 +00:00
|
|
|
|
2011-01-15 15:21:36 +00:00
|
|
|
if ( $this->isConflict ) {
|
2011-12-30 16:12:46 +00:00
|
|
|
wfDebug( __METHOD__ . ": conflict! getting section '$this->section' for time '$this->edittime' (article time '{$timestamp}')\n" );
|
2011-12-20 23:50:15 +00:00
|
|
|
$text = $this->mArticle->replaceSection( $this->section, $this->textbox1, $sectionTitle, $this->edittime );
|
2011-01-15 15:21:36 +00:00
|
|
|
} else {
|
|
|
|
|
wfDebug( __METHOD__ . ": getting section '$this->section'\n" );
|
2011-12-20 23:50:15 +00:00
|
|
|
$text = $this->mArticle->replaceSection( $this->section, $this->textbox1, $sectionTitle );
|
2011-01-15 15:21:36 +00:00
|
|
|
}
|
|
|
|
|
if ( is_null( $text ) ) {
|
|
|
|
|
wfDebug( __METHOD__ . ": activating conflict; section replace failed.\n" );
|
|
|
|
|
$this->isConflict = true;
|
|
|
|
|
$text = $this->textbox1; // do not try to merge here!
|
2011-06-17 16:03:52 +00:00
|
|
|
} elseif ( $this->isConflict ) {
|
2011-01-15 15:21:36 +00:00
|
|
|
# Attempt merge
|
|
|
|
|
if ( $this->mergeChangesInto( $text ) ) {
|
|
|
|
|
// Successful merge! Maybe we should tell the user the good news?
|
|
|
|
|
$this->isConflict = false;
|
|
|
|
|
wfDebug( __METHOD__ . ": Suppressing edit conflict, successful merge.\n" );
|
|
|
|
|
} else {
|
|
|
|
|
$this->section = '';
|
|
|
|
|
$this->textbox1 = $text;
|
|
|
|
|
wfDebug( __METHOD__ . ": Keeping edit conflict, failed merge.\n" );
|
|
|
|
|
}
|
|
|
|
|
}
|
2007-11-12 07:30:40 +00:00
|
|
|
|
2011-01-15 15:21:36 +00:00
|
|
|
if ( $this->isConflict ) {
|
2011-08-26 16:26:17 +00:00
|
|
|
$status->setResult( false, self::AS_CONFLICT_DETECTED );
|
2009-10-25 15:02:33 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2011-08-26 16:26:17 +00:00
|
|
|
return $status;
|
2006-11-02 13:33:38 +00:00
|
|
|
}
|
|
|
|
|
|
2011-01-15 15:21:36 +00:00
|
|
|
// Run post-section-merge edit filter
|
|
|
|
|
if ( !wfRunHooks( 'EditFilterMerged', array( $this, $text, &$this->hookError, $this->summary ) ) ) {
|
|
|
|
|
# Error messages etc. could be handled within the hook...
|
2011-08-26 16:26:17 +00:00
|
|
|
$status->fatal( 'hookaborted' );
|
|
|
|
|
$status->value = self::AS_HOOK_ERROR;
|
2011-01-15 15:21:36 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2011-08-26 16:26:17 +00:00
|
|
|
return $status;
|
2011-01-15 15:21:36 +00:00
|
|
|
} elseif ( $this->hookError != '' ) {
|
|
|
|
|
# ...or the hook could be expecting us to produce an error
|
2011-08-26 16:26:17 +00:00
|
|
|
$status->fatal( 'hookaborted' );
|
|
|
|
|
$status->value = self::AS_HOOK_ERROR_EXPECTED;
|
2009-10-25 15:02:33 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2011-08-26 16:26:17 +00:00
|
|
|
return $status;
|
2006-03-25 02:48:31 +00:00
|
|
|
}
|
2006-03-25 00:57:14 +00:00
|
|
|
|
2011-01-15 15:21:36 +00:00
|
|
|
# Handle the user preference to force summaries here, but not for null edits
|
2011-08-06 20:39:15 +00:00
|
|
|
if ( $this->section != 'new' && !$this->allowBlankSummary
|
2011-12-30 20:43:08 +00:00
|
|
|
&& $this->getOriginalContent() != $text
|
2011-01-15 15:21:36 +00:00
|
|
|
&& !Title::newFromRedirect( $text ) ) # check if it's not a redirect
|
|
|
|
|
{
|
|
|
|
|
if ( md5( $this->summary ) == $this->autoSumm ) {
|
|
|
|
|
$this->missingSummary = true;
|
2011-09-17 15:50:06 +00:00
|
|
|
$status->fatal( 'missingsummary' );
|
|
|
|
|
$status->value = self::AS_SUMMARY_NEEDED;
|
2011-01-15 15:21:36 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2011-09-17 15:50:06 +00:00
|
|
|
return $status;
|
2011-01-15 15:21:36 +00:00
|
|
|
}
|
2006-03-01 23:00:07 +00:00
|
|
|
}
|
2011-01-15 15:21:36 +00:00
|
|
|
|
|
|
|
|
# And a similar thing for new sections
|
2011-06-17 16:03:52 +00:00
|
|
|
if ( $this->section == 'new' && !$this->allowBlankSummary ) {
|
2011-01-15 15:21:36 +00:00
|
|
|
if ( trim( $this->summary ) == '' ) {
|
|
|
|
|
$this->missingSummary = true;
|
2011-08-26 16:26:17 +00:00
|
|
|
$status->fatal( 'missingsummary' ); // or 'missingcommentheader' if $section == 'new'. Blegh
|
|
|
|
|
$status->value = self::AS_SUMMARY_NEEDED;
|
2011-01-15 15:21:36 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2011-08-26 16:26:17 +00:00
|
|
|
return $status;
|
2011-01-15 15:21:36 +00:00
|
|
|
}
|
2005-08-20 06:57:21 +00:00
|
|
|
}
|
2011-01-15 15:21:36 +00:00
|
|
|
|
|
|
|
|
# All's well
|
|
|
|
|
wfProfileIn( __METHOD__ . '-sectionanchor' );
|
|
|
|
|
$sectionanchor = '';
|
2011-06-17 16:03:52 +00:00
|
|
|
if ( $this->section == 'new' ) {
|
2011-01-15 15:21:36 +00:00
|
|
|
if ( $this->textbox1 == '' ) {
|
|
|
|
|
$this->missingComment = true;
|
2011-08-26 16:26:17 +00:00
|
|
|
$status->fatal( 'missingcommenttext' );
|
|
|
|
|
$status->value = self::AS_TEXTBOX_EMPTY;
|
2011-01-15 15:21:36 +00:00
|
|
|
wfProfileOut( __METHOD__ . '-sectionanchor' );
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
2011-08-26 16:26:17 +00:00
|
|
|
return $status;
|
2011-01-15 15:21:36 +00:00
|
|
|
}
|
2011-12-20 23:50:15 +00:00
|
|
|
if ( $this->sectiontitle !== '' ) {
|
|
|
|
|
$sectionanchor = $wgParser->guessLegacySectionNameFromWikiText( $this->sectiontitle );
|
|
|
|
|
// If no edit summary was specified, create one automatically from the section
|
|
|
|
|
// title and have it link to the new section. Otherwise, respect the summary as
|
|
|
|
|
// passed.
|
|
|
|
|
if ( $this->summary === '' ) {
|
|
|
|
|
$cleanSectionTitle = $wgParser->stripSectionName( $this->sectiontitle );
|
|
|
|
|
$this->summary = wfMsgForContent( 'newsectionsummary', $cleanSectionTitle );
|
|
|
|
|
}
|
|
|
|
|
} elseif ( $this->summary !== '' ) {
|
2011-01-15 15:21:36 +00:00
|
|
|
$sectionanchor = $wgParser->guessLegacySectionNameFromWikiText( $this->summary );
|
|
|
|
|
# This is a new section, so create a link to the new section
|
|
|
|
|
# in the revision summary.
|
|
|
|
|
$cleanSummary = $wgParser->stripSectionName( $this->summary );
|
|
|
|
|
$this->summary = wfMsgForContent( 'newsectionsummary', $cleanSummary );
|
|
|
|
|
}
|
|
|
|
|
} elseif ( $this->section != '' ) {
|
|
|
|
|
# Try to get a section anchor from the section source, redirect to edited section if header found
|
|
|
|
|
# XXX: might be better to integrate this into Article::replaceSection
|
|
|
|
|
# for duplicate heading checking and maybe parsing
|
|
|
|
|
$hasmatch = preg_match( "/^ *([=]{1,6})(.*?)(\\1) *\\n/i", $this->textbox1, $matches );
|
|
|
|
|
# we can't deal with anchors, includes, html etc in the header for now,
|
|
|
|
|
# headline would need to be parsed to improve this
|
2011-05-28 14:52:55 +00:00
|
|
|
if ( $hasmatch && strlen( $matches[2] ) > 0 ) {
|
2011-01-15 15:21:36 +00:00
|
|
|
$sectionanchor = $wgParser->guessLegacySectionNameFromWikiText( $matches[2] );
|
|
|
|
|
}
|
2005-08-20 06:57:21 +00:00
|
|
|
}
|
2011-01-15 15:21:36 +00:00
|
|
|
$result['sectionanchor'] = $sectionanchor;
|
|
|
|
|
wfProfileOut( __METHOD__ . '-sectionanchor' );
|
2005-08-20 06:57:21 +00:00
|
|
|
|
2011-01-15 15:21:36 +00:00
|
|
|
// Save errors may fall down to the edit form, but we've now
|
|
|
|
|
// merged the section into full text. Clear the section field
|
|
|
|
|
// so that later submission of conflict forms won't try to
|
|
|
|
|
// replace that into a duplicated mess.
|
|
|
|
|
$this->textbox1 = $text;
|
|
|
|
|
$this->section = '';
|
|
|
|
|
|
2011-08-26 16:26:17 +00:00
|
|
|
$status->value = self::AS_SUCCESS_UPDATE;
|
2011-01-15 15:21:36 +00:00
|
|
|
}
|
2005-08-20 06:57:21 +00:00
|
|
|
|
2006-02-22 00:55:25 +00:00
|
|
|
// Check for length errors again now that the section is merged in
|
2009-10-25 15:02:33 +00:00
|
|
|
$this->kblength = (int)( strlen( $text ) / 1024 );
|
2008-09-16 04:59:49 +00:00
|
|
|
if ( $this->kblength > $wgMaxArticleSize ) {
|
2006-02-22 00:55:25 +00:00
|
|
|
$this->tooBig = true;
|
2011-08-26 16:26:17 +00:00
|
|
|
$status->setResult( false, self::AS_MAX_ARTICLE_SIZE_EXCEEDED );
|
2009-10-25 15:02:33 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2011-08-26 16:26:17 +00:00
|
|
|
return $status;
|
2006-02-22 00:55:25 +00:00
|
|
|
}
|
|
|
|
|
|
2011-01-15 15:21:36 +00:00
|
|
|
$flags = EDIT_DEFER_UPDATES | EDIT_AUTOSUMMARY |
|
|
|
|
|
( $new ? EDIT_NEW : EDIT_UPDATE ) |
|
2011-04-23 18:58:03 +00:00
|
|
|
( ( $this->minoredit && !$this->isNew ) ? EDIT_MINOR : 0 ) |
|
2011-01-15 15:21:36 +00:00
|
|
|
( $bot ? EDIT_FORCE_BOT : 0 );
|
|
|
|
|
|
2011-08-26 16:26:17 +00:00
|
|
|
$doEditStatus = $this->mArticle->doEdit( $text, $this->summary, $flags );
|
2011-01-15 15:21:36 +00:00
|
|
|
|
2011-08-26 16:26:17 +00:00
|
|
|
if ( $doEditStatus->isOK() ) {
|
2011-01-15 15:21:36 +00:00
|
|
|
$result['redirect'] = Title::newFromRedirect( $text ) !== null;
|
|
|
|
|
$this->commitWatch();
|
2009-10-25 15:02:33 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2011-08-26 16:26:17 +00:00
|
|
|
return $status;
|
2005-08-23 08:15:14 +00:00
|
|
|
} else {
|
2012-05-10 04:48:16 +00:00
|
|
|
// Failure from doEdit()
|
|
|
|
|
// Show the edit conflict page for certain recognized errors from doEdit(),
|
|
|
|
|
// but don't show it for errors from extension hooks
|
|
|
|
|
$errors = $doEditStatus->getErrorsArray();
|
|
|
|
|
if ( in_array( $errors[0][0], array( 'edit-gone-missing', 'edit-conflict',
|
|
|
|
|
'edit-already-exists' ) ) )
|
|
|
|
|
{
|
|
|
|
|
$this->isConflict = true;
|
|
|
|
|
// Destroys data doEdit() put in $status->value but who cares
|
|
|
|
|
$doEditStatus->value = self::AS_END;
|
|
|
|
|
}
|
2011-01-15 15:21:36 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2011-08-26 16:26:17 +00:00
|
|
|
return $doEditStatus;
|
2011-01-15 15:21:36 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Commit the change of watch status
|
|
|
|
|
*/
|
|
|
|
|
protected function commitWatch() {
|
WatchAction requires token (BREAKING CHANGE)
* (bug 27655) Require token for watching/unwatching pages
* Previously done for API (bug 29070) in r88522
* As with markpatrolled, the tokens are not compatible and made that way on purpose. The API requires the POST method and uses a universal token per-session. Since the front-end is all GET based (also per convention like in markpatrolled and rollback) they are stronger salted (title / action specific)
* ajax.watch used the API already and was switched in r88554.
* The actual watching/unwatching code was moved from WatchAction->onView to WatchAction::doWatch. This was done to allow the API to do the action without needing to generate a token like the front-end needs (or having to duplicate code). It is now similar to RecentChange::markPatrolled (in that it also a "central" function that does not care about tokens, it's called after the token-handling)
* JavaScript / Gadgets that utilize action=watch in their scripts:
** Effects should be minimal as they should be using the API (see r88522 and wikitech-l)
** If they use index.php and scrap the link from the page, they can continue to do so.
* There are links to the watch action all over the place. I've tried to catch most of them, but there may be some I miss. Migration in most cases is just a matter of adding an array item to the $query for:
'token' => WatchAction::getWatchToken( $title, $user [, $action] )
or changing:
Action::factory( 'watch', $article )->execute();
to:
WatchAction::doWatch( $title, $user );
While replacing the usages in some cases an instance of Article() no longer had to be created, in others $wgUser had to be retrieved from global (which was implied before but needs to be given directly now)
Other notes:
* Article->unwatch() and Article->watch(), which were deprecated as of 1.18 and are no longer used in core, may be broken in scenarios where the Request does not have a 'token' but is making a call to $article->watch()
* Some extensions need to be fixed, I'm currently running a grep search and will fix them a.s.a.p
[1] http://www.mediawiki.org/wiki/ResourceLoader/Default_modules?mw.user#tokens
2011-06-06 00:09:03 +00:00
|
|
|
global $wgUser;
|
2011-01-15 15:21:36 +00:00
|
|
|
if ( $this->watchthis xor $this->mTitle->userIsWatching() ) {
|
|
|
|
|
$dbw = wfGetDB( DB_MASTER );
|
2012-02-20 21:36:54 +00:00
|
|
|
$dbw->begin( __METHOD__ );
|
2011-01-15 15:21:36 +00:00
|
|
|
if ( $this->watchthis ) {
|
WatchAction requires token (BREAKING CHANGE)
* (bug 27655) Require token for watching/unwatching pages
* Previously done for API (bug 29070) in r88522
* As with markpatrolled, the tokens are not compatible and made that way on purpose. The API requires the POST method and uses a universal token per-session. Since the front-end is all GET based (also per convention like in markpatrolled and rollback) they are stronger salted (title / action specific)
* ajax.watch used the API already and was switched in r88554.
* The actual watching/unwatching code was moved from WatchAction->onView to WatchAction::doWatch. This was done to allow the API to do the action without needing to generate a token like the front-end needs (or having to duplicate code). It is now similar to RecentChange::markPatrolled (in that it also a "central" function that does not care about tokens, it's called after the token-handling)
* JavaScript / Gadgets that utilize action=watch in their scripts:
** Effects should be minimal as they should be using the API (see r88522 and wikitech-l)
** If they use index.php and scrap the link from the page, they can continue to do so.
* There are links to the watch action all over the place. I've tried to catch most of them, but there may be some I miss. Migration in most cases is just a matter of adding an array item to the $query for:
'token' => WatchAction::getWatchToken( $title, $user [, $action] )
or changing:
Action::factory( 'watch', $article )->execute();
to:
WatchAction::doWatch( $title, $user );
While replacing the usages in some cases an instance of Article() no longer had to be created, in others $wgUser had to be retrieved from global (which was implied before but needs to be given directly now)
Other notes:
* Article->unwatch() and Article->watch(), which were deprecated as of 1.18 and are no longer used in core, may be broken in scenarios where the Request does not have a 'token' but is making a call to $article->watch()
* Some extensions need to be fixed, I'm currently running a grep search and will fix them a.s.a.p
[1] http://www.mediawiki.org/wiki/ResourceLoader/Default_modules?mw.user#tokens
2011-06-06 00:09:03 +00:00
|
|
|
WatchAction::doWatch( $this->mTitle, $wgUser );
|
2011-01-15 15:21:36 +00:00
|
|
|
} else {
|
WatchAction requires token (BREAKING CHANGE)
* (bug 27655) Require token for watching/unwatching pages
* Previously done for API (bug 29070) in r88522
* As with markpatrolled, the tokens are not compatible and made that way on purpose. The API requires the POST method and uses a universal token per-session. Since the front-end is all GET based (also per convention like in markpatrolled and rollback) they are stronger salted (title / action specific)
* ajax.watch used the API already and was switched in r88554.
* The actual watching/unwatching code was moved from WatchAction->onView to WatchAction::doWatch. This was done to allow the API to do the action without needing to generate a token like the front-end needs (or having to duplicate code). It is now similar to RecentChange::markPatrolled (in that it also a "central" function that does not care about tokens, it's called after the token-handling)
* JavaScript / Gadgets that utilize action=watch in their scripts:
** Effects should be minimal as they should be using the API (see r88522 and wikitech-l)
** If they use index.php and scrap the link from the page, they can continue to do so.
* There are links to the watch action all over the place. I've tried to catch most of them, but there may be some I miss. Migration in most cases is just a matter of adding an array item to the $query for:
'token' => WatchAction::getWatchToken( $title, $user [, $action] )
or changing:
Action::factory( 'watch', $article )->execute();
to:
WatchAction::doWatch( $title, $user );
While replacing the usages in some cases an instance of Article() no longer had to be created, in others $wgUser had to be retrieved from global (which was implied before but needs to be given directly now)
Other notes:
* Article->unwatch() and Article->watch(), which were deprecated as of 1.18 and are no longer used in core, may be broken in scenarios where the Request does not have a 'token' but is making a call to $article->watch()
* Some extensions need to be fixed, I'm currently running a grep search and will fix them a.s.a.p
[1] http://www.mediawiki.org/wiki/ResourceLoader/Default_modules?mw.user#tokens
2011-06-06 00:09:03 +00:00
|
|
|
WatchAction::doUnwatch( $this->mTitle, $wgUser );
|
2011-01-15 15:21:36 +00:00
|
|
|
}
|
2012-02-20 21:36:54 +00:00
|
|
|
$dbw->commit( __METHOD__ );
|
2003-08-02 20:43:11 +00:00
|
|
|
}
|
2005-08-20 06:57:21 +00:00
|
|
|
}
|
2009-10-23 11:08:08 +00:00
|
|
|
|
2008-10-13 14:48:17 +00:00
|
|
|
/**
|
|
|
|
|
* Check if no edits were made by other users since
|
|
|
|
|
* the time a user started editing the page. Limit to
|
2008-10-15 14:23:23 +00:00
|
|
|
* 50 revisions for the sake of performance.
|
2011-06-05 14:46:55 +00:00
|
|
|
*
|
|
|
|
|
* @param $id int
|
|
|
|
|
* @param $edittime string
|
|
|
|
|
*
|
|
|
|
|
* @return bool
|
2008-10-13 14:48:17 +00:00
|
|
|
*/
|
|
|
|
|
protected function userWasLastToEdit( $id, $edittime ) {
|
2012-02-16 16:09:08 +00:00
|
|
|
if ( !$id ) return false;
|
2008-10-13 14:48:17 +00:00
|
|
|
$dbw = wfGetDB( DB_MASTER );
|
|
|
|
|
$res = $dbw->select( 'revision',
|
|
|
|
|
'rev_user',
|
2009-10-23 11:08:08 +00:00
|
|
|
array(
|
2012-03-11 22:05:54 +00:00
|
|
|
'rev_page' => $this->mTitle->getArticleID(),
|
2012-02-16 16:09:08 +00:00
|
|
|
'rev_timestamp > ' . $dbw->addQuotes( $dbw->timestamp( $edittime ) )
|
2008-10-13 19:08:27 +00:00
|
|
|
),
|
2008-10-13 14:48:17 +00:00
|
|
|
__METHOD__,
|
2008-10-15 14:23:23 +00:00
|
|
|
array( 'ORDER BY' => 'rev_timestamp ASC', 'LIMIT' => 50 ) );
|
2010-10-13 23:11:40 +00:00
|
|
|
foreach ( $res as $row ) {
|
2012-02-16 16:09:08 +00:00
|
|
|
if ( $row->rev_user != $id ) {
|
2008-10-13 14:48:17 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
here it is ... the upload-api, script-server, js2 (javascript phase2) branch merge 1st attempt.
Here is a short overview of changes and associated default configuration variables (most everything is off by default) also see ~soon to be updated~: http://www.mediawiki.org/wiki/Media_Projects_Overview
= Upload Improvements =
==Upload API ==
* Based on the early work of Bryan Tong and others it adds the upload option to the api.
* We rewrite Special:Upload page to include use the new refactoring
* Added in token checks in both the SpecialUpload.php page so avoids DOS / xss copy-by-url JavaScript based cross site POST file submissions
== Copy by URL==
$wgAllowCopyUploads = false;
* http class rewrite includes a new http background download see: includes/HttpFunctions.php
* spins off a php process that calls: maintenance/http_session_download.php
* pushes updates to the session and gives the user a progress bar on http copy uploads from other server progress (using js2 upload interface) (if not using the js2 upload interface it does the request in-place but the download is limited to the php ini timeout time)
== Firefogg ==
* Firefogg enables resumable upload by chunks
* progress indicators and conditional invokation (js2 system)
* and of-course client side transcoding.
= Script Server =
$wgEnableScriptLoader = false;
* off by default if $wgEnableScriptLoader is turned on script files are grouped, gziped, cached etc.
for more info see: http://www.mediawiki.org/wiki/Extension:ScriptLoader
* Includes some early skin js include fixes (skin/script system still lots of love)
* Includes a "javascript class autoloader" this is packaged into mwEmbed so that the mwEmbed library can work in stand alone mode (while retaining localization and script serving) (one such application is the make page for firefogg.org : http://www.firefogg.org/make/index.html )
* The file that contains the autojavascript loading classes is: js2/php/jsAutoloadLocalClasses.php
* One can use this auto class loading dependency system with extensions and add-ons but I need to better document that.
= js2 system / mwEmbed=
$wgEnableJS2system = false
* includes initial rewrite towards more jquery based javascript code
* especially for the Special:Upload page.
* Also the edit page include support for the "add-media-wizard"
* includes dependency loader for javascript that optionally takes advantage of the script-loader
* remote embedding of javascript interfaces (like embedding video, or commons media searching)
* $wgDebugJavaScript = false; .. .this variable lets you always get "always fresh javascript". When used with the script-loader it does not minify the script-loader output.
= mwEmbed =
* Will commit a separate patch to oggHandler that conditionally outputs <video tag> to use the new javascript video player.
** mv_embed player includes: play-head, volume control, remote embedding, oggz-chop support across plugins.
* add-media-wizard adds easy inserts of media to pages (with import)
== jQuery==
* we include a base install of jQuery, jQuery ui and some plugins.
* all the javascript classes are in the scriptloader so its easy to load any set of jquery ui components that you may need using the script-server. You get a callback so you can then execute js with dependencies loaded.
== other stuff ==
there is a bit more code in js2 that pertains to sequence editing, timed text display and basic image editing. We include a base import of pixastic-lib & pixastic-editor... will work with the pixastic developer to try and ensure upstream compatibility on our usage of the library for in-browser photo and sequence manipulation.
2009-07-14 23:52:14 +00:00
|
|
|
|
2011-11-12 13:47:17 +00:00
|
|
|
/**
|
|
|
|
|
* @private
|
|
|
|
|
* @todo document
|
|
|
|
|
*
|
|
|
|
|
* @parma $editText string
|
|
|
|
|
*
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
2012-02-16 16:09:08 +00:00
|
|
|
function mergeChangesInto( &$editText ) {
|
2011-11-12 13:47:17 +00:00
|
|
|
wfProfileIn( __METHOD__ );
|
|
|
|
|
|
|
|
|
|
$db = wfGetDB( DB_MASTER );
|
|
|
|
|
|
|
|
|
|
// This is the revision the editor started from
|
|
|
|
|
$baseRevision = $this->getBaseRevision();
|
|
|
|
|
if ( is_null( $baseRevision ) ) {
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
$baseText = $baseRevision->getText();
|
|
|
|
|
|
|
|
|
|
// The current state, we want to merge updates into it
|
|
|
|
|
$currentRevision = Revision::loadFromTitle( $db, $this->mTitle );
|
|
|
|
|
if ( is_null( $currentRevision ) ) {
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
$currentText = $currentRevision->getText();
|
|
|
|
|
|
|
|
|
|
$result = '';
|
|
|
|
|
if ( wfMerge( $baseText, $editText, $currentText, $result ) ) {
|
|
|
|
|
$editText = $result;
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
|
|
|
|
return true;
|
|
|
|
|
} else {
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return Revision
|
|
|
|
|
*/
|
|
|
|
|
function getBaseRevision() {
|
|
|
|
|
if ( !$this->mBaseRevision ) {
|
|
|
|
|
$db = wfGetDB( DB_MASTER );
|
|
|
|
|
$baseRevision = Revision::loadFromTimestamp(
|
|
|
|
|
$db, $this->mTitle, $this->edittime );
|
|
|
|
|
return $this->mBaseRevision = $baseRevision;
|
|
|
|
|
} else {
|
|
|
|
|
return $this->mBaseRevision;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-08-19 20:32:30 +00:00
|
|
|
/**
|
|
|
|
|
* Check given input text against $wgSpamRegex, and return the text of the first match.
|
2011-06-05 14:46:55 +00:00
|
|
|
*
|
|
|
|
|
* @param $text string
|
|
|
|
|
*
|
2012-02-09 18:01:54 +00:00
|
|
|
* @return string|bool matching string or false
|
2008-08-19 20:32:30 +00:00
|
|
|
*/
|
|
|
|
|
public static function matchSpamRegex( $text ) {
|
|
|
|
|
global $wgSpamRegex;
|
2009-02-27 20:50:25 +00:00
|
|
|
// For back compatibility, $wgSpamRegex may be a single string or an array of regexes.
|
|
|
|
|
$regexes = (array)$wgSpamRegex;
|
|
|
|
|
return self::matchSpamRegexInternal( $text, $regexes );
|
|
|
|
|
}
|
2009-10-23 11:08:08 +00:00
|
|
|
|
2009-02-27 20:50:25 +00:00
|
|
|
/**
|
|
|
|
|
* Check given input text against $wgSpamRegex, and return the text of the first match.
|
2011-06-05 14:46:55 +00:00
|
|
|
*
|
|
|
|
|
* @parma $text string
|
|
|
|
|
*
|
2012-02-09 18:01:54 +00:00
|
|
|
* @return string|bool matching string or false
|
2009-02-27 20:50:25 +00:00
|
|
|
*/
|
|
|
|
|
public static function matchSummarySpamRegex( $text ) {
|
|
|
|
|
global $wgSummarySpamRegex;
|
|
|
|
|
$regexes = (array)$wgSummarySpamRegex;
|
|
|
|
|
return self::matchSpamRegexInternal( $text, $regexes );
|
|
|
|
|
}
|
2009-10-23 11:08:08 +00:00
|
|
|
|
2011-06-05 14:46:55 +00:00
|
|
|
/**
|
|
|
|
|
* @param $text string
|
|
|
|
|
* @param $regexes array
|
|
|
|
|
* @return bool|string
|
|
|
|
|
*/
|
2009-02-27 20:50:25 +00:00
|
|
|
protected static function matchSpamRegexInternal( $text, $regexes ) {
|
2012-02-16 16:09:08 +00:00
|
|
|
foreach ( $regexes as $regex ) {
|
2009-02-27 20:50:25 +00:00
|
|
|
$matches = array();
|
2012-02-16 16:09:08 +00:00
|
|
|
if ( preg_match( $regex, $text, $matches ) ) {
|
2009-02-27 20:50:25 +00:00
|
|
|
return $matches[0];
|
2008-08-19 20:32:30 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2005-08-20 06:57:21 +00:00
|
|
|
|
2008-08-27 05:56:34 +00:00
|
|
|
function setHeaders() {
|
2012-01-11 10:33:31 +00:00
|
|
|
global $wgOut, $wgUser;
|
|
|
|
|
|
|
|
|
|
$wgOut->addModules( 'mediawiki.action.edit' );
|
|
|
|
|
|
|
|
|
|
if ( $wgUser->getOption( 'uselivepreview', false ) ) {
|
|
|
|
|
$wgOut->addModules( 'mediawiki.legacy.preview' );
|
|
|
|
|
}
|
|
|
|
|
// Bug #19334: textarea jumps when editing articles in IE8
|
|
|
|
|
$wgOut->addStyle( 'common/IE80Fixes.css', 'screen', 'IE 8' );
|
|
|
|
|
|
2008-08-27 05:56:34 +00:00
|
|
|
$wgOut->setRobotPolicy( 'noindex,nofollow' );
|
2012-01-11 10:33:31 +00:00
|
|
|
|
|
|
|
|
# Enabled article-related sidebar, toplinks, etc.
|
|
|
|
|
$wgOut->setArticleRelated( true );
|
|
|
|
|
|
2012-04-01 07:40:54 +00:00
|
|
|
$contextTitle = $this->getContextTitle();
|
2008-09-16 04:59:49 +00:00
|
|
|
if ( $this->isConflict ) {
|
2012-04-01 07:40:54 +00:00
|
|
|
$msg = 'editconflict';
|
|
|
|
|
} elseif ( $contextTitle->exists() && $this->section != '' ) {
|
2011-04-25 03:20:17 +00:00
|
|
|
$msg = $this->section == 'new' ? 'editingcomment' : 'editingsection';
|
2008-08-27 05:56:34 +00:00
|
|
|
} else {
|
2012-04-16 19:39:50 +00:00
|
|
|
$msg = $contextTitle->exists() || ( $contextTitle->getNamespace() == NS_MEDIAWIKI && $contextTitle->getDefaultMessageText() !== false ) ?
|
|
|
|
|
'editing' : 'creating';
|
2012-04-01 07:40:54 +00:00
|
|
|
}
|
|
|
|
|
# Use the title defined by DISPLAYTITLE magic word when present
|
2012-04-16 19:39:50 +00:00
|
|
|
$displayTitle = isset( $this->mParserOutput ) ? $this->mParserOutput->getDisplayTitle() : false;
|
|
|
|
|
if ( $displayTitle === false ) {
|
|
|
|
|
$displayTitle = $contextTitle->getPrefixedText();
|
2008-08-27 05:56:34 +00:00
|
|
|
}
|
2012-04-01 07:40:54 +00:00
|
|
|
$wgOut->setPageTitle( wfMessage( $msg, $displayTitle ) );
|
2008-08-27 05:56:34 +00:00
|
|
|
}
|
|
|
|
|
|
2011-11-12 13:47:17 +00:00
|
|
|
/**
|
|
|
|
|
* Show all applicable editing introductions
|
|
|
|
|
*/
|
|
|
|
|
protected function showIntro() {
|
|
|
|
|
global $wgOut, $wgUser;
|
|
|
|
|
if ( $this->suppressIntro ) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$namespace = $this->mTitle->getNamespace();
|
|
|
|
|
|
|
|
|
|
if ( $namespace == NS_MEDIAWIKI ) {
|
|
|
|
|
# Show a warning if editing an interface message
|
|
|
|
|
$wgOut->wrapWikiMsg( "<div class='mw-editinginterface'>\n$1\n</div>", 'editinginterface' );
|
2012-03-31 14:17:10 +00:00
|
|
|
} else if( $namespace == NS_FILE ) {
|
|
|
|
|
# Show a hint to shared repo
|
|
|
|
|
$file = wfFindFile( $this->mTitle );
|
|
|
|
|
if( $file && !$file->isLocal() ) {
|
|
|
|
|
$descUrl = $file->getDescriptionUrl();
|
|
|
|
|
# there must be a description url to show a hint to shared repo
|
|
|
|
|
if( $descUrl ) {
|
|
|
|
|
if( !$this->mTitle->exists() ) {
|
|
|
|
|
$wgOut->wrapWikiMsg( "<div class=\"mw-sharedupload-desc-create\">\n$1\n</div>", array (
|
|
|
|
|
'sharedupload-desc-create', $file->getRepo()->getDisplayName(), $descUrl
|
|
|
|
|
) );
|
|
|
|
|
} else {
|
|
|
|
|
$wgOut->wrapWikiMsg( "<div class=\"mw-sharedupload-desc-edit\">\n$1\n</div>", array(
|
|
|
|
|
'sharedupload-desc-edit', $file->getRepo()->getDisplayName(), $descUrl
|
|
|
|
|
) );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-11-12 13:47:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Show a warning message when someone creates/edits a user (talk) page but the user does not exist
|
|
|
|
|
# Show log extract when the user is currently blocked
|
|
|
|
|
if ( $namespace == NS_USER || $namespace == NS_USER_TALK ) {
|
|
|
|
|
$parts = explode( '/', $this->mTitle->getText(), 2 );
|
|
|
|
|
$username = $parts[0];
|
|
|
|
|
$user = User::newFromName( $username, false /* allow IP users*/ );
|
|
|
|
|
$ip = User::isIP( $username );
|
2012-02-16 16:09:08 +00:00
|
|
|
if ( !( $user && $user->isLoggedIn() ) && !$ip ) { # User does not exist
|
2011-11-12 13:47:17 +00:00
|
|
|
$wgOut->wrapWikiMsg( "<div class=\"mw-userpage-userdoesnotexist error\">\n$1\n</div>",
|
|
|
|
|
array( 'userpage-userdoesnotexist', wfEscapeWikiText( $username ) ) );
|
|
|
|
|
} elseif ( $user->isBlocked() ) { # Show log extract if the user is currently blocked
|
|
|
|
|
LogEventsList::showLogExtract(
|
|
|
|
|
$wgOut,
|
|
|
|
|
'block',
|
|
|
|
|
$user->getUserPage(),
|
|
|
|
|
'',
|
|
|
|
|
array(
|
|
|
|
|
'lim' => 1,
|
|
|
|
|
'showIfEmpty' => false,
|
|
|
|
|
'msgKey' => array(
|
|
|
|
|
'blocked-notice-logextract',
|
|
|
|
|
$user->getName() # Support GENDER in notice
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
# Try to add a custom edit intro, or use the standard one if this is not possible.
|
|
|
|
|
if ( !$this->showCustomIntro() && !$this->mTitle->exists() ) {
|
|
|
|
|
if ( $wgUser->isLoggedIn() ) {
|
|
|
|
|
$wgOut->wrapWikiMsg( "<div class=\"mw-newarticletext\">\n$1\n</div>", 'newarticletext' );
|
|
|
|
|
} else {
|
|
|
|
|
$wgOut->wrapWikiMsg( "<div class=\"mw-newarticletextanon\">\n$1\n</div>", 'newarticletextanon' );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
# Give a notice if the user is editing a deleted/moved page...
|
|
|
|
|
if ( !$this->mTitle->exists() ) {
|
|
|
|
|
LogEventsList::showLogExtract( $wgOut, array( 'delete', 'move' ), $this->mTitle,
|
|
|
|
|
'', array( 'lim' => 10,
|
|
|
|
|
'conds' => array( "log_action != 'revision'" ),
|
|
|
|
|
'showIfEmpty' => false,
|
2012-02-16 16:09:08 +00:00
|
|
|
'msgKey' => array( 'recreate-moveddeleted-warn' ) )
|
2011-11-12 13:47:17 +00:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Attempt to show a custom editing introduction, if supplied
|
|
|
|
|
*
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
|
|
|
|
protected function showCustomIntro() {
|
|
|
|
|
if ( $this->editintro ) {
|
|
|
|
|
$title = Title::newFromText( $this->editintro );
|
2011-12-13 11:05:30 +00:00
|
|
|
if ( $title instanceof Title && $title->exists() && $title->userCan( 'read' ) ) {
|
2011-11-12 13:47:17 +00:00
|
|
|
global $wgOut;
|
|
|
|
|
// Added using template syntax, to take <noinclude>'s into account.
|
|
|
|
|
$wgOut->addWikiTextTitleTidy( '{{:' . $title->getFullText() . '}}', $this->mTitle );
|
|
|
|
|
return true;
|
|
|
|
|
} else {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2005-08-20 06:57:21 +00:00
|
|
|
/**
|
|
|
|
|
* Send the edit form and related headers to $wgOut
|
2011-04-23 13:55:27 +00:00
|
|
|
* @param $formCallback Callback that takes an OutputPage parameter; will be called
|
|
|
|
|
* during form output near the top, for captchas and the like.
|
2005-08-20 06:57:21 +00:00
|
|
|
*/
|
2011-07-30 15:56:54 +00:00
|
|
|
function showEditForm( $formCallback = null ) {
|
2011-09-29 22:08:00 +00:00
|
|
|
global $wgOut, $wgUser;
|
2005-08-20 06:57:21 +00:00
|
|
|
|
2009-10-25 15:02:33 +00:00
|
|
|
wfProfileIn( __METHOD__ );
|
2005-08-21 04:45:28 +00:00
|
|
|
|
2012-02-16 16:09:08 +00:00
|
|
|
# need to parse the preview early so that we know which templates are used,
|
|
|
|
|
# otherwise users with "show preview after edit box" will get a blank list
|
|
|
|
|
# we parse this near the beginning so that setHeaders can do the title
|
|
|
|
|
# setting work instead of leaving it in getPreviewText
|
2008-08-27 05:56:34 +00:00
|
|
|
$previewOutput = '';
|
2008-09-16 04:59:49 +00:00
|
|
|
if ( $this->formtype == 'preview' ) {
|
2008-08-27 05:56:34 +00:00
|
|
|
$previewOutput = $this->getPreviewText();
|
|
|
|
|
}
|
2009-10-23 11:08:08 +00:00
|
|
|
|
2012-02-15 19:32:36 +00:00
|
|
|
wfRunHooks( 'EditPage::showEditForm:initial', array( &$this, &$wgOut ) );
|
2008-08-27 05:56:34 +00:00
|
|
|
|
|
|
|
|
$this->setHeaders();
|
2004-03-18 06:56:14 +00:00
|
|
|
|
2011-02-10 15:53:54 +00:00
|
|
|
if ( $this->showHeader() === false ) {
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
2009-12-02 07:22:29 +00:00
|
|
|
return;
|
2011-02-10 15:53:54 +00:00
|
|
|
}
|
2009-12-02 07:22:29 +00:00
|
|
|
|
|
|
|
|
$wgOut->addHTML( $this->editFormPageTop );
|
|
|
|
|
|
|
|
|
|
if ( $wgUser->getOption( 'previewontop' ) ) {
|
|
|
|
|
$this->displayPreviewArea( $previewOutput, true );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$wgOut->addHTML( $this->editFormTextTop );
|
|
|
|
|
|
2011-12-30 21:30:04 +00:00
|
|
|
$showToolbar = true;
|
|
|
|
|
if ( $this->wasDeletedSinceLastEdit() ) {
|
|
|
|
|
if ( $this->formtype == 'save' ) {
|
|
|
|
|
// Hide the toolbar and edit area, user can click preview to get it back
|
|
|
|
|
// Add an confirmation checkbox and explanation.
|
|
|
|
|
$showToolbar = false;
|
|
|
|
|
} else {
|
|
|
|
|
$wgOut->wrapWikiMsg( "<div class='error mw-deleted-while-editing'>\n$1\n</div>",
|
|
|
|
|
'deletedwhileediting' );
|
|
|
|
|
}
|
2009-12-02 07:22:29 +00:00
|
|
|
}
|
2011-12-30 21:30:04 +00:00
|
|
|
|
2012-04-24 17:54:08 +00:00
|
|
|
$wgOut->addHTML( Html::openElement( 'form', array( 'id' => self::EDITFORM_ID, 'name' => self::EDITFORM_ID,
|
2011-12-30 21:30:04 +00:00
|
|
|
'method' => 'post', 'action' => $this->getActionURL( $this->getContextTitle() ),
|
|
|
|
|
'enctype' => 'multipart/form-data' ) ) );
|
2009-12-02 07:22:29 +00:00
|
|
|
|
|
|
|
|
if ( is_callable( $formCallback ) ) {
|
|
|
|
|
call_user_func_array( $formCallback, array( &$wgOut ) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wfRunHooks( 'EditPage::showEditForm:fields', array( &$this, &$wgOut ) );
|
|
|
|
|
|
|
|
|
|
// Put these up at the top to ensure they aren't lost on early form submission
|
|
|
|
|
$this->showFormBeforeText();
|
|
|
|
|
|
|
|
|
|
if ( $this->wasDeletedSinceLastEdit() && 'save' == $this->formtype ) {
|
2011-01-09 11:30:36 +00:00
|
|
|
$username = $this->lastDelete->user_name;
|
|
|
|
|
$comment = $this->lastDelete->log_comment;
|
2011-02-12 04:06:22 +00:00
|
|
|
|
2011-01-09 11:30:36 +00:00
|
|
|
// It is better to not parse the comment at all than to have templates expanded in the middle
|
|
|
|
|
// TODO: can the checkLabel be moved outside of the div so that wrapWikiMsg could be used?
|
2011-03-30 18:06:05 +00:00
|
|
|
$key = $comment === ''
|
|
|
|
|
? 'confirmrecreate-noreason'
|
|
|
|
|
: 'confirmrecreate';
|
2009-12-02 07:22:29 +00:00
|
|
|
$wgOut->addHTML(
|
|
|
|
|
'<div class="mw-confirm-recreate">' .
|
2011-03-30 17:04:03 +00:00
|
|
|
wfMsgExt( $key, 'parseinline', $username, "<nowiki>$comment</nowiki>" ) .
|
2009-12-02 07:22:29 +00:00
|
|
|
Xml::checkLabel( wfMsg( 'recreate' ), 'wpRecreate', 'wpRecreate', false,
|
2011-07-16 19:19:01 +00:00
|
|
|
array( 'title' => Linker::titleAttrib( 'recreate' ), 'tabindex' => 1, 'id' => 'wpRecreate' )
|
2009-12-02 07:22:29 +00:00
|
|
|
) .
|
|
|
|
|
'</div>'
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2012-04-01 13:37:10 +00:00
|
|
|
# When the summary is hidden, also hide them on preview/show changes
|
|
|
|
|
if( $this->nosummary ) {
|
|
|
|
|
$wgOut->addHTML( Html::hidden( 'nosummary', true ) );
|
|
|
|
|
}
|
|
|
|
|
|
2009-12-02 07:22:29 +00:00
|
|
|
# If a blank edit summary was previously provided, and the appropriate
|
|
|
|
|
# user preference is active, pass a hidden tag as wpIgnoreBlankSummary. This will stop the
|
|
|
|
|
# user being bounced back more than once in the event that a summary
|
|
|
|
|
# is not required.
|
|
|
|
|
#####
|
|
|
|
|
# For a bit more sophisticated detection of blank summaries, hash the
|
|
|
|
|
# automatic one and pass that in the hidden field wpAutoSummary.
|
2011-12-30 21:30:04 +00:00
|
|
|
if ( $this->missingSummary || ( $this->section == 'new' && $this->nosummary ) ) {
|
|
|
|
|
$wgOut->addHTML( Html::hidden( 'wpIgnoreBlankSummary', true ) );
|
|
|
|
|
}
|
|
|
|
|
|
2012-02-09 21:06:19 +00:00
|
|
|
if ( $this->hasPresetSummary ) {
|
|
|
|
|
// If a summary has been preset using &summary= we dont want to prompt for
|
|
|
|
|
// a different summary. Only prompt for a summary if the summary is blanked.
|
|
|
|
|
// (Bug 17416)
|
2012-02-16 16:09:08 +00:00
|
|
|
$this->autoSumm = md5( '' );
|
2012-02-09 21:06:19 +00:00
|
|
|
}
|
2012-02-16 16:09:08 +00:00
|
|
|
|
2009-12-02 07:22:29 +00:00
|
|
|
$autosumm = $this->autoSumm ? $this->autoSumm : md5( $this->summary );
|
2010-10-31 16:33:48 +00:00
|
|
|
$wgOut->addHTML( Html::hidden( 'wpAutoSummary', $autosumm ) );
|
2009-12-02 07:22:29 +00:00
|
|
|
|
2011-12-30 16:12:46 +00:00
|
|
|
$wgOut->addHTML( Html::hidden( 'oldid', $this->oldid ) );
|
2010-02-05 15:01:07 +00:00
|
|
|
|
2011-04-25 03:20:17 +00:00
|
|
|
if ( $this->section == 'new' ) {
|
2009-12-02 07:22:29 +00:00
|
|
|
$this->showSummaryInput( true, $this->summary );
|
|
|
|
|
$wgOut->addHTML( $this->getSummaryPreview( true, $this->summary ) );
|
|
|
|
|
}
|
2009-09-16 20:43:14 +00:00
|
|
|
|
2009-12-02 07:22:29 +00:00
|
|
|
$wgOut->addHTML( $this->editFormTextBeforeContent );
|
2011-06-17 16:03:52 +00:00
|
|
|
|
2011-12-30 21:30:04 +00:00
|
|
|
if ( !$this->isCssJsSubpage && $showToolbar && $wgUser->getOption( 'showtoolbar' ) ) {
|
|
|
|
|
$wgOut->addHTML( EditPage::getEditToolbar() );
|
|
|
|
|
}
|
2010-07-20 15:50:25 +00:00
|
|
|
|
2008-09-16 04:59:49 +00:00
|
|
|
if ( $this->isConflict ) {
|
2009-12-02 07:22:29 +00:00
|
|
|
// In an edit conflict bypass the overrideable content form method
|
|
|
|
|
// and fallback to the raw wpTextbox1 since editconflicts can't be
|
|
|
|
|
// resolved between page source edits and custom ui edits using the
|
|
|
|
|
// custom edit ui.
|
2011-12-30 20:43:08 +00:00
|
|
|
$this->textbox2 = $this->textbox1;
|
|
|
|
|
$this->textbox1 = $this->getCurrentText();
|
|
|
|
|
|
|
|
|
|
$this->showTextbox1();
|
2009-12-02 07:22:29 +00:00
|
|
|
} else {
|
|
|
|
|
$this->showContentForm();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$wgOut->addHTML( $this->editFormTextAfterContent );
|
|
|
|
|
|
|
|
|
|
$wgOut->addWikiText( $this->getCopywarn() );
|
2011-12-30 21:30:04 +00:00
|
|
|
|
|
|
|
|
$wgOut->addHTML( $this->editFormTextAfterWarn );
|
2009-12-02 07:22:29 +00:00
|
|
|
|
|
|
|
|
$this->showStandardInputs();
|
|
|
|
|
|
|
|
|
|
$this->showFormAfterText();
|
|
|
|
|
|
|
|
|
|
$this->showTosSummary();
|
2011-12-30 21:30:04 +00:00
|
|
|
|
2009-12-02 07:22:29 +00:00
|
|
|
$this->showEditTools();
|
|
|
|
|
|
2011-12-30 21:30:04 +00:00
|
|
|
$wgOut->addHTML( $this->editFormTextAfterTools . "\n" );
|
|
|
|
|
|
|
|
|
|
$wgOut->addHTML( Html::rawElement( 'div', array( 'class' => 'templatesUsed' ),
|
|
|
|
|
Linker::formatTemplates( $this->getTemplates(), $this->preview, $this->section != '' ) ) );
|
|
|
|
|
|
|
|
|
|
$wgOut->addHTML( Html::rawElement( 'div', array( 'class' => 'hiddencats' ),
|
|
|
|
|
Linker::formatHiddenCategories( $this->mArticle->getHiddenCategories() ) ) );
|
2009-12-02 07:22:29 +00:00
|
|
|
|
2011-12-30 20:43:08 +00:00
|
|
|
if ( $this->isConflict ) {
|
2009-12-02 07:22:29 +00:00
|
|
|
$this->showConflict();
|
2011-12-30 20:43:08 +00:00
|
|
|
}
|
2010-07-20 15:50:25 +00:00
|
|
|
|
2011-12-30 21:30:04 +00:00
|
|
|
$wgOut->addHTML( $this->editFormTextBottom . "\n</form>\n" );
|
|
|
|
|
|
2009-12-02 07:22:29 +00:00
|
|
|
if ( !$wgUser->getOption( 'previewontop' ) ) {
|
|
|
|
|
$this->displayPreviewArea( $previewOutput, false );
|
|
|
|
|
}
|
2003-08-02 20:43:11 +00:00
|
|
|
|
2009-12-02 07:22:29 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
|
|
|
|
}
|
2010-07-20 15:50:25 +00:00
|
|
|
|
2011-12-06 23:35:42 +00:00
|
|
|
/**
|
|
|
|
|
* Extract the section title from current section text, if any.
|
|
|
|
|
*
|
|
|
|
|
* @param string $text
|
|
|
|
|
* @return Mixed|string or false
|
|
|
|
|
*/
|
|
|
|
|
public static function extractSectionTitle( $text ) {
|
2012-03-15 15:21:46 +00:00
|
|
|
preg_match( "/^(=+)(.+)\\1\\s*(\n|$)/i", $text, $matches );
|
2011-12-06 23:35:42 +00:00
|
|
|
if ( !empty( $matches[2] ) ) {
|
|
|
|
|
global $wgParser;
|
2012-02-16 16:09:08 +00:00
|
|
|
return $wgParser->stripSectionName( trim( $matches[2] ) );
|
2011-12-06 23:35:42 +00:00
|
|
|
} else {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-12-08 17:17:24 +00:00
|
|
|
protected function showHeader() {
|
2011-02-10 17:08:37 +00:00
|
|
|
global $wgOut, $wgUser, $wgMaxArticleSize, $wgLang;
|
2012-01-11 10:33:31 +00:00
|
|
|
|
|
|
|
|
if ( $this->mTitle->isTalkPage() ) {
|
|
|
|
|
$wgOut->addWikiMsg( 'talkpagetext' );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Optional notices on a per-namespace and per-page basis
|
2012-02-16 16:09:08 +00:00
|
|
|
$editnotice_ns = 'editnotice-' . $this->mTitle->getNamespace();
|
2012-04-13 23:57:12 +00:00
|
|
|
$editnotice_ns_message = wfMessage( $editnotice_ns );
|
2012-01-11 10:33:31 +00:00
|
|
|
if ( $editnotice_ns_message->exists() ) {
|
|
|
|
|
$wgOut->addWikiText( $editnotice_ns_message->plain() );
|
|
|
|
|
}
|
|
|
|
|
if ( MWNamespace::hasSubpages( $this->mTitle->getNamespace() ) ) {
|
|
|
|
|
$parts = explode( '/', $this->mTitle->getDBkey() );
|
|
|
|
|
$editnotice_base = $editnotice_ns;
|
|
|
|
|
while ( count( $parts ) > 0 ) {
|
2012-02-16 16:09:08 +00:00
|
|
|
$editnotice_base .= '-' . array_shift( $parts );
|
2012-04-13 23:57:12 +00:00
|
|
|
$editnotice_base_msg = wfMessage( $editnotice_base );
|
2012-01-11 10:33:31 +00:00
|
|
|
if ( $editnotice_base_msg->exists() ) {
|
2012-02-16 16:09:08 +00:00
|
|
|
$wgOut->addWikiText( $editnotice_base_msg->plain() );
|
2012-01-11 10:33:31 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
# Even if there are no subpages in namespace, we still don't want / in MW ns.
|
|
|
|
|
$editnoticeText = $editnotice_ns . '-' . str_replace( '/', '-', $this->mTitle->getDBkey() );
|
2012-04-13 23:57:12 +00:00
|
|
|
$editnoticeMsg = wfMessage( $editnoticeText );
|
2012-01-11 10:33:31 +00:00
|
|
|
if ( $editnoticeMsg->exists() ) {
|
|
|
|
|
$wgOut->addWikiText( $editnoticeMsg->plain() );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-12-02 07:22:29 +00:00
|
|
|
if ( $this->isConflict ) {
|
2010-05-28 21:22:45 +00:00
|
|
|
$wgOut->wrapWikiMsg( "<div class='mw-explainconflict'>\n$1\n</div>", 'explainconflict' );
|
2004-03-08 09:09:35 +00:00
|
|
|
$this->edittime = $this->mArticle->getTimestamp();
|
2003-08-02 20:43:11 +00:00
|
|
|
} else {
|
2009-12-02 07:22:29 +00:00
|
|
|
if ( $this->section != '' && !$this->isSectionEditSupported() ) {
|
|
|
|
|
// We use $this->section to much before this and getVal('wgSection') directly in other places
|
|
|
|
|
// at this point we can't reset $this->section to '' to fallback to non-section editing.
|
|
|
|
|
// Someone is welcome to try refactoring though
|
|
|
|
|
$wgOut->showErrorPage( 'sectioneditnotsupported-title', 'sectioneditnotsupported-text' );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-25 03:20:17 +00:00
|
|
|
if ( $this->section != '' && $this->section != 'new' ) {
|
2008-09-16 04:59:49 +00:00
|
|
|
if ( !$this->summary && !$this->preview && !$this->diff ) {
|
2011-12-06 23:35:42 +00:00
|
|
|
$sectionTitle = self::extractSectionTitle( $this->textbox1 );
|
|
|
|
|
if ( $sectionTitle !== false ) {
|
|
|
|
|
$this->summary = "/* $sectionTitle */ ";
|
2006-01-07 13:31:29 +00:00
|
|
|
}
|
2004-03-20 01:18:19 +00:00
|
|
|
}
|
2003-08-02 20:43:11 +00:00
|
|
|
}
|
2006-03-01 23:00:07 +00:00
|
|
|
|
2009-12-08 17:17:24 +00:00
|
|
|
if ( $this->missingComment ) {
|
2010-05-28 21:22:45 +00:00
|
|
|
$wgOut->wrapWikiMsg( "<div id='mw-missingcommenttext'>\n$1\n</div>", 'missingcommenttext' );
|
2009-12-08 17:17:24 +00:00
|
|
|
}
|
2007-01-13 19:58:40 +00:00
|
|
|
|
2011-04-25 03:20:17 +00:00
|
|
|
if ( $this->missingSummary && $this->section != 'new' ) {
|
2010-05-28 21:22:45 +00:00
|
|
|
$wgOut->wrapWikiMsg( "<div id='mw-missingsummary'>\n$1\n</div>", 'missingsummary' );
|
2009-12-08 17:17:24 +00:00
|
|
|
}
|
2006-11-03 01:37:06 +00:00
|
|
|
|
2011-04-25 03:20:17 +00:00
|
|
|
if ( $this->missingSummary && $this->section == 'new' ) {
|
2010-05-28 21:22:45 +00:00
|
|
|
$wgOut->wrapWikiMsg( "<div id='mw-missingcommentheader'>\n$1\n</div>", 'missingcommentheader' );
|
2009-12-08 17:17:24 +00:00
|
|
|
}
|
2007-01-13 19:58:40 +00:00
|
|
|
|
2009-12-08 17:17:24 +00:00
|
|
|
if ( $this->hookError !== '' ) {
|
2006-05-06 21:41:53 +00:00
|
|
|
$wgOut->addWikiText( $this->hookError );
|
2009-12-08 17:17:24 +00:00
|
|
|
}
|
2006-03-01 23:00:07 +00:00
|
|
|
|
2009-12-08 17:17:24 +00:00
|
|
|
if ( !$this->checkUnicodeCompliantBrowser() ) {
|
2008-02-18 07:25:35 +00:00
|
|
|
$wgOut->addWikiMsg( 'nonunicodebrowser' );
|
2009-12-08 17:17:24 +00:00
|
|
|
}
|
2009-12-02 07:22:29 +00:00
|
|
|
|
2011-12-30 16:12:46 +00:00
|
|
|
if ( $this->section != 'new' ) {
|
|
|
|
|
$revision = $this->mArticle->getRevisionFetched();
|
|
|
|
|
if ( $revision ) {
|
|
|
|
|
// Let sysop know that this will make private content public if saved
|
2008-09-04 13:57:52 +00:00
|
|
|
|
2011-12-30 16:12:46 +00:00
|
|
|
if ( !$revision->userCan( Revision::DELETED_TEXT ) ) {
|
|
|
|
|
$wgOut->wrapWikiMsg( "<div class='mw-warning plainlinks'>\n$1\n</div>\n", 'rev-deleted-text-permission' );
|
|
|
|
|
} elseif ( $revision->isDeleted( Revision::DELETED_TEXT ) ) {
|
|
|
|
|
$wgOut->wrapWikiMsg( "<div class='mw-warning plainlinks'>\n$1\n</div>\n", 'rev-deleted-text-view' );
|
|
|
|
|
}
|
2008-12-23 21:19:31 +00:00
|
|
|
|
2011-12-30 16:12:46 +00:00
|
|
|
if ( !$revision->isCurrent() ) {
|
|
|
|
|
$this->mArticle->setOldSubtitle( $revision->getId() );
|
|
|
|
|
$wgOut->addWikiMsg( 'editingold' );
|
|
|
|
|
}
|
2011-12-31 11:54:06 +00:00
|
|
|
} elseif ( $this->mTitle->exists() ) {
|
2011-12-30 20:43:08 +00:00
|
|
|
// Something went wrong
|
|
|
|
|
|
|
|
|
|
$wgOut->wrapWikiMsg( "<div class='errorbox'>\n$1\n</div>\n",
|
|
|
|
|
array( 'missing-article', $this->mTitle->getPrefixedText(),
|
|
|
|
|
wfMsgNoTrans( 'missingarticle-rev', $this->oldid ) ) );
|
2007-02-17 04:17:53 +00:00
|
|
|
}
|
2003-08-02 20:43:11 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-09-16 04:59:49 +00:00
|
|
|
if ( wfReadOnly() ) {
|
2008-08-20 21:27:12 +00:00
|
|
|
$wgOut->wrapWikiMsg( "<div id=\"mw-read-only-warning\">\n$1\n</div>", array( 'readonlywarning', wfReadOnlyReason() ) );
|
2010-03-29 22:44:59 +00:00
|
|
|
} elseif ( $wgUser->isAnon() ) {
|
|
|
|
|
if ( $this->formtype != 'preview' ) {
|
|
|
|
|
$wgOut->wrapWikiMsg( "<div id=\"mw-anon-edit-warning\">\n$1</div>", 'anoneditwarning' );
|
|
|
|
|
} else {
|
|
|
|
|
$wgOut->wrapWikiMsg( "<div id=\"mw-anon-preview-warning\">\n$1</div>", 'anonpreviewwarning' );
|
|
|
|
|
}
|
2008-12-23 21:19:31 +00:00
|
|
|
} else {
|
|
|
|
|
if ( $this->isCssJsSubpage ) {
|
|
|
|
|
# Check the skin exists
|
2010-11-25 23:12:05 +00:00
|
|
|
if ( $this->isWrongCaseCssJsPage ) {
|
2011-10-06 21:43:31 +00:00
|
|
|
$wgOut->wrapWikiMsg( "<div class='error' id='mw-userinvalidcssjstitle'>\n$1\n</div>", array( 'userinvalidcssjstitle', $this->mTitle->getSkinFromCssJsSubpage() ) );
|
2006-02-23 14:37:51 +00:00
|
|
|
}
|
2009-08-01 08:19:53 +00:00
|
|
|
if ( $this->formtype !== 'preview' ) {
|
|
|
|
|
if ( $this->isCssSubpage )
|
2010-06-02 19:30:55 +00:00
|
|
|
$wgOut->wrapWikiMsg( "<div id='mw-usercssyoucanpreview'>\n$1\n</div>", array( 'usercssyoucanpreview' ) );
|
2009-08-01 08:19:53 +00:00
|
|
|
if ( $this->isJsSubpage )
|
2010-06-02 19:30:55 +00:00
|
|
|
$wgOut->wrapWikiMsg( "<div id='mw-userjsyoucanpreview'>\n$1\n</div>", array( 'userjsyoucanpreview' ) );
|
2009-08-01 08:19:53 +00:00
|
|
|
}
|
2006-02-23 14:37:51 +00:00
|
|
|
}
|
2003-08-02 20:43:11 +00:00
|
|
|
}
|
2007-01-12 04:43:33 +00:00
|
|
|
|
2009-12-02 07:22:29 +00:00
|
|
|
if ( $this->mTitle->getNamespace() != NS_MEDIAWIKI && $this->mTitle->isProtected( 'edit' ) ) {
|
2007-01-20 19:17:45 +00:00
|
|
|
# Is the title semi-protected?
|
2008-09-16 04:59:49 +00:00
|
|
|
if ( $this->mTitle->isSemiProtected() ) {
|
2008-02-18 07:25:35 +00:00
|
|
|
$noticeMsg = 'semiprotectedpagewarning';
|
2006-02-06 09:49:28 +00:00
|
|
|
} else {
|
2008-01-09 21:40:40 +00:00
|
|
|
# Then it must be protected based on static groups (regular)
|
2008-02-18 07:25:35 +00:00
|
|
|
$noticeMsg = 'protectedpagewarning';
|
2006-02-06 09:49:28 +00:00
|
|
|
}
|
2011-09-24 17:52:53 +00:00
|
|
|
LogEventsList::showLogExtract( $wgOut, 'protect', $this->mTitle, '',
|
2009-09-16 17:17:16 +00:00
|
|
|
array( 'lim' => 1, 'msgKey' => array( $noticeMsg ) ) );
|
2003-08-02 20:43:11 +00:00
|
|
|
}
|
2008-09-16 04:59:49 +00:00
|
|
|
if ( $this->mTitle->isCascadeProtected() ) {
|
2007-04-21 19:02:02 +00:00
|
|
|
# Is this page under cascading protection from some source pages?
|
2012-02-16 16:09:08 +00:00
|
|
|
list( $cascadeSources, /* $restrictions */ ) = $this->mTitle->getCascadeProtectionSources();
|
2010-01-14 17:14:49 +00:00
|
|
|
$notice = "<div class='mw-cascadeprotectedwarning'>\n$1\n";
|
2009-01-22 12:57:09 +00:00
|
|
|
$cascadeSourcesCount = count( $cascadeSources );
|
|
|
|
|
if ( $cascadeSourcesCount > 0 ) {
|
2008-12-23 21:19:31 +00:00
|
|
|
# Explain, and list the titles responsible
|
2012-02-16 16:09:08 +00:00
|
|
|
foreach ( $cascadeSources as $page ) {
|
2008-12-23 21:19:31 +00:00
|
|
|
$notice .= '* [[:' . $page->getPrefixedText() . "]]\n";
|
|
|
|
|
}
|
2007-08-21 03:57:54 +00:00
|
|
|
}
|
2009-01-22 12:57:09 +00:00
|
|
|
$notice .= '</div>';
|
|
|
|
|
$wgOut->wrapWikiMsg( $notice, array( 'cascadeprotectedwarning', $cascadeSourcesCount ) );
|
2007-04-21 19:02:02 +00:00
|
|
|
}
|
2008-09-16 04:59:49 +00:00
|
|
|
if ( !$this->mTitle->exists() && $this->mTitle->getRestrictions( 'create' ) ) {
|
2011-09-24 17:52:53 +00:00
|
|
|
LogEventsList::showLogExtract( $wgOut, 'protect', $this->mTitle, '',
|
2012-02-16 16:09:08 +00:00
|
|
|
array( 'lim' => 1,
|
2010-01-16 11:24:23 +00:00
|
|
|
'showIfEmpty' => false,
|
|
|
|
|
'msgKey' => array( 'titleprotectedwarning' ),
|
|
|
|
|
'wrap' => "<div class=\"mw-titleprotectedwarning\">\n$1</div>" ) );
|
2008-01-02 19:51:34 +00:00
|
|
|
}
|
2006-02-22 00:55:25 +00:00
|
|
|
|
2009-12-08 17:17:24 +00:00
|
|
|
if ( $this->kblength === false ) {
|
2009-10-25 15:02:33 +00:00
|
|
|
$this->kblength = (int)( strlen( $this->textbox1 ) / 1024 );
|
2009-12-08 17:17:24 +00:00
|
|
|
}
|
2009-12-02 07:22:29 +00:00
|
|
|
|
2008-09-16 04:59:49 +00:00
|
|
|
if ( $this->tooBig || $this->kblength > $wgMaxArticleSize ) {
|
2010-11-23 12:57:27 +00:00
|
|
|
$wgOut->wrapWikiMsg( "<div class='error' id='mw-edit-longpageerror'>\n$1\n</div>",
|
|
|
|
|
array( 'longpageerror', $wgLang->formatNum( $this->kblength ), $wgLang->formatNum( $wgMaxArticleSize ) ) );
|
|
|
|
|
} else {
|
2012-02-16 16:09:08 +00:00
|
|
|
if ( !wfMessage( 'longpage-hint' )->isDisabled() ) {
|
2010-11-23 12:57:27 +00:00
|
|
|
$wgOut->wrapWikiMsg( "<div id='mw-edit-longpage-hint'>\n$1\n</div>",
|
|
|
|
|
array( 'longpage-hint', $wgLang->formatSize( strlen( $this->textbox1 ) ), strlen( $this->textbox1 ) )
|
|
|
|
|
);
|
|
|
|
|
}
|
2003-08-02 20:43:11 +00:00
|
|
|
}
|
2009-12-02 07:22:29 +00:00
|
|
|
}
|
New edit toolbar for bold, italic, links, headlines, math, images, media,
sigs, horizontal lines (more can be added easily). Select text and click
to apply, or just click to see an example. Mouseover should show speedtips.
Also, access keys for the edit window (ALT+P=Preview, ALT+S=Save) -> Moz+IE
2004-01-11 04:11:43 +00:00
|
|
|
|
2009-12-02 07:22:29 +00:00
|
|
|
/**
|
|
|
|
|
* Standard summary input and label (wgSummary), abstracted so EditPage
|
|
|
|
|
* subclasses may reorganize the form.
|
|
|
|
|
* Note that you do not need to worry about the label's for=, it will be
|
|
|
|
|
* inferred by the id given to the input. You can remove them both by
|
|
|
|
|
* passing array( 'id' => false ) to $userInputAttrs.
|
2010-07-20 15:50:25 +00:00
|
|
|
*
|
2011-06-05 14:46:55 +00:00
|
|
|
* @param $summary string The value of the summary input
|
|
|
|
|
* @param $labelText string The html to place inside the label
|
|
|
|
|
* @param $inputAttrs array of attrs to use on the input
|
|
|
|
|
* @param $spanLabelAttrs array of attrs to use on the span inside the label
|
2010-07-20 15:50:25 +00:00
|
|
|
*
|
2009-12-02 07:22:29 +00:00
|
|
|
* @return array An array in the format array( $label, $input )
|
|
|
|
|
*/
|
2012-02-16 16:09:08 +00:00
|
|
|
function getSummaryInput( $summary = "", $labelText = null, $inputAttrs = null, $spanLabelAttrs = null ) {
|
|
|
|
|
// Note: the maxlength is overriden in JS to 250 and to make it use UTF-8 bytes, not characters.
|
|
|
|
|
$inputAttrs = ( is_array( $inputAttrs ) ? $inputAttrs : array() ) + array(
|
2009-12-02 07:22:29 +00:00
|
|
|
'id' => 'wpSummary',
|
|
|
|
|
'maxlength' => '200',
|
2010-02-10 15:15:36 +00:00
|
|
|
'tabindex' => '1',
|
2009-12-02 07:22:29 +00:00
|
|
|
'size' => 60,
|
|
|
|
|
'spellcheck' => 'true',
|
2011-07-04 08:28:27 +00:00
|
|
|
) + Linker::tooltipAndAccesskeyAttribs( 'summary' );
|
2010-04-28 18:40:51 +00:00
|
|
|
|
2012-02-16 16:09:08 +00:00
|
|
|
$spanLabelAttrs = ( is_array( $spanLabelAttrs ) ? $spanLabelAttrs : array() ) + array(
|
2009-12-02 18:51:19 +00:00
|
|
|
'class' => $this->missingSummary ? 'mw-summarymissed' : 'mw-summary',
|
2009-12-02 07:22:29 +00:00
|
|
|
'id' => "wpSummaryLabel"
|
|
|
|
|
);
|
2006-11-26 13:58:40 +00:00
|
|
|
|
2009-12-02 07:22:29 +00:00
|
|
|
$label = null;
|
|
|
|
|
if ( $labelText ) {
|
|
|
|
|
$label = Xml::tags( 'label', $inputAttrs['id'] ? array( 'for' => $inputAttrs['id'] ) : null, $labelText );
|
|
|
|
|
$label = Xml::tags( 'span', $spanLabelAttrs, $label );
|
2005-03-19 12:01:57 +00:00
|
|
|
}
|
|
|
|
|
|
2009-12-02 07:22:29 +00:00
|
|
|
$input = Html::input( 'wpSummary', $summary, 'text', $inputAttrs );
|
2008-12-23 21:19:31 +00:00
|
|
|
|
2009-12-02 07:22:29 +00:00
|
|
|
return array( $label, $input );
|
|
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2009-12-02 07:22:29 +00:00
|
|
|
/**
|
2010-03-17 22:02:43 +00:00
|
|
|
* @param $isSubjectPreview Boolean: true if this is the section subject/title
|
2010-07-20 15:12:29 +00:00
|
|
|
* up top, or false if this is the comment summary
|
|
|
|
|
* down below the textarea
|
2010-03-17 22:02:43 +00:00
|
|
|
* @param $summary String: The text of the summary to display
|
|
|
|
|
* @return String
|
2009-12-02 07:22:29 +00:00
|
|
|
*/
|
|
|
|
|
protected function showSummaryInput( $isSubjectPreview, $summary = "" ) {
|
2009-12-08 17:17:24 +00:00
|
|
|
global $wgOut, $wgContLang;
|
2009-12-02 07:22:29 +00:00
|
|
|
# Add a class if 'missingsummary' is triggered to allow styling of the summary line
|
|
|
|
|
$summaryClass = $this->missingSummary ? 'mw-summarymissed' : 'mw-summary';
|
|
|
|
|
if ( $isSubjectPreview ) {
|
2011-06-05 14:46:55 +00:00
|
|
|
if ( $this->nosummary ) {
|
2009-12-02 07:22:29 +00:00
|
|
|
return;
|
2011-06-05 14:46:55 +00:00
|
|
|
}
|
2005-08-20 06:57:21 +00:00
|
|
|
} else {
|
2011-06-05 14:46:55 +00:00
|
|
|
if ( !$this->mShowSummaryField ) {
|
2009-12-02 07:22:29 +00:00
|
|
|
return;
|
2011-06-05 14:46:55 +00:00
|
|
|
}
|
2005-09-29 23:35:31 +00:00
|
|
|
}
|
2009-12-02 07:22:29 +00:00
|
|
|
$summary = $wgContLang->recodeForEdit( $summary );
|
|
|
|
|
$labelText = wfMsgExt( $isSubjectPreview ? 'subject' : 'summary', 'parseinline' );
|
2012-02-16 16:09:08 +00:00
|
|
|
list( $label, $input ) = $this->getSummaryInput( $summary, $labelText, array( 'class' => $summaryClass ), array() );
|
|
|
|
|
$wgOut->addHTML( "{$label} {$input}" );
|
2009-12-02 07:22:29 +00:00
|
|
|
}
|
2005-12-02 03:29:37 +00:00
|
|
|
|
2009-12-02 07:22:29 +00:00
|
|
|
/**
|
2010-03-17 22:02:43 +00:00
|
|
|
* @param $isSubjectPreview Boolean: true if this is the section subject/title
|
2010-07-20 15:12:29 +00:00
|
|
|
* up top, or false if this is the comment summary
|
|
|
|
|
* down below the textarea
|
2010-03-17 22:02:43 +00:00
|
|
|
* @param $summary String: the text of the summary to display
|
|
|
|
|
* @return String
|
2009-12-02 07:22:29 +00:00
|
|
|
*/
|
|
|
|
|
protected function getSummaryPreview( $isSubjectPreview, $summary = "" ) {
|
|
|
|
|
if ( !$summary || ( !$this->preview && !$this->diff ) )
|
|
|
|
|
return "";
|
2010-07-20 15:50:25 +00:00
|
|
|
|
2011-07-16 19:19:01 +00:00
|
|
|
global $wgParser;
|
2010-07-20 15:50:25 +00:00
|
|
|
|
2009-12-02 07:22:29 +00:00
|
|
|
if ( $isSubjectPreview )
|
|
|
|
|
$summary = wfMsgForContent( 'newsectionsummary', $wgParser->stripSectionName( $summary ) );
|
2005-12-02 03:29:37 +00:00
|
|
|
|
2010-05-09 12:41:57 +00:00
|
|
|
$message = $isSubjectPreview ? 'subject-preview' : 'summary-preview';
|
|
|
|
|
|
2011-07-16 19:19:01 +00:00
|
|
|
$summary = wfMsgExt( $message, 'parseinline' ) . Linker::commentBlock( $summary, $this->mTitle, $isSubjectPreview );
|
2009-12-02 07:22:29 +00:00
|
|
|
return Xml::tags( 'div', array( 'class' => 'mw-summary-preview' ), $summary );
|
|
|
|
|
}
|
2005-12-04 00:35:14 +00:00
|
|
|
|
2009-12-02 07:22:29 +00:00
|
|
|
protected function showFormBeforeText() {
|
|
|
|
|
global $wgOut;
|
|
|
|
|
$section = htmlspecialchars( $this->section );
|
2010-08-29 19:07:06 +00:00
|
|
|
$wgOut->addHTML( <<<HTML
|
2009-12-02 07:22:29 +00:00
|
|
|
<input type='hidden' value="{$section}" name="wpSection" />
|
|
|
|
|
<input type='hidden' value="{$this->starttime}" name="wpStarttime" />
|
|
|
|
|
<input type='hidden' value="{$this->edittime}" name="wpEdittime" />
|
|
|
|
|
<input type='hidden' value="{$this->scrolltop}" name="wpScrolltop" id="wpScrolltop" />
|
|
|
|
|
|
2010-08-29 19:07:06 +00:00
|
|
|
HTML
|
2009-12-02 07:22:29 +00:00
|
|
|
);
|
|
|
|
|
if ( !$this->checkUnicodeCompliantBrowser() )
|
2012-02-16 16:09:08 +00:00
|
|
|
$wgOut->addHTML( Html::hidden( 'safemode', '1' ) );
|
2009-12-02 07:22:29 +00:00
|
|
|
}
|
2010-07-20 15:50:25 +00:00
|
|
|
|
2009-12-02 07:22:29 +00:00
|
|
|
protected function showFormAfterText() {
|
|
|
|
|
global $wgOut, $wgUser;
|
2008-02-24 02:02:19 +00:00
|
|
|
/**
|
|
|
|
|
* To make it harder for someone to slip a user a page
|
|
|
|
|
* which submits an edit form to the wiki without their
|
|
|
|
|
* knowledge, a random token is associated with the login
|
|
|
|
|
* session. If it's not passed back with the submission,
|
|
|
|
|
* we won't save the page, or render user JavaScript and
|
|
|
|
|
* CSS previews.
|
|
|
|
|
*
|
|
|
|
|
* For anon editors, who may not have a session, we just
|
|
|
|
|
* include the constant suffix to prevent editing from
|
|
|
|
|
* broken text-mangling proxies.
|
|
|
|
|
*/
|
2011-11-16 04:37:17 +00:00
|
|
|
$wgOut->addHTML( "\n" . Html::hidden( "wpEditToken", $wgUser->getEditToken() ) . "\n" );
|
2008-08-27 05:56:34 +00:00
|
|
|
}
|
2007-01-13 19:58:40 +00:00
|
|
|
|
2009-12-02 07:22:29 +00:00
|
|
|
/**
|
|
|
|
|
* Subpage overridable method for printing the form for page content editing
|
|
|
|
|
* By default this simply outputs wpTextbox1
|
|
|
|
|
* Subclasses can override this to provide a custom UI for editing;
|
|
|
|
|
* be it a form, or simply wpTextbox1 with a modified content that will be
|
|
|
|
|
* reverse modified when extracted from the post data.
|
|
|
|
|
* Note that this is basically the inverse for importContentFormData
|
|
|
|
|
*/
|
|
|
|
|
protected function showContentForm() {
|
|
|
|
|
$this->showTextbox1();
|
2008-08-27 05:56:34 +00:00
|
|
|
}
|
2009-10-23 11:08:08 +00:00
|
|
|
|
2009-12-02 07:22:29 +00:00
|
|
|
/**
|
|
|
|
|
* Method to output wpTextbox1
|
|
|
|
|
* The $textoverride method can be used by subclasses overriding showContentForm
|
|
|
|
|
* to pass back to this method.
|
2010-07-20 15:50:25 +00:00
|
|
|
*
|
2012-02-09 19:30:01 +00:00
|
|
|
* @param $customAttribs array of html attributes to use in the textarea
|
2010-03-17 22:02:43 +00:00
|
|
|
* @param $textoverride String: optional text to override $this->textarea1 with
|
2009-12-02 07:22:29 +00:00
|
|
|
*/
|
2011-12-30 21:30:04 +00:00
|
|
|
protected function showTextbox1( $customAttribs = null, $textoverride = null ) {
|
|
|
|
|
if ( $this->wasDeletedSinceLastEdit() && $this->formtype == 'save' ) {
|
|
|
|
|
$attribs = array( 'style' => 'display:none;' );
|
|
|
|
|
} else {
|
|
|
|
|
$classes = array(); // Textarea CSS
|
|
|
|
|
if ( $this->mTitle->getNamespace() != NS_MEDIAWIKI && $this->mTitle->isProtected( 'edit' ) ) {
|
|
|
|
|
# Is the title semi-protected?
|
|
|
|
|
if ( $this->mTitle->isSemiProtected() ) {
|
|
|
|
|
$classes[] = 'mw-textarea-sprotected';
|
|
|
|
|
} else {
|
|
|
|
|
# Then it must be protected based on static groups (regular)
|
|
|
|
|
$classes[] = 'mw-textarea-protected';
|
|
|
|
|
}
|
|
|
|
|
# Is the title cascade-protected?
|
|
|
|
|
if ( $this->mTitle->isCascadeProtected() ) {
|
|
|
|
|
$classes[] = 'mw-textarea-cprotected';
|
|
|
|
|
}
|
2009-12-02 07:22:29 +00:00
|
|
|
}
|
2011-12-30 21:30:04 +00:00
|
|
|
|
|
|
|
|
$attribs = array( 'tabindex' => 1 );
|
|
|
|
|
|
|
|
|
|
if ( is_array( $customAttribs ) ) {
|
|
|
|
|
$attribs += $customAttribs;
|
2011-05-19 19:48:50 +00:00
|
|
|
}
|
2009-10-23 11:08:08 +00:00
|
|
|
|
2011-12-30 21:30:04 +00:00
|
|
|
if ( count( $classes ) ) {
|
|
|
|
|
if ( isset( $attribs['class'] ) ) {
|
|
|
|
|
$classes[] = $attribs['class'];
|
|
|
|
|
}
|
|
|
|
|
$attribs['class'] = implode( ' ', $classes );
|
|
|
|
|
}
|
2009-12-02 07:22:29 +00:00
|
|
|
}
|
2010-07-20 15:50:25 +00:00
|
|
|
|
2011-12-30 21:30:04 +00:00
|
|
|
$this->showTextbox( $textoverride !== null ? $textoverride : $this->textbox1, 'wpTextbox1', $attribs );
|
2008-08-27 05:56:34 +00:00
|
|
|
}
|
2009-10-23 11:08:08 +00:00
|
|
|
|
2008-08-27 05:56:34 +00:00
|
|
|
protected function showTextbox2() {
|
2011-05-14 22:57:55 +00:00
|
|
|
$this->showTextbox( $this->textbox2, 'wpTextbox2', array( 'tabindex' => 6, 'readonly' ) );
|
2008-08-27 05:56:34 +00:00
|
|
|
}
|
2009-10-23 11:08:08 +00:00
|
|
|
|
2009-12-02 07:22:29 +00:00
|
|
|
protected function showTextbox( $content, $name, $customAttribs = array() ) {
|
2008-08-27 05:56:34 +00:00
|
|
|
global $wgOut, $wgUser;
|
2009-10-23 11:08:08 +00:00
|
|
|
|
2008-08-27 05:56:34 +00:00
|
|
|
$wikitext = $this->safeUnicodeOutput( $content );
|
2012-02-16 16:09:08 +00:00
|
|
|
if ( strval( $wikitext ) !== '' ) {
|
2008-08-27 05:56:34 +00:00
|
|
|
// Ensure there's a newline at the end, otherwise adding lines
|
|
|
|
|
// is awkward.
|
|
|
|
|
// But don't add a newline if the ext is empty, or Firefox in XHTML
|
|
|
|
|
// mode will show an extra newline. A bit annoying.
|
|
|
|
|
$wikitext .= "\n";
|
|
|
|
|
}
|
2009-10-23 11:08:08 +00:00
|
|
|
|
2009-12-02 07:22:29 +00:00
|
|
|
$attribs = $customAttribs + array(
|
|
|
|
|
'accesskey' => ',',
|
|
|
|
|
'id' => $name,
|
2012-01-25 18:26:46 +00:00
|
|
|
'cols' => $wgUser->getIntOption( 'cols' ),
|
2009-12-02 07:22:29 +00:00
|
|
|
'rows' => $wgUser->getIntOption( 'rows' ),
|
2010-04-15 18:11:24 +00:00
|
|
|
'style' => '' // avoid php notices when appending preferences (appending allows customAttribs['style'] to still work
|
2009-12-02 07:22:29 +00:00
|
|
|
);
|
2009-10-23 11:08:08 +00:00
|
|
|
|
2011-07-06 02:26:06 +00:00
|
|
|
$pageLang = $this->mTitle->getPageLanguage();
|
|
|
|
|
$attribs['lang'] = $pageLang->getCode();
|
|
|
|
|
$attribs['dir'] = $pageLang->getDir();
|
2011-06-17 21:48:43 +00:00
|
|
|
|
2009-12-02 07:22:29 +00:00
|
|
|
$wgOut->addHTML( Html::textarea( $name, $wikitext, $attribs ) );
|
|
|
|
|
}
|
2006-02-20 21:18:11 +00:00
|
|
|
|
2008-08-27 14:47:41 +00:00
|
|
|
protected function displayPreviewArea( $previewOutput, $isOnTop = false ) {
|
2008-08-27 05:56:34 +00:00
|
|
|
global $wgOut;
|
2008-08-29 13:46:06 +00:00
|
|
|
$classes = array();
|
2008-09-16 04:59:49 +00:00
|
|
|
if ( $isOnTop )
|
2008-08-29 13:46:06 +00:00
|
|
|
$classes[] = 'ontop';
|
|
|
|
|
|
|
|
|
|
$attribs = array( 'id' => 'wikiPreview', 'class' => implode( ' ', $classes ) );
|
|
|
|
|
|
2008-09-16 04:59:49 +00:00
|
|
|
if ( $this->formtype != 'preview' )
|
2008-08-29 13:46:06 +00:00
|
|
|
$attribs['style'] = 'display: none;';
|
|
|
|
|
|
2008-08-28 21:16:46 +00:00
|
|
|
$wgOut->addHTML( Xml::openElement( 'div', $attribs ) );
|
2008-08-29 13:46:06 +00:00
|
|
|
|
2008-09-16 04:59:49 +00:00
|
|
|
if ( $this->formtype == 'preview' ) {
|
2008-08-27 05:56:34 +00:00
|
|
|
$this->showPreview( $previewOutput );
|
2008-08-26 14:07:31 +00:00
|
|
|
}
|
2008-08-29 13:46:06 +00:00
|
|
|
|
2008-08-28 21:16:46 +00:00
|
|
|
$wgOut->addHTML( '</div>' );
|
2008-08-26 14:07:31 +00:00
|
|
|
|
2012-02-16 16:09:08 +00:00
|
|
|
if ( $this->formtype == 'diff' ) {
|
2008-08-27 05:56:34 +00:00
|
|
|
$this->showDiff();
|
|
|
|
|
}
|
2011-11-12 13:47:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Append preview output to $wgOut.
|
|
|
|
|
* Includes category rendering if this is a category page.
|
|
|
|
|
*
|
|
|
|
|
* @param $text String: the HTML to be output for the preview.
|
|
|
|
|
*/
|
|
|
|
|
protected function showPreview( $text ) {
|
|
|
|
|
global $wgOut;
|
2012-02-16 16:09:08 +00:00
|
|
|
if ( $this->mTitle->getNamespace() == NS_CATEGORY ) {
|
2011-11-12 13:47:17 +00:00
|
|
|
$this->mArticle->openShowCategory();
|
|
|
|
|
}
|
|
|
|
|
# This hook seems slightly odd here, but makes things more
|
|
|
|
|
# consistent for extensions.
|
2012-02-16 16:09:08 +00:00
|
|
|
wfRunHooks( 'OutputPageBeforeHTML', array( &$wgOut, &$text ) );
|
2011-11-12 13:47:17 +00:00
|
|
|
$wgOut->addHTML( $text );
|
|
|
|
|
if ( $this->mTitle->getNamespace() == NS_CATEGORY ) {
|
|
|
|
|
$this->mArticle->closeShowCategory();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get a diff between the current contents of the edit box and the
|
|
|
|
|
* version of the page we're editing from.
|
|
|
|
|
*
|
|
|
|
|
* If this is a section edit, we'll replace the section as for final
|
|
|
|
|
* save and then make a comparison.
|
|
|
|
|
*/
|
|
|
|
|
function showDiff() {
|
2011-12-26 15:54:10 +00:00
|
|
|
global $wgUser, $wgContLang, $wgParser, $wgOut;
|
2011-11-15 21:46:05 +00:00
|
|
|
|
2012-04-05 19:58:00 +00:00
|
|
|
$oldtitlemsg = 'currentrev';
|
|
|
|
|
# if message does not exist, show diff against the preloaded default
|
|
|
|
|
if( $this->mTitle->getNamespace() == NS_MEDIAWIKI && !$this->mTitle->exists() ) {
|
|
|
|
|
$oldtext = $this->mTitle->getDefaultMessageText();
|
|
|
|
|
if( $oldtext !== false ) {
|
|
|
|
|
$oldtitlemsg = 'defaultmessagetext';
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
$oldtext = $this->mArticle->getRawText();
|
|
|
|
|
}
|
2011-11-12 13:47:17 +00:00
|
|
|
$newtext = $this->mArticle->replaceSection(
|
|
|
|
|
$this->section, $this->textbox1, $this->summary, $this->edittime );
|
|
|
|
|
|
|
|
|
|
wfRunHooks( 'EditPageGetDiffText', array( $this, &$newtext ) );
|
|
|
|
|
|
2011-11-15 21:46:05 +00:00
|
|
|
$popts = ParserOptions::newFromUserAndLang( $wgUser, $wgContLang );
|
|
|
|
|
$newtext = $wgParser->preSaveTransform( $newtext, $this->mTitle, $wgUser, $popts );
|
2011-12-26 15:54:10 +00:00
|
|
|
|
2011-11-12 13:47:17 +00:00
|
|
|
if ( $oldtext !== false || $newtext != '' ) {
|
2012-04-05 19:58:00 +00:00
|
|
|
$oldtitle = wfMsgExt( $oldtitlemsg, array( 'parseinline' ) );
|
2011-12-26 15:54:10 +00:00
|
|
|
$newtitle = wfMsgExt( 'yourtext', array( 'parseinline' ) );
|
|
|
|
|
|
2011-11-12 13:47:17 +00:00
|
|
|
$de = new DifferenceEngine( $this->mArticle->getContext() );
|
|
|
|
|
$de->setText( $oldtext, $newtext );
|
|
|
|
|
$difftext = $de->getDiff( $oldtitle, $newtitle );
|
|
|
|
|
$de->showDiffStyle();
|
|
|
|
|
} else {
|
|
|
|
|
$difftext = '';
|
|
|
|
|
}
|
2006-01-07 13:31:29 +00:00
|
|
|
|
2011-11-12 13:47:17 +00:00
|
|
|
$wgOut->addHTML( '<div id="wikiDiff">' . $difftext . '</div>' );
|
2008-08-28 21:16:46 +00:00
|
|
|
}
|
|
|
|
|
|
2010-03-26 11:21:14 +00:00
|
|
|
/**
|
|
|
|
|
* Give a chance for site and per-namespace customizations of
|
|
|
|
|
* terms of service summary link that might exist separately
|
|
|
|
|
* from the copyright notice.
|
2010-07-20 15:50:25 +00:00
|
|
|
*
|
2010-03-26 11:21:14 +00:00
|
|
|
* This will display between the save button and the edit tools,
|
|
|
|
|
* so should remain short!
|
|
|
|
|
*/
|
2009-06-24 16:49:28 +00:00
|
|
|
protected function showTosSummary() {
|
|
|
|
|
$msg = 'editpage-tos-summary';
|
|
|
|
|
wfRunHooks( 'EditPageTosSummary', array( $this->mTitle, &$msg ) );
|
2012-02-16 16:09:08 +00:00
|
|
|
if ( !wfMessage( $msg )->isDisabled() ) {
|
2009-06-24 16:49:28 +00:00
|
|
|
global $wgOut;
|
|
|
|
|
$wgOut->addHTML( '<div class="mw-tos-summary">' );
|
2011-07-16 19:19:01 +00:00
|
|
|
$wgOut->addWikiMsg( $msg );
|
2009-06-24 16:49:28 +00:00
|
|
|
$wgOut->addHTML( '</div>' );
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-06-30 11:42:51 +00:00
|
|
|
|
2008-08-27 05:56:34 +00:00
|
|
|
protected function showEditTools() {
|
|
|
|
|
global $wgOut;
|
2011-07-16 19:19:01 +00:00
|
|
|
$wgOut->addHTML( '<div class="mw-editTools">' .
|
|
|
|
|
wfMessage( 'edittools' )->inContentLanguage()->parse() .
|
|
|
|
|
'</div>' );
|
2008-08-27 05:56:34 +00:00
|
|
|
}
|
2010-07-20 15:50:25 +00:00
|
|
|
|
2009-12-02 07:22:29 +00:00
|
|
|
protected function getCopywarn() {
|
|
|
|
|
global $wgRightsText;
|
|
|
|
|
if ( $wgRightsText ) {
|
|
|
|
|
$copywarnMsg = array( 'copyrightwarning',
|
|
|
|
|
'[[' . wfMsgForContent( 'copyrightpage' ) . ']]',
|
|
|
|
|
$wgRightsText );
|
|
|
|
|
} else {
|
|
|
|
|
$copywarnMsg = array( 'copyrightwarning2',
|
|
|
|
|
'[[' . wfMsgForContent( 'copyrightpage' ) . ']]' );
|
|
|
|
|
}
|
|
|
|
|
// Allow for site and per-namespace customization of contribution/copyright notice.
|
|
|
|
|
wfRunHooks( 'EditPageCopyrightWarning', array( $this->mTitle, &$copywarnMsg ) );
|
2010-07-20 15:50:25 +00:00
|
|
|
|
2011-02-13 23:20:53 +00:00
|
|
|
return "<div id=\"editpage-copywarn\">\n" .
|
2012-02-16 16:09:08 +00:00
|
|
|
call_user_func_array( "wfMsgNoTrans", $copywarnMsg ) . "\n</div>";
|
2009-12-02 07:22:29 +00:00
|
|
|
}
|
2010-07-20 15:50:25 +00:00
|
|
|
|
2009-12-02 07:22:29 +00:00
|
|
|
protected function showStandardInputs( &$tabindex = 2 ) {
|
2011-07-16 19:19:01 +00:00
|
|
|
global $wgOut;
|
2009-12-02 07:22:29 +00:00
|
|
|
$wgOut->addHTML( "<div class='editOptions'>\n" );
|
|
|
|
|
|
2011-04-25 03:20:17 +00:00
|
|
|
if ( $this->section != 'new' ) {
|
2009-12-02 07:22:29 +00:00
|
|
|
$this->showSummaryInput( false, $this->summary );
|
|
|
|
|
$wgOut->addHTML( $this->getSummaryPreview( false, $this->summary ) );
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-16 19:19:01 +00:00
|
|
|
$checkboxes = $this->getCheckboxes( $tabindex,
|
2009-12-02 07:22:29 +00:00
|
|
|
array( 'minor' => $this->minoredit, 'watch' => $this->watchthis ) );
|
|
|
|
|
$wgOut->addHTML( "<div class='editCheckboxes'>" . implode( $checkboxes, "\n" ) . "</div>\n" );
|
|
|
|
|
$wgOut->addHTML( "<div class='editButtons'>\n" );
|
|
|
|
|
$wgOut->addHTML( implode( $this->getEditButtons( $tabindex ), "\n" ) . "\n" );
|
|
|
|
|
|
|
|
|
|
$cancel = $this->getCancelLink();
|
2011-07-12 15:38:07 +00:00
|
|
|
if ( $cancel !== '' ) {
|
|
|
|
|
$cancel .= wfMsgExt( 'pipe-separator' , 'escapenoentities' );
|
|
|
|
|
}
|
2009-12-02 07:22:29 +00:00
|
|
|
$edithelpurl = Skin::makeInternalOrExternalUrl( wfMsgForContent( 'edithelppage' ) );
|
2012-02-16 16:09:08 +00:00
|
|
|
$edithelp = '<a target="helpwindow" href="' . $edithelpurl . '">' .
|
|
|
|
|
htmlspecialchars( wfMsg( 'edithelp' ) ) . '</a> ' .
|
2009-12-02 07:22:29 +00:00
|
|
|
htmlspecialchars( wfMsg( 'newwindow' ) );
|
2011-07-12 15:38:07 +00:00
|
|
|
$wgOut->addHTML( " <span class='editHelp'>{$cancel}{$edithelp}</span>\n" );
|
2009-12-02 07:22:29 +00:00
|
|
|
$wgOut->addHTML( "</div><!-- editButtons -->\n</div><!-- editOptions -->\n" );
|
|
|
|
|
}
|
2010-04-10 14:11:40 +00:00
|
|
|
|
2011-05-21 19:35:16 +00:00
|
|
|
/**
|
2010-04-10 14:11:40 +00:00
|
|
|
* Show an edit conflict. textbox1 is already shown in showEditForm().
|
|
|
|
|
* If you want to use another entry point to this function, be careful.
|
|
|
|
|
*/
|
2009-12-02 07:22:29 +00:00
|
|
|
protected function showConflict() {
|
|
|
|
|
global $wgOut;
|
2011-12-30 20:43:08 +00:00
|
|
|
|
2009-12-02 07:22:29 +00:00
|
|
|
if ( wfRunHooks( 'EditPageBeforeConflictDiff', array( &$this, &$wgOut ) ) ) {
|
|
|
|
|
$wgOut->wrapWikiMsg( '<h2>$1</h2>', "yourdiff" );
|
|
|
|
|
|
2011-11-10 13:06:52 +00:00
|
|
|
$de = new DifferenceEngine( $this->mArticle->getContext() );
|
2009-12-02 07:22:29 +00:00
|
|
|
$de->setText( $this->textbox2, $this->textbox1 );
|
2011-10-05 14:42:45 +00:00
|
|
|
$de->showDiff( wfMsgExt( 'yourtext', 'parseinline' ), wfMsg( 'storedversion' ) );
|
2009-12-02 07:22:29 +00:00
|
|
|
|
|
|
|
|
$wgOut->wrapWikiMsg( '<h2>$1</h2>', "yourtext" );
|
|
|
|
|
$this->showTextbox2();
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-08-27 05:56:34 +00:00
|
|
|
|
2011-11-12 13:47:17 +00:00
|
|
|
/**
|
|
|
|
|
* @return string
|
|
|
|
|
*/
|
|
|
|
|
public function getCancelLink() {
|
|
|
|
|
$cancelParams = array();
|
2011-12-30 16:12:46 +00:00
|
|
|
if ( !$this->isConflict && $this->oldid > 0 ) {
|
|
|
|
|
$cancelParams['oldid'] = $this->oldid;
|
2011-11-12 13:47:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Linker::linkKnown(
|
|
|
|
|
$this->getContextTitle(),
|
|
|
|
|
wfMsgExt( 'cancel', array( 'parseinline' ) ),
|
|
|
|
|
array( 'id' => 'mw-editform-cancel' ),
|
|
|
|
|
$cancelParams
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns the URL to use in the form's action attribute.
|
|
|
|
|
* This is used by EditPage subclasses when simply customizing the action
|
|
|
|
|
* variable in the constructor is not enough. This can be used when the
|
|
|
|
|
* EditPage lives inside of a Special page rather than a custom page action.
|
|
|
|
|
*
|
|
|
|
|
* @param $title Title object for which is being edited (where we go to for &action= links)
|
|
|
|
|
* @return string
|
|
|
|
|
*/
|
|
|
|
|
protected function getActionURL( Title $title ) {
|
|
|
|
|
return $title->getLocalURL( array( 'action' => $this->action ) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check if a page was deleted while the user was editing it, before submit.
|
|
|
|
|
* Note that we rely on the logging table, which hasn't been always there,
|
|
|
|
|
* but that doesn't matter, because this only applies to brand new
|
|
|
|
|
* deletes.
|
|
|
|
|
*/
|
|
|
|
|
protected function wasDeletedSinceLastEdit() {
|
|
|
|
|
if ( $this->deletedSinceEdit !== null ) {
|
|
|
|
|
return $this->deletedSinceEdit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->deletedSinceEdit = false;
|
|
|
|
|
|
|
|
|
|
if ( $this->mTitle->isDeletedQuick() ) {
|
|
|
|
|
$this->lastDelete = $this->getLastDelete();
|
|
|
|
|
if ( $this->lastDelete ) {
|
|
|
|
|
$deleteTime = wfTimestamp( TS_MW, $this->lastDelete->log_timestamp );
|
|
|
|
|
if ( $deleteTime > $this->starttime ) {
|
|
|
|
|
$this->deletedSinceEdit = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $this->deletedSinceEdit;
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-09 09:21:48 +00:00
|
|
|
protected function getLastDelete() {
|
2007-01-22 23:50:42 +00:00
|
|
|
$dbr = wfGetDB( DB_SLAVE );
|
2008-09-16 04:59:49 +00:00
|
|
|
$data = $dbr->selectRow(
|
2005-08-02 20:17:23 +00:00
|
|
|
array( 'logging', 'user' ),
|
|
|
|
|
array( 'log_type',
|
2011-02-12 04:06:22 +00:00
|
|
|
'log_action',
|
|
|
|
|
'log_timestamp',
|
|
|
|
|
'log_user',
|
|
|
|
|
'log_namespace',
|
|
|
|
|
'log_title',
|
|
|
|
|
'log_comment',
|
|
|
|
|
'log_params',
|
|
|
|
|
'log_deleted',
|
|
|
|
|
'user_name' ),
|
2007-11-01 17:56:19 +00:00
|
|
|
array( 'log_namespace' => $this->mTitle->getNamespace(),
|
2011-02-12 04:06:22 +00:00
|
|
|
'log_title' => $this->mTitle->getDBkey(),
|
|
|
|
|
'log_type' => 'delete',
|
|
|
|
|
'log_action' => 'delete',
|
|
|
|
|
'user_id=log_user' ),
|
2008-09-16 04:59:49 +00:00
|
|
|
__METHOD__,
|
2009-03-09 09:21:48 +00:00
|
|
|
array( 'LIMIT' => 1, 'ORDER BY' => 'log_timestamp DESC' )
|
|
|
|
|
);
|
|
|
|
|
// Quick paranoid permission checks...
|
2012-02-16 16:09:08 +00:00
|
|
|
if ( is_object( $data ) ) {
|
|
|
|
|
if ( $data->log_deleted & LogPage::DELETED_USER )
|
2009-10-25 15:02:33 +00:00
|
|
|
$data->user_name = wfMsgHtml( 'rev-deleted-user' );
|
2012-02-16 16:09:08 +00:00
|
|
|
if ( $data->log_deleted & LogPage::DELETED_COMMENT )
|
2009-10-25 15:02:33 +00:00
|
|
|
$data->log_comment = wfMsgHtml( 'rev-deleted-comment' );
|
2009-03-09 09:21:48 +00:00
|
|
|
}
|
2005-08-02 20:17:23 +00:00
|
|
|
return $data;
|
|
|
|
|
}
|
|
|
|
|
|
2005-03-19 12:01:57 +00:00
|
|
|
/**
|
2008-08-02 02:39:09 +00:00
|
|
|
* Get the rendered text for previewing.
|
|
|
|
|
* @return string
|
2005-03-19 12:01:57 +00:00
|
|
|
*/
|
2005-08-20 06:57:21 +00:00
|
|
|
function getPreviewText() {
|
2012-04-16 19:39:50 +00:00
|
|
|
global $wgOut, $wgUser, $wgParser, $wgRawHtml, $wgLang;
|
2005-08-21 04:45:28 +00:00
|
|
|
|
2008-08-27 05:56:34 +00:00
|
|
|
wfProfileIn( __METHOD__ );
|
2005-08-21 04:45:28 +00:00
|
|
|
|
2011-11-15 21:46:05 +00:00
|
|
|
if ( $wgRawHtml && !$this->mTokenOk ) {
|
|
|
|
|
// Could be an offsite preview attempt. This is very unsafe if
|
|
|
|
|
// HTML is enabled, as it could be an attack.
|
|
|
|
|
$parsedNote = '';
|
|
|
|
|
if ( $this->textbox1 !== '' ) {
|
|
|
|
|
// Do not put big scary notice, if previewing the empty
|
|
|
|
|
// string, which happens when you initially edit
|
|
|
|
|
// a category page, due to automatic preview-on-open.
|
|
|
|
|
$parsedNote = $wgOut->parse( "<div class='previewnote'>" .
|
|
|
|
|
wfMsg( 'session_fail_preview_html' ) . "</div>", true, /* interface */true );
|
|
|
|
|
}
|
|
|
|
|
wfProfileOut( __METHOD__ );
|
|
|
|
|
return $parsedNote;
|
|
|
|
|
}
|
|
|
|
|
|
2008-09-16 04:59:49 +00:00
|
|
|
if ( $this->mTriedSave && !$this->mTokenOk ) {
|
|
|
|
|
if ( $this->mTokenOkExceptSuffix ) {
|
2007-12-10 06:02:29 +00:00
|
|
|
$note = wfMsg( 'token_suffix_mismatch' );
|
2007-07-01 22:22:16 +00:00
|
|
|
} else {
|
2007-12-10 06:02:29 +00:00
|
|
|
$note = wfMsg( 'session_fail_preview' );
|
2007-07-01 22:22:16 +00:00
|
|
|
}
|
2011-06-17 16:03:52 +00:00
|
|
|
} elseif ( $this->incompleteForm ) {
|
2011-02-14 03:10:08 +00:00
|
|
|
$note = wfMsg( 'edit_form_incomplete' );
|
2006-06-07 08:28:43 +00:00
|
|
|
} else {
|
2012-04-16 19:39:50 +00:00
|
|
|
$note = wfMsg( 'previewnote' ) .
|
2012-04-24 17:54:08 +00:00
|
|
|
' [[#' . self::EDITFORM_ID . '|' . $wgLang->getArrow() . ' ' . wfMsg( 'continue-editing' ) . ']]';
|
2004-12-19 02:36:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$parserOptions = ParserOptions::newFromUser( $wgUser );
|
|
|
|
|
$parserOptions->setEditSection( false );
|
2011-11-15 21:46:05 +00:00
|
|
|
$parserOptions->setTidy( true );
|
2009-01-26 18:02:13 +00:00
|
|
|
$parserOptions->setIsPreview( true );
|
2012-02-16 16:09:08 +00:00
|
|
|
$parserOptions->setIsSectionPreview( !is_null( $this->section ) && $this->section !== '' );
|
2004-12-19 02:36:04 +00:00
|
|
|
|
2011-08-11 17:21:31 +00:00
|
|
|
# don't parse non-wikitext pages, show message about preview
|
2012-04-22 23:56:09 +00:00
|
|
|
if ( $this->mTitle->isCssJsSubpage() || !$this->mTitle->isWikitextPage() ) {
|
2012-02-16 16:09:08 +00:00
|
|
|
if ( $this->mTitle->isCssJsSubpage() ) {
|
2011-08-11 17:21:31 +00:00
|
|
|
$level = 'user';
|
2012-02-16 16:09:08 +00:00
|
|
|
} elseif ( $this->mTitle->isCssOrJsPage() ) {
|
2010-12-11 22:44:42 +00:00
|
|
|
$level = 'site';
|
2011-08-11 17:21:31 +00:00
|
|
|
} else {
|
|
|
|
|
$level = false;
|
2010-12-07 14:53:36 +00:00
|
|
|
}
|
2007-01-13 19:58:40 +00:00
|
|
|
|
2010-12-07 17:25:49 +00:00
|
|
|
# Used messages to make sure grep find them:
|
2010-12-11 22:44:42 +00:00
|
|
|
# Messages: usercsspreview, userjspreview, sitecsspreview, sitejspreview
|
2012-04-22 23:56:09 +00:00
|
|
|
$class = 'mw-code';
|
2012-02-16 16:09:08 +00:00
|
|
|
if ( $level ) {
|
|
|
|
|
if ( preg_match( "/\\.css$/", $this->mTitle->getText() ) ) {
|
2011-08-11 17:21:31 +00:00
|
|
|
$previewtext = "<div id='mw-{$level}csspreview'>\n" . wfMsg( "{$level}csspreview" ) . "\n</div>";
|
2012-04-22 23:56:09 +00:00
|
|
|
$class .= " mw-css";
|
2012-02-16 16:09:08 +00:00
|
|
|
} elseif ( preg_match( "/\\.js$/", $this->mTitle->getText() ) ) {
|
2011-08-11 17:21:31 +00:00
|
|
|
$previewtext = "<div id='mw-{$level}jspreview'>\n" . wfMsg( "{$level}jspreview" ) . "\n</div>";
|
2012-04-22 23:56:09 +00:00
|
|
|
$class .= " mw-js";
|
2011-08-11 17:21:31 +00:00
|
|
|
} else {
|
|
|
|
|
throw new MWException( 'A CSS/JS (sub)page but which is not css nor js!' );
|
|
|
|
|
}
|
2012-04-22 23:56:09 +00:00
|
|
|
$parserOutput = $wgParser->parse( $previewtext, $this->mTitle, $parserOptions );
|
|
|
|
|
$previewHTML = $parserOutput->getText();
|
|
|
|
|
} else {
|
|
|
|
|
$previewHTML = '';
|
2004-12-19 02:36:04 +00:00
|
|
|
}
|
2010-12-07 14:53:36 +00:00
|
|
|
|
|
|
|
|
$previewHTML .= "<pre class=\"$class\" dir=\"ltr\">\n" . htmlspecialchars( $this->textbox1 ) . "\n</pre>\n";
|
2004-12-19 02:36:04 +00:00
|
|
|
} else {
|
2012-02-10 19:46:38 +00:00
|
|
|
$toparse = $this->textbox1;
|
2006-01-07 13:31:29 +00:00
|
|
|
|
2012-02-10 19:46:38 +00:00
|
|
|
# If we're adding a comment, we need to show the
|
|
|
|
|
# summary as the headline
|
|
|
|
|
if ( $this->section == "new" && $this->summary != "" ) {
|
|
|
|
|
$toparse = wfMsgForContent( 'newsectionheaderdefaultlevel', $this->summary ) . "\n\n" . $toparse;
|
|
|
|
|
}
|
2006-01-07 13:31:29 +00:00
|
|
|
|
2012-02-10 19:46:38 +00:00
|
|
|
wfRunHooks( 'EditPageGetPreviewText', array( $this, &$toparse ) );
|
2008-03-07 14:02:12 +00:00
|
|
|
|
2012-02-10 19:46:38 +00:00
|
|
|
$parserOptions->enableLimitReport();
|
2011-11-15 21:46:05 +00:00
|
|
|
|
2012-02-10 19:46:38 +00:00
|
|
|
$toparse = $wgParser->preSaveTransform( $toparse, $this->mTitle, $wgUser, $parserOptions );
|
|
|
|
|
$parserOutput = $wgParser->parse( $toparse, $this->mTitle, $parserOptions );
|
2005-08-02 13:35:19 +00:00
|
|
|
|
2012-02-10 19:46:38 +00:00
|
|
|
$rt = Title::newFromRedirectArray( $this->textbox1 );
|
|
|
|
|
if ( $rt ) {
|
|
|
|
|
$previewHTML = $this->mArticle->viewRedirect( $rt, false );
|
|
|
|
|
} else {
|
2010-11-01 00:07:17 +00:00
|
|
|
$previewHTML = $parserOutput->getText();
|
2012-02-10 19:46:38 +00:00
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2012-02-10 19:46:38 +00:00
|
|
|
$this->mParserOutput = $parserOutput;
|
|
|
|
|
$wgOut->addParserOutputNoText( $parserOutput );
|
|
|
|
|
|
|
|
|
|
if ( count( $parserOutput->getWarnings() ) ) {
|
|
|
|
|
$note .= "\n\n" . implode( "\n\n", $parserOutput->getWarnings() );
|
2007-12-10 06:02:29 +00:00
|
|
|
}
|
2004-12-19 02:36:04 +00:00
|
|
|
}
|
2007-12-10 06:02:29 +00:00
|
|
|
|
2012-02-16 16:09:08 +00:00
|
|
|
if ( $this->isConflict ) {
|
2009-05-17 17:55:15 +00:00
|
|
|
$conflict = '<h2 id="mw-previewconflict">' . htmlspecialchars( wfMsg( 'previewconflict' ) ) . "</h2>\n";
|
|
|
|
|
} else {
|
|
|
|
|
$conflict = '<hr />';
|
2007-12-10 06:02:29 +00:00
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2009-05-17 17:55:15 +00:00
|
|
|
$previewhead = "<div class='previewnote'>\n" .
|
|
|
|
|
'<h2 id="mw-previewheader">' . htmlspecialchars( wfMsg( 'preview' ) ) . "</h2>" .
|
2011-09-04 21:19:18 +00:00
|
|
|
$wgOut->parse( $note, true, /* interface */true ) . $conflict . "</div>\n";
|
2009-05-17 17:55:15 +00:00
|
|
|
|
2011-07-06 02:26:06 +00:00
|
|
|
$pageLang = $this->mTitle->getPageLanguage();
|
|
|
|
|
$attribs = array( 'lang' => $pageLang->getCode(), 'dir' => $pageLang->getDir(),
|
2012-02-16 16:09:08 +00:00
|
|
|
'class' => 'mw-content-' . $pageLang->getDir() );
|
2011-07-06 02:26:06 +00:00
|
|
|
$previewHTML = Html::rawElement( 'div', $attribs, $previewHTML );
|
|
|
|
|
|
2011-06-18 14:01:12 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2009-10-22 13:54:36 +00:00
|
|
|
return $previewhead . $previewHTML . $this->previewTextAfterContent;
|
2008-08-27 05:56:34 +00:00
|
|
|
}
|
2009-10-23 11:08:08 +00:00
|
|
|
|
2011-05-26 19:52:56 +00:00
|
|
|
/**
|
|
|
|
|
* @return Array
|
|
|
|
|
*/
|
2008-08-27 05:56:34 +00:00
|
|
|
function getTemplates() {
|
2008-09-16 04:59:49 +00:00
|
|
|
if ( $this->preview || $this->section != '' ) {
|
2008-08-27 05:56:34 +00:00
|
|
|
$templates = array();
|
2011-05-26 19:52:56 +00:00
|
|
|
if ( !isset( $this->mParserOutput ) ) {
|
|
|
|
|
return $templates;
|
|
|
|
|
}
|
2012-02-16 16:09:08 +00:00
|
|
|
foreach ( $this->mParserOutput->getTemplates() as $ns => $template ) {
|
|
|
|
|
foreach ( array_keys( $template ) as $dbk ) {
|
|
|
|
|
$templates[] = Title::makeTitle( $ns, $dbk );
|
2011-11-12 13:47:17 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $templates;
|
|
|
|
|
} else {
|
2011-12-29 15:12:00 +00:00
|
|
|
return $this->mTitle->getTemplateLinksFrom();
|
2011-11-12 13:47:17 +00:00
|
|
|
}
|
2004-10-26 05:44:54 +00:00
|
|
|
}
|
2004-11-25 13:52:56 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Shows a bulletin board style toolbar for common editing functions.
|
|
|
|
|
* It can be disabled in the user preferences.
|
2008-06-09 17:53:04 +00:00
|
|
|
* The necessary JavaScript code can be found in skins/common/edit.js.
|
2009-10-23 11:08:08 +00:00
|
|
|
*
|
2008-06-09 14:17:16 +00:00
|
|
|
* @return string
|
2004-11-25 13:52:56 +00:00
|
|
|
*/
|
2008-06-09 14:17:16 +00:00
|
|
|
static function getEditToolbar() {
|
2010-09-04 04:00:09 +00:00
|
|
|
global $wgStylePath, $wgContLang, $wgLang, $wgOut;
|
2010-09-29 23:27:26 +00:00
|
|
|
global $wgUseTeX, $wgEnableUploads, $wgForeignFileRepos;
|
|
|
|
|
|
|
|
|
|
$imagesAvailable = $wgEnableUploads || count( $wgForeignFileRepos );
|
2004-11-25 13:52:56 +00:00
|
|
|
|
|
|
|
|
/**
|
2011-02-17 18:41:44 +00:00
|
|
|
* $toolarray is an array of arrays each of which includes the
|
|
|
|
|
* filename of the button image (without path), the opening
|
|
|
|
|
* tag, the closing tag, optionally a sample text that is
|
|
|
|
|
* inserted between the two when no selection is highlighted
|
2011-07-20 23:51:52 +00:00
|
|
|
* and. The tip text is shown when the user moves the mouse
|
|
|
|
|
* over the button.
|
2004-11-25 13:52:56 +00:00
|
|
|
*
|
2011-02-17 18:41:44 +00:00
|
|
|
* Also here: accesskeys (key), which are not used yet until
|
|
|
|
|
* someone can figure out a way to make them work in
|
|
|
|
|
* IE. However, we should make sure these keys are not defined
|
|
|
|
|
* on the edit page.
|
2004-11-25 13:52:56 +00:00
|
|
|
*/
|
2007-02-19 11:46:52 +00:00
|
|
|
$toolarray = array(
|
2008-07-04 10:34:41 +00:00
|
|
|
array(
|
2010-07-20 15:12:29 +00:00
|
|
|
'image' => $wgLang->getImageFile( 'button-bold' ),
|
|
|
|
|
'id' => 'mw-editbutton-bold',
|
|
|
|
|
'open' => '\'\'\'',
|
|
|
|
|
'close' => '\'\'\'',
|
2009-10-25 15:02:33 +00:00
|
|
|
'sample' => wfMsg( 'bold_sample' ),
|
2010-07-20 15:12:29 +00:00
|
|
|
'tip' => wfMsg( 'bold_tip' ),
|
|
|
|
|
'key' => 'B'
|
2007-02-19 11:46:52 +00:00
|
|
|
),
|
2008-07-04 10:34:41 +00:00
|
|
|
array(
|
2010-07-20 15:12:29 +00:00
|
|
|
'image' => $wgLang->getImageFile( 'button-italic' ),
|
|
|
|
|
'id' => 'mw-editbutton-italic',
|
|
|
|
|
'open' => '\'\'',
|
|
|
|
|
'close' => '\'\'',
|
2009-10-25 15:02:33 +00:00
|
|
|
'sample' => wfMsg( 'italic_sample' ),
|
2010-07-20 15:12:29 +00:00
|
|
|
'tip' => wfMsg( 'italic_tip' ),
|
|
|
|
|
'key' => 'I'
|
2007-02-19 11:46:52 +00:00
|
|
|
),
|
2008-07-04 10:34:41 +00:00
|
|
|
array(
|
2010-07-20 15:12:29 +00:00
|
|
|
'image' => $wgLang->getImageFile( 'button-link' ),
|
|
|
|
|
'id' => 'mw-editbutton-link',
|
|
|
|
|
'open' => '[[',
|
|
|
|
|
'close' => ']]',
|
2009-10-25 15:02:33 +00:00
|
|
|
'sample' => wfMsg( 'link_sample' ),
|
2010-07-20 15:12:29 +00:00
|
|
|
'tip' => wfMsg( 'link_tip' ),
|
|
|
|
|
'key' => 'L'
|
2007-02-19 11:46:52 +00:00
|
|
|
),
|
2008-07-04 10:34:41 +00:00
|
|
|
array(
|
2010-07-20 15:12:29 +00:00
|
|
|
'image' => $wgLang->getImageFile( 'button-extlink' ),
|
|
|
|
|
'id' => 'mw-editbutton-extlink',
|
|
|
|
|
'open' => '[',
|
|
|
|
|
'close' => ']',
|
2009-10-25 15:02:33 +00:00
|
|
|
'sample' => wfMsg( 'extlink_sample' ),
|
2010-07-20 15:12:29 +00:00
|
|
|
'tip' => wfMsg( 'extlink_tip' ),
|
|
|
|
|
'key' => 'X'
|
2007-02-19 11:46:52 +00:00
|
|
|
),
|
2008-07-04 10:34:41 +00:00
|
|
|
array(
|
2010-07-20 15:12:29 +00:00
|
|
|
'image' => $wgLang->getImageFile( 'button-headline' ),
|
|
|
|
|
'id' => 'mw-editbutton-headline',
|
|
|
|
|
'open' => "\n== ",
|
|
|
|
|
'close' => " ==\n",
|
2009-10-25 15:02:33 +00:00
|
|
|
'sample' => wfMsg( 'headline_sample' ),
|
2010-07-20 15:12:29 +00:00
|
|
|
'tip' => wfMsg( 'headline_tip' ),
|
|
|
|
|
'key' => 'H'
|
2007-02-19 11:46:52 +00:00
|
|
|
),
|
2010-09-29 23:27:26 +00:00
|
|
|
$imagesAvailable ? array(
|
2010-07-20 15:12:29 +00:00
|
|
|
'image' => $wgLang->getImageFile( 'button-image' ),
|
|
|
|
|
'id' => 'mw-editbutton-image',
|
|
|
|
|
'open' => '[[' . $wgContLang->getNsText( NS_FILE ) . ':',
|
|
|
|
|
'close' => ']]',
|
2009-10-25 15:02:33 +00:00
|
|
|
'sample' => wfMsg( 'image_sample' ),
|
2010-07-20 15:12:29 +00:00
|
|
|
'tip' => wfMsg( 'image_tip' ),
|
2011-02-17 18:41:44 +00:00
|
|
|
'key' => 'D',
|
2010-09-29 23:27:26 +00:00
|
|
|
) : false,
|
|
|
|
|
$imagesAvailable ? array(
|
2010-07-20 15:12:29 +00:00
|
|
|
'image' => $wgLang->getImageFile( 'button-media' ),
|
|
|
|
|
'id' => 'mw-editbutton-media',
|
|
|
|
|
'open' => '[[' . $wgContLang->getNsText( NS_MEDIA ) . ':',
|
|
|
|
|
'close' => ']]',
|
2009-10-25 15:02:33 +00:00
|
|
|
'sample' => wfMsg( 'media_sample' ),
|
2010-07-20 15:12:29 +00:00
|
|
|
'tip' => wfMsg( 'media_tip' ),
|
|
|
|
|
'key' => 'M'
|
2010-09-29 23:27:26 +00:00
|
|
|
) : false,
|
2012-02-16 16:09:08 +00:00
|
|
|
$wgUseTeX ? array(
|
2010-07-20 15:12:29 +00:00
|
|
|
'image' => $wgLang->getImageFile( 'button-math' ),
|
|
|
|
|
'id' => 'mw-editbutton-math',
|
|
|
|
|
'open' => "<math>",
|
|
|
|
|
'close' => "</math>",
|
2009-10-25 15:02:33 +00:00
|
|
|
'sample' => wfMsg( 'math_sample' ),
|
2010-07-20 15:12:29 +00:00
|
|
|
'tip' => wfMsg( 'math_tip' ),
|
|
|
|
|
'key' => 'C'
|
2010-09-29 23:27:26 +00:00
|
|
|
) : false,
|
2008-07-04 10:34:41 +00:00
|
|
|
array(
|
2010-07-20 15:12:29 +00:00
|
|
|
'image' => $wgLang->getImageFile( 'button-nowiki' ),
|
|
|
|
|
'id' => 'mw-editbutton-nowiki',
|
|
|
|
|
'open' => "<nowiki>",
|
|
|
|
|
'close' => "</nowiki>",
|
2009-10-25 15:02:33 +00:00
|
|
|
'sample' => wfMsg( 'nowiki_sample' ),
|
2010-07-20 15:12:29 +00:00
|
|
|
'tip' => wfMsg( 'nowiki_tip' ),
|
|
|
|
|
'key' => 'N'
|
2007-02-19 11:46:52 +00:00
|
|
|
),
|
2008-07-04 10:34:41 +00:00
|
|
|
array(
|
2010-07-20 15:12:29 +00:00
|
|
|
'image' => $wgLang->getImageFile( 'button-sig' ),
|
|
|
|
|
'id' => 'mw-editbutton-signature',
|
|
|
|
|
'open' => '--~~~~',
|
|
|
|
|
'close' => '',
|
2008-07-04 10:34:41 +00:00
|
|
|
'sample' => '',
|
2010-07-20 15:12:29 +00:00
|
|
|
'tip' => wfMsg( 'sig_tip' ),
|
|
|
|
|
'key' => 'Y'
|
2007-02-19 11:46:52 +00:00
|
|
|
),
|
2008-07-04 10:34:41 +00:00
|
|
|
array(
|
2010-07-20 15:12:29 +00:00
|
|
|
'image' => $wgLang->getImageFile( 'button-hr' ),
|
|
|
|
|
'id' => 'mw-editbutton-hr',
|
|
|
|
|
'open' => "\n----\n",
|
|
|
|
|
'close' => '',
|
2008-07-04 10:34:41 +00:00
|
|
|
'sample' => '',
|
2010-07-20 15:12:29 +00:00
|
|
|
'tip' => wfMsg( 'hr_tip' ),
|
|
|
|
|
'key' => 'R'
|
2007-02-19 11:46:52 +00:00
|
|
|
)
|
2004-11-25 13:52:56 +00:00
|
|
|
);
|
|
|
|
|
|
2012-01-06 01:38:26 +00:00
|
|
|
$script = 'mw.loader.using("mediawiki.action.edit", function() {';
|
2009-08-11 00:09:24 +00:00
|
|
|
foreach ( $toolarray as $tool ) {
|
2010-11-25 22:22:53 +00:00
|
|
|
if ( !$tool ) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2010-09-29 23:27:26 +00:00
|
|
|
|
2008-03-03 01:53:45 +00:00
|
|
|
$params = array(
|
2009-10-25 15:02:33 +00:00
|
|
|
$image = $wgStylePath . '/common/images/' . $tool['image'],
|
2008-03-03 01:53:45 +00:00
|
|
|
// Note that we use the tip both for the ALT tag and the TITLE tag of the image.
|
|
|
|
|
// Older browsers show a "speedtip" type message only for ALT.
|
|
|
|
|
// Ideally these should be different, realistically they
|
|
|
|
|
// probably don't need to be.
|
|
|
|
|
$tip = $tool['tip'],
|
|
|
|
|
$open = $tool['open'],
|
|
|
|
|
$close = $tool['close'],
|
|
|
|
|
$sample = $tool['sample'],
|
|
|
|
|
$cssId = $tool['id'],
|
|
|
|
|
);
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2011-09-28 22:47:05 +00:00
|
|
|
$script .= Xml::encodeJsCall( 'mw.toolbar.addButton', $params );
|
2004-11-25 13:52:56 +00:00
|
|
|
}
|
2012-02-16 16:09:08 +00:00
|
|
|
|
2012-01-06 01:38:26 +00:00
|
|
|
// This used to be called on DOMReady from mediawiki.action.edit, which
|
|
|
|
|
// ended up causing race conditions with the setup code above.
|
|
|
|
|
$script .= "\n" .
|
|
|
|
|
"// Create button bar\n" .
|
|
|
|
|
"$(function() { mw.toolbar.init(); } );\n";
|
|
|
|
|
|
|
|
|
|
$script .= '});';
|
2011-09-28 22:47:05 +00:00
|
|
|
$wgOut->addScript( Html::inlineScript( ResourceLoader::makeLoaderConditionalScript( $script ) ) );
|
2011-02-12 04:06:22 +00:00
|
|
|
|
2011-09-28 22:47:05 +00:00
|
|
|
$toolbar = '<div id="toolbar"></div>';
|
here it is ... the upload-api, script-server, js2 (javascript phase2) branch merge 1st attempt.
Here is a short overview of changes and associated default configuration variables (most everything is off by default) also see ~soon to be updated~: http://www.mediawiki.org/wiki/Media_Projects_Overview
= Upload Improvements =
==Upload API ==
* Based on the early work of Bryan Tong and others it adds the upload option to the api.
* We rewrite Special:Upload page to include use the new refactoring
* Added in token checks in both the SpecialUpload.php page so avoids DOS / xss copy-by-url JavaScript based cross site POST file submissions
== Copy by URL==
$wgAllowCopyUploads = false;
* http class rewrite includes a new http background download see: includes/HttpFunctions.php
* spins off a php process that calls: maintenance/http_session_download.php
* pushes updates to the session and gives the user a progress bar on http copy uploads from other server progress (using js2 upload interface) (if not using the js2 upload interface it does the request in-place but the download is limited to the php ini timeout time)
== Firefogg ==
* Firefogg enables resumable upload by chunks
* progress indicators and conditional invokation (js2 system)
* and of-course client side transcoding.
= Script Server =
$wgEnableScriptLoader = false;
* off by default if $wgEnableScriptLoader is turned on script files are grouped, gziped, cached etc.
for more info see: http://www.mediawiki.org/wiki/Extension:ScriptLoader
* Includes some early skin js include fixes (skin/script system still lots of love)
* Includes a "javascript class autoloader" this is packaged into mwEmbed so that the mwEmbed library can work in stand alone mode (while retaining localization and script serving) (one such application is the make page for firefogg.org : http://www.firefogg.org/make/index.html )
* The file that contains the autojavascript loading classes is: js2/php/jsAutoloadLocalClasses.php
* One can use this auto class loading dependency system with extensions and add-ons but I need to better document that.
= js2 system / mwEmbed=
$wgEnableJS2system = false
* includes initial rewrite towards more jquery based javascript code
* especially for the Special:Upload page.
* Also the edit page include support for the "add-media-wizard"
* includes dependency loader for javascript that optionally takes advantage of the script-loader
* remote embedding of javascript interfaces (like embedding video, or commons media searching)
* $wgDebugJavaScript = false; .. .this variable lets you always get "always fresh javascript". When used with the script-loader it does not minify the script-loader output.
= mwEmbed =
* Will commit a separate patch to oggHandler that conditionally outputs <video tag> to use the new javascript video player.
** mv_embed player includes: play-head, volume control, remote embedding, oggz-chop support across plugins.
* add-media-wizard adds easy inserts of media to pages (with import)
== jQuery==
* we include a base install of jQuery, jQuery ui and some plugins.
* all the javascript classes are in the scriptloader so its easy to load any set of jquery ui components that you may need using the script-server. You get a callback so you can then execute js with dependencies loaded.
== other stuff ==
there is a bit more code in js2 that pertains to sequence editing, timed text display and basic image editing. We include a base import of pixastic-lib & pixastic-editor... will work with the pixastic developer to try and ensure upstream compatibility on our usage of the library for in-browser photo and sequence manipulation.
2009-07-14 23:52:14 +00:00
|
|
|
|
2009-05-29 21:40:19 +00:00
|
|
|
wfRunHooks( 'EditPageBeforeEditToolbar', array( &$toolbar ) );
|
here it is ... the upload-api, script-server, js2 (javascript phase2) branch merge 1st attempt.
Here is a short overview of changes and associated default configuration variables (most everything is off by default) also see ~soon to be updated~: http://www.mediawiki.org/wiki/Media_Projects_Overview
= Upload Improvements =
==Upload API ==
* Based on the early work of Bryan Tong and others it adds the upload option to the api.
* We rewrite Special:Upload page to include use the new refactoring
* Added in token checks in both the SpecialUpload.php page so avoids DOS / xss copy-by-url JavaScript based cross site POST file submissions
== Copy by URL==
$wgAllowCopyUploads = false;
* http class rewrite includes a new http background download see: includes/HttpFunctions.php
* spins off a php process that calls: maintenance/http_session_download.php
* pushes updates to the session and gives the user a progress bar on http copy uploads from other server progress (using js2 upload interface) (if not using the js2 upload interface it does the request in-place but the download is limited to the php ini timeout time)
== Firefogg ==
* Firefogg enables resumable upload by chunks
* progress indicators and conditional invokation (js2 system)
* and of-course client side transcoding.
= Script Server =
$wgEnableScriptLoader = false;
* off by default if $wgEnableScriptLoader is turned on script files are grouped, gziped, cached etc.
for more info see: http://www.mediawiki.org/wiki/Extension:ScriptLoader
* Includes some early skin js include fixes (skin/script system still lots of love)
* Includes a "javascript class autoloader" this is packaged into mwEmbed so that the mwEmbed library can work in stand alone mode (while retaining localization and script serving) (one such application is the make page for firefogg.org : http://www.firefogg.org/make/index.html )
* The file that contains the autojavascript loading classes is: js2/php/jsAutoloadLocalClasses.php
* One can use this auto class loading dependency system with extensions and add-ons but I need to better document that.
= js2 system / mwEmbed=
$wgEnableJS2system = false
* includes initial rewrite towards more jquery based javascript code
* especially for the Special:Upload page.
* Also the edit page include support for the "add-media-wizard"
* includes dependency loader for javascript that optionally takes advantage of the script-loader
* remote embedding of javascript interfaces (like embedding video, or commons media searching)
* $wgDebugJavaScript = false; .. .this variable lets you always get "always fresh javascript". When used with the script-loader it does not minify the script-loader output.
= mwEmbed =
* Will commit a separate patch to oggHandler that conditionally outputs <video tag> to use the new javascript video player.
** mv_embed player includes: play-head, volume control, remote embedding, oggz-chop support across plugins.
* add-media-wizard adds easy inserts of media to pages (with import)
== jQuery==
* we include a base install of jQuery, jQuery ui and some plugins.
* all the javascript classes are in the scriptloader so its easy to load any set of jquery ui components that you may need using the script-server. You get a callback so you can then execute js with dependencies loaded.
== other stuff ==
there is a bit more code in js2 that pertains to sequence editing, timed text display and basic image editing. We include a base import of pixastic-lib & pixastic-editor... will work with the pixastic developer to try and ensure upstream compatibility on our usage of the library for in-browser photo and sequence manipulation.
2009-07-14 23:52:14 +00:00
|
|
|
|
2004-11-25 13:52:56 +00:00
|
|
|
return $toolbar;
|
|
|
|
|
}
|
2005-08-02 13:35:19 +00:00
|
|
|
|
2007-02-10 15:30:31 +00:00
|
|
|
/**
|
|
|
|
|
* Returns an array of html code of the following checkboxes:
|
|
|
|
|
* minor and watch
|
|
|
|
|
*
|
2012-02-09 19:30:01 +00:00
|
|
|
* @param $tabindex int Current tabindex
|
2007-02-10 15:30:31 +00:00
|
|
|
* @param $checked Array of checkbox => bool, where bool indicates the checked
|
2010-07-20 15:12:29 +00:00
|
|
|
* status of the checkbox
|
2007-02-10 15:30:31 +00:00
|
|
|
*
|
|
|
|
|
* @return array
|
|
|
|
|
*/
|
2011-07-16 19:19:01 +00:00
|
|
|
public function getCheckboxes( &$tabindex, $checked ) {
|
2007-02-10 15:30:31 +00:00
|
|
|
global $wgUser;
|
|
|
|
|
|
|
|
|
|
$checkboxes = array();
|
|
|
|
|
|
2011-04-23 18:58:03 +00:00
|
|
|
// don't show the minor edit checkbox if it's a new page or section
|
|
|
|
|
if ( !$this->isNew ) {
|
|
|
|
|
$checkboxes['minor'] = '';
|
|
|
|
|
$minorLabel = wfMsgExt( 'minoredit', array( 'parseinline' ) );
|
|
|
|
|
if ( $wgUser->isAllowed( 'minoredit' ) ) {
|
|
|
|
|
$attribs = array(
|
|
|
|
|
'tabindex' => ++$tabindex,
|
|
|
|
|
'accesskey' => wfMsg( 'accesskey-minoredit' ),
|
|
|
|
|
'id' => 'wpMinoredit',
|
|
|
|
|
);
|
|
|
|
|
$checkboxes['minor'] =
|
|
|
|
|
Xml::check( 'wpMinoredit', $checked['minor'], $attribs ) .
|
|
|
|
|
" <label for='wpMinoredit' id='mw-editpage-minoredit'" .
|
2011-07-16 19:19:01 +00:00
|
|
|
Xml::expandAttributes( array( 'title' => Linker::titleAttrib( 'minoredit', 'withaccess' ) ) ) .
|
2011-04-23 18:58:03 +00:00
|
|
|
">{$minorLabel}</label>";
|
|
|
|
|
}
|
2007-02-10 15:30:31 +00:00
|
|
|
}
|
|
|
|
|
|
2009-10-25 15:02:33 +00:00
|
|
|
$watchLabel = wfMsgExt( 'watchthis', array( 'parseinline' ) );
|
2007-02-10 15:30:31 +00:00
|
|
|
$checkboxes['watch'] = '';
|
2008-09-16 04:59:49 +00:00
|
|
|
if ( $wgUser->isLoggedIn() ) {
|
2007-02-10 15:30:31 +00:00
|
|
|
$attribs = array(
|
2010-07-20 15:12:29 +00:00
|
|
|
'tabindex' => ++$tabindex,
|
2007-02-10 15:30:31 +00:00
|
|
|
'accesskey' => wfMsg( 'accesskey-watch' ),
|
2010-07-20 15:12:29 +00:00
|
|
|
'id' => 'wpWatchthis',
|
2007-02-10 15:30:31 +00:00
|
|
|
);
|
|
|
|
|
$checkboxes['watch'] =
|
|
|
|
|
Xml::check( 'wpWatchthis', $checked['watch'], $attribs ) .
|
2010-12-12 18:35:19 +00:00
|
|
|
" <label for='wpWatchthis' id='mw-editpage-watch'" .
|
2011-07-16 19:19:01 +00:00
|
|
|
Xml::expandAttributes( array( 'title' => Linker::titleAttrib( 'watch', 'withaccess' ) ) ) .
|
2010-12-12 18:35:19 +00:00
|
|
|
">{$watchLabel}</label>";
|
2007-02-10 15:30:31 +00:00
|
|
|
}
|
2008-12-20 01:15:40 +00:00
|
|
|
wfRunHooks( 'EditPageBeforeEditChecks', array( &$this, &$checkboxes, &$tabindex ) );
|
2007-02-10 15:30:31 +00:00
|
|
|
return $checkboxes;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns an array of html code of the following buttons:
|
|
|
|
|
* save, diff, preview and live
|
|
|
|
|
*
|
2012-02-09 19:30:01 +00:00
|
|
|
* @param $tabindex int Current tabindex
|
2007-02-10 15:30:31 +00:00
|
|
|
*
|
|
|
|
|
* @return array
|
|
|
|
|
*/
|
2010-11-07 23:17:04 +00:00
|
|
|
public function getEditButtons( &$tabindex ) {
|
2007-02-10 15:30:31 +00:00
|
|
|
$buttons = array();
|
|
|
|
|
|
|
|
|
|
$temp = array(
|
2010-07-20 15:12:29 +00:00
|
|
|
'id' => 'wpSave',
|
|
|
|
|
'name' => 'wpSave',
|
|
|
|
|
'type' => 'submit',
|
|
|
|
|
'tabindex' => ++$tabindex,
|
|
|
|
|
'value' => wfMsg( 'savearticle' ),
|
2009-10-25 15:02:33 +00:00
|
|
|
'accesskey' => wfMsg( 'accesskey-save' ),
|
2012-02-16 16:09:08 +00:00
|
|
|
'title' => wfMsg( 'tooltip-save' ) . ' [' . wfMsg( 'accesskey-save' ) . ']',
|
2007-02-10 15:30:31 +00:00
|
|
|
);
|
2012-02-16 16:09:08 +00:00
|
|
|
$buttons['save'] = Xml::element( 'input', $temp, '' );
|
2007-02-10 15:30:31 +00:00
|
|
|
|
|
|
|
|
++$tabindex; // use the same for preview and live preview
|
2009-11-26 12:00:36 +00:00
|
|
|
$temp = array(
|
2010-07-20 15:12:29 +00:00
|
|
|
'id' => 'wpPreview',
|
|
|
|
|
'name' => 'wpPreview',
|
|
|
|
|
'type' => 'submit',
|
|
|
|
|
'tabindex' => $tabindex,
|
|
|
|
|
'value' => wfMsg( 'showpreview' ),
|
2009-11-26 12:00:36 +00:00
|
|
|
'accesskey' => wfMsg( 'accesskey-preview' ),
|
2010-07-20 15:12:29 +00:00
|
|
|
'title' => wfMsg( 'tooltip-preview' ) . ' [' . wfMsg( 'accesskey-preview' ) . ']',
|
2009-11-26 12:00:36 +00:00
|
|
|
);
|
|
|
|
|
$buttons['preview'] = Xml::element( 'input', $temp, '' );
|
|
|
|
|
$buttons['live'] = '';
|
2007-02-10 15:30:31 +00:00
|
|
|
|
|
|
|
|
$temp = array(
|
2010-07-20 15:12:29 +00:00
|
|
|
'id' => 'wpDiff',
|
|
|
|
|
'name' => 'wpDiff',
|
|
|
|
|
'type' => 'submit',
|
|
|
|
|
'tabindex' => ++$tabindex,
|
|
|
|
|
'value' => wfMsg( 'showdiff' ),
|
2009-10-25 15:02:33 +00:00
|
|
|
'accesskey' => wfMsg( 'accesskey-diff' ),
|
2010-07-20 15:12:29 +00:00
|
|
|
'title' => wfMsg( 'tooltip-diff' ) . ' [' . wfMsg( 'accesskey-diff' ) . ']',
|
2007-02-10 15:30:31 +00:00
|
|
|
);
|
2009-10-25 15:02:33 +00:00
|
|
|
$buttons['diff'] = Xml::element( 'input', $temp, '' );
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2008-12-20 01:15:40 +00:00
|
|
|
wfRunHooks( 'EditPageBeforeEditButtons', array( &$this, &$buttons, &$tabindex ) );
|
2007-02-10 15:30:31 +00:00
|
|
|
return $buttons;
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-17 01:14:00 +00:00
|
|
|
/**
|
|
|
|
|
* Output preview text only. This can be sucked into the edit page
|
|
|
|
|
* via JavaScript, and saves the server time rendering the skin as
|
|
|
|
|
* well as theoretically being more robust on the client (doesn't
|
|
|
|
|
* disturb the edit box's undo history, won't eat your text on
|
|
|
|
|
* failure, etc).
|
|
|
|
|
*
|
|
|
|
|
* @todo This doesn't include category or interlanguage links.
|
2010-07-20 15:12:29 +00:00
|
|
|
* Would need to enhance it a bit, <s>maybe wrap them in XML
|
|
|
|
|
* or something...</s> that might also require more skin
|
|
|
|
|
* initialization, so check whether that's a problem.
|
2009-09-17 01:14:00 +00:00
|
|
|
*/
|
|
|
|
|
function livePreview() {
|
|
|
|
|
global $wgOut;
|
|
|
|
|
$wgOut->disable();
|
|
|
|
|
header( 'Content-type: text/xml; charset=utf-8' );
|
|
|
|
|
header( 'Cache-control: no-cache' );
|
|
|
|
|
|
|
|
|
|
$previewText = $this->getPreviewText();
|
|
|
|
|
#$categories = $skin->getCategoryLinks();
|
|
|
|
|
|
|
|
|
|
$s =
|
|
|
|
|
'<?xml version="1.0" encoding="UTF-8" ?>' . "\n" .
|
|
|
|
|
Xml::tags( 'livepreview', null,
|
|
|
|
|
Xml::element( 'preview', null, $previewText )
|
|
|
|
|
#. Xml::element( 'category', null, $categories )
|
|
|
|
|
);
|
|
|
|
|
echo $s;
|
|
|
|
|
}
|
|
|
|
|
|
2011-06-05 14:46:55 +00:00
|
|
|
/**
|
2011-11-12 13:47:17 +00:00
|
|
|
* Call the stock "user is blocked" page
|
|
|
|
|
*
|
|
|
|
|
* @deprecated in 1.19; throw an exception directly instead
|
2011-06-05 14:46:55 +00:00
|
|
|
*/
|
2011-11-12 13:47:17 +00:00
|
|
|
function blockedPage() {
|
2011-12-13 05:19:05 +00:00
|
|
|
wfDeprecated( __METHOD__, '1.19' );
|
2011-11-12 13:47:17 +00:00
|
|
|
global $wgUser;
|
2010-02-05 15:01:07 +00:00
|
|
|
|
2012-02-16 00:54:34 +00:00
|
|
|
throw new UserBlockedError( $wgUser->getBlock() );
|
2009-12-02 07:22:29 +00:00
|
|
|
}
|
|
|
|
|
|
2005-05-15 11:11:23 +00:00
|
|
|
/**
|
2011-11-12 13:47:17 +00:00
|
|
|
* Produce the stock "please login to edit pages" page
|
2005-05-15 11:11:23 +00:00
|
|
|
*
|
2011-11-12 13:47:17 +00:00
|
|
|
* @deprecated in 1.19; throw an exception directly instead
|
2005-05-15 11:11:23 +00:00
|
|
|
*/
|
2011-11-12 13:47:17 +00:00
|
|
|
function userNotLoggedInPage() {
|
2011-12-13 05:19:05 +00:00
|
|
|
wfDeprecated( __METHOD__, '1.19' );
|
2011-11-12 13:47:17 +00:00
|
|
|
throw new PermissionsError( 'edit' );
|
|
|
|
|
}
|
2010-02-20 17:05:56 +00:00
|
|
|
|
2011-11-12 13:47:17 +00:00
|
|
|
/**
|
|
|
|
|
* Show an error page saying to the user that he has insufficient permissions
|
|
|
|
|
* to create a new page
|
|
|
|
|
*
|
|
|
|
|
* @deprecated in 1.19; throw an exception directly instead
|
|
|
|
|
*/
|
|
|
|
|
function noCreatePermission() {
|
2011-12-13 05:19:05 +00:00
|
|
|
wfDeprecated( __METHOD__, '1.19' );
|
2011-11-12 13:47:17 +00:00
|
|
|
$permission = $this->mTitle->isTalkPage() ? 'createtalk' : 'createpage';
|
|
|
|
|
throw new PermissionsError( $permission );
|
|
|
|
|
}
|
2010-02-20 17:05:56 +00:00
|
|
|
|
2011-11-12 13:47:17 +00:00
|
|
|
/**
|
|
|
|
|
* Creates a basic error page which informs the user that
|
|
|
|
|
* they have attempted to edit a nonexistent section.
|
|
|
|
|
*/
|
|
|
|
|
function noSuchSectionPage() {
|
|
|
|
|
global $wgOut;
|
|
|
|
|
|
|
|
|
|
$wgOut->prepareErrorPage( wfMessage( 'nosuchsectiontitle' ) );
|
|
|
|
|
|
|
|
|
|
$res = wfMsgExt( 'nosuchsectiontext', 'parse', $this->section );
|
|
|
|
|
wfRunHooks( 'EditPageNoSuchSection', array( &$this, &$res ) );
|
|
|
|
|
$wgOut->addHTML( $res );
|
|
|
|
|
|
|
|
|
|
$wgOut->returnToMain( false, $this->mTitle );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Produce the stock "your edit contains spam" page
|
|
|
|
|
*
|
2012-02-09 19:30:01 +00:00
|
|
|
* @param $match string Text which triggered one or more filters
|
2011-11-12 13:47:17 +00:00
|
|
|
* @deprecated since 1.17 Use method spamPageWithContent() instead
|
|
|
|
|
*/
|
|
|
|
|
static function spamPage( $match = false ) {
|
2011-12-13 05:19:05 +00:00
|
|
|
wfDeprecated( __METHOD__, '1.17' );
|
2012-02-16 16:09:08 +00:00
|
|
|
|
2011-11-12 13:47:17 +00:00
|
|
|
global $wgOut, $wgTitle;
|
|
|
|
|
|
|
|
|
|
$wgOut->prepareErrorPage( wfMessage( 'spamprotectiontitle' ) );
|
|
|
|
|
|
|
|
|
|
$wgOut->addHTML( '<div id="spamprotected">' );
|
|
|
|
|
$wgOut->addWikiMsg( 'spamprotectiontext' );
|
|
|
|
|
if ( $match ) {
|
|
|
|
|
$wgOut->addWikiMsg( 'spamprotectionmatch', wfEscapeWikiText( $match ) );
|
2005-05-15 11:11:23 +00:00
|
|
|
}
|
2011-11-12 13:47:17 +00:00
|
|
|
$wgOut->addHTML( '</div>' );
|
2005-08-02 13:35:19 +00:00
|
|
|
|
2011-11-12 13:47:17 +00:00
|
|
|
$wgOut->returnToMain( false, $wgTitle );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Show "your edit contains spam" page with your diff and text
|
|
|
|
|
*
|
2012-03-26 21:50:34 +00:00
|
|
|
* @param $match string|Array|bool Text (or array of texts) which triggered one or more filters
|
2011-11-12 13:47:17 +00:00
|
|
|
*/
|
|
|
|
|
public function spamPageWithContent( $match = false ) {
|
2012-03-26 21:50:34 +00:00
|
|
|
global $wgOut, $wgLang;
|
2011-11-12 13:47:17 +00:00
|
|
|
$this->textbox2 = $this->textbox1;
|
|
|
|
|
|
2012-03-26 21:50:34 +00:00
|
|
|
if( is_array( $match ) ){
|
|
|
|
|
$match = $wgLang->listToText( $match );
|
|
|
|
|
}
|
2011-11-12 13:47:17 +00:00
|
|
|
$wgOut->prepareErrorPage( wfMessage( 'spamprotectiontitle' ) );
|
|
|
|
|
|
|
|
|
|
$wgOut->addHTML( '<div id="spamprotected">' );
|
|
|
|
|
$wgOut->addWikiMsg( 'spamprotectiontext' );
|
|
|
|
|
if ( $match ) {
|
|
|
|
|
$wgOut->addWikiMsg( 'spamprotectionmatch', wfEscapeWikiText( $match ) );
|
|
|
|
|
}
|
|
|
|
|
$wgOut->addHTML( '</div>' );
|
|
|
|
|
|
|
|
|
|
$wgOut->wrapWikiMsg( '<h2>$1</h2>', "yourdiff" );
|
2012-03-08 00:49:50 +00:00
|
|
|
$this->showDiff();
|
2011-11-12 13:47:17 +00:00
|
|
|
|
|
|
|
|
$wgOut->wrapWikiMsg( '<h2>$1</h2>', "yourtext" );
|
|
|
|
|
$this->showTextbox2();
|
|
|
|
|
|
|
|
|
|
$wgOut->addReturnTo( $this->getContextTitle(), array( 'action' => 'edit' ) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Format an anchor fragment as it would appear for a given section name
|
|
|
|
|
* @param $text String
|
|
|
|
|
* @return String
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
|
|
|
|
function sectionAnchor( $text ) {
|
|
|
|
|
global $wgParser;
|
|
|
|
|
return $wgParser->guessSectionNameFromWikiText( $text );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check if the browser is on a blacklist of user-agents known to
|
|
|
|
|
* mangle UTF-8 data on form submission. Returns true if Unicode
|
|
|
|
|
* should make it through, false if it's known to be a problem.
|
|
|
|
|
* @return bool
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
|
|
|
|
function checkUnicodeCompliantBrowser() {
|
|
|
|
|
global $wgBrowserBlackList;
|
|
|
|
|
if ( empty( $_SERVER["HTTP_USER_AGENT"] ) ) {
|
|
|
|
|
// No User-Agent header sent? Trust it by default...
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
$currentbrowser = $_SERVER["HTTP_USER_AGENT"];
|
|
|
|
|
foreach ( $wgBrowserBlackList as $browser ) {
|
2012-02-16 16:09:08 +00:00
|
|
|
if ( preg_match( $browser, $currentbrowser ) ) {
|
2011-11-12 13:47:17 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
2005-05-15 11:11:23 +00:00
|
|
|
}
|
|
|
|
|
|
2005-07-29 10:08:41 +00:00
|
|
|
/**
|
|
|
|
|
* Filter an input field through a Unicode de-armoring process if it
|
|
|
|
|
* came from an old browser with known broken Unicode editing issues.
|
|
|
|
|
*
|
2010-03-17 22:02:43 +00:00
|
|
|
* @param $request WebRequest
|
|
|
|
|
* @param $field String
|
|
|
|
|
* @return String
|
2006-04-19 15:46:24 +00:00
|
|
|
* @private
|
2005-07-29 10:08:41 +00:00
|
|
|
*/
|
|
|
|
|
function safeUnicodeInput( $request, $field ) {
|
|
|
|
|
$text = rtrim( $request->getText( $field ) );
|
|
|
|
|
return $request->getBool( 'safemode' )
|
|
|
|
|
? $this->unmakesafe( $text )
|
|
|
|
|
: $text;
|
|
|
|
|
}
|
2006-01-07 13:31:29 +00:00
|
|
|
|
2011-05-26 19:52:56 +00:00
|
|
|
/**
|
|
|
|
|
* @param $request WebRequest
|
|
|
|
|
* @param $text string
|
|
|
|
|
* @return string
|
|
|
|
|
*/
|
2009-12-02 07:22:29 +00:00
|
|
|
function safeUnicodeText( $request, $text ) {
|
|
|
|
|
$text = rtrim( $text );
|
|
|
|
|
return $request->getBool( 'safemode' )
|
|
|
|
|
? $this->unmakesafe( $text )
|
|
|
|
|
: $text;
|
|
|
|
|
}
|
|
|
|
|
|
2005-07-29 10:08:41 +00:00
|
|
|
/**
|
2005-07-30 08:03:04 +00:00
|
|
|
* Filter an output field through a Unicode armoring process if it is
|
|
|
|
|
* going to an old browser with known broken Unicode editing issues.
|
2005-07-29 10:08:41 +00:00
|
|
|
*
|
2010-03-17 22:02:43 +00:00
|
|
|
* @param $text String
|
|
|
|
|
* @return String
|
2006-04-19 15:46:24 +00:00
|
|
|
* @private
|
2005-07-29 10:08:41 +00:00
|
|
|
*/
|
|
|
|
|
function safeUnicodeOutput( $text ) {
|
|
|
|
|
global $wgContLang;
|
|
|
|
|
$codedText = $wgContLang->recodeForEdit( $text );
|
|
|
|
|
return $this->checkUnicodeCompliantBrowser()
|
|
|
|
|
? $codedText
|
|
|
|
|
: $this->makesafe( $codedText );
|
|
|
|
|
}
|
2006-01-07 13:31:29 +00:00
|
|
|
|
2005-07-29 10:08:41 +00:00
|
|
|
/**
|
|
|
|
|
* A number of web browsers are known to corrupt non-ASCII characters
|
|
|
|
|
* in a UTF-8 text editing environment. To protect against this,
|
|
|
|
|
* detected browsers will be served an armored version of the text,
|
|
|
|
|
* with non-ASCII chars converted to numeric HTML character references.
|
|
|
|
|
*
|
|
|
|
|
* Preexisting such character references will have a 0 added to them
|
|
|
|
|
* to ensure that round-trips do not alter the original data.
|
|
|
|
|
*
|
2010-03-17 22:02:43 +00:00
|
|
|
* @param $invalue String
|
|
|
|
|
* @return String
|
2006-04-19 15:46:24 +00:00
|
|
|
* @private
|
2005-07-29 10:08:41 +00:00
|
|
|
*/
|
|
|
|
|
function makesafe( $invalue ) {
|
|
|
|
|
// Armor existing references for reversability.
|
|
|
|
|
$invalue = strtr( $invalue, array( "&#x" => "�" ) );
|
2006-01-07 13:31:29 +00:00
|
|
|
|
2005-07-29 10:08:41 +00:00
|
|
|
$bytesleft = 0;
|
|
|
|
|
$result = "";
|
|
|
|
|
$working = 0;
|
2012-02-16 16:09:08 +00:00
|
|
|
for ( $i = 0; $i < strlen( $invalue ); $i++ ) {
|
2011-04-17 07:59:58 +00:00
|
|
|
$bytevalue = ord( $invalue[$i] );
|
2012-02-16 16:09:08 +00:00
|
|
|
if ( $bytevalue <= 0x7F ) { // 0xxx xxxx
|
2005-07-29 10:08:41 +00:00
|
|
|
$result .= chr( $bytevalue );
|
|
|
|
|
$bytesleft = 0;
|
2012-02-16 16:09:08 +00:00
|
|
|
} elseif ( $bytevalue <= 0xBF ) { // 10xx xxxx
|
2005-07-29 10:08:41 +00:00
|
|
|
$working = $working << 6;
|
2012-02-16 16:09:08 +00:00
|
|
|
$working += ( $bytevalue & 0x3F );
|
2005-07-29 10:08:41 +00:00
|
|
|
$bytesleft--;
|
2008-09-16 04:59:49 +00:00
|
|
|
if ( $bytesleft <= 0 ) {
|
2005-07-29 10:08:41 +00:00
|
|
|
$result .= "&#x" . strtoupper( dechex( $working ) ) . ";";
|
|
|
|
|
}
|
2012-02-16 16:09:08 +00:00
|
|
|
} elseif ( $bytevalue <= 0xDF ) { // 110x xxxx
|
2005-07-29 10:08:41 +00:00
|
|
|
$working = $bytevalue & 0x1F;
|
|
|
|
|
$bytesleft = 1;
|
2012-02-16 16:09:08 +00:00
|
|
|
} elseif ( $bytevalue <= 0xEF ) { // 1110 xxxx
|
2005-07-29 10:08:41 +00:00
|
|
|
$working = $bytevalue & 0x0F;
|
|
|
|
|
$bytesleft = 2;
|
2012-02-16 16:09:08 +00:00
|
|
|
} else { // 1111 0xxx
|
2005-07-29 10:08:41 +00:00
|
|
|
$working = $bytevalue & 0x07;
|
|
|
|
|
$bytesleft = 3;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $result;
|
|
|
|
|
}
|
2006-01-07 13:31:29 +00:00
|
|
|
|
2005-07-29 10:08:41 +00:00
|
|
|
/**
|
|
|
|
|
* Reverse the previously applied transliteration of non-ASCII characters
|
|
|
|
|
* back to UTF-8. Used to protect data from corruption by broken web browsers
|
|
|
|
|
* as listed in $wgBrowserBlackList.
|
|
|
|
|
*
|
2010-03-17 22:02:43 +00:00
|
|
|
* @param $invalue String
|
|
|
|
|
* @return String
|
2006-04-19 15:46:24 +00:00
|
|
|
* @private
|
2005-07-29 10:08:41 +00:00
|
|
|
*/
|
|
|
|
|
function unmakesafe( $invalue ) {
|
|
|
|
|
$result = "";
|
2012-02-16 16:09:08 +00:00
|
|
|
for ( $i = 0; $i < strlen( $invalue ); $i++ ) {
|
|
|
|
|
if ( ( substr( $invalue, $i, 3 ) == "&#x" ) && ( $invalue[$i + 3] != '0' ) ) {
|
2005-07-29 10:08:41 +00:00
|
|
|
$i += 3;
|
|
|
|
|
$hexstring = "";
|
|
|
|
|
do {
|
2011-04-17 07:59:58 +00:00
|
|
|
$hexstring .= $invalue[$i];
|
2005-07-29 10:08:41 +00:00
|
|
|
$i++;
|
2012-02-16 16:09:08 +00:00
|
|
|
} while ( ctype_xdigit( $invalue[$i] ) && ( $i < strlen( $invalue ) ) );
|
2006-01-07 13:31:29 +00:00
|
|
|
|
2005-07-29 10:08:41 +00:00
|
|
|
// Do some sanity checks. These aren't needed for reversability,
|
2006-01-07 13:09:30 +00:00
|
|
|
// but should help keep the breakage down if the editor
|
2005-07-29 10:08:41 +00:00
|
|
|
// breaks one of the entities whilst editing.
|
2012-02-16 16:09:08 +00:00
|
|
|
if ( ( substr( $invalue, $i, 1 ) == ";" ) and ( strlen( $hexstring ) <= 6 ) ) {
|
|
|
|
|
$codepoint = hexdec( $hexstring );
|
2005-07-29 10:08:41 +00:00
|
|
|
$result .= codepointToUtf8( $codepoint );
|
|
|
|
|
} else {
|
|
|
|
|
$result .= "&#x" . $hexstring . substr( $invalue, $i, 1 );
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
$result .= substr( $invalue, $i, 1 );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// reverse the transform that we made for reversability reasons.
|
|
|
|
|
return strtr( $result, array( "�" => "&#x" ) );
|
|
|
|
|
}
|
2003-08-02 20:43:11 +00:00
|
|
|
}
|