Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Replace jQuery with native API calls #86

Merged
31 commits merged into from
Jun 12, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
66c1845
Remove jQuery from dev convenience utilities
gundelsby May 9, 2019
3610257
Remove jquery and jquery types from dependencies
gundelsby May 9, 2019
bebf2a4
Removed jQuery from notification center panel
gundelsby May 14, 2019
2e32e70
Removed jQuery from viewPort lib
gundelsby May 15, 2019
48da266
Remove jQuery from ActiveRundownView
gundelsby May 15, 2019
5352ce8
Removed jQuery from VideoEditMonitor
gundelsby May 15, 2019
cea9799
Removed jQuery from ClockView
gundelsby May 15, 2019
af1ace7
Removed (unused) jQuery import from keyboard device
gundelsby May 15, 2019
1cba541
Removed jQuery from PrompterView
gundelsby May 16, 2019
42bbeec
Removed jQuery from RundownView
gundelsby May 16, 2019
e3a0bc8
Removed jQuery from RundownFullscreenControls
gundelsby May 16, 2019
947db8e
Removed jQuery from SegmentTimeline renderers
gundelsby May 21, 2019
444cab3
Removed jQuery from SegmentTimeline
gundelsby May 21, 2019
ba6548a
Removed jQuery from SegmentTimelineLine
gundelsby May 21, 2019
68c066e
Removed jQuery from SegmentTimelineZoomControls
gundelsby May 21, 2019
101a0d7
Removed jQuery from SourceLayerItem
gundelsby May 21, 2019
726c9ca
Removed jQuery from TimelineGrid
gundelsby May 21, 2019
9c8adbf
Removed jQuery from AdLibPanel
gundelsby May 22, 2019
d4054b0
Removed jQuery from Shelf component
gundelsby May 22, 2019
5a229f8
Removed jQuery entry from startup dependency omission list
gundelsby May 22, 2019
1ecf50d
Removed superfluous IE compatibility code in PrompterView
gundelsby May 22, 2019
afecd1d
getElementWidth util now replicates jQuery width() behavior
gundelsby May 22, 2019
132be9a
Wrote tests for client position utils
gundelsby May 27, 2019
88feb72
Tests for client/utils/dimensions
gundelsby May 27, 2019
9077a6d
Created an interface for element position to replace JQueryCoordinates
gundelsby Jun 7, 2019
f6ced5c
Remove jQuery from SegmentTimelineContainer
gundelsby Jun 7, 2019
f04360c
Implement client lib loadscript() without using jQuery
gundelsby Jun 7, 2019
28bd714
Merge branch 'develop' into feature/replace-jquery-with-native-api-calls
gundelsby Jun 11, 2019
82ff420
Reintroduce tests in the tsconfig exclusions (broke build)
gundelsby Jun 11, 2019
4947e1c
Convert document.querySelectorAll return values to array for iterations
gundelsby Jun 12, 2019
4813c0b
Replace references to removed method PrompterView#getScrollPosition()…
gundelsby Jun 12, 2019
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
70 changes: 70 additions & 0 deletions meteor/client/__tests__/utils/dimensions.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { getElementWidth, getElementHeight } from '../../utils/dimensions'
import { createSandbox } from 'sinon'

const sandbox = createSandbox()

describe('client/utils/dimensions', () => {
let getComputedStyle

beforeEach(() => {
getComputedStyle = sandbox.stub(window, 'getComputedStyle')
})

afterEach(() => {
sandbox.restore()
})

describe('getElementWidth', () => {
test('returns width from getComputedStyle when it has a numeric value', () => {
const expected = 20;
const element = document.createElement('div');
getComputedStyle.withArgs(element).returns({ width: expected })

const actual = getElementWidth(element)

expect(actual).toEqual(expected)
})

test('returns element.offsetWidth - computed horizontal padding when computed width is auto', () => {
const paddingLeft = 10
const paddingRight = 15
const offsetWidth = 63
const expected = offsetWidth - paddingLeft - paddingRight

const element = document.createElement('div');
Object.defineProperty(element, 'offsetWidth', { value: offsetWidth })
getComputedStyle.withArgs(element).returns({ width: 'auto', paddingLeft, paddingRight })

const actual = getElementWidth(element)

expect(actual).toEqual(expected)
})
})

describe('getElementHeight', () => {
test('returns height from getComputedStyle when it has a numeric value', () => {
const expected = 20;
const element = document.createElement('div');
getComputedStyle.withArgs(element).returns({ height: expected })

const actual = getElementHeight(element)

expect(actual).toEqual(expected)
})

test('returns element.scrollHeight - computed vertical padding when computed height is auto', () => {
const paddingTop = 8
const paddingBottom = 9
const scrollHeight = 37
const expected = scrollHeight - paddingTop - paddingBottom

const element = document.createElement('div');
Object.defineProperty(element, 'scrollHeight', { value: scrollHeight })
getComputedStyle.withArgs(element).returns({ height: 'auto', paddingTop, paddingBottom })

const actual = getElementHeight(element)

expect(actual).toEqual(expected)
})
})
})
95 changes: 95 additions & 0 deletions meteor/client/__tests__/utils/positions.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { getElementDocumentOffset } from '../../utils/positions'

describe('getElementDocumentOffset', () => {
const emptyRect: ClientRect = {
top: 0,
left: 0,
bottom: 0,
right: 0,
height: 0,
width: 0
}

test('should return null for null input', () => {
const actual = getElementDocumentOffset(null)

expect(actual).toBe(null)
})


describe('{top}', () => {
test('should be 0 when bounding client rect top is 0 and window.scrollY is 0', () => {
Object.defineProperty(window, 'scrollY', { value: 0 })
const container = document.createElement('div');
container.getBoundingClientRect = (): ClientRect => {
return Object.assign({}, emptyRect, { top: 0 })
}

const actual = getElementDocumentOffset(container)

expect(actual).toHaveProperty('top', 0)
})

test('should be 20 when bounding client rect top is 20 and window.scrollY is 0', () => {
Object.defineProperty(window, 'scrollY', { value: 0 })
const container = document.createElement('div');
container.getBoundingClientRect = (): ClientRect => {
return Object.assign({}, emptyRect, { top: 20 })
}

const actual = getElementDocumentOffset(container)

expect(actual).toHaveProperty('top', 20)
})

test('should be 31 when bounding client rect top is 10 and window.scrollY is 21', () => {
Object.defineProperty(window, 'scrollY', { value: 21 })
const container = document.createElement('div');
container.getBoundingClientRect = (): ClientRect => {
return Object.assign({}, emptyRect, { top: 10 })
}

const actual = getElementDocumentOffset(container)

expect(actual).toHaveProperty('top', 31)
})
})

describe('{left}', () => {
test('should be 0 when bounding client rect left is 0 and window.scrollX is 0', () => {
Object.defineProperty(window, 'scrollY', { value: 0 })
const container = document.createElement('div');
container.getBoundingClientRect = (): ClientRect => {
return Object.assign({}, emptyRect, { left: 0 })
}

const actual = getElementDocumentOffset(container)

expect(actual).toHaveProperty('left', 0)
})

test('should be 18 when bounding client rect left is 18 and window.scrollX is 0', () => {
Object.defineProperty(window, 'scrollX', { value: 0 })
const container = document.createElement('div');
container.getBoundingClientRect = (): ClientRect => {
return Object.assign({}, emptyRect, { left: 18 })
}

const actual = getElementDocumentOffset(container)

expect(actual).toHaveProperty('left', 18)
})

test('should be 42 when bounding client rect left is 2 and window.scrollX is 40', () => {
Object.defineProperty(window, 'scrollX', { value: 40 })
const container = document.createElement('div');
container.getBoundingClientRect = (): ClientRect => {
return Object.assign({}, emptyRect, { left: 2 })
}

const actual = getElementDocumentOffset(container)

expect(actual).toHaveProperty('left', 42)
})
})
})
3 changes: 0 additions & 3 deletions meteor/client/lib/dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { Session } from 'meteor/session'
import { Meteor } from 'meteor/meteor'
import { Tracker } from 'meteor/tracker'
import * as _ from 'underscore'
import * as $ from 'jquery'

// Note: These things are convenience functions to be used during development:

Expand All @@ -14,7 +13,6 @@ Meteor.startup(() => {
})
})

window['$'] = $
window['Collections'] = Collections
window['executeFunction'] = PeripheralDeviceAPI.executeFunction
window['getCurrentTime'] = getCurrentTime
Expand Down Expand Up @@ -48,5 +46,4 @@ export function expectToRunWithin (name, time: number = 1000) {
console.error('Expected to run within ' + time + 'ms: ' + name)
}, time)
expectToRunWithinCache[name] = timeout

}
61 changes: 35 additions & 26 deletions meteor/client/lib/lib.tsx
Original file line number Diff line number Diff line change
@@ -1,54 +1,63 @@
import * as _ from 'underscore'
import * as React from 'react'

export function multilineText (txt: string) {
export {multilineText, isEventInInputField, loadScript}

function multilineText (txt: string) {
return _.map((txt + '').split('\n'), (line: string, i) => {
return <p key={i}>{line}</p>
})
}
export function isEventInInputField (e: Event) {

function isEventInInputField (e: Event) {
// @ts-ignore localName
return (e && e.target && ['textarea', 'input'].indexOf(e.target.localName + '') !== -1)
}

const loadScriptCache: {[url: string]: {
status: 'loading' | 'ok',
callbacks: Array<(err?: any) => void>
}} = {}
export function loadScript (url: string, callback: (err?: any) => void) {

function doCallback (url:string, err?: any) {
loadScriptCache[url].callbacks.forEach((cb) => {
cb(err)
})
loadScriptCache[url].status = 'ok'
}

function loadScript (url: string, callback: (err?: any) => void) {
if ((loadScriptCache[url] || {}).status === 'ok') {
// already loaded
callback()
} else if ((loadScriptCache[url] || {}).status === 'loading') {
return
}

if ((loadScriptCache[url] || {}).status === 'loading') {
loadScriptCache[url].callbacks.push(callback)
} else {
loadScriptCache[url] = {
status: 'loading',
callbacks: [callback]
}
const doCallback = (err?: any) => {
loadScriptCache[url].callbacks.forEach((cb) => {
cb(err)
})
loadScriptCache[url].status = 'ok'
}
$.ajax({
url: url,
dataType: 'script',
success: () => {
doCallback()
},
error: (err) => {
doCallback(err)
}
})
return
}

loadScriptCache[url] = {
status: 'loading',
callbacks: [callback]
}

const script:HTMLScriptElement = document.createElement('script')
script.onerror = (error) => {
doCallback(url, error)
}
script.onload = () => {
doCallback(url)
}

document.head.appendChild(script)
script.src = url
}
/**
* Wrapper around fetch(), which doesn't rejects the promise if the result is an error
*/
export function fetchFrom (input: RequestInfo, init?: RequestInit) {

return fetch(input, init)
.then((response) => {
// Read the body:
Expand Down
Loading