text: 'use strict';
  const electron = require('electron');
  const cliTruncate = require('cli-truncate');
  const {download} = require('electron-dl');
  const isDev = require('electron-is-dev');
  
  const webContents = win => win.webContents || (win.getWebContents && win.getWebContents());
  
  const decorateMenuItem = menuItem => {
  	return (options = {}) => {
  		if (options.transform && !options.click) {
  			menuItem.transform = options.transform;
  		}
  
  		return menuItem;
  	};
  };
  
  const removeUnusedMenuItems = menuTemplate => {
  	let notDeletedPreviousElement;
  
  	return menuTemplate
  		.filter(menuItem => menuItem !== undefined && menuItem !== false && menuItem.visible !== false)
  		.filter((menuItem, index, array) => {
  			const toDelete = menuItem.type === 'separator' && (!notDeletedPreviousElement || index === array.length - 1 || array[index + 1].type === 'separator');
  			notDeletedPreviousElement = toDelete ? notDeletedPreviousElement : menuItem;
  			return !toDelete;
  		});
  };
  
  const create = (win, options) => {
  	webContents(win).on('context-menu', (event, props) => {
  		if (typeof options.shouldShowMenu === 'function' && options.shouldShowMenu(event, props) === false) {
  			return;
  		}
  
  		const {editFlags} = props;
  		const hasText = props.selectionText.trim().length > 0;
  		const isLink = Boolean(props.linkURL);
  		const can = type => editFlags[`can${type}`] && hasText;
  
  		const defaultActions = {
  			separator: () => ({type: 'separator'}),
  			lookUpSelection: decorateMenuItem({
  				id: 'lookUpSelection',
  				label: '查找 “{selection}”',
  				visible: process.platform === 'darwin' && hasText && !isLink,
  				click() {
  					if (process.platform === 'darwin') {
  						webContents(win).showDefinitionForSelection();
  					}
  				}
  			}),
  			cut: decorateMenuItem({
  				id: 'cut',
  				label: '剪切',
  				enabled: can('Cut'),
  				visible: props.isEditable,
  				click(menuItem) {
  					props.selectionText = menuItem.transform ? menuItem.transform(props.selectionText) : props.selectionText;
  					electron.clipboard.writeText(props.selectionText);
  					webContents(win).delete();
  				}
  			}),
  			copy: decorateMenuItem({
  				id: 'copy',
  				label: '复制',
  				enabled: can('Copy'),
  				visible: props.isEditable || hasText,
  				click(menuItem) {
  					props.selectionText = menuItem.transform ? menuItem.transform(props.selectionText) : props.selectionText;
  					electron.clipboard.writeText(props.selectionText);
  				}
  			}),
  			paste: decorateMenuItem({
  				id: 'paste',
  				label: '粘贴',
  				enabled: editFlags.canPaste,
  				visible: props.isEditable,
  				click(menuItem) {
  					let clipboardContent = electron.clipboard.readText(props.selectionText);
  					clipboardContent = menuItem.transform ? menuItem.transform(clipboardContent) : clipboardContent;
  					webContents(win).insertText(clipboardContent);
  				}
  			}),
  			saveImage: decorateMenuItem({
  				id: 'saveImage',
  				label: '保存图片',
  				visible: props.mediaType === 'image',
  				click(menuItem) {
  					props.srcURL = menuItem.transform ? menuItem.transform(props.srcURL) : props.srcURL;
  					download(win, props.srcURL);
  				}
  			}),
  			saveImageAs: decorateMenuItem({
  				id: 'saveImageAs',
  				label: '图片另存为…',
  				visible: props.mediaType === 'image',
  				click(menuItem) {
  					props.srcURL = menuItem.transform ? menuItem.transform(props.srcURL) : props.srcURL;
  					download(win, props.srcURL, {saveAs: true});
  				}
  			}),
  			copyLink: decorateMenuItem({
  				id: 'copyLink',
  				label: '复制链接',
  				visible: props.linkURL.length !== 0 && props.mediaType === 'none',
  				click(menuItem) {
  					props.linkURL = menuItem.transform ? menuItem.transform(props.linkURL) : props.linkURL;
  
  					electron.clipboard.write({
  						bookmark: props.linkText,
  						text: props.linkURL
  					});
  				}
  			}),
  			copyImage: decorateMenuItem({
  				id: 'copyImage',
  				label: '复制图片',
  				visible: props.mediaType === 'image',
  				click() {
  					webContents(win).copyImageAt(props.x, props.y);
  				}
  			}),
  			copyImageAddress: decorateMenuItem({
  				id: 'copyImageAddress',
  				label: '复制图片地址',
  				visible: props.mediaType === 'image',
  				click(menuItem) {
  					props.srcURL = menuItem.transform ? menuItem.transform(props.srcURL) : props.srcURL;
  
  					electron.clipboard.write({
  						bookmark: props.srcURL,
  						text: props.srcURL
  					});
  				}
  			}),
  			inspect: () => ({
  				id: 'inspect',
  				label: '查看元素',
  				click() {
  					win.inspectElement(props.x, props.y);
  
  					if (webContents(win).isDevToolsOpened()) {
  						webContents(win).devToolsWebContents.focus();
  					}
  				}
  			}),
  			services: () => ({
  				id: 'services',
  				label: '服务',
  				role: 'services',
  				visible: process.platform === 'darwin' && (props.isEditable || hasText)
  			})
  		};
  
  		const shouldShowInspectElement = typeof options.showInspectElement === 'boolean' ? options.showInspectElement : isDev;
  
  		let menuTemplate = [
  			defaultActions.separator(),
  			options.showLookUpSelection !== false && defaultActions.lookUpSelection(),
  			defaultActions.separator(),
  			defaultActions.cut(),
  			defaultActions.copy(),
  			defaultActions.paste(),
  			defaultActions.separator(),
  			defaultActions.saveImage(),
  			options.showSaveImageAs && defaultActions.saveImageAs(),
  			options.showCopyImage !== false && defaultActions.copyImage(),
  			options.showCopyImageAddress && defaultActions.copyImageAddress(),
  			defaultActions.separator(),
  			defaultActions.copyLink(),
  			defaultActions.separator(),
  			shouldShowInspectElement && defaultActions.inspect(),
  			options.showServices && defaultActions.services(),
  			defaultActions.separator()
  		];
  
  		if (options.menu) {
  			menuTemplate = options.menu(defaultActions, props, win);
  		}
  
  		if (options.prepend) {
  			const result = options.prepend(defaultActions, props, win);
  
  			if (Array.isArray(result)) {
  				menuTemplate.unshift(...result);
  			}
  		}
  
  		if (options.append) {
  			const result = options.append(defaultActions, props, win);
  
  			if (Array.isArray(result)) {
  				menuTemplate.push(...result);
  			}
  		}
  
  		// Filter out leading/trailing separators
  		// TODO: https://github.com/electron/electron/issues/5869
  		menuTemplate = removeUnusedMenuItems(menuTemplate);
  
  		for (const menuItem of menuTemplate) {
  			// Apply custom labels for default menu items
  			if (options.labels && options.labels[menuItem.id]) {
  				menuItem.label = options.labels[menuItem.id];
  			}
  
  			// Replace placeholders in menu item labels
  			if (typeof menuItem.label === 'string' && menuItem.label.includes('{selection}')) {
  				const selectionString = typeof props.selectionText === 'string' ? props.selectionText.trim() : '';
  				menuItem.label = menuItem.label.replace('{selection}', cliTruncate(selectionString, 25));
  			}
  		}
  
  		if (menuTemplate.length > 0) {
  			const menu = (electron.remote ? electron.remote.Menu : electron.Menu).buildFromTemplate(menuTemplate);
  
  			/*
  			When `electron.remote` is not available, this runs in the browser process.
  
  			We can safely use `win` in this case as it refers to the window the
  			context-menu should open in.
  
  			When this is being called from a web view, we can't use `win` as this
  			would refer to the web view which is not allowed to render a popup menu.
  			*/
  			menu.popup(electron.remote ? electron.remote.getCurrentWindow() : win);
  		}
  	});
  };
  
  module.exports = (options = {}) => {
  	if (options.window) {
  		const win = options.window;
  
  		// When window is a webview that has not yet finished loading webContents is not available
  		if (webContents(win) === undefined) {
  			win.addEventListener('dom-ready', () => {
  				create(win, options);
  			}, {once: true});
  			return;
  		}
  
  		return create(win, options);
  	}
  
  	for (const win of (electron.BrowserWindow || electron.remote.BrowserWindow).getAllWindows()) {
  		create(win, options);
  	}
  
  	(electron.app || electron.remote.app).on('browser-window-created', (event, win) => {
  		create(win, options);
  	});
  };
  