Skip to content
This repository has been archived by the owner on Dec 11, 2019. It is now read-only.

Fixing bookmarks toolbar "hover after click" behavior on folders #4361

Merged
merged 3 commits into from
Oct 10, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions js/lib/faviconUtil.js → app/common/lib/faviconUtil.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,18 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

const {isSourceAboutUrl} = require('./appUrlUtil')
const UrlUtil = require('./urlutil')
const { isSourceAboutUrl } = require('../../../js/lib/appUrlUtil')
const UrlUtil = require('../../../js/lib/urlutil')

module.exports = function getFavicon (frameProps, iconHref) {
module.exports.iconSize = 16

module.exports.getFavicon = (frameProps, iconHref) => {
return new Promise((resolve, reject) => {
if (!frameProps.get('location')) {
resolve(null)
}

const size = window.devicePixelRatio * 16
const size = window.devicePixelRatio * module.exports.iconSize
const resolution = '#-moz-resolution=' + size + ',' + size

// Default to favicon.ico if we can't find an icon.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,46 +4,69 @@

const React = require('react')
const ReactDOM = require('react-dom')
const ImmutableComponent = require('./immutableComponent')
const contextMenus = require('../contextMenus')
const windowActions = require('../actions/windowActions')
const bookmarkActions = require('../actions/bookmarkActions')
const appActions = require('../actions/appActions')
const siteTags = require('../constants/siteTags')
const siteUtil = require('../state/siteUtil')
const dragTypes = require('../constants/dragTypes')
const Button = require('../components/button')
const cx = require('../lib/classSet')
const dnd = require('../dnd')
const dndData = require('../dndData')
const calculateTextWidth = require('../lib/textCalculator').calculateTextWidth
const windowStore = require('../stores/windowStore')
const iconSize = 16
const ImmutableComponent = require('../../../js/components/immutableComponent')
const contextMenus = require('../../../js/contextMenus')
const windowActions = require('../../../js/actions/windowActions')
const bookmarkActions = require('../../../js/actions/bookmarkActions')
const appActions = require('../../../js/actions/appActions')
const siteTags = require('../../../js/constants/siteTags')
const siteUtil = require('../../../js/state/siteUtil')
const dragTypes = require('../../../js/constants/dragTypes')
const Button = require('../../../js/components/button')
const cx = require('../../../js/lib/classSet')
const dnd = require('../../../js/dnd')
const dndData = require('../../../js/dndData')
const calculateTextWidth = require('../../../js/lib/textCalculator').calculateTextWidth
const windowStore = require('../../../js/stores/windowStore')
const iconSize = require('../../common/lib/faviconUtil').iconSize

class BookmarkToolbarButton extends ImmutableComponent {
constructor () {
super()
this.onClick = this.onClick.bind(this)
this.onMouseOver = this.onMouseOver.bind(this)
this.onDragStart = this.onDragStart.bind(this)
this.onDragEnd = this.onDragEnd.bind(this)
this.onDragEnter = this.onDragEnter.bind(this)
this.onDragLeave = this.onDragLeave.bind(this)
this.onDragOver = this.onDragOver.bind(this)
this.onContextMenu = this.onContextMenu.bind(this)
}
get activeFrame () {
return windowStore.getFrame(this.props.activeFrameKey)

showBookmarkFolderMenu (e) {
e.target = ReactDOM.findDOMNode(this)

if (e && e.stopPropagation) {
e.stopPropagation()
}

const xPos = (e.target.getBoundingClientRect().left | 0) - 2
const yPos = (e.target.parentNode.getBoundingClientRect().bottom | 0) - 1

windowActions.onMouseOverBookmarkFolder(this.props.bookmark.get('folderId'), this.props.sites, this.props.bookmark, xPos, yPos)
}

onClick (e) {
if (!this.props.clickBookmarkItem(this.props.bookmark, e) &&
this.props.bookmark.get('tags').includes(siteTags.BOOKMARK_FOLDER)) {
if (this.props.contextMenuDetail) {
windowActions.setContextMenuDetail()
return
}
e.target = ReactDOM.findDOMNode(this)
this.props.showBookmarkFolderMenu(this.props.bookmark, e)
return
this.showBookmarkFolderMenu(e)
}
}

onMouseOver (e) {
// Behavior when a bookmarks toolbar folder has its list expanded
if (this.props.selectedFolderId) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that ideally this should trigger something like an onMouseOverBookmarkFolder action with whatever params are needed to allow the windowstore (browser process eventually) to update the state rather than having the logic here to open context menus and update state. The are two reasons for this:

  1. It's more inline with how flux is intended to work. We should have declarative actions instead of imperative
  2. We want to take node out of the main window renderers so we want to move electron api calls out of the react components (showBookmarkFolderMenu indirectly calls electron.remote methods) in preparation for moving them to the browser process

Copy link
Member Author

@bsclifton bsclifton Sep 28, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bridiver:

  1. I can update the code to do this. It would be a larger change and would put "business logic" into the WindowStore. For example, if the selection changes from null or -1 to a valid number, the WindowStore would know it needs to create a ContextMenu renderer control, which I guess it would handle by doing another windowAction? Maybe we can talk this out more
  2. This particular method (showBookmarkFolderMenu) doesn't use electron.remote. However, there are methods in that file (contextMenus.js) which do (specifically for creating / showing popup menu templates)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was looking at this.props.showBookmarkFolderMenu which at first looked like it called the electron api directly, but it calls setContextMenuDetails which eventually triggers a call the remote api. The windowStore really should directly care about any of this, the logic itself should be in a "reducer" similar extensionState. In the flux/redux model that is exactly where the logic is supposed to go. The UI should just fire off events and react to state changes. We have a bit of code to untangle because actions shouldn't call other actions, but some of the actions are "setters" and aren't written in a way that makes it easy to reuse the login in them.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implemented feedback- ready for re-review @bridiver 😄

if (this.isFolder && this.props.selectedFolderId !== this.props.bookmark.get('folderId')) {
// Auto-expand the menu if user mouses over another folder
this.showBookmarkFolderMenu(e)
} else if (!this.isFolder && this.props.selectedFolderId !== -1) {
// Hide the currently expanded menu if user mouses over a non-folder
windowActions.onMouseOverBookmarkFolder(-1)
}
}
}

Expand All @@ -61,7 +84,7 @@ class BookmarkToolbarButton extends ImmutableComponent {
e.target = ReactDOM.findDOMNode(this)
if (dnd.isMiddle(e.target, e.clientX)) {
e.target.getBoundingClientRect
this.props.showBookmarkFolderMenu(this.props.bookmark, e)
this.showBookmarkFolderMenu(e)
windowActions.setIsBeingDraggedOverDetail(dragTypes.BOOKMARK, this.props.bookmark, {
expanded: true
})
Expand Down Expand Up @@ -168,6 +191,7 @@ class BookmarkToolbarButton extends ImmutableComponent {
ref={(node) => { this.bookmarkNode = node }}
title={hoverTitle}
onClick={this.onClick}
onMouseOver={this.onMouseOver}
onDragStart={this.onDragStart}
onDragEnd={this.onDragEnd}
onDragEnter={this.onDragEnter}
Expand Down Expand Up @@ -214,7 +238,6 @@ class BookmarksToolbar extends ImmutableComponent {
this.onMoreBookmarksMenu = this.onMoreBookmarksMenu.bind(this)
this.openContextMenu = this.openContextMenu.bind(this)
this.clickBookmarkItem = this.clickBookmarkItem.bind(this)
this.showBookmarkFolderMenu = this.showBookmarkFolderMenu.bind(this)
}
get activeFrame () {
return windowStore.getFrame(this.props.activeFrameKey)
Expand Down Expand Up @@ -270,9 +293,6 @@ class BookmarksToolbar extends ImmutableComponent {
clickBookmarkItem (bookmark, e) {
return bookmarkActions.clickBookmarkItem(this.bookmarks, bookmark, this.activeFrame, e)
}
showBookmarkFolderMenu (bookmark, e) {
contextMenus.onShowBookmarkFolderMenu(this.bookmarks, bookmark, this.activeFrame, e)
}
updateBookmarkData (props) {
this.bookmarks = siteUtil.getBookmarks(props.sites)

Expand Down Expand Up @@ -387,14 +407,14 @@ class BookmarksToolbar extends ImmutableComponent {
ref={(node) => this.bookmarkRefs.push(node)}
key={i}
contextMenuDetail={this.props.contextMenuDetail}
activeFrameKey={this.props.activeFrameKey}
draggingOverData={this.props.draggingOverData}
openContextMenu={this.openContextMenu}
clickBookmarkItem={this.clickBookmarkItem}
showBookmarkFolderMenu={this.showBookmarkFolderMenu}
bookmark={bookmark}
sites={this.bookmarks}
showFavicon={this.props.showFavicon}
showOnlyFavicon={this.props.showOnlyFavicon} />)
showOnlyFavicon={this.props.showOnlyFavicon}
selectedFolderId={this.props.selectedFolderId} />)
}
{
this.overflowBookmarkItems.size !== 0
Expand Down
3 changes: 3 additions & 0 deletions docs/state.md
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,9 @@ WindowStore
isVisible: boolean, // true if Menubar control is visible
selectedIndex: Array<number>, // indices of the selected menu item(s) (or null for none selected)
lastFocusedSelector: string // selector for the last selected element (browser ui, not frame content)
},
bookmarksToolbar: {
selectedFolderId: number // folderId from the siteDetail of the currently expanded folder
}
},
searchDetail: {
Expand Down
19 changes: 19 additions & 0 deletions docs/windowActions.md
Original file line number Diff line number Diff line change
Expand Up @@ -891,6 +891,25 @@ See `eventStore.js` for an example use-case



### onMouseOverBookmarkFolder(folderId, bookmarks, bookmark, xPos, yPos)

Fired when the mouse clicks or hovers over a bookmark folder in the bookmarks toolbar

**Parameters**

**folderId**: `number`, from the siteDetail for the bookmark folder
If set to null, no menu is open. If set to -1, mouse is over a bookmark, not a folder

**bookmarks**: `Object`, all of the users bookmarks

**bookmark**: `Object`, the object representing the selected folder

**xPos**: `number`, x position of the left corner of the context mennu

**yPos**: `number`, y position of the top corner of the context menu




* * *

Expand Down
20 changes: 20 additions & 0 deletions js/actions/windowActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -1121,6 +1121,26 @@ const windowActions = {
tabId,
details
})
},

/**
* Fired when the mouse clicks or hovers over a bookmark folder in the bookmarks toolbar
* @param {number} folderId - from the siteDetail for the bookmark folder
* If set to null, no menu is open. If set to -1, mouse is over a bookmark, not a folder
* @param {Object} bookmarks - all of the users bookmarks
* @param {Object} bookmark - the object representing the selected folder
* @param {number} xPos - x position of the left corner of the context mennu
* @param {number} yPos - y position of the top corner of the context menu
*/
onMouseOverBookmarkFolder: function (folderId, bookmarks, bookmark, xPos, yPos) {
dispatch({
actionType: WindowConstants.WINDOW_ON_MOUSE_OVER_BOOKMARK_FOLDER,
folderId,
bookmarks,
bookmark,
xPos,
yPos
})
}
}

Expand Down
5 changes: 3 additions & 2 deletions js/components/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const AutofillCreditCardPanel = require('./autofillCreditCardPanel')
const AddEditBookmark = require('./addEditBookmark')
const LoginRequired = require('./loginRequired')
const ReleaseNotes = require('./releaseNotes')
const BookmarksToolbar = require('./bookmarksToolbar')
const BookmarksToolbar = require('../../app/renderer/components/bookmarksToolbar')
const ContextMenu = require('./contextMenu')
const PopupWindow = require('./popupWindow')
const NoScriptInfo = require('./noScriptInfo')
Expand Down Expand Up @@ -1027,7 +1027,8 @@ class Main extends ImmutableComponent {
activeFrameKey={activeFrame && activeFrame.get('key') || undefined}
windowWidth={window.innerWidth}
contextMenuDetail={this.props.windowState.get('contextMenuDetail')}
sites={this.props.appState.get('sites')} />
sites={this.props.appState.get('sites')}
selectedFolderId={this.props.windowState.getIn(['ui', 'bookmarksToolbar', 'selectedFolderId'])} />
: null
}
<div className={cx({
Expand Down
3 changes: 2 additions & 1 deletion js/constants/windowConstants.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ const windowConstants = {
WINDOW_RESET_MENU_STATE: _,
WINDOW_SET_SUBMENU_SELECTED_INDEX: _,
WINDOW_SET_LAST_FOCUSED_SELECTOR: _,
WINDOW_GOT_RESPONSE_DETAILS: _
WINDOW_GOT_RESPONSE_DETAILS: _,
WINDOW_ON_MOUSE_OVER_BOOKMARK_FOLDER: _
}

module.exports = mapValuesByKeys(windowConstants)
18 changes: 2 additions & 16 deletions js/contextMenus.js
Original file line number Diff line number Diff line change
Expand Up @@ -1103,20 +1103,6 @@ function onLedgerContextMenu (location, hostPattern) {
menu.destroy()
}

function onShowBookmarkFolderMenu (bookmarks, bookmark, activeFrame, e) {
if (e && e.stopPropagation) {
e.stopPropagation()
}
const menuTemplate = showBookmarkFolderInit(bookmarks, bookmark, activeFrame)
const rectLeft = e.target.getBoundingClientRect()
const rectBottom = e.target.parentNode.getBoundingClientRect()
windowActions.setContextMenuDetail(Immutable.fromJS({
left: (rectLeft.left | 0) - 2,
top: (rectBottom.bottom | 0) - 1,
template: menuTemplate
}))
}

/**
* @param {Object} usernames - map of username to plaintext password
* @param {string} origin - origin of the form
Expand Down Expand Up @@ -1256,10 +1242,10 @@ module.exports = {
onTabPageContextMenu,
onUrlBarContextMenu,
onSiteDetailContextMenu,
onShowBookmarkFolderMenu,
onShowUsernameMenu,
onShowAutofillMenu,
onMoreBookmarksMenu,
onBackButtonHistoryMenu,
onForwardButtonHistoryMenu
onForwardButtonHistoryMenu,
showBookmarkFolderInit
}
47 changes: 39 additions & 8 deletions js/stores/windowStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ const UrlUtil = require('../lib/urlutil')
const urlParse = require('url').parse
const currentWindow = require('../../app/renderer/currentWindow')
const {tabFromFrame} = require('../state/frameStateUtil')

const {l10nErrorText} = require('../../app/common/lib/httpUtil')
const {aboutUrls, getSourceAboutUrl, isIntermediateAboutPage, navigatableTypes} = require('../lib/appUrlUtil')
const Serializer = require('../dispatcher/serializer')
const { showBookmarkFolderInit } = require('../contextMenus')

let windowState = Immutable.fromJS({
activeFrameKey: null,
Expand Down Expand Up @@ -238,6 +238,35 @@ const newFrame = (frameOpts, openInForeground, insertionIndex) => {
const windowStore = new WindowStore()
const emitChanges = debounce(windowStore.emitChanges.bind(windowStore), 5)

const showContextMenu = (action) => {
windowState = windowState.set('contextMenuDetail', action.detail)
// Drag and drop bookmarks code expects this to be set sync
windowStore.emitChanges()
}

const hideContextMenu = (action) => {
windowState = windowState.delete('contextMenuDetail')
// Drag and drop bookmarks code expects this to be set sync
windowStore.emitChanges()
}

const onMouseOverBookmarkFolder = (action) => {
windowState = windowState.setIn(['ui', 'bookmarksToolbar', 'selectedFolderId'], action.folderId)

if (action.folderId && action.folderId !== -1) {
const activeFrame = FrameStateUtil.getActiveFrame(windowState)
showContextMenu({
detail: Immutable.fromJS({
left: action.xPos,
top: action.yPos,
template: showBookmarkFolderInit(action.bookmarks, action.bookmark, activeFrame)
})
})
} else if (action.folderId === -1) {
hideContextMenu(action)
}
}

// Register callback to handle all updates
const doAction = (action) => {
// console.log(action.actionType, action, windowState.toJS())
Expand Down Expand Up @@ -605,12 +634,10 @@ const doAction = (action) => {
return
case WindowConstants.WINDOW_SET_CONTEXT_MENU_DETAIL:
if (!action.detail) {
windowState = windowState.delete('contextMenuDetail')
hideContextMenu(action)
} else {
windowState = windowState.set('contextMenuDetail', action.detail)
showContextMenu(action)
}
// Drag and drop bookmarks code expects this to be set sync
windowStore.emitChanges()
return
case WindowConstants.WINDOW_SET_POPUP_WINDOW_DETAIL:
if (!action.detail) {
Expand Down Expand Up @@ -797,8 +824,7 @@ const doAction = (action) => {
break
case WindowConstants.WINDOW_TOGGLE_MENUBAR_VISIBLE:
if (getSetting(settings.AUTO_HIDE_MENU)) {
// Close existing context menus
doAction({actionType: WindowConstants.WINDOW_SET_CONTEXT_MENU_DETAIL})
hideContextMenu(action)
// Use value if provided; if not, toggle to opposite.
const newVisibleStatus = typeof action.isVisible === 'boolean'
? action.isVisible
Expand All @@ -815,9 +841,11 @@ const doAction = (action) => {
if (getSetting(settings.AUTO_HIDE_MENU)) {
doAction({actionType: WindowConstants.WINDOW_TOGGLE_MENUBAR_VISIBLE, isVisible: false})
} else {
doAction({actionType: WindowConstants.WINDOW_SET_CONTEXT_MENU_DETAIL})
hideContextMenu(action)
}
doAction({actionType: WindowConstants.WINDOW_SET_SUBMENU_SELECTED_INDEX})
doAction({actionType: WindowConstants.WINDOW_SET_BOOKMARKS_TOOLBAR_SELECTED_FOLDER_ID})
windowState = windowState.setIn(['ui', 'bookmarksToolbar', 'selectedFolderId'], null)
break
case WindowConstants.WINDOW_SET_SUBMENU_SELECTED_INDEX:
windowState = windowState.setIn(['ui', 'menubar', 'selectedIndex'],
Expand All @@ -828,6 +856,9 @@ const doAction = (action) => {
case WindowConstants.WINDOW_SET_LAST_FOCUSED_SELECTOR:
windowState = windowState.setIn(['ui', 'menubar', 'lastFocusedSelector'], action.selector)
break
case WindowConstants.WINDOW_ON_MOUSE_OVER_BOOKMARK_FOLDER:
onMouseOverBookmarkFolder(action)
break

default:
}
Expand Down
Loading