Skip to content
This repository has been archived by the owner on Jun 26, 2020. It is now read-only.

Commit

Permalink
Merge pull request #300 from ckeditor/t/297
Browse files Browse the repository at this point in the history
Feature: Replaced `StickyToolbarView` with a generic `StickyPanelView`. Closes #297.

BREAKING CHANGE: The `StickyToolbarView` and corresponding CSS `.ck-sticky-panel` classes are no longer available. `StickyPanelView` + `ToolbarView` combo should be used instead.
  • Loading branch information
oleq authored Sep 14, 2017
2 parents b8b1ccd + df712c0 commit b10b43c
Show file tree
Hide file tree
Showing 10 changed files with 145 additions and 121 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,20 @@
*/

/**
* @module ui/toolbar/sticky/stickytoolbarview
* @module ui/panel/sticky/stickypanelview
*/

import global from '@ckeditor/ckeditor5-utils/src/dom/global';
import View from '../../view';
import Template from '../../template';
import ToolbarView from '../toolbarview';
import toUnit from '@ckeditor/ckeditor5-utils/src/dom/tounit';

const toPx = toUnit( 'px' );

/**
* The sticky toolbar view class.
*
* @extends module:ui/toolbar/toolbarview~ToolbarView
* The sticky panel view class.
*/
export default class StickyToolbarView extends ToolbarView {
export default class StickyPanelView extends View {
/**
* @inheritDoc
*/
Expand All @@ -29,8 +27,7 @@ export default class StickyToolbarView extends ToolbarView {
const bind = this.bindTemplate;

/**
* Controls whether the sticky toolbar should be active. When any editable
* is focused in the editor, toolbar becomes active.
* Controls whether the sticky panel should be active.
*
* @readonly
* @observable
Expand All @@ -39,7 +36,7 @@ export default class StickyToolbarView extends ToolbarView {
this.set( 'isActive', false );

/**
* Controls whether the sticky toolbar is in the "sticky" state.
* Controls whether the sticky panel is in the "sticky" state.
*
* @readonly
* @observable
Expand All @@ -48,10 +45,10 @@ export default class StickyToolbarView extends ToolbarView {
this.set( 'isSticky', false );

/**
* The limiter element for the sticky toolbar instance. Its bounding rect limits
* the "stickyness" of the toolbar, i.e. when the toolbar reaches the bottom
* The limiter element for the sticky panel instance. Its bounding rect limits
* the "stickyness" of the panel, i.e. when the panel reaches the bottom
* edge of the limiter, it becomes sticky to that edge and does not float
* off the limiter. It is mandatory for the toolbar to work properly and once
* off the limiter. It is mandatory for the panel to work properly and once
* set, it cannot be changed.
*
* @readonly
Expand All @@ -62,7 +59,7 @@ export default class StickyToolbarView extends ToolbarView {

/**
* The offset from the bottom edge of {@link #limiterElement}
* which stops the toolbar from stickying any further to prevent limiter's content
* which stops the panel from stickying any further to prevent limiter's content
* from being completely covered.
*
* @readonly
Expand All @@ -74,12 +71,12 @@ export default class StickyToolbarView extends ToolbarView {

/**
* The offset from the top edge of the web browser's viewport which makes the
* toolbar become sticky. The default value is `0`, which means the toolbar becomes
* panel become sticky. The default value is `0`, which means the panel becomes
* sticky when it's upper edge touches the top of the page viewport.
*
* This attribute is useful when the web page has UI elements positioned to the top
* either using `position: fixed` or `position: sticky`, which would cover the
* sticky toolbar or vice–versa (depending on the `z-index` hierarchy).
* sticky panel or vice–versa (depending on the `z-index` hierarchy).
*
* @readonly
* @observable
Expand All @@ -89,7 +86,7 @@ export default class StickyToolbarView extends ToolbarView {
this.set( 'viewportTopOffset', 0 );

/**
* Controls the `margin-left` CSS style of the toolbar.
* Controls the `margin-left` CSS style of the panel.
*
* @protected
* @readonly
Expand All @@ -99,7 +96,7 @@ export default class StickyToolbarView extends ToolbarView {
this.set( '_marginLeft', null );

/**
* Set `true` if the sticky toolbar reached the bottom edge of the
* Set `true` if the sticky panel reached the bottom edge of the
* {@link #limiterElement}.
*
* @protected
Expand All @@ -110,7 +107,7 @@ export default class StickyToolbarView extends ToolbarView {
this.set( '_isStickyToTheLimiter', false );

/**
* Set `true` if the sticky toolbar uses the {@link #viewportTopOffset},
* Set `true` if the sticky panel uses the {@link #viewportTopOffset},
* i.e. not {@link #_isStickyToTheLimiter} and the {@link #viewportTopOffset}
* is not `0`.
*
Expand All @@ -122,26 +119,37 @@ export default class StickyToolbarView extends ToolbarView {
this.set( '_hasViewportTopOffset', false );

/**
* The DOM bounding client rect of the {@link module:ui/view~View#element} of the toolbar.
* Collection of the child views which creates balloon panel contents.
*
* @readonly
* @member {module:ui/viewcollection~ViewCollection}
*/
this.content = this.createCollection();

/**
* The DOM bounding client rect of the {@link module:ui/view~View#element} of the panel.
*
* @protected
* @member {Object} #_toolbarRect
* @member {Object} #_panelRect
*/

/**
* The DOM bounding client rect of the {@link #limiterElement}
* of the toolbar.
* of the panel.
*
* @protected
* @member {Object} #_limiterRect
*/

Template.extend( this.template, {
this.template = new Template( {
tag: 'div',

attributes: {
class: [
// Toggle class of the toolbar when "sticky" state changes in the view.
bind.if( 'isSticky', 'ck-toolbar_sticky' ),
bind.if( '_isStickyToTheLimiter', 'ck-toolbar_sticky_bottom-limit' ),
'ck-sticky-panel',
// Toggle class of the panel when "sticky" state changes in the view.
bind.if( 'isSticky', 'ck-sticky-panel_sticky' ),
bind.if( '_isStickyToTheLimiter', 'ck-sticky-panel_sticky_bottom-limit' ),
],
style: {
width: bind.to( 'isSticky', isSticky => {
Expand All @@ -158,12 +166,14 @@ export default class StickyToolbarView extends ToolbarView {

marginLeft: bind.to( '_marginLeft' )
}
}
},

children: this.content
} );

/**
* A dummy element which visually fills the space as long as the
* actual toolbar is sticky. It prevents flickering of the UI.
* actual panel is sticky. It prevents flickering of the UI.
*
* @private
* @property {HTMLElement}
Expand All @@ -172,12 +182,12 @@ export default class StickyToolbarView extends ToolbarView {
tag: 'div',
attributes: {
class: [
'ck-toolbar__placeholder'
'ck-sticky-panel__placeholder'
],
style: {
display: bind.to( 'isSticky', isSticky => isSticky ? 'block' : 'none' ),
height: bind.to( 'isSticky', isSticky => {
return isSticky ? toPx( this._toolbarRect.height ) : null;
return isSticky ? toPx( this._panelRect.height ) : null;
} )
}
}
Expand All @@ -192,57 +202,57 @@ export default class StickyToolbarView extends ToolbarView {

this.element.parentNode.insertBefore( this._elementPlaceholder, this.element );

// Check if the toolbar should go into the sticky state immediately.
// Check if the panel should go into the sticky state immediately.
this._checkIfShouldBeSticky();

// Update sticky state of the toolbar as the window is being scrolled.
// Update sticky state of the panel as the window is being scrolled.
this.listenTo( global.window, 'scroll', () => {
this._checkIfShouldBeSticky();
} );

// Synchronize with `model.isActive` because sticking an inactive toolbar is pointless.
// Synchronize with `model.isActive` because sticking an inactive panel is pointless.
this.listenTo( this, 'change:isActive', () => {
this._checkIfShouldBeSticky();
} );
}

/**
* Destroys the toolbar and removes the {@link #_elementPlaceholder}.
* Destroys the panel and removes the {@link #_elementPlaceholder}.
*/
destroy() {
super.destroy();
this._elementPlaceholder.remove();
}

/**
* Analyzes the environment to decide whether the toolbar should
* Analyzes the environment to decide whether the panel should
* be sticky or not.
*
* @protected
*/
_checkIfShouldBeSticky() {
const limiterRect = this._limiterRect = this.limiterElement.getBoundingClientRect();
const toolbarRect = this._toolbarRect = this.element.getBoundingClientRect();
const panelRect = this._panelRect = this.element.getBoundingClientRect();

// The toolbar must be active to become sticky.
// The panel must be active to become sticky.
this.isSticky = this.isActive &&
// The limiter's top edge must be beyond the upper edge of the visible viewport (+the viewportTopOffset).
limiterRect.top < this.viewportTopOffset &&
// The model#limiterElement's height mustn't be smaller than the toolbar's height and model#limiterBottomOffset.
// The model#limiterElement's height mustn't be smaller than the panel's height and model#limiterBottomOffset.
// There's no point in entering the sticky mode if the model#limiterElement is very, very small, because
// it would immediately set model#_isStickyToTheLimiter true and, given model#limiterBottomOffset, the toolbar
// it would immediately set model#_isStickyToTheLimiter true and, given model#limiterBottomOffset, the panel
// would be positioned before the model#limiterElement.
this._toolbarRect.height + this.limiterBottomOffset < limiterRect.height;
this._panelRect.height + this.limiterBottomOffset < limiterRect.height;

// Stick the toolbar to the top edge of the viewport simulating CSS position:sticky.
// Stick the panel to the top edge of the viewport simulating CSS position:sticky.
// TODO: Possibly replaced by CSS in the future http://caniuse.com/#feat=css-sticky
if ( this.isSticky ) {
this._isStickyToTheLimiter =
limiterRect.bottom < toolbarRect.height + this.limiterBottomOffset + this.viewportTopOffset;
limiterRect.bottom < panelRect.height + this.limiterBottomOffset + this.viewportTopOffset;
this._hasViewportTopOffset = !this._isStickyToTheLimiter && !!this.viewportTopOffset;
this._marginLeft = this._isStickyToTheLimiter ? null : toPx( -global.window.scrollX );
}
// Detach the toolbar from the top edge of the viewport.
// Detach the panel from the top edge of the viewport.
else {
this._isStickyToTheLimiter = false;
this._hasViewportTopOffset = false;
Expand Down
4 changes: 2 additions & 2 deletions src/view.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
import ViewCollection from './viewcollection';
import Template from './template';
import DomEmmiterMixin from '@ckeditor/ckeditor5-utils/src/dom/emittermixin';
import DomEmitterMixin from '@ckeditor/ckeditor5-utils/src/dom/emittermixin';
import ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';
import Collection from '@ckeditor/ckeditor5-utils/src/collection';
import mix from '@ckeditor/ckeditor5-utils/src/mix';
Expand Down Expand Up @@ -326,5 +326,5 @@ export default class View {
}
}

mix( View, DomEmmiterMixin );
mix( View, DomEmitterMixin );
mix( View, ObservableMixin );
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ <h2>Sticky to the green box</h2>
<div class="ck-reset_all offset-visualizer"></div>
</div>

<div id="fixed">The toolbar should stick to me instead of the viewport.</div>
<div id="fixed">The panel should stick to me instead of the viewport.</div>
</div>
</div>

Expand All @@ -62,13 +62,13 @@ <h2>Sticky to the green box</h2>
position: relative;
}

.ck-toolbar {
.ck-sticky-panel {
background: yellow !important;
padding: 1em;
}

.ck-toolbar:after {
content: "A toolbar mock–up.";
.ck-sticky-panel:after {
content: "A sticky panel mock–up.";
}

.offset-visualizer {
Expand Down
30 changes: 30 additions & 0 deletions tests/manual/panel/sticky/stickypanelview.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md.
*/

import testUtils from '../../../_utils/utils';
import StickyPanelView from '../../../../src/panel/sticky/stickypanelview';

import '@ckeditor/ckeditor5-theme-lark/theme/theme.scss';

const ui = testUtils.createTestUIView( {
stickyToTheTop: '.ck-sticky_to-the-top .ck-editor__top',
stickyToTheBox: '.ck-sticky_to-the-box .ck-editor__top'
} );

createStickyPanel( ui.stickyToTheTop );
const stickyToTheBoxTPanel = createStickyPanel( ui.stickyToTheBox );

stickyToTheBoxTPanel.viewportTopOffset = 100;

function createStickyPanel( collection ) {
const panel = new StickyPanelView();

panel.limiterElement = collection._parentElement.parentNode;

collection.add( panel );
panel.isActive = true;

return panel;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,24 @@

### Sticky to the top of the viewport

1. When the page is scrolled vertically, the toolbar should
1. When the page is scrolled vertically, the panel should
1. stick to the top of the viewport first,
1. then disappear beyond the upper edge of the viewport as it touches the red area
1. but never cover the red area or go beyond the upper edge of editor mock–up.

### Sticky to the green box

1. When the page is scrolled vertically, the toolbar should
1. When the page is scrolled vertically, the panel should
1. stick to the bottom of the green box first,
1. then disappear beyond the bottom edge of the green box as it touches the red area
1. but never cover the red area or go beyond the upper edge of editor mock–up.

## Horizontal scrolling

1. The toolbar should always fit horizontally within the editor mock–up, regardless of the position of the h– and v–scrolls of the web page.
1. The panel should always fit horizontally within the editor mock–up, regardless of the position of the h– and v–scrolls of the web page.

## On–load positioning

1. Scroll the web page vertically and horizontally, so the toolbar is sticky.
1. Scroll the web page vertically and horizontally, so the panel is sticky.
1. Reload the web page.
1. The toolbar should get sticky as the page reloads, if the position of scrollbars and the geometry of the viewport creates such a need.
1. The panel should get sticky as the page reloads, if the position of scrollbars and the geometry of the viewport creates such a need.
30 changes: 0 additions & 30 deletions tests/manual/stickytoolbarview/stickytoolbarview.js

This file was deleted.

Loading

0 comments on commit b10b43c

Please sign in to comment.