Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
code / usr / share / code / resources / app / extensions / markdown / media / main.js
Size: Mime:
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

'use strict';

(function () {
	// From https://remysharp.com/2010/07/21/throttling-function-calls
	function throttle(fn, threshhold, scope) {
		threshhold || (threshhold = 250);
		var last, deferTimer;
		return function () {
			var context = scope || this;

			var now = +new Date,
				args = arguments;
			if (last && now < last + threshhold) {
				// hold on to it
				clearTimeout(deferTimer);
				deferTimer = setTimeout(function () {
					last = now;
					fn.apply(context, args);
				}, threshhold + last - now);
			} else {
				last = now;
				fn.apply(context, args);
			}
		};
	}

	/**
	 * Find the html elements that map to a specific target line in the editor.
	 *
	 * If an exact match, returns a single element. If the line is between elements,
	 * returns the element prior to and the element after the given line.
	 */
	function getElementsForSourceLine(targetLine) {
		const lines = document.getElementsByClassName('code-line');
		let previous = lines[0] && +lines[0].getAttribute('data-line') ? { line: +lines[0].getAttribute('data-line'), element: lines[0] } : null;
		for (const element of lines) {
			const lineNumber = +element.getAttribute('data-line');
			if (isNaN(lineNumber)) {
				continue;
			}
			const entry = { line: lineNumber, element: element };
			if (lineNumber === targetLine) {
				return { previous: entry, next: null };
			} else if (lineNumber > targetLine) {
				return { previous, next: entry };
			}
			previous = entry;
		}
		return { previous };
	}

	/**
	 * Find the html elements that are at a specific pixel offset on the page.
	 */
	function getLineElementsAtPageOffset(offset) {
		const lines = document.getElementsByClassName('code-line');
		let previous = null;
		for (const element of lines) {
			const line = +element.getAttribute('data-line');
			if (isNaN(line)) {
				continue;
			}
			const bounds = element.getBoundingClientRect();
			const entry = { element, line };
			if (offset >= window.scrollY + bounds.top && offset <= window.scrollY + bounds.top + bounds.height) {
				// add progress through element
				entry.line += (offset - (window.scrollY + bounds.top)) / (bounds.height);
				return { previous: entry };
			} else if (offset < window.scrollY + bounds.top) {
				return { previous, next: entry };
			}
			previous = entry;
		}
		return { previous };
	}

	function getSourceRevealAddedOffset() {
		return -(window.innerHeight * 1 / 5);
	}

	/**
	 * Attempt to reveal the element for a source line in the editor.
	 */
	function scrollToRevealSourceLine(line) {
		const {previous, next} = getElementsForSourceLine(line);
		marker.update(previous && previous.element);
		if (previous && window.initialData.scrollPreviewWithEditorSelection) {
			let scrollTo = 0;
			if (next) {
				// Between two elements. Go to percentage offset between them.
				const betweenProgress = (line - previous.line) / (next.line - previous.line);
				const elementOffset = next.element.getBoundingClientRect().top - previous.element.getBoundingClientRect().top;
				scrollTo = previous.element.getBoundingClientRect().top + betweenProgress * elementOffset;
			} else {
				scrollTo = previous.element.getBoundingClientRect().top;
			}
			window.scroll(0, window.scrollY + scrollTo + getSourceRevealAddedOffset());
		}
	}

	function getEditorLineNumberForPageOffset(offset) {
		const {previous, next} = getLineElementsAtPageOffset(offset);
		if (previous) {
			if (next) {
				const betweenProgress = (offset - window.scrollY - previous.element.getBoundingClientRect().top) / (next.element.getBoundingClientRect().top - previous.element.getBoundingClientRect().top);
				return previous.line + betweenProgress * (next.line - previous.line);
			} else {
				return previous.line;
			}
		}
		return null;
	}


	class ActiveLineMarker {
		update(before) {
			this._unmarkActiveElement(this._current);
			this._markActiveElement(before);
			this._current = before;
		}

		_unmarkActiveElement(element) {
			if (!element) {
				return;
			}
			element.className = element.className.replace(/\bcode-active-line\b/g);
		}

		_markActiveElement(element) {
			if (!element) {
				return;
			}
			element.className += ' code-active-line';
		}
	}

	var scrollDisabled = true;
	var marker = new ActiveLineMarker();

	window.onload = () => {
		if (window.initialData.scrollPreviewWithEditorSelection) {
			const initialLine = +window.initialData.line;
			if (!isNaN(initialLine)) {
				setTimeout(() => {
					scrollDisabled = true;
					scrollToRevealSourceLine(initialLine);
				}, 0);
			}
		}
	};

	window.addEventListener('resize', () => {
		scrollDisabled = true;
	}, true);

	window.addEventListener('message', event => {
		const line = +event.data.line;
		if (!isNaN(line)) {
			scrollDisabled = true;
			scrollToRevealSourceLine(line);
		}
	}, false);

	document.addEventListener('dblclick', event => {
		if (!window.initialData.doubleClickToSwitchToEditor) {
			return;
		}

		// Ignore clicks on links
		for (let node = event.target; node; node = node.parentNode) {
			if (node.tagName === "A") {
				return;
			}
		}

		const offset = event.pageY;
		const line = getEditorLineNumberForPageOffset(offset);
		if (!isNaN(line)) {
			const args = [window.initialData.source, line];
			window.parent.postMessage({
				command: "did-click-link",
				data: `command:_markdown.didClick?${encodeURIComponent(JSON.stringify(args))}`
			}, "file://");
		}
	});

	if (window.initialData.scrollEditorWithPreview) {

		window.addEventListener('scroll', throttle(() => {
			if (scrollDisabled) {
				scrollDisabled = false;
			} else {
				const line = getEditorLineNumberForPageOffset(window.scrollY);
				if (!isNaN(line)) {
					const args = [window.initialData.source, line];
					window.parent.postMessage({
						command: "did-click-link",
						data: `command:_markdown.revealLine?${encodeURIComponent(JSON.stringify(args))}`
					}, "file://");
				}
			}
		}, 50));
	}
}());