diff options
Diffstat (limited to 'phpBB/assets/javascript')
| -rw-r--r-- | phpBB/assets/javascript/core.js | 21 | ||||
| -rw-r--r-- | phpBB/assets/javascript/editor.js | 64 | ||||
| -rw-r--r-- | phpBB/assets/javascript/installer.js | 567 | 
3 files changed, 639 insertions, 13 deletions
diff --git a/phpBB/assets/javascript/core.js b/phpBB/assets/javascript/core.js index 4efebcacd1..5844537fc8 100644 --- a/phpBB/assets/javascript/core.js +++ b/phpBB/assets/javascript/core.js @@ -27,7 +27,10 @@ phpbb.isTouch = (window && typeof window.ontouchstart !== 'undefined');   */  phpbb.loadingIndicator = function() {  	if (!$loadingIndicator) { -		$loadingIndicator = $('<div />', { id: 'loading_indicator' }); +		$loadingIndicator = $('<div />', {  +			id: 'loading_indicator',  +			class: 'loading_indicator',  +		});  		$loadingIndicator.appendTo('#page-footer');  	} @@ -958,12 +961,6 @@ phpbb.addAjaxCallback('toggle_link', function() {  	$anchor.each(function() {  		var $this = $(this); -		// Toggle link text -		toggleText = $this.attr('data-toggle-text'); -		$this.attr('data-toggle-text', $this.text()); -		$this.attr('title', $.trim(toggleText)); -		$this.text(toggleText); -  		// Toggle link url  		toggleUrl = $this.attr('data-toggle-url');  		$this.attr('data-toggle-url', $this.attr('href')); @@ -971,8 +968,14 @@ phpbb.addAjaxCallback('toggle_link', function() {  		// Toggle class of link parent  		toggleClass = $this.attr('data-toggle-class'); -		$this.attr('data-toggle-class', $this.parent().attr('class')); -		$this.parent().attr('class', toggleClass); +		$this.attr('data-toggle-class', $this.children().attr('class')); +		$this.children('.icon').attr('class', toggleClass); + +		// Toggle link text +		toggleText = $this.attr('data-toggle-text'); +		$this.attr('data-toggle-text', $this.children('span').text()); +		$this.attr('title', $.trim(toggleText)); +		$this.children('span').text(toggleText);  	});  }); diff --git a/phpBB/assets/javascript/editor.js b/phpBB/assets/javascript/editor.js index 298526ab1f..df353bc29d 100644 --- a/phpBB/assets/javascript/editor.js +++ b/phpBB/assets/javascript/editor.js @@ -111,7 +111,6 @@ function bbfontstyle(bbopen, bbclose) {  	}  	textarea.focus(); -	return;  }  /** @@ -167,7 +166,7 @@ function attachInline(index, filename) {  /**  * Add quote text to message  */ -function addquote(post_id, username, l_wrote) { +function addquote(post_id, username, l_wrote, attributes) {  	var message_name = 'message_' + post_id;  	var theSelection = '';  	var divarea = false; @@ -177,6 +176,9 @@ function addquote(post_id, username, l_wrote) {  		// Backwards compatibility  		l_wrote = 'wrote';  	} +	if (typeof attributes !== 'object') { +		attributes = {}; +	}  	if (document.all) {  		divarea = document.all[message_name]; @@ -213,7 +215,8 @@ function addquote(post_id, username, l_wrote) {  	if (theSelection) {  		if (bbcodeEnabled) { -			insert_text('[quote="' + username + '"]' + theSelection + '[/quote]'); +			attributes.author = username; +			insert_text(generateQuote(theSelection, attributes));  		} else {  			insert_text(username + ' ' + l_wrote + ':' + '\n');  			var lines = split_lines(theSelection); @@ -222,8 +225,61 @@ function addquote(post_id, username, l_wrote) {  			}  		}  	} +} -	return; +/** +* Create a quote block for given text +* +* Possible attributes: +*   - author:  author's name (usually a username) +*   - post_id: post_id of the post being quoted +*   - user_id: user_id of the user being quoted +*   - time:    timestamp of the original message +* +* @param  {!string} text       Quote's text +* @param  {!Object} attributes Quote's attributes +* @return {!string}            Quote block to be used in a new post/text +*/ +function generateQuote(text, attributes) { +	text = text.replace(/^\s+/, '').replace(/\s+$/, ''); +	var quote = '[quote'; +	if (attributes.author) { +		// Add the author as the BBCode's default attribute +		quote += '=' + formatAttributeValue(attributes.author); +		delete attributes.author; +	} +	for (var name in attributes) { +		if (attributes.hasOwnProperty(name)) { +			var value = attributes[name]; +			quote += ' ' + name + '=' + formatAttributeValue(value.toString()); +		} +	} +	quote += ']'; +	var newline = ((quote + text + '[/quote]').length > 80 || text.indexOf('\n') > -1) ? '\n' : ''; +	quote += newline + text + newline + '[/quote]'; + +	return quote; +} + +/** +* Format given string to be used as an attribute value +* +* Will return the string as-is if it can be used in a BBCode without quotes. Otherwise, +* it will use either single- or double- quotes depending on whichever requires less escaping. +* Quotes and backslashes are escaped with backslashes where necessary +* +* @param  {!string} str Original string +* @return {!string}     Same string if possible, escaped string within quotes otherwise +*/ +function formatAttributeValue(str) { +	if (!/[ "'\\\]]/.test(str)) { +		// Return as-is if it contains none of: space, ' " \ or ] +		return str; +	} +	var singleQuoted = "'" + str.replace(/[\\']/g, '\\$&') + "'", +		doubleQuoted = '"' + str.replace(/[\\"]/g, '\\$&') + '"'; + +	return (singleQuoted.length < doubleQuoted.length) ? singleQuoted : doubleQuoted;  }  function split_lines(text) { diff --git a/phpBB/assets/javascript/installer.js b/phpBB/assets/javascript/installer.js new file mode 100644 index 0000000000..d9f446a28d --- /dev/null +++ b/phpBB/assets/javascript/installer.js @@ -0,0 +1,567 @@ +/** + * Installer's AJAX frontend handler + */ + +(function($) { // Avoid conflicts with other libraries +	'use strict'; + +	// Installer variables +	var pollTimer = null; +	var nextReadPosition = 0; +	var progressBarTriggered = false; +	var progressTimer = null; +	var currentProgress = 0; +	var refreshRequested = false; +	var transmissionOver = false; + +	// Template related variables +	var $contentWrapper = $('.install-body').find('.main'); + +	// Intercept form submits +	interceptFormSubmit($('#install_install')); + +	/** +	 * Creates an XHR object +	 * +	 * jQuery cannot be used as the response is streamed, and +	 * as of now, jQuery does not provide access to the response until +	 * the connection is not closed. +	 * +	 * @return XMLHttpRequest +	 */ +	function createXhrObject() { +		return new XMLHttpRequest(); +	} + +	/** +	 * Displays error, warning and log messages +	 * +	 * @param type +	 * @param messages +	 */ +	function addMessage(type, messages) { +		// Get message containers +		var $errorContainer = $('#error-container'); +		var $warningContainer = $('#warning-container'); +		var $logContainer = $('#log-container'); + +		var $title, $description, $msgElement, arraySize = messages.length; +		for (var i = 0; i < arraySize; i++) { +			$msgElement = $('<div />'); +			$title = $('<strong />'); +			$title.text(messages[i].title); +			$msgElement.append($title); + +			if (messages[i].hasOwnProperty('description')) { +				$description = $('<p />'); +				$description.html(messages[i].description); +				$msgElement.append($description); +			} + +			switch (type) { +				case 'error': +					$msgElement.addClass('errorbox'); +					$errorContainer.append($msgElement); +					break; +				case 'warning': +					$msgElement.addClass('warningbox'); +					$warningContainer.append($msgElement); +					break; +				case 'log': +					$msgElement.addClass('log'); +					$logContainer.prepend($msgElement); +					$logContainer.addClass('show_log_container'); +					break; +				case 'success': +					$msgElement.addClass('successbox'); +					$errorContainer.prepend($msgElement); +					break; +			} +		} +	} + +	/** +	 * Render a download box +	 */ +	function addDownloadBox(downloadArray) +	{ +		var $downloadContainer = $('#download-wrapper'); +		var $downloadBox, $title, $content, $link; + +		for (var i = 0; i < downloadArray.length; i++) { +			$downloadBox = $('<div />'); +			$downloadBox.addClass('download-box'); + +			$title = $('<strong />'); +			$title.text(downloadArray[i].title); +			$downloadBox.append($title); + +			if (downloadArray[i].hasOwnProperty('msg')) { +				$content = $('<p />'); +				$content.text(downloadArray[i].msg); +				$downloadBox.append($content); +			} + +			$link = $('<a />'); +			$link.addClass('button1'); +			$link.attr('href', downloadArray[i].href); +			$link.text(downloadArray[i].download); +			$downloadBox.append($link); + +			$downloadContainer.append($downloadBox); +		} +	} + +	/** +	 * Render update files' status +	 */ +	function addUpdateFileStatus(fileStatus) +	{ +		var $statusContainer = $('#file-status-wrapper'); +		$statusContainer.html(fileStatus); +	} + +	/** +	 * Displays a form from the response +	 * +	 * @param formHtml +	 */ +	function addForm(formHtml) { +		var $formContainer = $('#form-wrapper'); +		$formContainer.html(formHtml); +		var $form = $('#install_install'); +		interceptFormSubmit($form); +	} + +	/** +	 * Handles navigation status updates +	 * +	 * @param navObj +	 */ +	function updateNavbarStatus(navObj) { +		var navID, $stage, $stageListItem, $active; +		$active = $('#activemenu'); + +		if (navObj.hasOwnProperty('finished')) { +			// This should be an Array +			var navItems = navObj.finished; + +			for (var i = 0; i < navItems.length; i++) { +				navID = 'installer-stage-' + navItems[i]; +				$stage = $('#' + navID); +				$stageListItem = $stage.parent(); + +				if ($active.length && $active.is($stageListItem)) { +					$active.removeAttr('id'); +				} + +				$stage.addClass('completed'); +			} +		} + +		if (navObj.hasOwnProperty('active')) { +			navID = 'installer-stage-' + navObj.active; +			$stage = $('#' + navID); +			$stageListItem = $stage.parent(); + +			if ($active.length && !$active.is($stageListItem)) { +				$active.removeAttr('id'); +			} + +			$stageListItem.attr('id', 'activemenu'); +		} +	} + +	/** +	 * Renders progress bar +	 * +	 * @param progressObject +	 */ +	function setProgress(progressObject) { +		var $statusText, $progressBar, $progressText, $progressFiller, $progressFillerText; + +		if (progressObject.task_name.length) { +			if (!progressBarTriggered) { +				// Create progress bar +				var $progressBarWrapper = $('#progress-bar-container'); + +				// Create progress bar elements +				$progressBar = $('<div />'); +				$progressBar.attr('id', 'progress-bar'); +				$progressText = $('<p />'); +				$progressText.attr('id', 'progress-bar-text'); +				$progressFiller = $('<div />'); +				$progressFiller.attr('id', 'progress-bar-filler'); +				$progressFillerText = $('<p />'); +				$progressFillerText.attr('id', 'progress-bar-filler-text'); + +				$statusText = $('<p />'); +				$statusText.attr('id', 'progress-status-text'); + +				$progressFiller.append($progressFillerText); +				$progressBar.append($progressText); +				$progressBar.append($progressFiller); + +				$progressBarWrapper.append($statusText); +				$progressBarWrapper.append($progressBar); + +				$progressFillerText.css('width', $progressBar.width()); + +				progressBarTriggered = true; +			} else if (progressObject.hasOwnProperty('restart')) { +				clearInterval(progressTimer); + +				$progressFiller = $('#progress-bar-filler'); +				$progressFillerText = $('#progress-bar-filler-text'); +				$progressText = $('#progress-bar-text'); +				$statusText = $('#progress-status-text'); + +				$progressText.text('0%'); +				$progressFillerText.text('0%'); +				$progressFiller.css('width', '0%'); + +				currentProgress = 0; +			} else { +				$statusText = $('#progress-status-text'); +			} + +			// Update progress bar +			$statusText.text(progressObject.task_name + '…'); +			incrementProgressBar(Math.round(progressObject.task_num / progressObject.task_count * 100)); +		} +	} + +	// Set cookies +	function setCookies(cookies) { +		var cookie; + +		for (var i = 0; i < cookies.length; i++) { +			// Set cookie name and value +			cookie = encodeURIComponent(cookies[i].name) + '=' + encodeURIComponent(cookies[i].value); +			// Set path +			cookie += '; path=/'; +			document.cookie = cookie; +		} +	} + +	// Redirects user +	function redirect(url, use_ajax) { +		if (use_ajax) { +			resetPolling(); + +			var xhReq = createXhrObject(); +			xhReq.open('GET', url, true); +			xhReq.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); +			xhReq.send(); + +			startPolling(xhReq); +		} else { +			window.location.href = url; +		} +	} + +	/** +	 * Parse messages from the response object +	 * +	 * @param messageJSON +	 */ +	function parseMessage(messageJSON) { +		$('#loading_indicator').css('display', 'none'); +		var responseObject; + +		try { +			responseObject = JSON.parse(messageJSON); +		} catch (err) { +			if (window.console) { +				console.log('Failed to parse JSON object\n\nMessage: ' + err.message + '\n\nServer Response: ' + messageJSON); +			} else { +				alert('Failed to parse JSON object\n\nMessage: ' + err.message + '\n\nServer Response: ' + messageJSON); +			} + +			resetPolling(); +			return; +		} + +		// Parse object +		if (responseObject.hasOwnProperty('errors')) { +			addMessage('error', responseObject.errors); +		} + +		if (responseObject.hasOwnProperty('warnings')) { +			addMessage('warning', responseObject.warnings); +		} + +		if (responseObject.hasOwnProperty('logs')) { +			addMessage('log', responseObject.logs); +		} + +		if (responseObject.hasOwnProperty('success')) { +			addMessage('success', responseObject.success); +		} + +		if (responseObject.hasOwnProperty('form')) { +			addForm(responseObject.form); +		} + +		if (responseObject.hasOwnProperty('progress')) { +			setProgress(responseObject.progress); +		} + +		if (responseObject.hasOwnProperty('download')) { +			addDownloadBox(responseObject.download); +		} + +		if (responseObject.hasOwnProperty('file_status')) { +			addUpdateFileStatus(responseObject.file_status); +		} + +		if (responseObject.hasOwnProperty('nav')) { +			updateNavbarStatus(responseObject.nav); +		} + +		if (responseObject.hasOwnProperty('cookies')) { +			setCookies(responseObject.cookies); +		} + +		if (responseObject.hasOwnProperty('refresh')) { +			refreshRequested = true; +		} + +		if (responseObject.hasOwnProperty('redirect')) { +			redirect(responseObject.redirect.url, responseObject.redirect.use_ajax); +		} + +		if (responseObject.hasOwnProperty('over')) { +			if (responseObject.over) { +				transmissionOver = true; +			} +		} +	} + +	/** +	 * Process updates in streamed response +	 * +	 * @param xhReq   XHR object +	 */ +	function pollContent(xhReq) { +		var messages = xhReq.responseText; +		var msgSeparator = '}\n\n'; +		var unprocessed, messageEndIndex, endOfMessageIndex, message; + +		do { +			unprocessed = messages.substring(nextReadPosition); +			messageEndIndex = unprocessed.indexOf(msgSeparator); + +			if (messageEndIndex !== -1) { +				endOfMessageIndex = messageEndIndex + msgSeparator.length; +				message = unprocessed.substring(0, endOfMessageIndex); +				parseMessage($.trim(message)); +				nextReadPosition += endOfMessageIndex; +			} +		} while (messageEndIndex !== -1); + +		if (xhReq.readyState === 4) { +			$('#loading_indicator').css('display', 'none'); +			resetPolling(); + +			var timeoutDetected = !transmissionOver; + +			if (refreshRequested) { +				refreshRequested = false; +				doRefresh(); +			} + +			if (timeoutDetected) { +				addMessage('error', +					[{ +						title: installLang.title, +						description: installLang.msg +					}] +				); +			} +		} +	} + +	/** +	 * Animates the progress bar +	 * +	 * @param $progressText +	 * @param $progressFiller +	 * @param $progressFillerText +	 * @param progressLimit +	 */ +	function incrementFiller($progressText, $progressFiller, $progressFillerText, progressLimit) { +		if (currentProgress >= progressLimit || currentProgress >= 100) { +			clearInterval(progressTimer); +			return; +		} + +		var $progressBar = $('#progress-bar'); + +		currentProgress++; +		$progressFillerText.css('width', $progressBar.width()); +		$progressFillerText.text(currentProgress + '%'); +		$progressText.text(currentProgress + '%'); +		$progressFiller.css('width', currentProgress + '%'); +	} + +	/** +	 * Wrapper function for progress bar rendering and animating +	 * +	 * @param progressLimit +	 */ +	function incrementProgressBar(progressLimit) { +		var $progressFiller = $('#progress-bar-filler'); +		var $progressFillerText = $('#progress-bar-filler-text'); +		var $progressText = $('#progress-bar-text'); +		var progressStart = $progressFiller.width() / $progressFiller.offsetParent().width() * 100; +		currentProgress = Math.floor(progressStart); + +		clearInterval(progressTimer); +		progressTimer = setInterval(function() { +			incrementFiller($progressText, $progressFiller, $progressFillerText, progressLimit); +		}, 10); +	} + +	/** +	 * Resets the polling timer +	 */ +	function resetPolling() { +		clearInterval(pollTimer); +		nextReadPosition = 0; +	} + +	/** +	 * Sets up timer for processing the streamed HTTP response +	 * +	 * @param xhReq +	 */ +	function startPolling(xhReq) { +		resetPolling(); +		transmissionOver = false; +		pollTimer = setInterval(function () { +			pollContent(xhReq); +		}, 250); +	} + +	/** +	 * Refresh page +	 */ +	function doRefresh() { +		resetPolling(); + +		var xhReq = createXhrObject(); +		xhReq.open('GET', $(location).attr('pathname'), true); +		xhReq.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); +		xhReq.send(); + +		startPolling(xhReq); +	} + +	/** +	 * Renders the AJAX UI layout +	 */ +	function setupAjaxLayout() { +		progressBarTriggered = false; + +		// Clear content +		$contentWrapper.html(''); + +		var $header = $('<div />'); +		$header.attr('id', 'header-container'); +		$contentWrapper.append($header); + +		var $description = $('<div />'); +		$description.attr('id', 'description-container'); +		$contentWrapper.append($description); + +		var $errorContainer = $('<div />'); +		$errorContainer.attr('id', 'error-container'); +		$contentWrapper.append($errorContainer); + +		var $warningContainer = $('<div />'); +		$warningContainer.attr('id', 'warning-container'); +		$contentWrapper.append($warningContainer); + +		var $progressContainer = $('<div />'); +		$progressContainer.attr('id', 'progress-bar-container'); +		$contentWrapper.append($progressContainer); + +		var $logContainer = $('<div />'); +		$logContainer.attr('id', 'log-container'); +		$contentWrapper.append($logContainer); + +		var $installerContentWrapper = $('<div />'); +		$installerContentWrapper.attr('id', 'content-container'); +		$contentWrapper.append($installerContentWrapper); + +		var $installerDownloadWrapper = $('<div />'); +		$installerDownloadWrapper.attr('id', 'download-wrapper'); +		$installerContentWrapper.append($installerDownloadWrapper); + +		var $updaterFileStatusWrapper = $('<div />'); +		$updaterFileStatusWrapper.attr('id', 'file-status-wrapper'); +		$installerContentWrapper.append($updaterFileStatusWrapper); + +		var $formWrapper = $('<div />'); +		$formWrapper.attr('id', 'form-wrapper'); +		$installerContentWrapper.append($formWrapper); + +		var $spinner = $('<div />'); +		$spinner.attr('id', 'loading_indicator'); +		$spinner.html(' '); +		$contentWrapper.append($spinner); +	} + +	// Submits a form +	function submitForm($form, $submitBtn) { +		$form.css('display', 'none'); + +		var xhReq = createXhrObject(); +		xhReq.open('POST', $form.attr('action'), true); +		xhReq.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); +		xhReq.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); +		xhReq.send(getFormFields($form, $submitBtn)); + +		// Disable language selector +		$('#language_selector :input, label').css('display', 'none'); + +		// Clear content +		setupAjaxLayout(); +		$('#loading_indicator').css('display', 'block'); + +		startPolling(xhReq); +	} + +	/** +	 * Add submit button to the POST information +	 * +	 * @param $form +	 * @param $submitBtn +	 * +	 * @returns {*} +	 */ +	function getFormFields($form, $submitBtn) { +		var formData = $form.serialize(); +		formData += ((formData.length) ? '&' : '') + encodeURIComponent($submitBtn.attr('name')) + '='; +		formData += encodeURIComponent($submitBtn.attr('value')); + +		return formData; +	} + +	/** +	 * Intercept form submit events and determine the submit button used +	 * +	 * @param $form +	 */ +	function interceptFormSubmit($form) { +		if (!$form.length) { +			return; +		} + +		$form.find(':submit').bind('click', function (event) { +			event.preventDefault(); +			submitForm($form, $(this)); +		}); +	} +})(jQuery); // Avoid conflicts with other libraries  | 
