repackaging: all the file moves
This commit is contained in:
44
modules/@angular/platform-browser/src/dom/debug/by.ts
Normal file
44
modules/@angular/platform-browser/src/dom/debug/by.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import {Type, isPresent, isBlank} from 'angular2/src/facade/lang';
|
||||
import {Predicate} from 'angular2/src/facade/collection';
|
||||
import {DOM} from 'angular2/src/platform/dom/dom_adapter';
|
||||
import {DebugElement} from 'angular2/core';
|
||||
|
||||
/**
|
||||
* Predicates for use with {@link DebugElement}'s query functions.
|
||||
*/
|
||||
export class By {
|
||||
/**
|
||||
* Match all elements.
|
||||
*
|
||||
* ## Example
|
||||
*
|
||||
* {@example platform/dom/debug/ts/by/by.ts region='by_all'}
|
||||
*/
|
||||
static all(): Predicate<DebugElement> { return (debugElement) => true; }
|
||||
|
||||
/**
|
||||
* Match elements by the given CSS selector.
|
||||
*
|
||||
* ## Example
|
||||
*
|
||||
* {@example platform/dom/debug/ts/by/by.ts region='by_css'}
|
||||
*/
|
||||
static css(selector: string): Predicate<DebugElement> {
|
||||
return (debugElement) => {
|
||||
return isPresent(debugElement.nativeElement) ?
|
||||
DOM.elementMatches(debugElement.nativeElement, selector) :
|
||||
false;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Match elements that have the given directive present.
|
||||
*
|
||||
* ## Example
|
||||
*
|
||||
* {@example platform/dom/debug/ts/by/by.ts region='by_directive'}
|
||||
*/
|
||||
static directive(type: Type): Predicate<DebugElement> {
|
||||
return (debugElement) => { return debugElement.providerTokens.indexOf(type) !== -1; };
|
||||
}
|
||||
}
|
52
modules/@angular/platform-browser/src/dom/debug/ng_probe.ts
Normal file
52
modules/@angular/platform-browser/src/dom/debug/ng_probe.ts
Normal file
@ -0,0 +1,52 @@
|
||||
import {assertionsEnabled} from 'angular2/src/facade/lang';
|
||||
import {DOM} from 'angular2/src/platform/dom/dom_adapter';
|
||||
import {DebugNode, getDebugNode} from 'angular2/src/core/debug/debug_node';
|
||||
import {DomRootRenderer} from 'angular2/src/platform/dom/dom_renderer';
|
||||
import {RootRenderer, NgZone, ApplicationRef} from 'angular2/core';
|
||||
import {DebugDomRootRenderer} from 'angular2/src/core/debug/debug_renderer';
|
||||
|
||||
const CORE_TOKENS = /*@ts2dart_const*/ {'ApplicationRef': ApplicationRef, 'NgZone': NgZone};
|
||||
|
||||
const INSPECT_GLOBAL_NAME = 'ng.probe';
|
||||
const CORE_TOKENS_GLOBAL_NAME = 'ng.coreTokens';
|
||||
|
||||
/**
|
||||
* Returns a {@link DebugElement} for the given native DOM element, or
|
||||
* null if the given native element does not have an Angular view associated
|
||||
* with it.
|
||||
*/
|
||||
export function inspectNativeElement(element): DebugNode {
|
||||
return getDebugNode(element);
|
||||
}
|
||||
|
||||
function _createConditionalRootRenderer(rootRenderer) {
|
||||
if (assertionsEnabled()) {
|
||||
return _createRootRenderer(rootRenderer);
|
||||
}
|
||||
return rootRenderer;
|
||||
}
|
||||
|
||||
function _createRootRenderer(rootRenderer) {
|
||||
DOM.setGlobalVar(INSPECT_GLOBAL_NAME, inspectNativeElement);
|
||||
DOM.setGlobalVar(CORE_TOKENS_GLOBAL_NAME, CORE_TOKENS);
|
||||
return new DebugDomRootRenderer(rootRenderer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Providers which support debugging Angular applications (e.g. via `ng.probe`).
|
||||
*/
|
||||
export const ELEMENT_PROBE_PROVIDERS: any[] = /*@ts2dart_const*/[
|
||||
/*@ts2dart_Provider*/ {
|
||||
provide: RootRenderer,
|
||||
useFactory: _createConditionalRootRenderer,
|
||||
deps: [DomRootRenderer]
|
||||
}
|
||||
];
|
||||
|
||||
export const ELEMENT_PROBE_PROVIDERS_PROD_MODE: any[] = /*@ts2dart_const*/[
|
||||
/*@ts2dart_Provider*/ {
|
||||
provide: RootRenderer,
|
||||
useFactory: _createRootRenderer,
|
||||
deps: [DomRootRenderer]
|
||||
}
|
||||
];
|
143
modules/@angular/platform-browser/src/dom/dom_adapter.ts
Normal file
143
modules/@angular/platform-browser/src/dom/dom_adapter.ts
Normal file
@ -0,0 +1,143 @@
|
||||
import {isBlank, Type} from 'angular2/src/facade/lang';
|
||||
|
||||
export var DOM: DomAdapter = null;
|
||||
|
||||
export function setRootDomAdapter(adapter: DomAdapter) {
|
||||
if (isBlank(DOM)) {
|
||||
DOM = adapter;
|
||||
}
|
||||
}
|
||||
|
||||
/* tslint:disable:requireParameterType */
|
||||
/**
|
||||
* Provides DOM operations in an environment-agnostic way.
|
||||
*/
|
||||
export abstract class DomAdapter {
|
||||
abstract hasProperty(element, name: string): boolean;
|
||||
abstract setProperty(el: Element, name: string, value: any);
|
||||
abstract getProperty(el: Element, name: string): any;
|
||||
abstract invoke(el: Element, methodName: string, args: any[]): any;
|
||||
|
||||
abstract logError(error);
|
||||
abstract log(error);
|
||||
abstract logGroup(error);
|
||||
abstract logGroupEnd();
|
||||
|
||||
/** @deprecated */
|
||||
abstract getXHR(): Type;
|
||||
|
||||
/**
|
||||
* Maps attribute names to their corresponding property names for cases
|
||||
* where attribute name doesn't match property name.
|
||||
*/
|
||||
get attrToPropMap(): {[key: string]: string} { return this._attrToPropMap; };
|
||||
set attrToPropMap(value: {[key: string]: string}) { this._attrToPropMap = value; };
|
||||
/** @internal */
|
||||
_attrToPropMap: {[key: string]: string};
|
||||
|
||||
abstract parse(templateHtml: string);
|
||||
abstract query(selector: string): any;
|
||||
abstract querySelector(el, selector: string): HTMLElement;
|
||||
abstract querySelectorAll(el, selector: string): any[];
|
||||
abstract on(el, evt, listener);
|
||||
abstract onAndCancel(el, evt, listener): Function;
|
||||
abstract dispatchEvent(el, evt);
|
||||
abstract createMouseEvent(eventType): any;
|
||||
abstract createEvent(eventType: string): any;
|
||||
abstract preventDefault(evt);
|
||||
abstract isPrevented(evt): boolean;
|
||||
abstract getInnerHTML(el): string;
|
||||
abstract getOuterHTML(el): string;
|
||||
abstract nodeName(node): string;
|
||||
abstract nodeValue(node): string;
|
||||
abstract type(node): string;
|
||||
abstract content(node): any;
|
||||
abstract firstChild(el): Node;
|
||||
abstract nextSibling(el): Node;
|
||||
abstract parentElement(el): Node;
|
||||
abstract childNodes(el): Node[];
|
||||
abstract childNodesAsList(el): Node[];
|
||||
abstract clearNodes(el);
|
||||
abstract appendChild(el, node);
|
||||
abstract removeChild(el, node);
|
||||
abstract replaceChild(el, newNode, oldNode);
|
||||
abstract remove(el): Node;
|
||||
abstract insertBefore(el, node);
|
||||
abstract insertAllBefore(el, nodes);
|
||||
abstract insertAfter(el, node);
|
||||
abstract setInnerHTML(el, value);
|
||||
abstract getText(el): string;
|
||||
abstract setText(el, value: string);
|
||||
abstract getValue(el): string;
|
||||
abstract setValue(el, value: string);
|
||||
abstract getChecked(el): boolean;
|
||||
abstract setChecked(el, value: boolean);
|
||||
abstract createComment(text: string): any;
|
||||
abstract createTemplate(html): HTMLElement;
|
||||
abstract createElement(tagName, doc?): HTMLElement;
|
||||
abstract createElementNS(ns: string, tagName: string, doc?): Element;
|
||||
abstract createTextNode(text: string, doc?): Text;
|
||||
abstract createScriptTag(attrName: string, attrValue: string, doc?): HTMLElement;
|
||||
abstract createStyleElement(css: string, doc?): HTMLStyleElement;
|
||||
abstract createShadowRoot(el): any;
|
||||
abstract getShadowRoot(el): any;
|
||||
abstract getHost(el): any;
|
||||
abstract getDistributedNodes(el): Node[];
|
||||
abstract clone /*<T extends Node>*/ (node: Node /*T*/): Node /*T*/;
|
||||
abstract getElementsByClassName(element, name: string): HTMLElement[];
|
||||
abstract getElementsByTagName(element, name: string): HTMLElement[];
|
||||
abstract classList(element): any[];
|
||||
abstract addClass(element, className: string);
|
||||
abstract removeClass(element, className: string);
|
||||
abstract hasClass(element, className: string): boolean;
|
||||
abstract setStyle(element, styleName: string, styleValue: string);
|
||||
abstract removeStyle(element, styleName: string);
|
||||
abstract getStyle(element, styleName: string): string;
|
||||
abstract hasStyle(element, styleName: string, styleValue?: string): boolean;
|
||||
abstract tagName(element): string;
|
||||
abstract attributeMap(element): Map<string, string>;
|
||||
abstract hasAttribute(element, attribute: string): boolean;
|
||||
abstract hasAttributeNS(element, ns: string, attribute: string): boolean;
|
||||
abstract getAttribute(element, attribute: string): string;
|
||||
abstract getAttributeNS(element, ns: string, attribute: string): string;
|
||||
abstract setAttribute(element, name: string, value: string);
|
||||
abstract setAttributeNS(element, ns: string, name: string, value: string);
|
||||
abstract removeAttribute(element, attribute: string);
|
||||
abstract removeAttributeNS(element, ns: string, attribute: string);
|
||||
abstract templateAwareRoot(el);
|
||||
abstract createHtmlDocument(): HTMLDocument;
|
||||
abstract defaultDoc(): HTMLDocument;
|
||||
abstract getBoundingClientRect(el);
|
||||
abstract getTitle(): string;
|
||||
abstract setTitle(newTitle: string);
|
||||
abstract elementMatches(n, selector: string): boolean;
|
||||
abstract isTemplateElement(el: any): boolean;
|
||||
abstract isTextNode(node): boolean;
|
||||
abstract isCommentNode(node): boolean;
|
||||
abstract isElementNode(node): boolean;
|
||||
abstract hasShadowRoot(node): boolean;
|
||||
abstract isShadowRoot(node): boolean;
|
||||
abstract importIntoDoc /*<T extends Node>*/ (node: Node /*T*/): Node /*T*/;
|
||||
abstract adoptNode /*<T extends Node>*/ (node: Node /*T*/): Node /*T*/;
|
||||
abstract getHref(element): string;
|
||||
abstract getEventKey(event): string;
|
||||
abstract resolveAndSetHref(element, baseUrl: string, href: string);
|
||||
abstract supportsDOMEvents(): boolean;
|
||||
abstract supportsNativeShadowDOM(): boolean;
|
||||
abstract getGlobalEventTarget(target: string): any;
|
||||
abstract getHistory(): History;
|
||||
abstract getLocation(): Location;
|
||||
abstract getBaseHref(): string;
|
||||
abstract resetBaseElement(): void;
|
||||
abstract getUserAgent(): string;
|
||||
abstract setData(element, name: string, value: string);
|
||||
abstract getComputedStyle(element): any;
|
||||
abstract getData(element, name: string): string;
|
||||
abstract setGlobalVar(name: string, value: any);
|
||||
abstract requestAnimationFrame(callback): number;
|
||||
abstract cancelAnimationFrame(id);
|
||||
abstract performanceNow(): number;
|
||||
abstract getAnimationPrefix(): string;
|
||||
abstract getTransitionEnd(): string;
|
||||
abstract supportsAnimation(): boolean;
|
||||
}
|
339
modules/@angular/platform-browser/src/dom/dom_renderer.ts
Normal file
339
modules/@angular/platform-browser/src/dom/dom_renderer.ts
Normal file
@ -0,0 +1,339 @@
|
||||
import {Inject, Injectable, OpaqueToken} from 'angular2/src/core/di';
|
||||
import {AnimationBuilder} from 'angular2/src/animate/animation_builder';
|
||||
import {
|
||||
isPresent,
|
||||
isBlank,
|
||||
Json,
|
||||
RegExpWrapper,
|
||||
stringify,
|
||||
StringWrapper,
|
||||
isArray,
|
||||
isString
|
||||
} from 'angular2/src/facade/lang';
|
||||
|
||||
import {BaseException, WrappedException} from 'angular2/src/facade/exceptions';
|
||||
import {DomSharedStylesHost} from './shared_styles_host';
|
||||
|
||||
import {
|
||||
Renderer,
|
||||
RootRenderer,
|
||||
RenderComponentType,
|
||||
RenderDebugInfo
|
||||
} from 'angular2/src/core/render/api';
|
||||
|
||||
import {EventManager} from './events/event_manager';
|
||||
|
||||
import {DOCUMENT} from './dom_tokens';
|
||||
import {ViewEncapsulation} from 'angular2/src/core/metadata';
|
||||
import {DOM} from 'angular2/src/platform/dom/dom_adapter';
|
||||
import {camelCaseToDashCase} from './util';
|
||||
|
||||
const NAMESPACE_URIS =
|
||||
/*@ts2dart_const*/
|
||||
{'xlink': 'http://www.w3.org/1999/xlink', 'svg': 'http://www.w3.org/2000/svg'};
|
||||
const TEMPLATE_COMMENT_TEXT = 'template bindings={}';
|
||||
var TEMPLATE_BINDINGS_EXP = /^template bindings=(.*)$/g;
|
||||
|
||||
export abstract class DomRootRenderer implements RootRenderer {
|
||||
private _registeredComponents: Map<string, DomRenderer> = new Map<string, DomRenderer>();
|
||||
|
||||
constructor(public document: any, public eventManager: EventManager,
|
||||
public sharedStylesHost: DomSharedStylesHost, public animate: AnimationBuilder) {}
|
||||
|
||||
renderComponent(componentProto: RenderComponentType): Renderer {
|
||||
var renderer = this._registeredComponents.get(componentProto.id);
|
||||
if (isBlank(renderer)) {
|
||||
renderer = new DomRenderer(this, componentProto);
|
||||
this._registeredComponents.set(componentProto.id, renderer);
|
||||
}
|
||||
return renderer;
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class DomRootRenderer_ extends DomRootRenderer {
|
||||
constructor(@Inject(DOCUMENT) _document: any, _eventManager: EventManager,
|
||||
sharedStylesHost: DomSharedStylesHost, animate: AnimationBuilder) {
|
||||
super(_document, _eventManager, sharedStylesHost, animate);
|
||||
}
|
||||
}
|
||||
|
||||
export class DomRenderer implements Renderer {
|
||||
private _contentAttr: string;
|
||||
private _hostAttr: string;
|
||||
private _styles: string[];
|
||||
|
||||
constructor(private _rootRenderer: DomRootRenderer, private componentProto: RenderComponentType) {
|
||||
this._styles = _flattenStyles(componentProto.id, componentProto.styles, []);
|
||||
if (componentProto.encapsulation !== ViewEncapsulation.Native) {
|
||||
this._rootRenderer.sharedStylesHost.addStyles(this._styles);
|
||||
}
|
||||
if (this.componentProto.encapsulation === ViewEncapsulation.Emulated) {
|
||||
this._contentAttr = _shimContentAttribute(componentProto.id);
|
||||
this._hostAttr = _shimHostAttribute(componentProto.id);
|
||||
} else {
|
||||
this._contentAttr = null;
|
||||
this._hostAttr = null;
|
||||
}
|
||||
}
|
||||
|
||||
selectRootElement(selectorOrNode: string | any, debugInfo: RenderDebugInfo): Element {
|
||||
var el;
|
||||
if (isString(selectorOrNode)) {
|
||||
el = DOM.querySelector(this._rootRenderer.document, selectorOrNode);
|
||||
if (isBlank(el)) {
|
||||
throw new BaseException(`The selector "${selectorOrNode}" did not match any elements`);
|
||||
}
|
||||
} else {
|
||||
el = selectorOrNode;
|
||||
}
|
||||
DOM.clearNodes(el);
|
||||
return el;
|
||||
}
|
||||
|
||||
createElement(parent: Element, name: string, debugInfo: RenderDebugInfo): Node {
|
||||
var nsAndName = splitNamespace(name);
|
||||
var el = isPresent(nsAndName[0]) ?
|
||||
DOM.createElementNS(NAMESPACE_URIS[nsAndName[0]], nsAndName[1]) :
|
||||
DOM.createElement(nsAndName[1]);
|
||||
if (isPresent(this._contentAttr)) {
|
||||
DOM.setAttribute(el, this._contentAttr, '');
|
||||
}
|
||||
if (isPresent(parent)) {
|
||||
DOM.appendChild(parent, el);
|
||||
}
|
||||
return el;
|
||||
}
|
||||
|
||||
createViewRoot(hostElement: any): any {
|
||||
var nodesParent;
|
||||
if (this.componentProto.encapsulation === ViewEncapsulation.Native) {
|
||||
nodesParent = DOM.createShadowRoot(hostElement);
|
||||
this._rootRenderer.sharedStylesHost.addHost(nodesParent);
|
||||
for (var i = 0; i < this._styles.length; i++) {
|
||||
DOM.appendChild(nodesParent, DOM.createStyleElement(this._styles[i]));
|
||||
}
|
||||
} else {
|
||||
if (isPresent(this._hostAttr)) {
|
||||
DOM.setAttribute(hostElement, this._hostAttr, '');
|
||||
}
|
||||
nodesParent = hostElement;
|
||||
}
|
||||
return nodesParent;
|
||||
}
|
||||
|
||||
createTemplateAnchor(parentElement: any, debugInfo: RenderDebugInfo): any {
|
||||
var comment = DOM.createComment(TEMPLATE_COMMENT_TEXT);
|
||||
if (isPresent(parentElement)) {
|
||||
DOM.appendChild(parentElement, comment);
|
||||
}
|
||||
return comment;
|
||||
}
|
||||
|
||||
createText(parentElement: any, value: string, debugInfo: RenderDebugInfo): any {
|
||||
var node = DOM.createTextNode(value);
|
||||
if (isPresent(parentElement)) {
|
||||
DOM.appendChild(parentElement, node);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
projectNodes(parentElement: any, nodes: any[]) {
|
||||
if (isBlank(parentElement)) return;
|
||||
appendNodes(parentElement, nodes);
|
||||
}
|
||||
|
||||
attachViewAfter(node: any, viewRootNodes: any[]) {
|
||||
moveNodesAfterSibling(node, viewRootNodes);
|
||||
for (let i = 0; i < viewRootNodes.length; i++) this.animateNodeEnter(viewRootNodes[i]);
|
||||
}
|
||||
|
||||
detachView(viewRootNodes: any[]) {
|
||||
for (var i = 0; i < viewRootNodes.length; i++) {
|
||||
var node = viewRootNodes[i];
|
||||
DOM.remove(node);
|
||||
this.animateNodeLeave(node);
|
||||
}
|
||||
}
|
||||
|
||||
destroyView(hostElement: any, viewAllNodes: any[]) {
|
||||
if (this.componentProto.encapsulation === ViewEncapsulation.Native && isPresent(hostElement)) {
|
||||
this._rootRenderer.sharedStylesHost.removeHost(DOM.getShadowRoot(hostElement));
|
||||
}
|
||||
}
|
||||
|
||||
listen(renderElement: any, name: string, callback: Function): Function {
|
||||
return this._rootRenderer.eventManager.addEventListener(renderElement, name,
|
||||
decoratePreventDefault(callback));
|
||||
}
|
||||
|
||||
listenGlobal(target: string, name: string, callback: Function): Function {
|
||||
return this._rootRenderer.eventManager.addGlobalEventListener(target, name,
|
||||
decoratePreventDefault(callback));
|
||||
}
|
||||
|
||||
setElementProperty(renderElement: any, propertyName: string, propertyValue: any): void {
|
||||
DOM.setProperty(renderElement, propertyName, propertyValue);
|
||||
}
|
||||
|
||||
setElementAttribute(renderElement: any, attributeName: string, attributeValue: string): void {
|
||||
var attrNs;
|
||||
var nsAndName = splitNamespace(attributeName);
|
||||
if (isPresent(nsAndName[0])) {
|
||||
attributeName = nsAndName[0] + ':' + nsAndName[1];
|
||||
attrNs = NAMESPACE_URIS[nsAndName[0]];
|
||||
}
|
||||
if (isPresent(attributeValue)) {
|
||||
if (isPresent(attrNs)) {
|
||||
DOM.setAttributeNS(renderElement, attrNs, attributeName, attributeValue);
|
||||
} else {
|
||||
DOM.setAttribute(renderElement, attributeName, attributeValue);
|
||||
}
|
||||
} else {
|
||||
if (isPresent(attrNs)) {
|
||||
DOM.removeAttributeNS(renderElement, attrNs, nsAndName[1]);
|
||||
} else {
|
||||
DOM.removeAttribute(renderElement, attributeName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setBindingDebugInfo(renderElement: any, propertyName: string, propertyValue: string): void {
|
||||
var dashCasedPropertyName = camelCaseToDashCase(propertyName);
|
||||
if (DOM.isCommentNode(renderElement)) {
|
||||
var existingBindings = RegExpWrapper.firstMatch(
|
||||
TEMPLATE_BINDINGS_EXP, StringWrapper.replaceAll(DOM.getText(renderElement), /\n/g, ''));
|
||||
var parsedBindings = Json.parse(existingBindings[1]);
|
||||
parsedBindings[dashCasedPropertyName] = propertyValue;
|
||||
DOM.setText(renderElement, StringWrapper.replace(TEMPLATE_COMMENT_TEXT, '{}',
|
||||
Json.stringify(parsedBindings)));
|
||||
} else {
|
||||
this.setElementAttribute(renderElement, propertyName, propertyValue);
|
||||
}
|
||||
}
|
||||
|
||||
setElementClass(renderElement: any, className: string, isAdd: boolean): void {
|
||||
if (isAdd) {
|
||||
DOM.addClass(renderElement, className);
|
||||
} else {
|
||||
DOM.removeClass(renderElement, className);
|
||||
}
|
||||
}
|
||||
|
||||
setElementStyle(renderElement: any, styleName: string, styleValue: string): void {
|
||||
if (isPresent(styleValue)) {
|
||||
DOM.setStyle(renderElement, styleName, stringify(styleValue));
|
||||
} else {
|
||||
DOM.removeStyle(renderElement, styleName);
|
||||
}
|
||||
}
|
||||
|
||||
invokeElementMethod(renderElement: any, methodName: string, args: any[]): void {
|
||||
DOM.invoke(renderElement, methodName, args);
|
||||
}
|
||||
|
||||
setText(renderNode: any, text: string): void { DOM.setText(renderNode, text); }
|
||||
|
||||
/**
|
||||
* Performs animations if necessary
|
||||
* @param node
|
||||
*/
|
||||
animateNodeEnter(node: Node) {
|
||||
if (DOM.isElementNode(node) && DOM.hasClass(node, 'ng-animate')) {
|
||||
DOM.addClass(node, 'ng-enter');
|
||||
this._rootRenderer.animate.css()
|
||||
.addAnimationClass('ng-enter-active')
|
||||
.start(<HTMLElement>node)
|
||||
.onComplete(() => { DOM.removeClass(node, 'ng-enter'); });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If animations are necessary, performs animations then removes the element; otherwise, it just
|
||||
* removes the element.
|
||||
* @param node
|
||||
*/
|
||||
animateNodeLeave(node: Node) {
|
||||
if (DOM.isElementNode(node) && DOM.hasClass(node, 'ng-animate')) {
|
||||
DOM.addClass(node, 'ng-leave');
|
||||
this._rootRenderer.animate.css()
|
||||
.addAnimationClass('ng-leave-active')
|
||||
.start(<HTMLElement>node)
|
||||
.onComplete(() => {
|
||||
DOM.removeClass(node, 'ng-leave');
|
||||
DOM.remove(node);
|
||||
});
|
||||
} else {
|
||||
DOM.remove(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function moveNodesAfterSibling(sibling, nodes) {
|
||||
var parent = DOM.parentElement(sibling);
|
||||
if (nodes.length > 0 && isPresent(parent)) {
|
||||
var nextSibling = DOM.nextSibling(sibling);
|
||||
if (isPresent(nextSibling)) {
|
||||
for (var i = 0; i < nodes.length; i++) {
|
||||
DOM.insertBefore(nextSibling, nodes[i]);
|
||||
}
|
||||
} else {
|
||||
for (var i = 0; i < nodes.length; i++) {
|
||||
DOM.appendChild(parent, nodes[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function appendNodes(parent, nodes) {
|
||||
for (var i = 0; i < nodes.length; i++) {
|
||||
DOM.appendChild(parent, nodes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function decoratePreventDefault(eventHandler: Function): Function {
|
||||
return (event) => {
|
||||
var allowDefaultBehavior = eventHandler(event);
|
||||
if (allowDefaultBehavior === false) {
|
||||
// TODO(tbosch): move preventDefault into event plugins...
|
||||
DOM.preventDefault(event);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
var COMPONENT_REGEX = /%COMP%/g;
|
||||
export const COMPONENT_VARIABLE = '%COMP%';
|
||||
export const HOST_ATTR = /*@ts2dart_const*/ `_nghost-${COMPONENT_VARIABLE}`;
|
||||
export const CONTENT_ATTR = /*@ts2dart_const*/ `_ngcontent-${COMPONENT_VARIABLE}`;
|
||||
|
||||
function _shimContentAttribute(componentShortId: string): string {
|
||||
return StringWrapper.replaceAll(CONTENT_ATTR, COMPONENT_REGEX, componentShortId);
|
||||
}
|
||||
|
||||
function _shimHostAttribute(componentShortId: string): string {
|
||||
return StringWrapper.replaceAll(HOST_ATTR, COMPONENT_REGEX, componentShortId);
|
||||
}
|
||||
|
||||
function _flattenStyles(compId: string, styles: Array<any | any[]>, target: string[]): string[] {
|
||||
for (var i = 0; i < styles.length; i++) {
|
||||
var style = styles[i];
|
||||
if (isArray(style)) {
|
||||
_flattenStyles(compId, style, target);
|
||||
} else {
|
||||
style = StringWrapper.replaceAll(style, COMPONENT_REGEX, compId);
|
||||
target.push(style);
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
var NS_PREFIX_RE = /^@([^:]+):(.+)/g;
|
||||
|
||||
function splitNamespace(name: string): string[] {
|
||||
if (name[0] != '@') {
|
||||
return [null, name];
|
||||
}
|
||||
let match = RegExpWrapper.firstMatch(NS_PREFIX_RE, name);
|
||||
return [match[1], match[2]];
|
||||
}
|
9
modules/@angular/platform-browser/src/dom/dom_tokens.ts
Normal file
9
modules/@angular/platform-browser/src/dom/dom_tokens.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import {OpaqueToken} from 'angular2/src/core/di';
|
||||
|
||||
/**
|
||||
* A DI Token representing the main rendering context. In a browser this is the DOM Document.
|
||||
*
|
||||
* Note: Document might not be available in the Application Context when Application and Rendering
|
||||
* Contexts are not the same (e.g. when running the application into a Web Worker).
|
||||
*/
|
||||
export const DOCUMENT: OpaqueToken = /*@ts2dart_const*/ new OpaqueToken('DocumentToken');
|
@ -0,0 +1,25 @@
|
||||
import {DOM} from 'angular2/src/platform/dom/dom_adapter';
|
||||
import {Injectable} from 'angular2/core';
|
||||
import {EventManagerPlugin, EventManager} from './event_manager';
|
||||
|
||||
@Injectable()
|
||||
export class DomEventsPlugin extends EventManagerPlugin {
|
||||
// This plugin should come last in the list of plugins, because it accepts all
|
||||
// events.
|
||||
supports(eventName: string): boolean { return true; }
|
||||
|
||||
addEventListener(element: HTMLElement, eventName: string, handler: Function): Function {
|
||||
var zone = this.manager.getZone();
|
||||
var outsideHandler = (event) => zone.runGuarded(() => handler(event));
|
||||
return this.manager.getZone().runOutsideAngular(
|
||||
() => DOM.onAndCancel(element, eventName, outsideHandler));
|
||||
}
|
||||
|
||||
addGlobalEventListener(target: string, eventName: string, handler: Function): Function {
|
||||
var element = DOM.getGlobalEventTarget(target);
|
||||
var zone = this.manager.getZone();
|
||||
var outsideHandler = (event) => zone.runGuarded(() => handler(event));
|
||||
return this.manager.getZone().runOutsideAngular(
|
||||
() => DOM.onAndCancel(element, eventName, outsideHandler));
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
import {BaseException, WrappedException} from 'angular2/src/facade/exceptions';
|
||||
import {Injectable, Inject, OpaqueToken} from 'angular2/src/core/di';
|
||||
import {NgZone} from 'angular2/src/core/zone/ng_zone';
|
||||
import {ListWrapper} from 'angular2/src/facade/collection';
|
||||
|
||||
export const EVENT_MANAGER_PLUGINS: OpaqueToken =
|
||||
/*@ts2dart_const*/ new OpaqueToken("EventManagerPlugins");
|
||||
|
||||
@Injectable()
|
||||
export class EventManager {
|
||||
private _plugins: EventManagerPlugin[];
|
||||
|
||||
constructor(@Inject(EVENT_MANAGER_PLUGINS) plugins: EventManagerPlugin[], private _zone: NgZone) {
|
||||
plugins.forEach(p => p.manager = this);
|
||||
this._plugins = ListWrapper.reversed(plugins);
|
||||
}
|
||||
|
||||
addEventListener(element: HTMLElement, eventName: string, handler: Function): Function {
|
||||
var plugin = this._findPluginFor(eventName);
|
||||
return plugin.addEventListener(element, eventName, handler);
|
||||
}
|
||||
|
||||
addGlobalEventListener(target: string, eventName: string, handler: Function): Function {
|
||||
var plugin = this._findPluginFor(eventName);
|
||||
return plugin.addGlobalEventListener(target, eventName, handler);
|
||||
}
|
||||
|
||||
getZone(): NgZone { return this._zone; }
|
||||
|
||||
/** @internal */
|
||||
_findPluginFor(eventName: string): EventManagerPlugin {
|
||||
var plugins = this._plugins;
|
||||
for (var i = 0; i < plugins.length; i++) {
|
||||
var plugin = plugins[i];
|
||||
if (plugin.supports(eventName)) {
|
||||
return plugin;
|
||||
}
|
||||
}
|
||||
throw new BaseException(`No event manager plugin found for event ${eventName}`);
|
||||
}
|
||||
}
|
||||
|
||||
export class EventManagerPlugin {
|
||||
manager: EventManager;
|
||||
|
||||
// That is equivalent to having supporting $event.target
|
||||
supports(eventName: string): boolean { return false; }
|
||||
|
||||
addEventListener(element: HTMLElement, eventName: string, handler: Function): Function {
|
||||
throw "not implemented";
|
||||
}
|
||||
|
||||
addGlobalEventListener(element: string, eventName: string, handler: Function): Function {
|
||||
throw "not implemented";
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
import {EventManagerPlugin} from './event_manager';
|
||||
import {StringMapWrapper} from 'angular2/src/facade/collection';
|
||||
|
||||
var _eventNames = {
|
||||
// pan
|
||||
'pan': true,
|
||||
'panstart': true,
|
||||
'panmove': true,
|
||||
'panend': true,
|
||||
'pancancel': true,
|
||||
'panleft': true,
|
||||
'panright': true,
|
||||
'panup': true,
|
||||
'pandown': true,
|
||||
// pinch
|
||||
'pinch': true,
|
||||
'pinchstart': true,
|
||||
'pinchmove': true,
|
||||
'pinchend': true,
|
||||
'pinchcancel': true,
|
||||
'pinchin': true,
|
||||
'pinchout': true,
|
||||
// press
|
||||
'press': true,
|
||||
'pressup': true,
|
||||
// rotate
|
||||
'rotate': true,
|
||||
'rotatestart': true,
|
||||
'rotatemove': true,
|
||||
'rotateend': true,
|
||||
'rotatecancel': true,
|
||||
// swipe
|
||||
'swipe': true,
|
||||
'swipeleft': true,
|
||||
'swiperight': true,
|
||||
'swipeup': true,
|
||||
'swipedown': true,
|
||||
// tap
|
||||
'tap': true,
|
||||
};
|
||||
|
||||
|
||||
export class HammerGesturesPluginCommon extends EventManagerPlugin {
|
||||
constructor() { super(); }
|
||||
|
||||
supports(eventName: string): boolean {
|
||||
eventName = eventName.toLowerCase();
|
||||
return StringMapWrapper.contains(_eventNames, eventName);
|
||||
}
|
||||
}
|
@ -0,0 +1,114 @@
|
||||
library angular.events;
|
||||
|
||||
import 'dart:html';
|
||||
import './hammer_common.dart';
|
||||
import 'package:angular2/src/facade/exceptions.dart' show BaseException;
|
||||
import "package:angular2/src/core/di.dart" show Injectable, Inject, OpaqueToken;
|
||||
|
||||
import 'dart:js' as js;
|
||||
|
||||
const OpaqueToken HAMMER_GESTURE_CONFIG = const OpaqueToken("HammerGestureConfig");
|
||||
|
||||
overrideDefault(js.JsObject mc, String eventName, Object config) {
|
||||
var jsObj = mc.callMethod('get', [eventName]);
|
||||
jsObj.callMethod('set', [
|
||||
new js.JsObject.jsify(config)
|
||||
]);
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
class HammerGestureConfig {
|
||||
List<String> events = [];
|
||||
Map overrides = {};
|
||||
|
||||
buildHammer(Element element) {
|
||||
var mc = new js.JsObject(js.context['Hammer'], [element]);
|
||||
overrideDefault(mc, 'pinch', {'enable': true});
|
||||
overrideDefault(mc, 'rotate', {'enable': true});
|
||||
this.overrides.forEach((Object config, String eventName) => overrideDefault(mc, eventName, config));
|
||||
return mc;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
class HammerGesturesPlugin extends HammerGesturesPluginCommon {
|
||||
HammerGestureConfig _config;
|
||||
|
||||
HammerGesturesPlugin(@Inject(HAMMER_GESTURE_CONFIG) this._config) {}
|
||||
|
||||
bool supports(String eventName) {
|
||||
if (!super.supports(eventName) && !this.isCustomEvent(eventName)) return false;
|
||||
|
||||
if (!js.context.hasProperty('Hammer')) {
|
||||
throw new BaseException(
|
||||
'Hammer.js is not loaded, can not bind ${eventName} event');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
addEventListener(Element element, String eventName, Function handler) {
|
||||
var zone = this.manager.getZone();
|
||||
eventName = eventName.toLowerCase();
|
||||
|
||||
zone.runOutsideAngular(() {
|
||||
// Creating the manager bind events, must be done outside of angular
|
||||
var mc = this._config.buildHammer(element);
|
||||
|
||||
mc.callMethod('on', [
|
||||
eventName,
|
||||
(eventObj) {
|
||||
zone.runGuarded(() {
|
||||
var dartEvent = new HammerEvent._fromJsEvent(eventObj);
|
||||
handler(dartEvent);
|
||||
});
|
||||
}
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
isCustomEvent(String eventName) { return this._config.events.indexOf(eventName) > -1; }
|
||||
|
||||
}
|
||||
|
||||
class HammerEvent {
|
||||
num angle;
|
||||
num centerX;
|
||||
num centerY;
|
||||
int deltaTime;
|
||||
int deltaX;
|
||||
int deltaY;
|
||||
int direction;
|
||||
int distance;
|
||||
num rotation;
|
||||
num scale;
|
||||
Node target;
|
||||
int timeStamp;
|
||||
String type;
|
||||
num velocity;
|
||||
num velocityX;
|
||||
num velocityY;
|
||||
js.JsObject jsEvent;
|
||||
|
||||
HammerEvent._fromJsEvent(js.JsObject event) {
|
||||
angle = event['angle'];
|
||||
var center = event['center'];
|
||||
centerX = center['x'];
|
||||
centerY = center['y'];
|
||||
deltaTime = event['deltaTime'];
|
||||
deltaX = event['deltaX'];
|
||||
deltaY = event['deltaY'];
|
||||
direction = event['direction'];
|
||||
distance = event['distance'];
|
||||
rotation = event['rotation'];
|
||||
scale = event['scale'];
|
||||
target = event['target'];
|
||||
timeStamp = event['timeStamp'];
|
||||
type = event['type'];
|
||||
velocity = event['velocity'];
|
||||
velocityX = event['velocityX'];
|
||||
velocityY = event['velocityY'];
|
||||
jsEvent = event;
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
import {HammerGesturesPluginCommon} from './hammer_common';
|
||||
import {isPresent} from 'angular2/src/facade/lang';
|
||||
import {BaseException, WrappedException} from 'angular2/src/facade/exceptions';
|
||||
import {Injectable, Inject, OpaqueToken} from 'angular2/core';
|
||||
|
||||
export const HAMMER_GESTURE_CONFIG: OpaqueToken =
|
||||
/*@ts2dart_const*/ new OpaqueToken("HammerGestureConfig");
|
||||
|
||||
export interface HammerInstance {
|
||||
on(eventName: string, callback: Function): void;
|
||||
off(eventName: string, callback: Function): void;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class HammerGestureConfig {
|
||||
events: string[] = [];
|
||||
|
||||
overrides: {[key: string]: Object} = {};
|
||||
|
||||
buildHammer(element: HTMLElement): HammerInstance {
|
||||
var mc = new Hammer(element);
|
||||
|
||||
mc.get('pinch').set({enable: true});
|
||||
mc.get('rotate').set({enable: true});
|
||||
|
||||
for (let eventName in this.overrides) {
|
||||
mc.get(eventName).set(this.overrides[eventName]);
|
||||
}
|
||||
|
||||
return mc;
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class HammerGesturesPlugin extends HammerGesturesPluginCommon {
|
||||
constructor(@Inject(HAMMER_GESTURE_CONFIG) private _config: HammerGestureConfig) { super(); }
|
||||
|
||||
supports(eventName: string): boolean {
|
||||
if (!super.supports(eventName) && !this.isCustomEvent(eventName)) return false;
|
||||
|
||||
if (!isPresent(window['Hammer'])) {
|
||||
throw new BaseException(`Hammer.js is not loaded, can not bind ${eventName} event`);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
addEventListener(element: HTMLElement, eventName: string, handler: Function): Function {
|
||||
var zone = this.manager.getZone();
|
||||
eventName = eventName.toLowerCase();
|
||||
|
||||
return zone.runOutsideAngular(() => {
|
||||
// Creating the manager bind events, must be done outside of angular
|
||||
var mc = this._config.buildHammer(element);
|
||||
var callback = function(eventObj) { zone.runGuarded(function() { handler(eventObj); }); };
|
||||
mc.on(eventName, callback);
|
||||
return () => { mc.off(eventName, callback); };
|
||||
});
|
||||
}
|
||||
|
||||
isCustomEvent(eventName: string): boolean { return this._config.events.indexOf(eventName) > -1; }
|
||||
}
|
113
modules/@angular/platform-browser/src/dom/events/key_events.ts
Normal file
113
modules/@angular/platform-browser/src/dom/events/key_events.ts
Normal file
@ -0,0 +1,113 @@
|
||||
import {DOM} from 'angular2/src/platform/dom/dom_adapter';
|
||||
import {
|
||||
isPresent,
|
||||
isBlank,
|
||||
StringWrapper,
|
||||
RegExpWrapper,
|
||||
NumberWrapper
|
||||
} from 'angular2/src/facade/lang';
|
||||
import {StringMapWrapper, ListWrapper} from 'angular2/src/facade/collection';
|
||||
import {EventManagerPlugin} from './event_manager';
|
||||
import {NgZone} from 'angular2/src/core/zone/ng_zone';
|
||||
import {Injectable} from 'angular2/src/core/di';
|
||||
|
||||
var modifierKeys = ['alt', 'control', 'meta', 'shift'];
|
||||
var modifierKeyGetters: {[key: string]: (event: KeyboardEvent) => boolean} = {
|
||||
'alt': (event: KeyboardEvent) => event.altKey,
|
||||
'control': (event: KeyboardEvent) => event.ctrlKey,
|
||||
'meta': (event: KeyboardEvent) => event.metaKey,
|
||||
'shift': (event: KeyboardEvent) => event.shiftKey
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class KeyEventsPlugin extends EventManagerPlugin {
|
||||
constructor() { super(); }
|
||||
|
||||
supports(eventName: string): boolean {
|
||||
return isPresent(KeyEventsPlugin.parseEventName(eventName));
|
||||
}
|
||||
|
||||
addEventListener(element: HTMLElement, eventName: string, handler: Function): Function {
|
||||
var parsedEvent = KeyEventsPlugin.parseEventName(eventName);
|
||||
|
||||
var outsideHandler = KeyEventsPlugin.eventCallback(
|
||||
element, StringMapWrapper.get(parsedEvent, 'fullKey'), handler, this.manager.getZone());
|
||||
|
||||
return this.manager.getZone().runOutsideAngular(() => {
|
||||
return DOM.onAndCancel(element, StringMapWrapper.get(parsedEvent, 'domEventName'),
|
||||
outsideHandler);
|
||||
});
|
||||
}
|
||||
|
||||
static parseEventName(eventName: string): {[key: string]: string} {
|
||||
var parts: string[] = eventName.toLowerCase().split('.');
|
||||
|
||||
var domEventName = parts.shift();
|
||||
if ((parts.length === 0) ||
|
||||
!(StringWrapper.equals(domEventName, 'keydown') ||
|
||||
StringWrapper.equals(domEventName, 'keyup'))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var key = KeyEventsPlugin._normalizeKey(parts.pop());
|
||||
|
||||
var fullKey = '';
|
||||
modifierKeys.forEach(modifierName => {
|
||||
if (ListWrapper.contains(parts, modifierName)) {
|
||||
ListWrapper.remove(parts, modifierName);
|
||||
fullKey += modifierName + '.';
|
||||
}
|
||||
});
|
||||
fullKey += key;
|
||||
|
||||
if (parts.length != 0 || key.length === 0) {
|
||||
// returning null instead of throwing to let another plugin process the event
|
||||
return null;
|
||||
}
|
||||
var result = StringMapWrapper.create();
|
||||
StringMapWrapper.set(result, 'domEventName', domEventName);
|
||||
StringMapWrapper.set(result, 'fullKey', fullKey);
|
||||
return result;
|
||||
}
|
||||
|
||||
static getEventFullKey(event: KeyboardEvent): string {
|
||||
var fullKey = '';
|
||||
var key = DOM.getEventKey(event);
|
||||
key = key.toLowerCase();
|
||||
if (StringWrapper.equals(key, ' ')) {
|
||||
key = 'space'; // for readability
|
||||
} else if (StringWrapper.equals(key, '.')) {
|
||||
key = 'dot'; // because '.' is used as a separator in event names
|
||||
}
|
||||
modifierKeys.forEach(modifierName => {
|
||||
if (modifierName != key) {
|
||||
var modifierGetter = StringMapWrapper.get(modifierKeyGetters, modifierName);
|
||||
if (modifierGetter(event)) {
|
||||
fullKey += modifierName + '.';
|
||||
}
|
||||
}
|
||||
});
|
||||
fullKey += key;
|
||||
return fullKey;
|
||||
}
|
||||
|
||||
static eventCallback(element: HTMLElement, fullKey: any, handler: Function,
|
||||
zone: NgZone): Function {
|
||||
return (event) => {
|
||||
if (StringWrapper.equals(KeyEventsPlugin.getEventFullKey(event), fullKey)) {
|
||||
zone.runGuarded(() => handler(event));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
static _normalizeKey(keyName: string): string {
|
||||
// TODO: switch to a StringMap if the mapping grows too much
|
||||
switch (keyName) {
|
||||
case 'esc':
|
||||
return 'escape';
|
||||
default:
|
||||
return keyName;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
import {DOM} from 'angular2/src/platform/dom/dom_adapter';
|
||||
import {Inject, Injectable} from 'angular2/src/core/di';
|
||||
import {SetWrapper} from 'angular2/src/facade/collection';
|
||||
import {DOCUMENT} from './dom_tokens';
|
||||
|
||||
@Injectable()
|
||||
export class SharedStylesHost {
|
||||
/** @internal */
|
||||
_styles: string[] = [];
|
||||
/** @internal */
|
||||
_stylesSet = new Set<string>();
|
||||
|
||||
constructor() {}
|
||||
|
||||
addStyles(styles: string[]) {
|
||||
var additions = [];
|
||||
styles.forEach(style => {
|
||||
if (!SetWrapper.has(this._stylesSet, style)) {
|
||||
this._stylesSet.add(style);
|
||||
this._styles.push(style);
|
||||
additions.push(style);
|
||||
}
|
||||
});
|
||||
this.onStylesAdded(additions);
|
||||
}
|
||||
|
||||
onStylesAdded(additions: string[]) {}
|
||||
|
||||
getAllStyles(): string[] { return this._styles; }
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class DomSharedStylesHost extends SharedStylesHost {
|
||||
private _hostNodes = new Set<Node>();
|
||||
constructor(@Inject(DOCUMENT) doc: any) {
|
||||
super();
|
||||
this._hostNodes.add(doc.head);
|
||||
}
|
||||
/** @internal */
|
||||
_addStylesToHost(styles: string[], host: Node) {
|
||||
for (var i = 0; i < styles.length; i++) {
|
||||
var style = styles[i];
|
||||
DOM.appendChild(host, DOM.createStyleElement(style));
|
||||
}
|
||||
}
|
||||
addHost(hostNode: Node) {
|
||||
this._addStylesToHost(this._styles, hostNode);
|
||||
this._hostNodes.add(hostNode);
|
||||
}
|
||||
removeHost(hostNode: Node) { SetWrapper.delete(this._hostNodes, hostNode); }
|
||||
|
||||
onStylesAdded(additions: string[]) {
|
||||
this._hostNodes.forEach((hostNode) => { this._addStylesToHost(additions, hostNode); });
|
||||
}
|
||||
}
|
15
modules/@angular/platform-browser/src/dom/util.ts
Normal file
15
modules/@angular/platform-browser/src/dom/util.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import {StringWrapper} from 'angular2/src/facade/lang';
|
||||
|
||||
var CAMEL_CASE_REGEXP = /([A-Z])/g;
|
||||
var DASH_CASE_REGEXP = /-([a-z])/g;
|
||||
|
||||
|
||||
export function camelCaseToDashCase(input: string): string {
|
||||
return StringWrapper.replaceAllMapped(input, CAMEL_CASE_REGEXP,
|
||||
(m) => { return '-' + m[1].toLowerCase(); });
|
||||
}
|
||||
|
||||
export function dashCaseToCamelCase(input: string): string {
|
||||
return StringWrapper.replaceAllMapped(input, DASH_CASE_REGEXP,
|
||||
(m) => { return m[1].toUpperCase(); });
|
||||
}
|
Reference in New Issue
Block a user