зеркало из https://github.com/github/catalyst.git
refactor core
This commit is contained in:
Родитель
08c65de090
Коммит
244bbf7f68
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"name": "@catalyst/core",
|
||||
"version": "1.0.0",
|
||||
"description": "Helpers for creating HTML Elements as Controllers",
|
||||
"license": "MIT",
|
||||
"author": "Keith Cirkel (https://keithcirkel.co.uk/)",
|
||||
"contributors": [
|
||||
"Kristján Oddsson <koddsson@gmail.com>"
|
||||
],
|
||||
"main": "dist/index.esm.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
}
|
||||
}
|
|
@ -1,31 +1,27 @@
|
|||
import {dasherize} from './dasherize'
|
||||
import {wrap} from './wrap'
|
||||
import {getMethods} from './getmethods'
|
||||
|
||||
/**
|
||||
/*
|
||||
* Bind `[data-action]` elements from the DOM to their actions.
|
||||
*
|
||||
*/
|
||||
export function bindEvents(classObject: any) {
|
||||
wrap(classObject.prototype, 'connectedCallback', function (this: HTMLElement) {
|
||||
for(const el of this.querySelectorAll(`[data-action*=":${this.tagName.toLowerCase()}#"]`)) {
|
||||
// Ignore nested elements
|
||||
if (el.closest(this.tagName) !== this) continue
|
||||
export function bind(controller: HTMLElement) {
|
||||
const tag = controller.tagName.toLowerCase()
|
||||
for(const el of controller.querySelectorAll(`[data-action*=":${tag}#"]`)) {
|
||||
// Ignore nested elements
|
||||
if (el.closest(tag) !== controller) continue
|
||||
|
||||
// Match the pattern of `eventName:constructor#method`.
|
||||
for(const binding of (el.getAttribute('data-action')||'').split(' ')) {
|
||||
const [rest, method] = binding.split('#')
|
||||
const [eventName, handler] = rest.split(':')
|
||||
if (handler !== this.tagName.toLowerCase()) continue
|
||||
if (handler !== tag) continue
|
||||
|
||||
// Check the `method` is present on the prototype
|
||||
const methodDescriptor = Object.getOwnPropertyDescriptor(classObject.prototype, method)
|
||||
const methodDescriptor = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(controller), method)
|
||||
if (methodDescriptor && typeof methodDescriptor.value == 'function') {
|
||||
el.addEventListener(eventName, (event: Event) => {
|
||||
if (event.target === el) (this as any)[method](event)
|
||||
if (event.target === el) (controller as any)[method](event)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
export const dasherize = (str: string) => str.replace(/([a-zA-Z])(?=[A-Z])/g, '$1-').toLowerCase()
|
|
@ -0,0 +1,22 @@
|
|||
/**
|
||||
* Create a property on the controller instance referencing the element with a
|
||||
* `data-target` element of the same name.
|
||||
*/
|
||||
|
||||
const createSelector = (receiver: Element, key: string) => `[data-target*="${receiver.tagName.toLowerCase()}.${key}"]`
|
||||
|
||||
export function findTarget(controller: HTMLElement, name: string) {
|
||||
const tag = controller.tagName.toLowerCase()
|
||||
for (const el of controller.querySelectorAll(`[data-target*="${tag}.${name}"]`)) {
|
||||
if (el.closest(tag) === controller) return el
|
||||
}
|
||||
}
|
||||
|
||||
export function findTargets(controller: HTMLElement, name: string) {
|
||||
const tag = controller.tagName.toLowerCase()
|
||||
const targets = []
|
||||
for (const el of controller.querySelectorAll(`[data-target*="${tag}.${name}"]`)) {
|
||||
if (el.closest(tag) === controller) targets.push(el)
|
||||
}
|
||||
return targets
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
export {bindEvents} from './bind'
|
||||
export {register} from './register'
|
||||
export {target, targets, assertTargets} from './target'
|
|
@ -1,15 +1,5 @@
|
|||
import {bindEvents, register, target, assertTargets} from './helpers'
|
||||
import {bind} from './bind'
|
||||
import {register} from './register'
|
||||
import {target, targets} from './target'
|
||||
|
||||
@register
|
||||
@assertTargets
|
||||
@bindEvents
|
||||
class HelloController extends HTMLElement {
|
||||
@target outputTarget!: HTMLElement;
|
||||
@target nameTarget!: HTMLInputElement;
|
||||
@target buttonTarget!: HTMLButtonElement;
|
||||
|
||||
greet() {
|
||||
this.dataset.foo = 'foo'
|
||||
this.outputTarget.textContent = `Hello, ${this.nameTarget.value}!`;
|
||||
}
|
||||
}
|
||||
export {bind, register, target, targets}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import {dasherize} from './dasherize'
|
||||
/**
|
||||
* Register the controller as a custom element.
|
||||
*
|
||||
|
@ -6,9 +5,10 @@ import {dasherize} from './dasherize'
|
|||
*
|
||||
* Example: HelloController => hello-controller
|
||||
*/
|
||||
export function register(classObject: any) {
|
||||
const name = dasherize(classObject.name)
|
||||
export function register(classObject: Function) {
|
||||
const name = classObject.name.replace(/([a-zA-Z])(?=[A-Z])/g, '$1-').toLowerCase()
|
||||
if (!window.customElements.get(name)) {
|
||||
// @ts-ignore
|
||||
window[classObject.name] = classObject;
|
||||
window.customElements.define(name, classObject);
|
||||
}
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
import {dasherize} from './dasherize'
|
||||
|
||||
/**
|
||||
* Create a property on the controller instance referencing the element with a
|
||||
* `data-target` element of the same name.
|
||||
*/
|
||||
|
||||
const createSelector = (receiver: Element, key: string) => `[data-target*="${receiver.tagName.toLowerCase()}.${key}"]`
|
||||
|
||||
export function target(proto: object, key: string) {
|
||||
Object.defineProperty(
|
||||
proto,
|
||||
key,
|
||||
{
|
||||
configurable: true,
|
||||
get: function() {
|
||||
return this.querySelectorAll(createSelector(this, key)).find((el: Element) => el.closest(this.tagName) === this)
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function targets(proto: object, key: string) {
|
||||
Object.defineProperty(
|
||||
proto,
|
||||
key,
|
||||
{
|
||||
configurable: true,
|
||||
get: function() {
|
||||
return this.querySelectorAll(createSelector(this, key)).filter((el: Element) => el.closest(this.tagName) === this)
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function assertTargets(_: object) {
|
||||
// This is an empty stub that does nothing at runtime, but can be used by
|
||||
// compilers to generate code that asserts Targets are the Element types they
|
||||
// declare themselves to be, otherwise throw an Invariant Error.
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
export const wrap = (obj: any, name: string, fn: (...args: any[]) => any) => {
|
||||
if (!obj[name]) {
|
||||
obj[name] = fn
|
||||
} else {
|
||||
const oldFn = obj[name]
|
||||
obj[name] = function () {
|
||||
oldFn.call(this)
|
||||
fn.call(this)
|
||||
}
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче