-
Notifications
You must be signed in to change notification settings - Fork 56
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(components): new Orange navbar component (#1099)
Co-authored-by: Kevin Le Diouron <kevin.lediouron.ext@orange.com> Co-authored-by: Julien Déramond <julien.deramond@orange.com> Co-authored-by: Isabelle Chanclou <isabelle.chanclou@orange.com> Co-authored-by: Louis-Maxime Piton <louismaxime.piton@orange.com> Co-authored-by: Mewen Le Hô <mewen.leho.ext@orange.com>
- Loading branch information
1 parent
b467da2
commit 46b2202
Showing
31 changed files
with
1,555 additions
and
359 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
/** | ||
* -------------------------------------------------------------------------- | ||
* Boosted (v5.1.3): orange-navbar.js | ||
* Licensed under MIT (https://github.com/Orange-OpenSource/Orange-Boosted-Bootstrap/blob/main/LICENSE) | ||
* -------------------------------------------------------------------------- | ||
*/ | ||
|
||
import { defineJQueryPlugin } from './util/index' | ||
import EventHandler from './dom/event-handler' | ||
import BaseComponent from './base-component' | ||
import SelectorEngine from './dom/selector-engine' | ||
|
||
/** | ||
* Constants | ||
*/ | ||
|
||
const NAME = 'orangenavbar' | ||
const DATA_KEY = 'bs.orangenavbar' | ||
const EVENT_KEY = `.${DATA_KEY}` | ||
const DATA_API_KEY = '.data-api' | ||
const EVENT_SCROLL_DATA_API = `scroll${EVENT_KEY}${DATA_API_KEY}` | ||
const EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}` | ||
const SELECTOR_STICKY_TOP = 'header.sticky-top' | ||
|
||
/** | ||
* Class definition | ||
*/ | ||
|
||
class OrangeNavbar extends BaseComponent { | ||
// Getters | ||
static get NAME() { | ||
return NAME | ||
} | ||
|
||
// Static | ||
static enableMinimizing(el) { | ||
// The minimized behaviour works only if your header has .sticky-top (fixed-top will be sticky without minimizing) | ||
const scroll = window.scrollY | ||
const headerChildren = [...el.children] | ||
const globalHeaderChild = headerChildren.find(element => !element.classList.contains('supra')) | ||
|
||
if (globalHeaderChild) { | ||
if (scroll > 0) { | ||
// Consider first element not having .supra in array is the first header | ||
globalHeaderChild.classList.add('header-minimized') | ||
} else { | ||
globalHeaderChild.classList.remove('header-minimized') | ||
} | ||
} | ||
} | ||
|
||
static jQueryInterface(config) { | ||
return this.each(function () { | ||
const data = OrangeNavbar.getOrCreateInstance(this, config) | ||
|
||
if (typeof config !== 'string') { | ||
return | ||
} | ||
|
||
if (typeof data[config] === 'undefined') { | ||
throw new TypeError(`No method named "${config}"`) | ||
} | ||
|
||
data[config]() | ||
}) | ||
} | ||
} | ||
|
||
/** | ||
* Data API implementation | ||
*/ | ||
|
||
EventHandler.on(window, EVENT_SCROLL_DATA_API, () => { | ||
for (const el of SelectorEngine.find(SELECTOR_STICKY_TOP)) { | ||
OrangeNavbar.enableMinimizing(el) | ||
} | ||
}) | ||
|
||
EventHandler.on(window, EVENT_LOAD_DATA_API, () => { | ||
for (const el of SelectorEngine.find(SELECTOR_STICKY_TOP)) { | ||
OrangeNavbar.enableMinimizing(el) | ||
} | ||
}) | ||
|
||
/** | ||
* jQuery | ||
*/ | ||
|
||
defineJQueryPlugin(OrangeNavbar) | ||
|
||
export default OrangeNavbar |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
import OrangeNavbar from '../../src/orange-navbar' | ||
import { clearFixture, getFixture, createEvent, jQueryMock } from '../helpers/fixture' | ||
|
||
describe('OrangeNavbar', () => { | ||
let fixtureEl | ||
|
||
beforeAll(() => { | ||
fixtureEl = getFixture() | ||
}) | ||
|
||
afterEach(() => { | ||
clearFixture() | ||
}) | ||
|
||
describe('VERSION', () => { | ||
it('should return plugin version', () => { | ||
expect(OrangeNavbar.VERSION).toEqual(jasmine.any(String)) | ||
}) | ||
}) | ||
|
||
describe('Default', () => { | ||
it('should return plugin default config', () => { | ||
expect(OrangeNavbar.Default).toEqual(jasmine.any(Object)) | ||
}) | ||
}) | ||
|
||
describe('DefaultType', () => { | ||
it('should return plugin default type config', () => { | ||
expect(OrangeNavbar.DefaultType).toEqual(jasmine.any(Object)) | ||
}) | ||
}) | ||
|
||
describe('DATA_KEY', () => { | ||
it('should return plugin data key', () => { | ||
expect(OrangeNavbar.DATA_KEY).toEqual('bs.orangenavbar') | ||
}) | ||
}) | ||
|
||
describe('jQueryInterface', () => { | ||
it('should create an orange navbar', () => { | ||
fixtureEl.innerHTML = '<div></div>' | ||
|
||
const div = fixtureEl.querySelector('div') | ||
|
||
jQueryMock.fn.orangenavbar = OrangeNavbar.jQueryInterface | ||
jQueryMock.elements = [div] | ||
|
||
jQueryMock.fn.orangenavbar.call(jQueryMock) | ||
|
||
expect(OrangeNavbar.getInstance(div)).not.toBeNull() | ||
}) | ||
|
||
it('should not re create an orange navbar', () => { | ||
fixtureEl.innerHTML = '<div></div>' | ||
|
||
const div = fixtureEl.querySelector('div') | ||
const orangenavbar = new OrangeNavbar(div) | ||
|
||
jQueryMock.fn.orangenavbar = OrangeNavbar.jQueryInterface | ||
jQueryMock.elements = [div] | ||
|
||
jQueryMock.fn.orangenavbar.call(jQueryMock) | ||
|
||
expect(OrangeNavbar.getInstance(div)).toEqual(orangenavbar) | ||
}) | ||
|
||
it('should throw error on undefined method', () => { | ||
fixtureEl.innerHTML = '<div></div>' | ||
|
||
const div = fixtureEl.querySelector('div') | ||
const action = 'undefinedMethod' | ||
|
||
jQueryMock.fn.orangenavbar = OrangeNavbar.jQueryInterface | ||
jQueryMock.elements = [div] | ||
|
||
expect(() => { | ||
jQueryMock.fn.orangenavbar.call(jQueryMock, action) | ||
}).toThrowError(TypeError, `No method named "${action}"`) | ||
}) | ||
}) | ||
|
||
it('should call enableMinimizing when the page finish loading', () => { | ||
fixtureEl.innerHTML = [ | ||
'<header class="sticky-top"></header>' | ||
].join('') | ||
|
||
const loadEvent = createEvent('load') | ||
spyOn(OrangeNavbar, 'enableMinimizing') | ||
|
||
window.dispatchEvent(loadEvent) | ||
|
||
expect(OrangeNavbar.enableMinimizing).toHaveBeenCalled() | ||
}) | ||
|
||
it('should call enableMinimizing when there is a scroll on the page', () => { | ||
fixtureEl.innerHTML = [ | ||
'<header class="sticky-top" style="height: 20000px;"></header>' | ||
].join('') | ||
|
||
const scrollEvent = createEvent('scroll') | ||
spyOn(OrangeNavbar, 'enableMinimizing') | ||
window.scrollY = 1 | ||
|
||
window.dispatchEvent(scrollEvent) | ||
|
||
expect(OrangeNavbar.enableMinimizing).toHaveBeenCalled() | ||
}) | ||
|
||
it('should not call enableMinimizing when there is a scroll on the page and the header does not have .sticky-top', () => { | ||
fixtureEl.innerHTML = [ | ||
'<header style="height: 20000px;"></header>' | ||
].join('') | ||
|
||
const scrollEvent = createEvent('scroll') | ||
spyOn(OrangeNavbar, 'enableMinimizing') | ||
window.scrollY = 1 | ||
|
||
window.dispatchEvent(scrollEvent) | ||
|
||
expect(OrangeNavbar.enableMinimizing).not.toHaveBeenCalled() | ||
}) | ||
|
||
it('should add .header-minimized to the global header non-supra first <nav> when enableMinimizing is called not at the top of the page', () => { | ||
fixtureEl.innerHTML = [ | ||
'<header class="sticky-top" style="height: 20000px;">', | ||
' <nav id="notTargeted" class="supra"></nav>', | ||
' <nav id="target"></nav>', | ||
' <nav id="notTargeted2"></nav>', | ||
'</header>' | ||
].join('') | ||
|
||
const targetEl = fixtureEl.querySelector('#target') | ||
const notTargetedEl = fixtureEl.querySelector('#notTargeted') | ||
const notTargeted2El = fixtureEl.querySelector('#notTargeted2') | ||
window.scrollY = 1 | ||
|
||
OrangeNavbar.enableMinimizing(fixtureEl.querySelector('header.sticky-top')) | ||
|
||
expect(targetEl).toHaveClass('header-minimized') | ||
expect(notTargetedEl).not.toHaveClass('header-minimized') | ||
expect(notTargeted2El).not.toHaveClass('header-minimized') | ||
}) | ||
|
||
it('should remove .header-minimized to the global header non-supra first <nav> when enableMinimizing is called at the top of the page', () => { | ||
fixtureEl.innerHTML = [ | ||
'<header class="sticky-top" style="height: 20000px;">', | ||
' <nav id="notTargeted" class="supra"></nav>', | ||
' <nav id="target" class="header-minimized"></nav>', | ||
' <nav id="notTargeted2"></nav>', | ||
'</header>' | ||
].join('') | ||
|
||
const targetEl = fixtureEl.querySelector('#target') | ||
const notTargetedEl = fixtureEl.querySelector('#notTargeted') | ||
const notTargeted2El = fixtureEl.querySelector('#notTargeted2') | ||
window.scrollY = 0 | ||
|
||
OrangeNavbar.enableMinimizing(fixtureEl.querySelector('header.sticky-top')) | ||
|
||
expect(targetEl).not.toHaveClass('header-minimized') | ||
expect(notTargetedEl).not.toHaveClass('header-minimized') | ||
expect(notTargeted2El).not.toHaveClass('header-minimized') | ||
}) | ||
|
||
it('should not add .header-minimized to the global header non-supra first <nav> when the header only has .supra <nav>', () => { | ||
fixtureEl.innerHTML = [ | ||
'<header class="sticky-top" style="height: 20000px;">', | ||
' <nav id="target0" class="supra"></nav>', | ||
' <nav id="target1" class="supra"></nav>', | ||
' <nav id="target2" class="supra"></nav>', | ||
'</header>' | ||
].join('') | ||
|
||
const target0El = fixtureEl.querySelector('#target0') | ||
const target1El = fixtureEl.querySelector('#target1') | ||
const target2El = fixtureEl.querySelector('#target2') | ||
window.scrollY = 1 | ||
|
||
OrangeNavbar.enableMinimizing(fixtureEl.querySelector('header.sticky-top')) | ||
|
||
expect(target0El).not.toHaveClass('header-minimized') | ||
expect(target1El).not.toHaveClass('header-minimized') | ||
expect(target2El).not.toHaveClass('header-minimized') | ||
}) | ||
}) |
Oops, something went wrong.