electron#WebContents TypeScript Examples

The following examples show how to use electron#WebContents. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: overlay-window.ts    From awakened-poe-trade with MIT License 6 votes vote down vote up
function modifyResponseHeaders (webContents: WebContents) {
  webContents.session.webRequest.onHeadersReceived({
    urls: ['https://*/*']
  }, (details, next) => {
    if (!details.responseHeaders) return next({})

    for (const key in details.responseHeaders) {
      if (key.toLowerCase() === 'set-cookie') {
        details.responseHeaders[key] = details.responseHeaders[key].map(cookie => {
          cookie = cookie
            .split(';')
            .map(_ => _.trim())
            .filter(_ =>
              !_.toLowerCase().startsWith('samesite') &&
              !_.toLowerCase().startsWith('secure'))
            .join('; ')

          return `${cookie}; SameSite=None; Secure`
        })
      }
    }

    next({ responseHeaders: details.responseHeaders })
  })
}
Example #2
Source File: contextMenuBuilder.ts    From TidGi-Desktop with Mozilla Public License 2.0 6 votes vote down vote up
/**
   * Creates an instance of ContextMenuBuilder
   *
   * @param   webContents  The hosting window's WebView
   * @param   processMenu If passed, this method will be passed the menu to change
   *                                it prior to display. Signature: (menu, info) => menu
   */
  constructor(webContents: WebContents, processMenu = (m: Menu) => m) {
    this.processMenu = processMenu;
    this.stringTable = { ...contextMenuStringTable };
    this.webContents = webContents;
  }
Example #3
Source File: rendererMenuItemProxy.ts    From TidGi-Desktop with Mozilla Public License 2.0 6 votes vote down vote up
/**
 * Reconstruct the object with callback on the main process, the callback is just IPCMain.invoke(uuid
 */
export function mainMenuItemProxy(menus: IpcSafeMenuItem[], webContents: WebContents): MenuItemConstructorOptions[] {
  const newMenus: MenuItemConstructorOptions[] = [];
  for (const menu of menus) {
    const clickIpcCallback = (): void => {
      webContents.send(menu.click);
    };
    newMenus.push({ ...menu, click: clickIpcCallback });
  }

  return newMenus;
}
Example #4
Source File: index.ts    From TidGi-Desktop with Mozilla Public License 2.0 6 votes vote down vote up
/** Register `on('context-menu', openContextMenuForWindow)` for a window, return an unregister function */
  public async initContextMenuForWindowWebContents(webContents: WebContents): Promise<() => void> {
    const openContextMenuForWindow = async (event: Electron.Event, parameters: ContextMenuParams): Promise<void> =>
      await this.buildContextMenuAndPopup([], parameters, webContents);
    webContents.on('context-menu', openContextMenuForWindow);

    return () => {
      if (webContents.isDestroyed()) {
        return;
      }

      webContents.removeListener('context-menu', openContextMenuForWindow);
    };
  }
Example #5
Source File: store.ts    From electron-browser-shell with GNU General Public License v3.0 6 votes vote down vote up
async createTab(details: chrome.tabs.CreateProperties) {
    if (typeof this.impl.createTab !== 'function') {
      throw new Error('createTab is not implemented')
    }

    // Fallback to current window
    if (!details.windowId) {
      details.windowId = this.lastFocusedWindowId
    }

    const result = await this.impl.createTab(details)

    if (!Array.isArray(result)) {
      throw new Error('createTab must return an array of [tab, window]')
    }

    const [tab, window] = result

    if (typeof tab !== 'object' || !webContents.fromId(tab.id)) {
      throw new Error('createTab must return a WebContents')
    } else if (typeof window !== 'object') {
      throw new Error('createTab must return a BrowserWindow')
    }

    this.addTab(tab, window)

    return tab
  }
Example #6
Source File: main.ts    From desktop with MIT License 5 votes vote down vote up
function listenForNewWindow(webContents: WebContents): void {
  webContents.on(`new-window`, (event, url) => {
    // Intercept window.open/target=_blank from admin and open in browser
    event.preventDefault()
    shell.openExternal(url)
  })
}
Example #7
Source File: router.ts    From electron-browser-shell with GNU General Public License v3.0 5 votes vote down vote up
private observeListenerHost(host: Electron.WebContents) {
    debug(`observing listener [id:${host.id}, url:'${host.getURL()}']`)
    host.once('destroyed', () => {
      debug(`extension host destroyed [id:${host.id}]`)
      this.filterListeners((listener) => listener.host !== host)
    })
  }
Example #8
Source File: router.ts    From electron-browser-shell with GNU General Public License v3.0 5 votes vote down vote up
/**
   * Collection of all extension hosts in the session.
   *
   * Currently the router has no ability to wake up non-persistent background
   * scripts to deliver events. For now we just hold a reference to them to
   * prevent them from being terminated.
   */
  private extensionHosts: Set<Electron.WebContents> = new Set()
Example #9
Source File: index.ts    From electron-playground with MIT License 5 votes vote down vote up
listenerDownload = async (
  event: Event,
  item: DownloadItem,
  webContents: WebContents,
): Promise<void> => {
  // 新建下载为空时,会执行 electron 默认的下载处理
  if (!newDownloadItem) return

  let prevReceivedBytes = 0 // 记录上一次下载的字节数据
  // 添加下载项
  const downloadItem: IDownloadFile = await addDownloadItem({
    item,
    downloadIds: tempDownloadItemIds,
    data: downloadItemData,
    newDownloadItem,
  })

  setTaskbar(downloadItemData, downloadCompletedIds, -1, win)

  // 新下载任务创建完成,渲染进程监听该事件,添加到下载管理器列表
  webContents.send('newDownloadItem', { ...downloadItem, _sourceItem: null })

  // 更新下载
  item.on('updated', (e, state) => {
    const receivedBytes = updateDownloadItem({
      item,
      downloadItem,
      data: downloadItemData,
      prevReceivedBytes,
      state,
    })
    prevReceivedBytes = receivedBytes

    // 获取所有下载中的接受字节和总字节数据
    const bytes = getDownloadBytes(downloadItemData)
    // 更新任务栏进度
    win?.setProgressBar(bytes.receivedBytes / bytes.totalBytes)
    // 通知渲染进程,更新下载状态
    webContents.send('downloadItemUpdate', { ...downloadItem, _sourceItem: null })
  })

  // 下载完成
  item.on('done', (e, state) => {
    downloadItem.state = state
    downloadItem.receivedBytes = item.getReceivedBytes()

    if (state !== 'cancelled') {
      downloadCompletedIds.push(downloadItem.id)
    }

    setTaskbar(downloadItemData, downloadCompletedIds, 0, win)
    // 下载成功
    if (state === 'completed' && process.platform === 'darwin') {
      app.dock.downloadFinished(downloadItem.path)
    }

    setDownloadStore(downloadItemData)
    // 通知渲染进程,更新下载状态
    webContents.send('downloadItemDone', { ...downloadItem, _sourceItem: null })
  })
}
Example #10
Source File: contextMenuBuilder.ts    From TidGi-Desktop with Mozilla Public License 2.0 5 votes vote down vote up
webContents: WebContents;
Example #11
Source File: chrome-browserAction-spec.ts    From electron-browser-shell with GNU General Public License v3.0 4 votes vote down vote up
describe('chrome.browserAction', () => {
  const server = useServer()

  const defaultAnchorRect = {
    x: 0,
    y: 0,
    width: 16,
    height: 16,
  }

  const activateExtension = async (
    partition: string,
    webContents: WebContents,
    extension: Extension,
    tabId: number = -1
  ) => {
    const details = {
      eventType: 'click',
      extensionId: extension.id,
      tabId,
      anchorRect: defaultAnchorRect,
    }

    const js = `browserAction.activate('${partition}', ${JSON.stringify(details)})`
    await webContents.executeJavaScript(js)
  }

  describe('messaging', () => {
    const browser = useExtensionBrowser({
      url: server.getUrl,
      extensionName: 'chrome-browserAction-click',
    })

    it('supports cross-session communication', async () => {
      const otherSession = session.fromPartition(`persist:crx-${uuid()}`)
      otherSession.setPreloads(browser.session.getPreloads())

      const view = new BrowserView({
        webPreferences: { session: otherSession, nodeIntegration: false, contextIsolation: true },
      })
      await view.webContents.loadURL(server.getUrl())
      browser.window.addBrowserView(view)
      await activateExtension(browser.partition, view.webContents, browser.extension)
    })

    it('can request action for specific tab', async () => {
      const tab = browser.window.webContents
      await activateExtension(browser.partition, tab, browser.extension, tab.id)
    })

    it('throws for unknown tab', async () => {
      const tab = browser.window.webContents
      const unknownTabId = 99999
      let caught = false
      try {
        await activateExtension(browser.partition, tab, browser.extension, unknownTabId)
      } catch {
        caught = true
      }
      expect(caught).to.be.true
    })
  })

  describe('onClicked', () => {
    const browser = useExtensionBrowser({
      url: server.getUrl,
      extensionName: 'chrome-browserAction-click',
    })

    it('fires listeners when activated', async () => {
      const tabPromise = emittedOnce(ipcMain, 'success')
      await activateExtension(browser.partition, browser.window.webContents, browser.extension)
      const [_, tabDetails] = await tabPromise
      expect(tabDetails).to.be.an('object')
      expect(tabDetails.id).to.equal(browser.window.webContents.id)
    })
  })

  describe('popup', () => {
    const browser = useExtensionBrowser({
      url: server.getUrl,
      extensionName: 'chrome-browserAction-popup',
    })

    it('opens when the browser action is clicked', async () => {
      const popupPromise = emittedOnce(browser.extensions, 'browser-action-popup-created')
      await activateExtension(browser.partition, browser.window.webContents, browser.extension)
      const [popup] = await popupPromise
      expect(popup.extensionId).to.equal(browser.extension.id)
    })

    it('opens when BrowserView is the active tab', async () => {
      const view = new BrowserView({
        webPreferences: {
          session: browser.session,
          nodeIntegration: false,
          contextIsolation: true,
        },
      })
      await view.webContents.loadURL(server.getUrl())
      browser.window.addBrowserView(view)
      browser.extensions.addTab(view.webContents, browser.window)
      browser.extensions.selectTab(view.webContents)

      const popupPromise = emittedOnce(browser.extensions, 'browser-action-popup-created')
      await activateExtension(browser.partition, browser.window.webContents, browser.extension)
      const [popup] = await popupPromise
      expect(popup.extensionId).to.equal(browser.extension.id)
    })
  })

  describe('details', () => {
    const browser = useExtensionBrowser({
      url: server.getUrl,
      extensionName: 'rpc',
    })

    const props = [
      { method: 'BadgeBackgroundColor', detail: 'color', value: '#cacaca' },
      { method: 'BadgeText', detail: 'text' },
      { method: 'Popup', detail: 'popup' },
      { method: 'Title', detail: 'title' },
    ]

    for (const { method, detail, value } of props) {
      it(`sets and gets '${detail}'`, async () => {
        const newValue = value || uuid()
        await browser.crx.exec(`browserAction.set${method}`, { [detail]: newValue })
        const result = await browser.crx.exec(`browserAction.get${method}`)
        expect(result).to.equal(newValue)
      })

      it(`restores initial values for '${detail}'`, async () => {
        const newValue = value || uuid()
        const initial = await browser.crx.exec(`browserAction.get${method}`)
        await browser.crx.exec(`browserAction.set${method}`, { [detail]: newValue })
        await browser.crx.exec(`browserAction.set${method}`, { [detail]: null })
        const result = await browser.crx.exec(`browserAction.get${method}`)
        expect(result).to.equal(initial)
      })
    }

    it('uses custom popup when opening browser action', async () => {
      const popupUuid = uuid()
      const popupPath = `popup.html?${popupUuid}`
      await browser.crx.exec('browserAction.setPopup', { popup: popupPath })
      const popupPromise = emittedOnce(browser.extensions, 'browser-action-popup-created')
      await activateExtension(browser.partition, browser.window.webContents, browser.extension)
      const [popup] = await popupPromise
      await popup.whenReady()
      expect(popup.browserWindow.webContents.getURL()).to.equal(
        `chrome-extension://${browser.extension.id}/${popupPath}`
      )
    })
  })

  describe('<browser-action-list> element', () => {
    const basePath = path.join(__dirname, 'fixtures/browser-action-list')

    const browser = useExtensionBrowser({
      extensionName: 'chrome-browserAction-popup',
    })

    it('lists actions', async () => {
      await browser.webContents.loadFile(path.join(basePath, 'default.html'))

      const extensionIds = await browser.webContents.executeJavaScript(
        `(${() => {
          const list = document.querySelector('browser-action-list')!
          const actions = list.shadowRoot!.querySelectorAll('.action')
          const ids = Array.from(actions).map((elem) => elem.id)
          return ids
        }})();`
      )

      expect(extensionIds).to.deep.equal([browser.extension.id])
    })

    it('lists actions in remote partition', async () => {
      const remoteWindow = createCrxRemoteWindow()
      const remoteTab = remoteWindow.webContents

      await remoteTab.loadURL(server.getUrl())

      // Add <browser-action-list> for remote partition.
      await remoteTab.executeJavaScript(
        `(${(partition: string) => {
          const list = document.createElement('browser-action-list')
          list.setAttribute('partition', partition)
          document.body.appendChild(list)
        }})('${browser.partition}');`
      )

      const extensionIds = await remoteTab.executeJavaScript(
        `(${() => {
          const list = document.querySelector('browser-action-list')!
          const actions = list.shadowRoot!.querySelectorAll('.action')
          const ids = Array.from(actions).map((elem) => elem.id)
          return ids
        }})();`
      )

      expect(extensionIds).to.deep.equal([browser.extension.id])
    })
  })
})
Example #12
Source File: index.ts    From TidGi-Desktop with Mozilla Public License 2.0 4 votes vote down vote up
public async buildContextMenuAndPopup(
    template: MenuItemConstructorOptions[] | IpcSafeMenuItem[],
    info: IOnContextMenuInfo,
    webContentsOrWindowName: WindowNames | WebContents = WindowNames.main,
  ): Promise<void> {
    let webContents: WebContents;
    if (typeof webContentsOrWindowName === 'string') {
      const windowToPopMenu = this.windowService.get(webContentsOrWindowName);
      const webContentsOfWindowToPopMenu = windowToPopMenu?.webContents;
      if (windowToPopMenu === undefined || webContentsOfWindowToPopMenu === undefined) {
        return;
      }
      webContents = webContentsOfWindowToPopMenu;
    } else {
      webContents = webContentsOrWindowName;
    }
    const sidebar = await this.preferenceService.get('sidebar');
    const contextMenuBuilder = new ContextMenuBuilder(webContents);
    const menu = contextMenuBuilder.buildMenuForElement(info);
    // show workspace menu to manipulate workspaces if sidebar is not open
    if (!sidebar) {
      menu.append(new MenuItem({ type: 'separator' }));
      const workspaces = await this.workspaceService.getWorkspacesAsList();
      const services = {
        auth: this.authService,
        context: this.contextService,
        git: this.gitService,
        native: this.nativeService,
        view: this.viewService,
        wiki: this.wikiService,
        wikiGitWorkspace: this.wikiGitWorkspaceService,
        window: this.windowService,
        workspace: this.workspaceService,
        workspaceView: this.workspaceViewService,
      };
      menu.append(
        new MenuItem({
          label: i18next.t('ContextMenu.OpenCommandPalette'),
          enabled: workspaces.length > 0,
          click: () => {
            void this.wikiService.requestWikiSendActionMessage('open-command-palette');
          },
        }),
      );
      menu.append(
        new MenuItem({
          label: i18next.t('Menu.Workspaces'),
          submenu: [
            ...(await Promise.all(
              workspaces.map(async (workspace) => {
                const workspaceContextMenuTemplate = await getWorkspaceMenuTemplate(workspace, i18next.t.bind(i18next), services);
                return {
                  label: workspace.name,
                  submenu: workspaceContextMenuTemplate,
                };
              }),
            )),
            {
              label: i18next.t('WorkspaceSelector.Add'),
              click: async () => await this.windowService.open(WindowNames.addWorkspace),
            },
          ],
        }),
      );
      menu.append(
        new MenuItem({
          label: i18next.t('WorkspaceSelector.OpenWorkspaceMenuName'),
          submenu: workspaces.map((workspace) => ({
            label: i18next.t('WorkspaceSelector.OpenWorkspaceTagTiddler', { tagName: workspace.tagName ?? workspace.name }),
            click: async () => {
              await openWorkspaceTagTiddler(workspace, services);
            },
          })),
        }),
      );
    }
    menu.append(
      new MenuItem({
        label: i18next.t('ContextMenu.Back'),
        enabled: webContents.canGoBack(),
        click: () => {
          webContents.goBack();
        },
      }),
    );
    menu.append(
      new MenuItem({
        label: i18next.t('ContextMenu.Forward'),
        enabled: webContents.canGoForward(),
        click: () => {
          webContents.goForward();
        },
      }),
    );
    menu.append(
      new MenuItem({
        label: i18next.t('ContextMenu.Reload'),
        click: () => {
          webContents.reload();
        },
      }),
    );
    menu.append(
      new MenuItem({
        label: i18next.t('ContextMenu.RestartService'),
        click: async () => {
          const workspace = await this.workspaceService.getActiveWorkspace();
          if (workspace !== undefined) {
            await this.workspaceViewService.restartWorkspaceViewService(workspace.id);
            await this.workspaceViewService.realignActiveWorkspace(workspace.id);
          }
        },
      }),
    );
    menu.append(
      new MenuItem({
        label: sidebar ? i18next.t('Preference.HideSideBar') : i18next.t('Preference.ShowSideBar'),
        click: async () => {
          await this.preferenceService.set('sidebar', !sidebar);
          await this.workspaceViewService.realignActiveWorkspace();
        },
      }),
    );
    menu.append(new MenuItem({ type: 'separator' }));
    menu.append(
      new MenuItem({
        label: i18next.t('ContextMenu.More'),
        submenu: [
          {
            label: i18next.t('ContextMenu.Preferences'),
            click: async () => await this.windowService.open(WindowNames.preferences),
          },
          { type: 'separator' },
          {
            label: i18next.t('ContextMenu.About'),
            click: async () => await this.windowService.open(WindowNames.about),
          },
          {
            label: i18next.t('ContextMenu.TidGiSupport'),
            click: async () => await shell.openExternal('https://github.com/tiddly-gittly/TidGi-Desktop/issues/new/choose'),
          },
          {
            label: i18next.t('ContextMenu.TidGiWebsite'),
            click: async () => await shell.openExternal('https://github.com/tiddly-gittly/TidGi-Desktop'),
          },
          { type: 'separator' },
          {
            label: i18next.t('ContextMenu.Quit'),
            click: () => app.quit(),
          },
        ],
      }),
    );

    // add custom menu items
    if (template !== undefined && Array.isArray(template) && template.length > 0) {
      // if our menu item config is pass from the renderer process, we reconstruct callback from the ipc.on channel id.
      const menuItems = (typeof template?.[0]?.click === 'string'
        ? mainMenuItemProxy(template as IpcSafeMenuItem[], webContents)
        : template) as unknown as MenuItemConstructorOptions[];
      menu.insert(0, new MenuItem({ type: 'separator' }));
      // we are going to prepend items, so inverse first, so order will remain
      reverse(menuItems)
        .map((menuItem) => new MenuItem(menuItem))
        .forEach((menuItem) => menu.insert(0, menuItem));
    }

    menu.popup();
  }