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

Adopt builtin components #1

Merged
merged 13 commits into from
Nov 10, 2021
19 changes: 19 additions & 0 deletions addon/components/_has-dom.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// check if window exists and actually is the global
export default typeof self === 'object' &&
self !== null &&
(self as Window['self']).Object === Object &&
typeof Window !== 'undefined' &&
self.constructor === Window &&
typeof document === 'object' &&
document !== null &&
self.document === document &&
typeof location === 'object' &&
location !== null &&
self.location === location &&
typeof history === 'object' &&
history !== null &&
self.history === history &&
typeof navigator === 'object' &&
navigator !== null &&
self.navigator === navigator &&
typeof navigator.userAgent === 'string';
78 changes: 78 additions & 0 deletions addon/components/_internals.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
function intern(str: string): string {
let obj = {};
//@ts-ignore
obj[str] = 1;
for (let key in obj) {
if (key === str) {
return key;
}
}
return str;
}

const GUID_KEY = intern(`__ember${Date.now()}`);

// `enumerableSymbol` copied from https://github.com/emberjs/ember.js/blob/master/packages/@ember/-internals/utils/lib/symbol.ts
// for not exported code these legacy components are dependant on.

// Some legacy symbols still need to be enumerable for a variety of reasons.
// This code exists for that, and as a fallback in IE11. In general, prefer
// `symbol` below when creating a new symbol.
function enumerableSymbol(debugName: string): string {
let id = GUID_KEY + Math.floor(Math.random() * Date.now());
let symbol = intern(`__${debugName}${id}__`);
return symbol;
}

export const HAS_BLOCK = enumerableSymbol('HAS_BLOCK');

export function isSimpleClick(event: MouseEvent): boolean {
let modifier =
event.shiftKey || event.metaKey || event.altKey || event.ctrlKey;
let secondaryClick = event.which > 1; // IE9 may return undefined

return !modifier && !secondaryClick;
}

// export interface GlobalContext {
// imports: object;
// exports: object;
// lookup: object;
// }

// /* globals global, window, self */
// declare const mainContext: object | undefined;

// // from lodash to catch fake globals
// function checkGlobal(value: any | null | undefined): value is object {
// return value && value.Object === Object ? value : undefined;
// }

// // element ids can ruin global miss checks
// function checkElementIdShadowing(value: any | null | undefined) {
// return value && value.nodeType === undefined ? value : undefined;
// }

// // export real global
// export default checkGlobal(checkElementIdShadowing(typeof global === 'object' && global)) ||
// checkGlobal(typeof self === 'object' && self) ||
// checkGlobal(typeof window === 'object' && window) ||
// (typeof mainContext !== 'undefined' && mainContext) || // set before strict mode in Ember loader/wrapper
// new Function('return this')(); // eval outside of strict mode

// // legacy imports/exports/lookup stuff (should we keep this??)
// export const context = (function (
// global: object,
// Ember: Partial<GlobalContext> | undefined
// ): GlobalContext {
// return Ember === undefined
// ? { imports: global, exports: global, lookup: global }
// : {
// // import jQuery
// imports: Ember.imports || global,
// // export Ember
// exports: Ember.exports || global,
// // search for Namespaces
// lookup: Ember.lookup || global,
// };
// })(global, global.Ember);
1 change: 1 addition & 0 deletions addon/components/checkbox.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{{yield}}
162 changes: 162 additions & 0 deletions addon/components/checkbox.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
//@ts-check
/* eslint-disable ember/no-component-lifecycle-hooks */
/* eslint-disable ember/require-tagless-components */
/* eslint-disable ember/no-classic-classes */
/* eslint-disable ember/no-classic-components */
import { set } from '@ember/object';
import { assert } from '@ember/debug';
import { DEBUG } from '@glimmer/env';
import EmberComponent from '@ember/component';

/**
@module @ember/component
*/

/**
The internal class used to create text inputs when the `{{input}}`
helper is used with `type` of `checkbox`.

See [Ember.Templates.helpers.input](/ember/release/classes/Ember.Templates.helpers/methods/input?anchor=input) for usage details.

## Direct manipulation of `checked`

The `checked` attribute of an `Checkbox` object should always be set
through the Ember object or by interacting with its rendered element
representation via the mouse, keyboard, or touch. Updating the value of the
checkbox via jQuery will result in the checked value of the object and its
element losing synchronization.

## Layout and LayoutName properties

Because HTML `input` elements are self closing `layout` and `layoutName`
properties will not be applied.

@class Checkbox
@public
*/
const Checkbox = EmberComponent.extend({
/**
By default, this component will add the `ember-checkbox` class to the component's element.

@property classNames
@type Array | String
@default ['ember-checkbox']
@public
*/
classNames: ['ember-checkbox'],

tagName: 'input',

/**
By default this component will forward a number of arguments to attributes on the the
component's element:

* indeterminate
* disabled
* tabindex
* name
* autofocus
* required
* form

When invoked with curly braces, this is the exhaustive list of HTML attributes you can
customize (i.e. `{{input type="checkbox" disabled=true}}`).

When invoked with angle bracket invocation, this list is irrelevant, because you can use HTML
attribute syntax to customize the element (i.e.
`<Input @type="checkbox" disabled data-custom="custom value" />`). However, `@type` and
`@checked` must be passed as named arguments, not attributes.

@property attributeBindings
@type Array | String
@default ['type', 'checked', 'indeterminate', 'disabled', 'tabindex', 'name', 'autofocus', 'required', 'form']
@public
*/
attributeBindings: [
'type',
'checked',
'indeterminate',
'disabled',
'tabindex',
'name',
'autofocus',
'required',
'form',
],

/**
Sets the `type` attribute of the `Checkbox`'s element

@property disabled
@default false
@private
*/
type: 'checkbox',

/**
Sets the `disabled` attribute of the `Checkbox`'s element

@property disabled
@default false
@public
*/
disabled: false,

/**
Corresponds to the `indeterminate` property of the `Checkbox`'s element

@property disabled
@default false
@public
*/
indeterminate: false,

/**
Whenever the checkbox is inserted into the DOM, perform initialization steps, which include
setting the indeterminate property if needed.

If this method is overridden, `super` must be called.

@method
@public
*/
didInsertElement() {
this._super(...arguments);
this.element.indeterminate = Boolean(this.indeterminate);
},

/**
Whenever the `change` event is fired on the checkbox, update its `checked` property to reflect
whether the checkbox is checked.

If this method is overridden, `super` must be called.

@method
@public
*/
change() {
set(this, 'checked', this.element.checked);
},
});

if (DEBUG) {
const UNSET = {};

Checkbox.reopen({
value: UNSET,

didReceiveAttrs() {
this._super();

assert(
"`<Input @type='checkbox' @value={{...}} />` is not supported; " +
"please use `<Input @type='checkbox' @checked={{...}} />` instead.",
!(this.type === 'checkbox' && this.value !== UNSET)
);
},
});
}

Checkbox.toString = () => '@ember/component/checkbox';

export default Checkbox;
5 changes: 5 additions & 0 deletions addon/components/link-to.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{{~#if (has-block)~}}
{{yield}}
{{~else~}}
{{this.linkTitle}}
{{~/if~}}
Loading