All files ux-optgroup.ts

27.78% Statements 15/54
0% Branches 0/10
6.67% Functions 1/15
25.49% Lines 13/51
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146                                                                  1x           1x                         1x           1x         1x               1x             1x                     1x         1x             1x       1x       1x                                         1x                              
import {
  customElement,
  bindable,
  ViewCompiler,
  ViewResources,
  processContent,
  DOM,
  inject,
  BindingEngine,
  Disposable,
} from 'aurelia-framework';
 
import { UxOptionElement } from './ux-option';
import { getAuViewModel } from './util';
 
declare module './ux-option' {
  interface UxOption {
    optGroup: UxOptGroup | null;
  }
}
 
export interface UxOptGroupElement extends HTMLElement {
  nodeName: 'UX-OPTGROUP';
  options: UxOptionElement[];
}
 
export interface OptGroupOptionsCt extends HTMLElement {
  children: HTMLCollectionOf<UxOptionElement>;
}
 
@inject(DOM.Element, BindingEngine)
@processContent(ensureOnlyUxOption)
@customElement('ux-optgroup')
export class UxOptGroup {
 
  private subscriptions: Disposable[];
  private parentDisabled: boolean;
 
  @bindable()
  public label: string;
 
  public disabled: boolean;
  public isDisabled: boolean;
  public readonly optionsCt: OptGroupOptionsCt;
 
  constructor(
    public readonly element: UxOptGroupElement,
    private bindingEngine: BindingEngine
  ) {
    Object.setPrototypeOf(element, UxOptGroupElementProto);
  }
 
  public created() {
    const element = this.element;
    this.setDisabled(element.hasAttribute('disabled'));
    element.removeAttribute('disabled');
  }
 
  public bind() {
    const uxSelect = this.uxSelect = this.getUxSelect();
    this.setParentDisabled(uxSelect.isDisabled);
  }
 
  public attached() {
    const be = this.bindingEngine;
    const uxSelect = this.uxSelect;
    this.subscriptions = [
      be.propertyObserver(uxSelect, 'isDisabled').subscribe(this.setParentDisabled.bind(this))
    ];
  }
 
  public detached() {
    for (const s of this.subscriptions) {
      s.dispose();
    }
    this.subscriptions.length = 0;
  }
 
  private getUxSelect() {
    let el: HTMLElement | null = this.element;
    while (el) {
      if (el.tagName === 'UX-SELECT') {
        return getAuViewModel<UxOptGroup['uxSelect']>(el);
      }
      el = el.parentElement;
    }
    throw new Error('Ux option group has no "ux-select" parent');
  }
 
  private setParentDisabled(disabled: boolean) {
    this.parentDisabled = !!disabled;
    this.isDisabled = this.disabled || this.parentDisabled;
  }
 
  public getOptions(): UxOptionElement[] {
    if (!this.optionsCt) {
      return [];
    }
    return Array.from(this.optionsCt.children);
  }
 
  public getDisabled() {
    return this.disabled;
  }
 
  public setDisabled(disabled: boolean) {
    this.disabled = disabled;
    this.isDisabled = disabled || this.parentDisabled;
  }
}
 
/**
 * A View-compiler hook that will remove any element that is not `<ux-option>` as child of `<ux-optgroup/>`
 */
function ensureOnlyUxOption(
  _: ViewCompiler,
  __: ViewResources,
  node: Element
) {
  let currentChild: any = node.firstChild;
  while (currentChild) {
    const nextSibling = currentChild.nextSibling;
    if (currentChild.nodeName !== 'UX-OPTION') {
      node.removeChild(currentChild);
    }
    currentChild = nextSibling;
  }
  return true;
}
 
const UxOptGroupElementProto = Object.create(HTMLElement.prototype, {
  options: {
    get() {
      return getAuViewModel<UxOptGroup>(this).getOptions();
    }
  },
  disabled: {
    get() {
      return getAuViewModel<UxOptGroup>(this).getDisabled();
    },
    set(disabled: boolean) {
      return getAuViewModel<UxOptGroup>(this).setDisabled(disabled);
    }
  }
});