MediaWiki:Gadget-edit-form-ui.js

Uwaga: aby zobaczyć zmiany po opublikowaniu, może zajść potrzeba wyczyszczenia pamięci podręcznej przeglądarki.

  • Firefox / Safari: Przytrzymaj Shift podczas klikania Odśwież bieżącą stronę, lub naciśnij klawisze Ctrl+F5, lub Ctrl+R (⌘-R na komputerze Mac)
  • Google Chrome: Naciśnij Ctrl-Shift-R (⌘-Shift-R na komputerze Mac)
  • Internet Explorer / Edge: Przytrzymaj Ctrl, jednocześnie klikając Odśwież, lub naciśnij klawisze Ctrl+F5
  • Opera: Naciśnij klawisze Ctrl+F5.
EUi = {
	oldform:        undefined,
	tbox:           undefined,
	form:           $( '<div>' ).attr( 'id', 'ed' ).hide(),
	menu_ctrl:      $( '<ul>' ).attr( 'id', 'ed_menu_controls' ),
	menu_sect:      $( '<ul>' ).attr( 'id', 'ed_menu_sections' ),
	content:        $( '<div>' ).attr( 'id', 'ed_content' ),
	ajr:            $( '<div>' ).attr( 'id', 'ajax_results' ),
	usingNew:       true,
	activeLangCode: '',
	activeLangId:   '',
	formChanged:    false,

	prepareForm: function ( oldform, tbox ) {
		this.oldform = oldform;
		this.tbox = tbox;
		
		EUi.form.append(
			$( '<div>' )
				.attr( 'id', 'ed_menu' )
				.append( EUi.menu_ctrl, EUi.menu_sect ),
			EUi.content,
			EUi.ajr.hide()
		);
		
		oldform.first().before( EUi.form );
		EUi.usingNew = ( mw.storage.get( 'ext.gadget.edit-form.default' ) !== 'old' );

		if ( EUi.usingNew ) {
			oldform.hide();
			EUi.form.show();
		}
		
		EUi.prepareFormSections();
		EUi.addControlButtons();
		EUi.rebindFormActions();
		EKeyboard.init();
		
		if (
			Number( mw.user.options.get( 'previewonfirst' ) ) &&
			Number( mw.user.options.get( 'previewontop' ) ) &&
			Ed.code !== ''
		) {
			EUi.form[ 0 ].scrollIntoView();
		}
		
		EUi.form
			.on( 'mouseover', '.tip', $( this ).showtip )
			.on( 'mouseout',  '.tip', $( this ).hidetip )
			.on( 'input propertychange', '.keyboardable', function () {
				EUi.formChanged = true;
			} );
		
		$( window )
			.on( 'resize', EUi.resizeTextareas )
			.on( 'resize', EUi.organizeSectionMenu )
			.on( 'resize', EUi.relocateResult );
		
		$( document ).on( 'keyup', function ( e ) {
			if ( e.keyCode === 27 ) {
				EUi.hideResult();
				return false;
			}
		} );
	},
	
	addControlButtons: function () {
		var newformToggle, oldformToggle;
		
		var onclickToggle = function () {
			var cm;
			EUi.usingNew = !EUi.usingNew;
			
			if ( EUi.usingNew ) {
				EUi.oldform.hide();
				EUi.form.show();
				Ed.resetNew();
			} else {
				cm = $( '.CodeMirror' );
				
				// Zdaje się, że podświetlanie składni ustala wysokość pola
				// edycji (to NIE jest #wpTextbox1) na samym początku, lecz
				// formularz edycji go ubiega i chowa tradycyjny formularz. W
				// takim układzie CodeMirror ustala wysokość pola jako równą
				// 0px, co powoduje, że przełączenie z powrotem na stary
				// formularz ukazuje pole o wysokości równej zero. Poniższe
				// rozwiązanie przywraca domyślną wysokość pola (nadaną przez
				// arkusz stylów CSS), co jest trochę mniejsza niż ta obliczona
				// przez CodeMirror dla większości ekranów podczas edycji z
				// wyłączonym gadżetem.
				if ( cm.length && cm.css( 'height' ) === '0px' ) {
					$( '.CodeMirror' ).css( 'height', '' );
				}
				
				EUi.oldform.show();
				EUi.form.hide();
				EUi.tbox.textSelection( 'setContents', EPrinter.recalculateCode() );
			}
			
			ESpecialChars.toggle();
			
			mw.storage.set( 'ext.gadget.edit-form.default', EUi.usingNew
				? 'new'
				: 'old'
			);
			
			return false;
		};
		
		newformToggle = $( '<li>' )
			.attr( {
				'id':    'ed_menuitem_toggle',
				'class': 'tip menuitem active ed_toggle_editor'
			} )
			.appendTo( EUi.menu_ctrl )
			.on( 'click', onclickToggle )
			.data( 'tip', EStr.TOGGLE_EDITOR );
		
		oldformToggle = $( '<div>' )
			.attr( {
				'class': 'ed_toggle_editor',
				'title': EStr.TOGGLE_EDITOR
			} )
			.on( 'click', onclickToggle );
		
		mw.loader.using( 'ext.wikiEditor' ).done( function () {
			oldformToggle
				.addClass( 'group group-ed-toggle' )
				.prependTo( $( '#wikiEditor-section-main' ) );
		} );
	},

	reset: function () {
		EUi.menu_sect.html( '' );
		EUi.content.html( '' );

		EUi.prepareFormSections();
	},

	clickDefaultSection: function () {
		var firstTab;

		if ( !EUi.usingNew ) {
			return false;
		}
		
		firstTab = EUi.menu_sect
			.children( ':not(#ed_menuitem_' + EConstants.SECTION_ID_INTRO + ')' )
			.first();
		
		if ( firstTab.attr( 'id' ) !== 'ed_menuitem_new' ) {
			firstTab.trigger( 'click' );
		} else if ( Ed.content.sections[ EConstants.SECTION_ID_INTRO ] !== undefined ) {
			$( '#ed_menuitem_' + EConstants.SECTION_ID_INTRO ).trigger( 'click' );
		} else {
			$( '#ed_menuitem_new' ).trigger( 'click' );
		}
		
		return true;
	},

	prepareFormSections: function () {
		var id, addItem;

		for ( id in Ed.content.sections ) {
			if ( Ed.content.sections.hasOwnProperty( id ) ) {
				EUi.addSection( id );
				EUi.prepareFormSubsections( id );
			}
		}

		if ( !EUtil.isEditingSection() ) {
			addItem = $( '<li>' )
				.attr( {
					'id':   'ed_menuitem_new',
					'class': 'tip menuitem'
				} )
				.text( EStr.ADD )
				.appendTo( EUi.menu_sect )
				.on( 'click', function () {
					EUi.addNewSection();
					return false;
				} )
				.data( 'tip', EStr.ADD_SECTION );
		}

		EUi.organizeSectionMenu();
		EUi.clickDefaultSection();
		EUi.resizeTextareas();
		
		if (
			$( '#ed_menuitem_' + EConstants.SECTION_ID_INTRO ).length === 0 &&
			!EUtil.isEditingSection()
		) {
			EUi.addIntroAdder();
		}
	},

	addSection: function ( id ) {
		var item, tip, added = false,
		sec = Ed.content.sections[ id ],
		fset = $( '<fieldset>' ).attr( {
				'id':    'ed_section_' + id,
				'class': 'ed_section'
			} )
			.appendTo( EUi.content );

		if ( id === EConstants.SECTION_ID_INTRO ) {
			sec.code = EStr.INTRO_MENU;
			sec.title = '';
		}

		item = $( '<li>' )
			.attr( {
				'id':    'ed_menuitem_' + id,
				'class': 'tip menuitem'
			} )
			.text( sec.code );
		
		tip = ( id === EConstants.SECTION_ID_INTRO )
			? EStr.INTRO_SECTION
			: EParser.insideTemplate( sec.title ) + '<br/><small>tytuł sekcji: <tt>' + sec.title + '</tt></small>';
		
		item.data( {
			section: 'ed_section_' + id,
			code:    sec.code,
			tip:     tip
		} )
		.on( 'click', function () {
			var defFocus,
			$this = $( this );

			EKeyboard.hide();
			EUi.hideResult();
			
			EUi.content
				.find( '.ed_section' )
				.removeClass( 'active' );
			
			EUi.content
				.find( '#' + $this.data( 'section' ) )
				.addClass( 'active' );
			
			$this
				.addClass( 'active' )
				.siblings()
				.removeClass( 'active' );
			
			EUi.resizeTextareas();
			EUi.activeLangCode = $this.data( 'code' );
			EUi.activeLangId = id;
			
			defFocus = $( '#ed_content textarea.oblig_subsection:visible' );
			
			if ( defFocus.length === 0 ) {
				defFocus = $( '#ed_content fieldset.active textarea:first' );
			}
			
			window.setTimeout( function () {
				defFocus.focus();
			}, 100 ); //FIXME why?
			
			return false;
		} );

		// insert alphabetically
		EUi.menu_sect.children( 'li' ).each( function () {
			var $this = $( this ),
				thisId = $this.attr( 'id' ).replace( /[- ]/g, '' ),
				thatId = item.attr( 'id' ).replace( /[- ]/g, '' );
			
			if ( thisId === 'ed_menuitem_new' || thisId.localeCompare( thatId, 'pl' ) > 0 ) {
				item.insertBefore( $this );
				added = true;
				return false;
			}
		} );
		
		if ( !added ) {
			item.appendTo( EUi.menu_sect );
		}
	},

	addNewSection: function () {
		var defaultText, message,
		defaultLang = EUtil.getSection();

		if ( !defaultLang || defaultLang === 'editform' ) {
			defaultLang = mw.storage.get( 'ext.gadget.edit-form.lang' );
		}
		
		defaultText = defaultLang
			? EParser.getTitleFromCode( defaultLang )
			: mw.config.get( 'wgPageName' ).replace( /_/g, ' ' ) + EStr.ADD_SECTION_TEMPLATE;
		
		message = defaultLang
			? EStr.ADD_SECTION_MESSAGE_DEFAULT
			: EStr.ADD_SECTION_MESSAGE;
		
		$.alerts.prompt(
			message,
			defaultText,
			EStr.ADD_SECTION_TITLE,
			function ( val ) {
				var sec, id;
	
				if ( !val ) {
					return;
				}
				
				sec = EParser.getSectionFromInput( val );
	
				if ( EConstants.CODE_TO_LANG[ sec.code ] ) {
					id = sec.id;
					
					if ( Ed.content.sections[ id ] !== undefined ) {
						$.alerts.alert(
							EStr.ADD_SECTION_ALREADY,
							EStr.ADD_SECTION_ALREADY_TITLE
						);
					} else {
						Ed.content.sections[ id ] = sec;
						ESectionParser.parse( sec );
	
						EUi.addSection( id );
						EUi.prepareFormSubsections( id );
						EUi.addDefaultTexts( id, sec.code );
						EUi.checkToc();
						
						mw.storage.set( 'ext.gadget.edit-form.lang', sec.code );
					}
					
					$( '#ed_menuitem_' + id ).trigger( 'click' );
					$( '#ed_section_' + id + ' textarea' ).reverse().autoresize();
					
					EPrinter.appendEditDescription(
						'+sekcja: ' +
						EConstants.CODE_TO_LANG[ sec.code ]
					);
					
					location.hash = 'editform';
				} else {
					$.alerts.alert(
						EStr.ADD_SECTION_NONEXISTENT,
						EStr.ADD_SECTION_NONEXISTENT_TITLE,
						EUi.addNewSection
					);
				}
		} )
		.find( '#popup_prompt' )
		.suggestions( 'fetch', function ( input, response ) {
			var template = EParser.insideTemplate( input ),
				tmplShort = template.replace( /^język /, '' ),
				suggestions = $.map( EConstants.LANG_CODES, function ( code, lang ) {
					if ( tmplShort && lang.indexOf( tmplShort ) === 0 ) {
						if ( EConstants.SHORT_LANGS.indexOf( lang ) !== -1 ) {
							return input.replace( template, lang );
						} else {
							return input.replace( template, 'język ' + lang );
						}
					} else if ( !template && lang.indexOf( input ) === 0 ) {
						return lang;
					}
				} );
			
			response( suggestions.splice( 0, 10 ) );
		} );
	},

	editSectionTitle: function ( id, section ) {
		$.alerts.prompt(
			EStr.EDIT_SECTION_TITLE_MESSAGE,
			section.title,
			EStr.EDIT_SECTION_TITLE,
			function ( res ) {
				var tip;
	
				if ( !res ) {
					return;
				}
				
				section.title = res;
				tip = EParser.insideTemplate( res ) + '<br/><small>tytuł sekcji: <tt>' + res + '</tt></small>';
				$( '#ed_menuitem_' + id ).data( 'tip', tip );
		} );
	},

	deleteSection: function ( id, force ) {
		var del = function () {
			delete Ed.content.sections[ id ];
			
			$( '#ed_menuitem_' + id ).remove();
			$( '#ed_section_' + id ).remove();
			
			EUi.checkToc();
			EUi.clickDefaultSection();
		};

		if ( force ) {
			del();
		} else {
			$.alerts.confirm(
				EStr.DELETE_SECTION_MESSAGE,
				EStr.DELETE_SECTION_TITLE,
				function ( res ) {
					if ( res ) {
						del();
					}
			} );
		}
	},

	deleteEmptySections: function () {
		var id, sec, empty,
		setNotEmpty = function () {
			if ( $( this ).val() ) {
				empty = false;
			}
		};

		for ( id in Ed.content.sections ) {
			if ( Ed.content.sections.hasOwnProperty( id ) ) {
				sec = Ed.content.sections[ id ];
				empty = true;
				$( '#ed_section_' + id ).find( 'textarea' ).each( setNotEmpty );
				
				if ( empty ) {
					EUi.deleteSection( id, 1 );
				}
			}
		}
	},

	prepareFormSubsections: function ( id ) {
		var editlink, deletelink, i,
		section = Ed.content.sections[ id ],
		fset = $( '#ed_section_' + id );

		if ( id !== EConstants.SECTION_ID_INTRO ) {
			editlink = $( '<a>' )
				.text( EStr.EDIT_SECTION_TITLE )
				.on( 'click', function () {
					EUi.editSectionTitle( id, section );
					return false;
				} );
			
			deletelink = $( '<a>' )
				.text( EStr.DELETE_SECTION )
				.on( 'click', function () {
					EUi.deleteSection( id );
					return false;
				} );
			
			$( '<p>' )
				.addClass( 'top' )
				.append( editlink, deletelink )
				.appendTo( fset );
		}

		$.each( section.subsections, function () {
			if ( this.active ) {
				fset.append( EUi.getSubsectionObj( id, section, this ) );
			}
		} );
		
		EUi.prepareSectionAutomation( id );
		EAutomator.addTransliteration( id, section.code );
	},

	getSubsectionObj: function ( langid, section, subsection ) {
		var name = langid + '_' + subsection.title.replace( / /g, '_' ),
		p = $( '<p>' ).attr( 'id', 'ed_subsection_' + name ),
		caption = ( langid === EConstants.SECTION_ID_INTRO )
			? EStr.INTRO
			: EConstants.SUBSECTION_TITLE[ subsection.title ],
		label = $( '<label>' )
			.attr( {
				'class': 'newform',
				'for':   'ed_' + name
			} )
			.text( caption ),
		textarea = $( '<textarea>' )
			.attr( {
				'id':    'ed_' + name,
				'class': 'newform keyboardable',
				'name':  'ed_' + name
			} )
			.val( subsection.content ),
		extra = $( '<div>' ).attr( {
				'id':    'ed_' + name + '_extra',
				'class': 'subsection_extra'
			} );

		if ( ESectionParser.obligatorySubsection( subsection, section ) ) {
			label
				.addClass( 'oblig_subsection' )
				.append( EStr.OBLIGATORY_SUBSECTION );
			
			textarea.addClass( 'oblig_subsection' );
		} else if ( ESectionParser.botSubsection( subsection, section ) ) {
			label
				.addClass( 'bot_subsection' )
				.append( EStr.BOT_SUBSECTION );
			
			textarea.addClass( 'bot_subsection' );
		}
		
		p.append( label, textarea, extra );

		return p;
	},

	rebindFormActions: function () {
		var allowCloseWindow, handler;
		
		if ( Number( mw.user.options.get( 'useeditwarning' ) ) ) {
			// mediawiki.action.edit.editWarning.js
			allowCloseWindow = mw.confirmCloseWindow( {
				test:       function () {
					return EUi.formChanged;
				},
				message:    mw.msg( 'editwarning-warning' ),
				namespace: 'ed_editwarning'
			} );
		} else {
			allowCloseWindow = { release: function () { return true; } };
		}
	
		handler = function () {
			if ( EUi.usingNew ) {
				EUi.deleteEmptySections();
				EUi.tbox.textSelection( 'setContents', EPrinter.recalculateCode() );
			}
			
			return true;
		};
	
		EUi.form
			.find( 'textarea' )
			.removeAttr( 'name' );
		
		$( '#editform' )
			.on( 'submit', handler )
			.on( 'submit', allowCloseWindow.release );
		
		// LivePreview, mediawiki.action.edit.preview.js
		if ( Number( mw.user.options.get( 'uselivepreview' ) ) ) {
			$( '#wpPreview, #wpDiff' ).on( 'click', handler );
		}
	},

	resizeTextareas: function () {
		$( '#ed_content fieldset.active' )
			.find( 'textarea' )
			.reverse()
			.autoresize();
	},
	
	organizeSectionMenu: function () {
		var menu = EUi.menu_sect.find( '.menuitem' );
		var size = menu.length - 1; // przycisk '+ dodaj'
		
		menu.removeClass( 'lastofline' );
		
		if ( menu.first().offset().top !== menu.last().offset().top ) {
			menu.eq( Math.floor( size / 2 ) - 1 ).addClass( 'lastofline' );
		}
	},

	addIntroAdder: function () {
		var addIntro = $( '<li>' )
			.attr( {
				'id':    'ed_menuitem_newintro',
				'class': 'tip menuitem'
			} )
			.text( EStr.ADD_INTRO )
			.appendTo( EUi.menu_sect )
			.on( 'click', function () {
				var sec = {
					title:       '',
					content:     '',
					id:          EConstants.SECTION_ID_INTRO,
					initcontent: ''
				};
	
				Ed.content.sections[ EConstants.SECTION_ID_INTRO ] = sec;
				ESectionParser.parse( sec );
				EUi.addSection( EConstants.SECTION_ID_INTRO );
				EUi.prepareFormSubsections( EConstants.SECTION_ID_INTRO );
				
				$( '#ed_menuitem_newintro' ).hide();
				$( '#ed_menuitem_' + EConstants.SECTION_ID_INTRO ).trigger( 'click' );
				
				return false;
			} )
			.data( 'tip', EStr.ADD_INTRO_SECTION );
	},

	addExtraButtons: function ( sectionName, subsectionName, mode, buttonContent, onclick, tooltip ) {
		var extra, button;

		extra = $( '#ed_' + sectionName + '_' + subsectionName + '_extra' );
		
		button = $( '<span>' )
			.html( buttonContent )
			.on( 'click', function () {
				EApi.handleRequest( mode, onclick );
				return false;
			} )
			.data( 'tip', tooltip )
			.attr( {
				'id':    'ed_' + sectionName + '_extra_' + EConstants.API_ID[ mode ],
				'class': 'tip tipdown'
			} );
		
		extra.append( button ).addClass( 'active' );
	},

	prepareSectionAutomation: function ( id ) {
		if ( id !== EConstants.SECTION_ID_INTRO ) {
			EUi.addExtraButtons(
				id,
				'',
				EConstants.MODE_PICTURE,
				EStr.ADD_PICTURE,
				EAutomator.getPicture,
				EStr.GET_PICTURE + EStr.WILL_BE_SHOWN
			);
		}
		
		EUi.addExtraButtons(
			id,
			'wymowa',
			EConstants.MODE_IPA,
			EStr.ADD_IPA,
			EAutomator.getIPA,
			EStr.GET_IPA + EStr.WILL_BE_SHOWN
		);
		
		EUi.addExtraButtons(
			id,
			'wymowa',
			EConstants.MODE_AUDIO,
			EStr.ADD_AUDIO,
			EAutomator.getAudio,
			EStr.GET_AUDIO + EStr.WILL_BE_SHOWN
		);
		
		EUi.addExtraButtons(
			id,
			'przykłady',
			EConstants.MODE_INTERNAL_EXAMPLE,
			EStr.ADD_INTERNAL_EXAMPLE,
			EAutomator.getInternalExample,
			EStr.GET_INTERNAL_EXAMPLE + EStr.WILL_BE_SHOWN
		);
	},

	showResult: function ( ajaxResult, buttonIdPart ) {
		var closelink = $( '<a>' )
			.attr( {
				'id':    'closelink',
				'class': 'tip'
			} )
			.text( '×' );

		EUi.ajr
			.empty()
			.append( ajaxResult )
			.show()
			.data( 'buttonIdPart', buttonIdPart );
		
		EUi.relocateResult();

		closelink
			.prependTo( EUi.ajr )
			.data( 'tip', EStr.ESCAPE )
			.on( 'click', function () {
				EUi.hideResult();
				return false;
			} );
	},

	relocateResult: function () {
		var nPos = {},
		button = $( '#ed_' + EUtil.getActiveLangId() + '_extra_' + EUi.ajr.data( 'buttonIdPart' ) ),
		textbox = button.parent().prev();

		if ( button.length ) {
			nPos.top  = button.position().top;
			nPos.left = textbox.position().left + 60;
			
			EUi.ajr
				.css( nPos )
				.width( textbox.outerWidth() - 120 );
		}
	},

	hideResult: function () {
		EUi.ajr.hide();
	},

	addDefaultTexts: function ( langid, code ) {
		var subs, defaultText,
		arr = ( code === 'pl' )
			? EConstants.SAMPLE_SUBSECTION_CONTENTS_POLISH
			: EConstants.SAMPLE_SUBSECTION_CONTENTS_FOREIGN;

		for ( subs in arr ) {
			if ( arr.hasOwnProperty( subs ) ) {
				defaultText = arr[ subs ];
				EUi.val( langid, subs, defaultText );
			}
		}
	},

	removeDefaultTexts: function ( langid ) {
		var subs, defaultText,
		arr = ( langid === '0002' )
			? EConstants.SAMPLE_SUBSECTION_CONTENTS_POLISH
			: EConstants.SAMPLE_SUBSECTION_CONTENTS_FOREIGN;

		for ( subs in arr ) {
			if ( arr.hasOwnProperty( subs ) ) {
				defaultText = arr[ subs ];
				
				if ( EUi.isDefaultText( langid, subs, 0 ) ) {
					EUi.val( langid, subs, '' );
				}
			}
		}
	},

	isDefaultText: function ( langid, subsection, extendedMode ) {
		var arr = ( langid === '0002' )
			? EConstants.SAMPLE_SUBSECTION_CONTENTS_POLISH
			: EConstants.SAMPLE_SUBSECTION_CONTENTS_FOREIGN,
		val = EUi.val( langid, subsection );

		if ( extendedMode && val.search( /^: \(\d+\.\d+\)$/ ) !== -1 ) {
			EUi.val( langid, subsection, val + ' ' );
			return true;
		} else {
			return ( val === $.trim( arr[ subsection ] ) );
		}
	},

	val: function ( langid, subsectionTitle, newValue ) {
		if ( newValue === undefined ) {
			return $.trim( $( '#ed_' + langid + '_' + subsectionTitle.replace( / /g, '_' ) ).val() );
		} else {
			$( '#ed_' + langid + '_' + subsectionTitle ).val( newValue );
			return 0;
		}
	},
	
	checkToc: function () {
		var id,
		n = 0,
		sections = Ed.content.sections,
		intro = sections[ EConstants.SECTION_ID_INTRO ];
		
		for ( id in sections ) {
			if ( id !== EConstants.SECTION_ID_INTRO ) {
				n++;
			}
		}
		
		if ( n > 0 && intro ) {
			intro.content = intro.content.replace( '__TOC__', '' ).replace( '\n\n', '' );
			intro.content = $.trim( intro.content );
		} else {
			return;
		}
		
		if ( n === 2 || n === 3 ) {
			intro.content += '\n__TOC__';
			intro.content = $.trim( intro.content );
		}
		
		EUi.val( EConstants.SECTION_ID_INTRO, '', intro.content );
	},
	
	removeDefaultExampleNum: function ( langid ) {
		var re = /^:(?: *\(\d+\.\d+\) *)?$/,
		val = EUi.val( langid, 'przykłady' );
		
		if ( re.test( val ) ) {
			EUi.val( langid, 'przykłady', '' );
		}
	}
};