mediawiki-extensions-Visual.../VisualEditor.php

388 lines
12 KiB
PHP
Raw Normal View History

2011-11-28 20:28:28 +00:00
<?php
/**
* VisualEditor extension
*
2011-11-28 20:28:28 +00:00
* @file
* @ingroup Extensions
* @copyright 2011-2012 VisualEditor Team and others; see AUTHORS.txt
* @license The MIT License (MIT); see LICENSE.txt
2011-11-28 20:28:28 +00:00
*/
/* Configuration */
// URL to the Parsoid instance
// MUST NOT end in a slash due to Parsoid bug
Kranitor #1: On-boarding '''Kranitor commits''' are commits by Krinkle with his janitor hat on. Must never contain functional changes mixed with miscellaneous changes. .gitignore: * Add .DS_Store to the ignore list so that browsing the directories on Mac OS X, will not add these files to the list of untracked files. * Fix missing newline at end of file .jshintrc * raises -> throws * +module (QUnit.module) * remove 'Node' (as of node-jshint 1.7.2 this is now part of 'browser:true', as it should be) Authors: * Adding myself MWExtension/VisualEditor.php * Fix default value of wgVisualEditorParsoidURL to not point to the experimental instance in WMF Labs. Issues: * ve.ce.TextNode: - Fix TODO: Don't perform a useless clone of an already-jQuerified object. - Use .html() to set html content instead of encapsulating between two strings. This is slightly faster but more importantly safer, and prevents situations where the resulting jQuery collection actually contains 2 elements instead of 1, thus messing up what .contents() is iterating over. * ve.ce.Document.test.js - Fix: ReferenceError: assert is not defined * ve.dm.Document.test.js - Fix: ReferenceError: assert is not defined * ve.dm.Transaction.test.js - Fix: ReferenceError: assert is not defined * ve.dm.TransactionProcessor.test.js - Fix: ReferenceError: assert is not defined * ext.visualEditor.viewPageTarget - Missing dependency on 'mediawiki.Title' Code conventions / Misc cleanup * Various JSHint warnings. * Whitespace * jQuery(): Use '<tag>' for element creation, use '<valid><xml/></valid>' for parsing * Use the default operator instead of ternary when the condition and first value are the same. x = foo ? foo : bar; -> x = foo || bar; Because contrary to some programming language (PHP...), in JS the default operator does not enforce a boolean result but returns the original value, hence it being called the 'default' operator, as opposed to the 'or' operator. * No need to call addClass() twice, it takes a space-separated list (jQuery splits by space and adds if needed) * Use .on( event[, selector], fn ) instead of the deprecated routers to it such as .bind(), .delegate() and .live(). All these three are now built-in and fully compatible with .on() * Add 'XXX:' comments for suspicious code that I don't want to change as part of a clean up commit. * Remove unused variables (several var x = this; where x was not used anywhere, possibly from boilerplate copy/paste) * Follows-up Trevor's commit that converts test suites to the new QUnit format. Also removed the globals since we no longer use those any more. Change-Id: I7e37c9bff812e371c7f65a6fd85d9e2af3e0a22f
2012-07-27 08:43:33 +00:00
$wgVisualEditorParsoidURL = 'http://localhost:8000';
// Interwiki prefix to pass to the Parsoid instance
// Parsoid will be called as $url/$prefix/$pagename
$wgVisualEditorParsoidPrefix = 'localhost';
// Timeout for HTTP requests to Parsoid in seconds
$wgVisualEditorParsoidTimeout = 100;
// Namespaces to enable VisualEditor in
$wgVisualEditorNamespaces = array( NS_MAIN );
// Whether to use change tagging for VisualEditor edits
$wgVisualEditorUseChangeTagging = true;
2011-11-28 20:28:28 +00:00
/* Setup */
$wgExtensionCredits['other'][] = array(
'path' => __FILE__,
'name' => 'VisualEditor',
'author' => array(
'Trevor Parscal',
'Inez Korczyński',
'Roan Kattouw',
'Neil Kandalgaonkar',
'Gabriel Wicke',
'Brion Vibber',
'Christian Williams',
'Rob Moen',
'Subramanya Sastry',
'Timo Tijhof',
2011-11-28 20:28:28 +00:00
),
'version' => '0.1.0',
'url' => 'https://www.mediawiki.org/wiki/Extension:VisualEditor',
2011-11-28 20:28:28 +00:00
'descriptionmsg' => 'visualeditor-desc',
);
$dir = dirname( __FILE__ ) . '/';
$wgExtensionMessagesFiles['VisualEditor'] = $dir . 'VisualEditor.i18n.php';
$wgVisualEditorResourceTemplate = array(
'localBasePath' => dirname( __FILE__ ) . '/modules',
'remoteExtPath' => 'VisualEditor/modules',
'group' => 'ext.visualEditor',
);
$wgResourceModules += array(
'rangy' => $wgVisualEditorResourceTemplate + array(
'scripts' => array(
'rangy/rangy-core.js',
'rangy/rangy-position.js',
),
),
'jquery.multiSuggest' => $wgVisualEditorResourceTemplate + array(
'scripts' => array(
'jquery/jquery.multiSuggest.js'
),
),
// Alias for backwards compat, safe to remove after
'ext.visualEditor.editPageInit' => $wgVisualEditorResourceTemplate + array(
2011-11-28 20:28:28 +00:00
'dependencies' => array(
'ext.visualEditor.viewPageTarget',
)
2011-11-28 20:28:28 +00:00
),
'ext.visualEditor.viewPageTarget.icons-raster' => $wgVisualEditorResourceTemplate + array(
'styles' => array(
've/init/mw/styles/ve.init.mw.ViewPageTarget.Icons-raster.css',
),
),
'ext.visualEditor.viewPageTarget.icons-vector' => $wgVisualEditorResourceTemplate + array(
'styles' => array(
've/init/mw/styles/ve.init.mw.ViewPageTarget.Icons-vector.css',
),
),
'ext.visualEditor.viewPageTarget' => $wgVisualEditorResourceTemplate + array(
'scripts' => array(
've/init/mw/ve.init.mw.js',
've/init/mw/ve.init.mw.Platform.js',
've/init/mw/ve.init.mw.Target.js',
've/init/mw/targets/ve.init.mw.ViewPageTarget.js',
),
'styles' => array(
've/init/mw/styles/ve.init.mw.ViewPageTarget.css',
),
'skinStyles' => array(
'vector' => array(
've/init/mw/styles/ve.init.mw.ViewPageTarget-vector.css',
've/init/mw/styles/ve.init.mw.ViewPageTarget-vector-hd.css' => array(
'media' => 'screen and (min-width: 982px)'
),
),
'apex' => array(
've/init/mw/styles/ve.init.mw.ViewPageTarget-apex.css',
),
'monobook' => array(
've/init/mw/styles/ve.init.mw.ViewPageTarget-monobook.css',
)
),
'dependencies' => array(
'ext.visualEditor.base',
'jquery.byteLength',
'jquery.byteLimit',
'jquery.client',
'jquery.placeholder',
'mediawiki.jqueryMsg',
'mediawiki.Title',
'mediawiki.Uri',
'mediawiki.user',
'mediawiki.util',
'user.options',
'user.tokens',
),
'messages' => array(
'minoredit',
'savearticle',
'cancel',
'watchthis',
'tooltip-save',
'copyrightwarning',
'copyrightpage',
'edit',
'create',
'accesskey-ca-edit',
'accesskey-ca-ve-edit',
'tooltip-ca-edit',
'tooltip-ca-ve-edit',
'viewsource',
'visualeditor-ca-ve-edit',
'visualeditor-ca-ve-create',
'visualeditor-notification-saved',
'visualeditor-notification-created',
'visualeditor-notification-restored',
'visualeditor-ca-editsource',
'visualeditor-loadwarning',
'visualeditor-editsummary',
'visualeditor-editnotices-button',
'visualeditor-restore-page',
'visualeditor-create-page',
),
),
'ext.visualEditor.base' => $wgVisualEditorResourceTemplate + array(
2011-11-28 20:28:28 +00:00
'scripts' => array(
// ve
've/ve.js',
've/ve.EventEmitter.js',
've/init/ve.init.js',
've/init/ve.init.Platform.js',
),
'dependencies' => array(
'jquery.json',
),
'debugScripts' => array(
've/ve.debug.js',
),
),
'ext.visualEditor.specialMessages' => $wgVisualEditorResourceTemplate + array(
'class' => 'VisualEditorMessagesModule'
),
'ext.visualEditor.core' => $wgVisualEditorResourceTemplate + array(
'scripts' => array(
// ve
've/ve.Registry.js',
've/ve.Factory.js',
've/ve.Position.js',
've/ve.Command.js',
've/ve.CommandRegistry.js',
've/ve.Range.js',
've/ve.Node.js',
've/ve.BranchNode.js',
've/ve.LeafNode.js',
've/ve.Surface.js',
've/ve.Document.js',
've/ve.OrderedHashSet.js',
've/ve.AnnotationSet.js',
've/ve.Action.js',
've/ve.ActionFactory.js',
// actions
've/actions/ve.AnnotationAction.js',
've/actions/ve.ContentAction.js',
've/actions/ve.FormatAction.js',
've/actions/ve.HistoryAction.js',
've/actions/ve.IndentationAction.js',
've/actions/ve.InspectorAction.js',
've/actions/ve.ListAction.js',
// dm
've/dm/ve.dm.js',
've/dm/ve.dm.NodeFactory.js',
've/dm/ve.dm.AnnotationFactory.js',
've/dm/ve.dm.Node.js',
've/dm/ve.dm.BranchNode.js',
've/dm/ve.dm.LeafNode.js',
've/dm/ve.dm.Annotation.js',
've/dm/ve.dm.TransactionProcessor.js',
've/dm/ve.dm.Transaction.js',
've/dm/ve.dm.Surface.js',
've/dm/ve.dm.SurfaceFragment.js',
've/dm/ve.dm.Document.js',
've/dm/ve.dm.DocumentSlice.js',
've/dm/ve.dm.DocumentSynchronizer.js',
've/dm/ve.dm.Converter.js',
've/dm/nodes/ve.dm.AlienInlineNode.js',
've/dm/nodes/ve.dm.AlienBlockNode.js',
've/dm/nodes/ve.dm.BreakNode.js',
've/dm/nodes/ve.dm.CenterNode.js',
've/dm/nodes/ve.dm.DefinitionListItemNode.js',
've/dm/nodes/ve.dm.DefinitionListNode.js',
've/dm/nodes/ve.dm.DocumentNode.js',
've/dm/nodes/ve.dm.HeadingNode.js',
've/dm/nodes/ve.dm.ImageNode.js',
've/dm/nodes/ve.dm.ListItemNode.js',
've/dm/nodes/ve.dm.ListNode.js',
've/dm/nodes/ve.dm.MetaBlockNode.js',
've/dm/nodes/ve.dm.MetaInlineNode.js',
've/dm/nodes/ve.dm.MWEntityNode.js',
've/dm/nodes/ve.dm.ParagraphNode.js',
've/dm/nodes/ve.dm.PreformattedNode.js',
've/dm/nodes/ve.dm.TableCellNode.js',
've/dm/nodes/ve.dm.TableNode.js',
've/dm/nodes/ve.dm.TableRowNode.js',
've/dm/nodes/ve.dm.TableSectionNode.js',
've/dm/nodes/ve.dm.TextNode.js',
've/dm/annotations/ve.dm.LinkAnnotation.js',
've/dm/annotations/ve.dm.MWExternalLinkAnnotation.js',
've/dm/annotations/ve.dm.MWInternalLinkAnnotation.js',
've/dm/annotations/ve.dm.TextStyleAnnotation.js',
// ce
've/ce/ve.ce.js',
've/ce/ve.ce.NodeFactory.js',
've/ce/ve.ce.Document.js',
've/ce/ve.ce.Node.js',
've/ce/ve.ce.BranchNode.js',
've/ce/ve.ce.ContentBranchNode.js',
've/ce/ve.ce.LeafNode.js',
've/ce/ve.ce.Surface.js',
've/ce/ve.ce.SurfaceObserver.js',
've/ce/nodes/ve.ce.AlienNode.js',
've/ce/nodes/ve.ce.AlienInlineNode.js',
've/ce/nodes/ve.ce.AlienBlockNode.js',
've/ce/nodes/ve.ce.BreakNode.js',
've/ce/nodes/ve.ce.CenterNode.js',
've/ce/nodes/ve.ce.DefinitionListItemNode.js',
've/ce/nodes/ve.ce.DefinitionListNode.js',
've/ce/nodes/ve.ce.DocumentNode.js',
've/ce/nodes/ve.ce.HeadingNode.js',
've/ce/nodes/ve.ce.ImageNode.js',
've/ce/nodes/ve.ce.ListItemNode.js',
've/ce/nodes/ve.ce.ListNode.js',
've/ce/nodes/ve.ce.MetaBlockNode.js',
've/ce/nodes/ve.ce.MetaInlineNode.js',
've/ce/nodes/ve.ce.MWEntityNode.js',
've/ce/nodes/ve.ce.ParagraphNode.js',
've/ce/nodes/ve.ce.PreformattedNode.js',
've/ce/nodes/ve.ce.TableCellNode.js',
've/ce/nodes/ve.ce.TableNode.js',
've/ce/nodes/ve.ce.TableRowNode.js',
've/ce/nodes/ve.ce.TableSectionNode.js',
've/ce/nodes/ve.ce.TextNode.js',
// ui
've/ui/ve.ui.js',
've/ui/ve.ui.Context.js',
've/ui/ve.ui.Frame.js',
've/ui/ve.ui.Inspector.js',
've/ui/ve.ui.InspectorFactory.js',
've/ui/ve.ui.Menu.js',
've/ui/ve.ui.Tool.js',
've/ui/ve.ui.Toolbar.js',
've/ui/ve.ui.ToolFactory.js',
've/ui/inspectors/ve.ui.LinkInspector.js',
've/ui/tools/ve.ui.ButtonTool.js',
've/ui/tools/ve.ui.AnnotationButtonTool.js',
've/ui/tools/ve.ui.InspectorButtonTool.js',
've/ui/tools/ve.ui.IndentationButtonTool.js',
've/ui/tools/ve.ui.ListButtonTool.js',
've/ui/tools/ve.ui.DropdownTool.js',
've/ui/tools/buttons/ve.ui.BoldButtonTool.js',
've/ui/tools/buttons/ve.ui.ItalicButtonTool.js',
've/ui/tools/buttons/ve.ui.ClearButtonTool.js',
've/ui/tools/buttons/ve.ui.LinkButtonTool.js',
've/ui/tools/buttons/ve.ui.BulletButtonTool.js',
've/ui/tools/buttons/ve.ui.NumberButtonTool.js',
've/ui/tools/buttons/ve.ui.IndentButtonTool.js',
've/ui/tools/buttons/ve.ui.OutdentButtonTool.js',
've/ui/tools/buttons/ve.ui.RedoButtonTool.js',
've/ui/tools/buttons/ve.ui.UndoButtonTool.js',
've/ui/tools/dropdowns/ve.ui.FormatDropdownTool.js',
2011-11-28 20:28:28 +00:00
),
'styles' => array(
// ce
've/ce/styles/ve.ce.DocumentNode.css',
've/ce/styles/ve.ce.Node.css',
've/ce/styles/ve.ce.Surface.css',
// ui
've/ui/styles/ve.ui.Context.css',
've/ui/styles/ve.ui.Inspector.css',
've/ui/styles/ve.ui.Menu.css',
've/ui/styles/ve.ui.Surface.css',
've/ui/styles/ve.ui.Toolbar.css',
've/ui/styles/ve.ui.Tool.css',
),
2011-11-28 20:28:28 +00:00
'dependencies' => array(
'jquery',
'rangy',
'ext.visualEditor.base',
'mediawiki.Title',
'jquery.autoEllipsis',
'jquery.multiSuggest'
2011-11-28 20:28:28 +00:00
),
2012-02-07 16:37:08 +00:00
'messages' => array(
'visualeditor',
The great inspector and context rewrite of 2012 ve.AnnotationAction * Added filter to the clearAll method to allow clearing all matching annotations only ve.dm.Document * Some variable renaming for consistency ve.dm.SurfaceFragment * Added truncateRange method * Added annotation scope to expandRange method * Added support for passing an annotation object into annotateContent method * Switched to using name instead of type in annotateContent method to match the ve.dm.Annotation class * Fixed logic in annotation mode of expandSelection so that expansion only takes place if the annotation is found ve.ui.LinkInspector * Moved most of the functionality elsewhere * General reorganization * Changed setOverlayPosition to accept 2 arguments instead of an object with 2 properties and renamed it to positionOverlayBelow * Check for annotation object before extracting target information from it * Initialize default target as empty string to avoid undefined being cast to a string and the default target becoming 'undefined' icons.ai, inspector.png, inspector.svg * Added generic inspector icon which will be used when a custom icon is not specified in future inspector subclasses ve.ui.Inspector.Icons * Added inspector icon * Renamed clear icon to remove to match it's actual image ve.ui.Context * Greatly simplified the interface, reducing the number of methods by inlining a few things and combining others * Now always listening to resize events on the window rather than only while document is focused * Not listening to scroll events anymore, they used to affect the top/bottom positioning of the menu which we don't do anymore * Lots of cleanup and reorganization * No need to fallback to empty array since getInspectorsForAnnotations does so already * Only consider fully-covered annotations for inspectors ve.ui.Frame * Simplified the constructor by introducing the createFrame method * General cleanup * Typo fixes ve.ui.Inspector * Generalized lots of functionality previously located in the link inspector class which will be useful to all inspectors (such as title, clear button, saving changes, etc.) * Added setDisabled and isDisabled methods to manage CSS changes and avoid needing to check the CSS to determine the state of the inspector (storing state in the view is evil) * Added getMatchingAnnotations method for convenience * Added prepareSelection stub * Lots of cleanup and documentation * Type pattern is now defined in base class * Added stubs for onOpen and onClose with documentation so that subclass authors know what these methods do * Removed checks for onOpen or onClose methods since they are now noop stubs and are always there * Added stub and removed checks for onRemove * Made esc key close and accept - the illusion is supposed to be that the link changes are applied instantly, even though they are only updated when you close, so all closing except for when removing should apply changes - i.e. esc is now equal to back rather than being a special function that doesn't have an associated affordance * Only consider fully-covered annotations when getting matching annotations ve.ui.InspectorFactory * Depending on type pattern now since it's always there * Added getInspectorsForAnnotations method * Return empty array if annotation set is empty VisualEditor, VisualEditor.i18n * Added default inspector message Change-Id: I1cc008445bcbc8cba6754ca4b6ac0397575980d5
2012-11-16 20:40:05 +00:00
'visualeditor-inspector-title',
'visualeditor-linkinspector-title',
'visualeditor-linkinspector-label-pagetitle',
'visualeditor-linkinspector-suggest-existing-page',
'visualeditor-linkinspector-suggest-new-page',
'visualeditor-linkinspector-suggest-external-link',
'visualeditor-formatdropdown-title',
'visualeditor-formatdropdown-format-paragraph',
'visualeditor-formatdropdown-format-heading1',
'visualeditor-formatdropdown-format-heading2',
'visualeditor-formatdropdown-format-heading3',
'visualeditor-formatdropdown-format-heading4',
'visualeditor-formatdropdown-format-heading5',
'visualeditor-formatdropdown-format-heading6',
'visualeditor-formatdropdown-format-preformatted',
'visualeditor-annotationbutton-bold-tooltip',
'visualeditor-annotationbutton-italic-tooltip',
'visualeditor-annotationbutton-link-tooltip',
'visualeditor-indentationbutton-indent-tooltip',
'visualeditor-indentationbutton-outdent-tooltip',
'visualeditor-listbutton-number-tooltip',
'visualeditor-listbutton-bullet-tooltip',
'visualeditor-clearbutton-tooltip',
'visualeditor-historybutton-undo-tooltip',
'visualeditor-historybutton-redo-tooltip',
'visualeditor-inspector-close-tooltip',
'visualeditor-inspector-remove-tooltip',
'visualeditor-viewpage-savewarning',
'visualeditor-saveerror',
'visualeditor-editconflict',
'visualeditor-aliennode-tooltip',
2012-02-07 16:37:08 +00:00
),
),
'ext.visualEditor.icons-raster' => $wgVisualEditorResourceTemplate + array(
'styles' => array(
've/ui/styles/ve.ui.Icons-raster.css',
),
),
'ext.visualEditor.icons-vector' => $wgVisualEditorResourceTemplate + array(
'styles' => array(
've/ui/styles/ve.ui.Icons-vector.css',
),
),
2011-11-28 20:28:28 +00:00
);
// Parsoid Wrapper API
$wgAutoloadClasses['ApiVisualEditor'] = $dir . 'ApiVisualEditor.php';
$wgAPIModules['visualeditor'] = 'ApiVisualEditor';
// Integration Hooks
$wgAutoloadClasses['VisualEditorHooks'] = $dir . 'VisualEditor.hooks.php';
$wgHooks['BeforePageDisplay'][] = 'VisualEditorHooks::onBeforePageDisplay';
$wgHooks['GetPreferences'][] = 'VisualEditorHooks::onGetPreferences';
$wgHooks['ListDefinedTags'][] = 'VisualEditorHooks::onListDefinedTags';
$wgHooks['MakeGlobalVariablesScript'][] = 'VisualEditorHooks::onMakeGlobalVariablesScript';
$wgHooks['ResourceLoaderTestModules'][] = 'VisualEditorHooks::onResourceLoaderTestModules';
$wgAutoloadClasses['VisualEditorMessagesModule'] = $dir . 'VisualEditorMessagesModule.php';