From ed1b7d4fc588c6db126d0ffe61273f42345ad1da Mon Sep 17 00:00:00 2001 From: Sean Roberts Date: Fri, 14 Jul 2017 14:19:24 -0400 Subject: [PATCH] Adding support for onLayoutChange notifier configuration --- src/annotator/config/index.js | 19 +++---- src/annotator/sidebar.coffee | 44 +++++++++++++--- src/annotator/test/sidebar-test.coffee | 73 +++++++++++++++++++++++++- 3 files changed, 117 insertions(+), 19 deletions(-) diff --git a/src/annotator/config/index.js b/src/annotator/config/index.js index d1a47669158..2a39f590bef 100644 --- a/src/annotator/config/index.js +++ b/src/annotator/config/index.js @@ -10,29 +10,26 @@ var settingsFrom = require('./settings'); function configFrom(window_) { var settings = settingsFrom(window_); return { + annotations: settings.annotations, // URL where client assets are served from. Used when injecting the client // into child iframes. assetRoot: settings.hostPageSetting('assetRoot', {allowInBrowserExt: true}), + branding: settings.hostPageSetting('branding'), // URL of the client's boot script. Used when injecting the client into // child iframes. clientUrl: settings.clientUrl, - - annotations: settings.annotations, - branding: settings.hostPageSetting('branding'), + // Temporary feature flag override for 1st-party OAuth + oauthEnabled: settings.hostPageSetting('oauthEnabled'), + onLayoutChange: settings.hostPageSetting('onLayoutChange'), + openLoginForm: settings.hostPageSetting('openLoginForm', {allowInBrowserExt: true}), + openSidebar: settings.hostPageSetting('openSidebar', {allowInBrowserExt: true}), + query: settings.query, services: settings.hostPageSetting('services'), showHighlights: settings.showHighlights, sidebarAppUrl: settings.sidebarAppUrl, - // Subframe identifier given when a frame is being embedded into // by a top level client subFrameIdentifier: settings.hostPageSetting('subFrameIdentifier', {allowInBrowserExt: true}), - - openLoginForm: settings.hostPageSetting('openLoginForm', {allowInBrowserExt: true}), - openSidebar: settings.hostPageSetting('openSidebar', {allowInBrowserExt: true}), - query: settings.query, - - // Temporary feature flag override for 1st-party OAuth - oauthEnabled: settings.hostPageSetting('oauthEnabled'), }; } diff --git a/src/annotator/sidebar.coffee b/src/annotator/sidebar.coffee index 223a90f02f0..449e22351fa 100644 --- a/src/annotator/sidebar.coffee +++ b/src/annotator/sidebar.coffee @@ -5,8 +5,8 @@ Hammer = require('hammerjs') Host = require('./host') annotationCounts = require('./annotation-counts') sidebarTrigger = require('./sidebar-trigger') -events = require('../shared/bridge-events'); -features = require('./features'); +events = require('../shared/bridge-events') +features = require('./features') # Minimum width to which the frame can be resized. MIN_RESIZE = 280 @@ -46,6 +46,11 @@ module.exports = class Sidebar extends Host @onProfileRequest = serviceConfig.onProfileRequest @onHelpRequest = serviceConfig.onHelpRequest + @onLayoutChange = config.onLayoutChange + + # initial layout notification + this._notifyOfLayoutChange(false) + this._setupSidebarEvents() _setupSidebarEvents: -> @@ -58,23 +63,23 @@ module.exports = class Sidebar extends Host @crossframe.on(events.LOGIN_REQUESTED, => if @onLoginRequest @onLoginRequest() - ); + ) @crossframe.on(events.LOGOUT_REQUESTED, => if @onLogoutRequest @onLogoutRequest() - ); + ) @crossframe.on(events.SIGNUP_REQUESTED, => if @onSignupRequest @onSignupRequest() - ); + ) @crossframe.on(events.PROFILE_REQUESTED, => if @onProfileRequest @onProfileRequest() - ); + ) @crossframe.on(events.HELP_REQUESTED, => if @onHelpRequest @onHelpRequest() - ); + ) # Return this for chaining this @@ -120,6 +125,27 @@ module.exports = class Sidebar extends Host w = -m @frame.css('margin-left', "#{m}px") if w >= MIN_RESIZE then @frame.css('width', "#{w}px") + this._notifyOfLayoutChange() + + _notifyOfLayoutChange: (expanded) => + BUCKETBAR_WIDTH = 37 + + if @onLayoutChange + # because we use a combination of marginLeft and width to slide the + # sidebar into and out of view, we can't base the width off of + # the client rect width but rather a subtraction of the left side of the + # sidebar from the total widow width. That will give us the visible width + # regardless of what properties are being used to slide away the sidebar + windowWidth = Math.max(document.documentElement.clientWidth, window.innerWidth || 0) + rect = @frame[0].getBoundingClientRect() + frameVisbileWidth = windowWidth - rect.left + BUCKETBAR_WIDTH + expanded = if expanded? then expanded else frameVisbileWidth > BUCKETBAR_WIDTH + + @onLayoutChange({ + expanded: expanded, + width: frameVisbileWidth, + height: rect.height, + }) onPan: (event) => switch event.type @@ -176,6 +202,8 @@ module.exports = class Sidebar extends Host if @options.showHighlights == 'whenSidebarOpen' @setVisibleHighlights(true) + this._notifyOfLayoutChange(true) + hide: -> @frame.css 'margin-left': '' @frame.addClass 'annotator-collapsed' @@ -188,6 +216,8 @@ module.exports = class Sidebar extends Host if @options.showHighlights == 'whenSidebarOpen' @setVisibleHighlights(false) + this._notifyOfLayoutChange(false) + isOpen: -> !@frame.hasClass('annotator-collapsed') diff --git a/src/annotator/test/sidebar-test.coffee b/src/annotator/test/sidebar-test.coffee index 00414791d54..32dd9dd8442 100644 --- a/src/annotator/test/sidebar-test.coffee +++ b/src/annotator/test/sidebar-test.coffee @@ -1,7 +1,11 @@ events = require('../../shared/bridge-events') proxyquire = require('proxyquire') -Sidebar = proxyquire('../sidebar', {}) + +rafStub = (fn) -> + fn() + +Sidebar = proxyquire('../sidebar', { raf: rafStub }) describe 'Sidebar', -> sandbox = sinon.sandbox.create() @@ -253,3 +257,70 @@ describe 'Sidebar', -> assert.calledWith(fakeCrossFrame.call, 'setVisibleHighlights', true) assert.calledWith(sidebar.publish, 'setVisibleHighlights', true) + describe 'layout change notifier', -> + + layoutChangeHandlerSpy = null + sidebar = null + frame = null + DEFAULT_WIDTH = 350 + DEFAULT_HEIGHT = 600 + BUCKETBAR_WIDTH = 37 + + assertLayoutValues = (args, expectations) -> + expected = Object.assign { + width: DEFAULT_WIDTH, + height: DEFAULT_HEIGHT, + expanded: true + }, expectations + + expected.width += BUCKETBAR_WIDTH + + assert.deepEqual args, expected + + beforeEach -> + layoutChangeHandlerSpy = sandbox.spy() + sidebar = createSidebar { onLayoutChange: layoutChangeHandlerSpy, sidebarAppUrl: '/' } + + # remove info about call that happens on creation of sidebar + layoutChangeHandlerSpy.reset() + + frame = sidebar.frame[0] + Object.assign frame.style, { + display: 'block', + width: DEFAULT_WIDTH + 'px', + height: DEFAULT_HEIGHT + 'px', + + # width is based on left position of the window, + # we need to apply the css that puts the frame in the + # correct position + position: 'fixed', + top: 0, + left: '100%', + } + + document.body.appendChild frame + + afterEach -> + frame.remove() + + it 'notifies when sidebar changes expanded state', -> + sidebar.show() + assert.calledOnce layoutChangeHandlerSpy + assertLayoutValues layoutChangeHandlerSpy.lastCall.args[0], {expanded: true} + + sidebar.hide() + assert.calledTwice layoutChangeHandlerSpy + assertLayoutValues layoutChangeHandlerSpy.lastCall.args[0], { + expanded: false, + width: 0, + } + + it 'notifies when sidebar is panned left', -> + sidebar.gestureState = { initial: -DEFAULT_WIDTH } + sidebar.onPan({type: 'panleft', deltaX: -50}) + assertLayoutValues layoutChangeHandlerSpy.lastCall.args[0], { width: 400 } + + it 'notifies when sidebar is panned right', -> + sidebar.gestureState = { initial: -DEFAULT_WIDTH } + sidebar.onPan({type: 'panright', deltaX: 50}) + assertLayoutValues layoutChangeHandlerSpy.lastCall.args[0], { width: 300 }