查看“︁MediaWiki:Common.js”︁的源代码
←
MediaWiki:Common.js
跳转到导航
跳转到搜索
因为以下原因,您没有权限编辑该页面:
您请求的操作仅限属于该用户组的用户执行:
管理员
本页面提供本维基软件的界面文本,并受到保护以防止滥用。 要添加或更改所有维基的翻译,请使用MediaWiki的本地化项目
translatewiki.net
。
您无权编辑此JavaScript页面,因为编辑此页面可能会影响所有网站访客。
您可以查看和复制此页面的源代码。
/* * 尘月维基 · 排版工具条 * 在源代码编辑器(WikiEditor)上增加:颜色 / 字号 / 对齐 / 插图 / 调图 * 依赖:ext.wikiEditor、oojs-ui-widgets、oojs-ui-windows */ ( function () { 'use strict'; var COLORS = [ { label: '红', value: '#d32f2f' }, { label: '橙', value: '#ef6c00' }, { label: '黄', value: '#f9a825' }, { label: '绿', value: '#2e7d32' }, { label: '青', value: '#00838f' }, { label: '蓝', value: '#1565c0' }, { label: '紫', value: '#6b3fa0' }, { label: '粉', value: '#d81b60' }, { label: '灰', value: '#666666' }, { label: '黑', value: '#000000' } ]; var SIZES = [ '80%', '100%', '120%', '150%', '200%', '250%' ]; var WIDTHS = [ '', '100', '150', '200', '250', '300', '400', '500', '600' ]; var ALIGN_OPTIONS = [ { label: '默认', value: '' }, { label: '居中', value: 'center' }, { label: '靠左', value: 'left' }, { label: '靠右', value: 'right' } ]; var ALIGN_MAP = { '居中': 'center', '居左': 'left', '居右': 'right', '无': '' }; var FILE_RE = /^\s*\[\[\s*(?:File|Image|文件|图像)\s*:\s*([^|\]]+)((?:\|[^[\]]*)*)\s*\]\]\s*$/i; var ALIGN_RE = /^(?:center|left|right|none|居中|居左|居右|无)$/i; var DialogClass = null; var windowManager = null; /** * 生成"包裹选中文字"的动作,套用站内模板 * * 只用于「对齐」这类块级排版;颜色和字号改用内联样式(见 spanAction)。 * * @param {string} template 模板名 * @param {string} arg 第一个参数 * @return {Object} WikiEditor action */ function wrapAction( template, arg ) { return { type: 'encapsulate', options: { pre: '{{' + template + '|1=' + arg + '|2=', peri: '', post: '}}' } }; } /** * 颜色 / 字号用内联样式包裹,而不是模板 * * 模板在可视化编辑器里是不可分割的块,里面的文字没法再选中加链接; * span + style 则仍然是普通文字,两个编辑器都能继续编辑。 * * @param {string} prop CSS 属性(color / font-size) * @param {string} value 值 * @return {Object} WikiEditor action */ function spanAction( prop, value ) { return { type: 'encapsulate', options: { pre: '<span style="' + prop + ':' + value + '">', peri: '', post: '</span>' } }; } /** * 把 [{label, value}] 转成 WikiEditor select 需要的 list * * @param {Object[]} items * @param {Function} actionFactory 由 value 生成 action * @return {Object} */ function makeList( items, actionFactory ) { var list = {}; items.forEach( function ( item, index ) { list[ 'opt' + index ] = { label: item.label, action: actionFactory( item.value ) }; } ); return list; } /** * 从 [[File:...]] 代码里解析文件名、宽度、位置、说明 * * @param {string} text * @return {Object|null} */ function parseFileLink( text ) { var match = FILE_RE.exec( text || '' ); if ( !match ) { return null; } var parsed = { name: match[ 1 ].trim(), width: '', align: '', caption: '' }; var params = match[ 2 ] ? match[ 2 ].split( '|' ).slice( 1 ) : []; params.forEach( function ( raw ) { var param = raw.trim(); if ( !param ) { return; } if ( /^\d+\s*px$/i.test( param ) ) { parsed.width = String( parseInt( param, 10 ) ); } else if ( ALIGN_RE.test( param ) ) { parsed.align = Object.prototype.hasOwnProperty.call( ALIGN_MAP, param ) ? ALIGN_MAP[ param ] : param.toLowerCase(); } else if ( !parsed.caption ) { parsed.caption = param; } } ); return parsed; } /** * 拼出 [[File:名字|宽度px|位置|说明]] * * @param {Object} data * @return {string} */ function buildFileLink( data ) { var parts = [ '[[File:' + data.name ]; if ( data.width ) { parts.push( data.width + 'px' ); } if ( data.align ) { parts.push( data.align ); } if ( data.caption ) { parts.push( data.caption ); } return parts.join( '|' ) + ']]'; } /** * 上传页地址 * * @return {string} */ function uploadUrl() { if ( mw.util && typeof mw.util.getUrl === 'function' ) { return mw.util.getUrl( 'Special:Upload' ); } return '/Special:Upload'; } /** * 提示条 * * @param {string} text */ function notify( text ) { mw.loader.using( 'mediawiki.notification' ).then( function () { mw.notify( text, { type: 'warn', autoHideSeconds: 5 } ); } ); } /** * 图片对话框(插入 / 调整共用一个) * * @return {Function} 对话框类 */ function getDialogClass() { if ( DialogClass ) { return DialogClass; } /** * @param {Object} config */ function ImageDialog( config ) { ImageDialog.super.call( this, config ); } OO.inheritClass( ImageDialog, OO.ui.ProcessDialog ); ImageDialog.static.name = 'chenyue-image'; ImageDialog.static.size = 'medium'; ImageDialog.static.title = '图片'; ImageDialog.static.actions = [ { action: 'apply', label: '确定', flags: [ 'primary', 'progressive' ] }, { action: 'cancel', label: '取消', flags: 'safe' } ]; /** * @param {Object} context * @param {Object} data * @param {boolean} isNew * @return {ImageDialog} */ ImageDialog.prototype.setData = function ( context, data, isNew ) { this.context = context; this.data = data; this.isNew = isNew; return this; }; ImageDialog.prototype.initialize = function () { ImageDialog.super.prototype.initialize.apply( this, arguments ); var data = this.data; this.title.setLabel( this.isNew ? '插入图片' : '调整图片' ); this.nameInput = new OO.ui.TextInputWidget( { value: data.name, placeholder: '图片文件名,例如 熊猫.png', icon: 'image' } ); this.widthInput = new OO.ui.DropdownInputWidget( { options: WIDTHS.map( function ( width ) { return { data: width, label: width ? width + ' 像素宽' : '按原始大小' }; } ), value: data.width || '' } ); this.alignInput = new OO.ui.DropdownInputWidget( { options: ALIGN_OPTIONS.map( function ( option ) { return { data: option.value, label: option.label }; } ), value: data.align || '' } ); this.captionInput = new OO.ui.TextInputWidget( { value: data.caption, placeholder: '图片说明,可留空' } ); var fieldset = new OO.ui.FieldsetLayout(); fieldset.addItems( [ new OO.ui.FieldLayout( this.nameInput, { label: '文件名', align: 'top' } ), new OO.ui.FieldLayout( this.widthInput, { label: '大小', align: 'top' } ), new OO.ui.FieldLayout( this.alignInput, { label: '位置', align: 'top' } ), new OO.ui.FieldLayout( this.captionInput, { label: '说明', align: 'top' } ) ] ); var hint = new OO.ui.HtmlSnippet( '<p class="chenyue-img-hint">还没上传?' + '<a href="' + uploadUrl() + '" target="_blank" rel="noopener">去上传图片 →</a></p>' ); var panel = new OO.ui.PanelLayout( { padded: true, expanded: false } ); panel.$element.append( fieldset.$element, hint.$element ); this.$body.append( panel.$element ); }; ImageDialog.prototype.getBodyHeight = function () { return 380; }; ImageDialog.prototype.getActionProcess = function ( action ) { var dialog = this; if ( action !== 'apply' ) { return new OO.ui.Process( function () { dialog.close( { action: action || 'cancel' } ); } ); } return new OO.ui.Process( function () { var name = dialog.nameInput.getValue().trim() .replace( /^(?:File|Image|文件|图像)\s*:\s*/i, '' ); if ( !name ) { dialog.nameInput.setValidityFlag( false ); dialog.nameInput.focus(); return; } var text = buildFileLink( { name: name, width: dialog.widthInput.getValue(), align: dialog.alignInput.getValue(), caption: dialog.captionInput.getValue().trim() } ); // textSelection 没有 insertText 方法,统一用 encapsulateSelection: // 有选区就替换,没选区就插在光标处 dialog.context.$textarea.textSelection( 'encapsulateSelection', { pre: text, peri: '', post: '', replace: true, splitlines: false, ownline: false } ); dialog.close( { action: 'apply' } ); } ); }; DialogClass = ImageDialog; return DialogClass; } /** * 打开图片对话框 * * @param {Object} context WikiEditor context * @param {Object|null} parsed 已有图片信息(调整时传入) */ function openImageDialog( context, parsed ) { var isNew = !parsed; mw.loader.using( [ 'oojs-ui-core', 'oojs-ui-widgets', 'oojs-ui-windows' ] ).then( function () { if ( !windowManager ) { windowManager = new OO.ui.WindowManager(); $( document.body ).append( windowManager.$element ); } var ImageDialog = getDialogClass(); var dialog = new ImageDialog(); dialog.setData( context, parsed || { name: '', width: '', align: '', caption: '' }, isNew ); windowManager.addWindows( [ dialog ] ); // openWindow 返回的 promise 在窗口关闭时才 resolve,用它来销毁实例 var opened = windowManager.openWindow( dialog, {} ); if ( opened && typeof opened.then === 'function' ) { opened.then( cleanup, cleanup ); } else if ( dialog.closed && typeof dialog.closed.then === 'function' ) { dialog.closed.then( cleanup, cleanup ); } /** * 关闭后从 DOM 中移除,避免旧窗口残留 */ function cleanup() { windowManager.removeWindows( [ dialog ] ); if ( dialog.$element && dialog.$element.parent() ) { dialog.$element.remove(); } } } ); } /** * 调整选中图片的大小 / 位置 * * @param {Object} context */ function adjustImage( context ) { var selection = context.$textarea.textSelection( 'getSelection' ); var parsed = parseFileLink( selection ); if ( !parsed ) { notify( '先选中整段图片代码再点「调图」,例如 [[File:熊猫.png|300px|center]]' ); return; } openImageDialog( context, parsed ); } /** * 把排版工具条插进 WikiEditor */ function addLayoutTools() { if ( $( '#wikiEditor-ui-toolbar .group-layout' ).length ) { return; } $( '#wpTextbox1' ).wikiEditor( 'addToToolbar', { section: 'main', groups: { layout: { tools: { layoutColor: { type: 'select', label: '颜色', list: makeList( COLORS, function ( value ) { return spanAction( 'color', value ); } ) }, layoutSize: { type: 'select', label: '字号', list: makeList( SIZES.map( function ( size ) { return { label: size, value: size }; } ), function ( value ) { return spanAction( 'font-size', value ); } ) }, layoutAlign: { type: 'select', label: '对齐', list: makeList( ALIGN_OPTIONS.filter( function ( option ) { return option.value !== ''; } ), function ( value ) { return wrapAction( '对齐', value ); } ) }, layoutImage: { type: 'button', label: '插图', action: { type: 'callback', execute: function ( context ) { openImageDialog( context, null ); } } }, layoutAdjust: { type: 'button', label: '调图', action: { type: 'callback', execute: function ( context ) { adjustImage( context ); } } } } } } } ); } /** * 等 WikiEditor 渲染出工具条后再挂工具组 */ function bootstrap() { if ( !document.getElementById( 'wpTextbox1' ) ) { return; } mw.loader.using( 'ext.wikiEditor' ).then( function () { var tries = 0; function waitForToolbar() { if ( document.getElementById( 'wikiEditor-ui-toolbar' ) ) { addLayoutTools(); return; } tries += 1; if ( tries <= 30 ) { window.setTimeout( waitForToolbar, 100 ); } } waitForToolbar(); } ); } $( bootstrap ); }() );
此页面嵌入的页面:
Template:' + template + '
(
查看源代码
)
返回
MediaWiki:Common.js
。
导航菜单
个人工具
登录
associated-pages
系统消息
讨论
English
查看
阅读
查看源代码
查看历史
更多
搜索
导航
首页
创建新页面
最近更改
随机页面
特殊页面
社区
帮助
社区专页
工具
上传文件
链入页面
相关更改
个人
登录
工具
链入页面
相关更改
页面信息