Skip to content

Instantly share code, notes, and snippets.

@robgha01
Last active February 21, 2017 20:37
Show Gist options
  • Save robgha01/4227758b580083df482ca1dad9b04b11 to your computer and use it in GitHub Desktop.
Save robgha01/4227758b580083df482ca1dad9b04b11 to your computer and use it in GitHub Desktop.
@Component({
selector: "inline-editor-group",
template: require("./inline-editor-group.html"),
providers: [FocusService]
})
export class DaycareComponent implements OnInit, AfterContentInit {
@ContentChildren(SomeChildComponent, { descendants: true }) public childrenToWatch: QueryList<SomeChildComponent>;
constructor(protected element: ElementRef, protected renderer: Renderer, protected focusService: FocusService) {}
}
import { Directive, ElementRef, Inject, Input, OnChanges, SimpleChanges, AfterContentInit, AfterContentChecked } from "@angular/core";
import { FocusService } from "./focus.service";
@Directive({ selector: "[focus]" })
export class FocusDirective implements OnChanges, AfterContentInit, AfterContentChecked {
@Input() focus: boolean = false; // focus this element when "OnChange" or "AfterContentChecked" is triggered if this is set to true.
hasFocus: boolean;
private contentChecked: boolean = null;
constructor( @Inject(ElementRef) private element: ElementRef, @Inject(FocusService) private focusService: FocusService ) { }
ngOnChanges(changes: SimpleChanges): void {
let focus = changes["focus"];
// We only wants to focus if the previus value was false.
if (focus.currentValue && focus.previousValue === false) {
this.focusService.focus(this.element);
}
}
ngAfterContentInit(): void {
this.focusService.register(this, this.element);
}
ngAfterContentChecked(): void {
if (this.focus) {
// We need to track if this is the first call to content checked.
if (this.contentChecked === null) {
this.contentChecked = false;
return;
}
// If content checked is set to false we run the focus else do nothing.
if (this.contentChecked === false) {
this.contentChecked = true;
this.focusService.focus(this.element);
}
}
}
}
import { Injectable, ElementRef } from "@angular/core";
import * as Rx from "rxjs/Rx";
import { FocusDirective } from "./focus.directive";
@Injectable()
export class FocusService {
focusDirectives: { focusDir: FocusDirective, element: ElementRef }[] = [];
public register(focusDir: FocusDirective, element: ElementRef) {
this.focusDirectives.push({ focusDir, element });
}
public focus(element: ElementRef) {
this.focusDirectives.forEach((value) => {
if (element === value.element) {
this.doFocus(value);
}
});
}
public reCheckAll() {
this.focusDirectives.forEach((value) => {
if (value.focusDir.hasFocus) {
value.element.nativeElement.focus(); // Trigger a focus.
}
});
}
private doFocus(item: { focusDir: FocusDirective, element: ElementRef }) {
// Reset all hasFocus to false exept item
this.focusDirectives.forEach((value) => {
if (item !== value) {
value.focusDir.hasFocus = false;
value.focusDir.focus = false;
}
});
item.element.nativeElement.focus(); // Trigger the focus.
item.focusDir.focus = true; // Ensure item focus is true.
item.focusDir.hasFocus = true; // Ensure item hasFocus is true.
}
}
<template #DefaultTemplate>
<inline-editor-group [openInModal]="true" (onSave)="this.doSave()" (onCancel)="this.doCancel()" [(disableSave)]="this?.profileForm.invalid || !this?.profileForm.dirty">
<form class="form-horizontal" [formGroup]="profileForm">
<inline-text-editor formControlName="name" [focusThis]="true" type="text" name="Namn">
<presentation-state>
<template let-editor>
<div>
<i class="fa fa-user" aria-hidden="true"></i> namn
</div>
<p>{{ editor?.value }}</p>
</template>
</presentation-state>
<edit-state>
<template let-editor>
<div class="row">
<div class="col-xs-12">
<label for="inline-editor-{{ editor.name }}" class="control-label">{{ editor.name }}</label>
<render-editor></render-editor>
</div>
</div>
</template>
</edit-state>
</inline-text-editor>
</form>
</inline-editor-group>
<inline-editor-group class="row modal-row" [openInModal]="false" (onSave)="this.doSave()" (onCancel)="this.doCancel()" [(disableSave)]="this?.photosForm.invalid || !this?.photosForm.dirty">
<form class="form-horizontal" [formGroup]="photosForm">
<div formArrayName="photoChanges">
<div *ngFor="let change of photosForm?.controls?.photoChanges?.controls; let i=index">
<div [formGroupName]="i">
<inline-text-editor style="display: inline-block;" formControlName="displayName" [focusThis]="true" type="text" name="Namn">
<presentation-state>
<template let-editor>
<div class="form-group">
<label>Name</label>
<span>{{ editor?.value }}</span>
</div>
</template>
</presentation-state>
<edit-state>
<template let-editor>
<div class="row">
<div class="col-xs-12">
<label for="inline-editor-{{ editor.name }}" class="control-label">{{ editor.name }}</label>
<template #DefaultPresentation>
<div *ngIf="!editing">
<a [ngClass]="{'editable-empty': isEmpty }" (click)="edit(value)">{{ presentControl() }}</a>
</div>
</template>
<template #DefaultEdit>
<input #inlineEditControl class="form-control" id="inline-editor-{{ this.name }}" [value]="value" (input)="value = $event.target.value"
(blur)="onTouched()" (focusout)="onTouched()"
[required]="required" [disabled]="disabled" [name]="name" [placeholder]="placeholder" [(focus)]="focusThis" />
</template>
</div>
</div>
</template>
</edit-state>
</inline-text-editor>
</div>
</div>
</div>
</form>
</inline-editor-group>
</template>
<template [ngTemplateOutlet]="this.currentTemplate" [ngOutletContext]="{ $implicit: this }">
</template>
<template #DefaultTemplate>
<div class="col-lg-10 col-sm-11">
<div *ngIf="alerts?.length > 0" class="row">
<div class="col-xs-12" *ngFor="let alert of this?.alerts">
<alert [type]="alert.type" dismissOnTimeout="5000"><span [innerHtml]="alert.msg"></span></alert>
</div>
</div>
<div class="row profile">
<div class="col-sm-3">
<div class="row">
<div class="col-xs-7 col-sm-12">
<img class="profile-image" src="{{ this?.profile.user.avatar }}">
</div>
<div class="col-xs-5 col-sm-12">
<inline-editor-group [openInModal]="true" (onSave)="this.doSave()" (onCancel)="this.doCancel()" [(disableSave)]="this?.profileForm.invalid || !this?.profileForm.dirty">
<form class="form-horizontal" [formGroup]="profileForm">
<h3>Allmän information</h3>
<ul class="profile-details">
<li>
<inline-text-editor formControlName="name" [focusThis]="true" type="text" name="Namn">
<presentation-state>
<template let-editor>
<div>
<i class="fa fa-user" aria-hidden="true"></i> namn
</div>
<p>{{ editor?.value }}</p>
</template>
</presentation-state>
<edit-state>
<template let-editor>
<div class="row">
<div class="col-xs-12">
<label for="inline-editor-{{ editor.name }}" class="control-label">{{ editor.name }}</label>
<render-editor></render-editor>
</div>
</div>
</template>
</edit-state>
</inline-text-editor>
</li>
</ul>
<h3>Kontakt information</h3>
<ul class="profile-details">
<li>
<div>
<i class="fa fa-envelope"></i> e-post
</div>
<p>{{ this?.profile.user.email }}</p>
</li>
</ul>
</form>
</inline-editor-group>
</div>
</div>
</div>
<div class="col-sm-9">
<ul class="nav nav-tabs nav-tabs-default" role="tablist">
<li role="presentation" class="active"><a href="#info" aria-controls="skills" role="tab" data-toggle="tab">Info</a></li>
<li role="presentation"><a href="#photos" aria-controls="photos" role="tab" data-toggle="tab">Bilder</a></li>
</ul>
<div class="tab-content">
<div class="tab-pane active" id="info">
<div class="row">
<div class="col-sm-12">
<h2>Om mig</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</p>
<h2>Bio</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</p>
</div>
<div class="col-sm-7"></div>
</div>
</div>
<div class="tab-pane pane-photos" id="photos">
<div class="row">
<div [ngBusy]="{busy: this?.busy, message: 'Var god vänta...', backdrop: true, minDuration: 600, delay: 1000}"></div>
</div>
<div class="row">
<div class="col-xs-12">
<input type="file" ng2FileSelect [uploader]="uploader" multiple />
<div class="table-responsive">
<table *ngIf="this?.uploader.queue.length > 1" class="table">
<thead>
<tr>
<th width="50%">Namn</th>
<th>Förlopp</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let item of uploader.queue">
<td><strong>{{ item?.file?.name | truncate : 10 }}</strong></td>
<td *ngIf="uploader.isHTML5" nowrap>{{ item?.file?.size/1024/1024 | number:'.2' }} MB</td>
<td *ngIf="uploader.isHTML5">
<div class="progress" style="margin-bottom: 0;">
<div class="progress-bar" role="progressbar" [ngStyle]="{ 'width': item.progress + '%' }"></div>
</div>
</td>
<td class="text-center">
<span *ngIf="item.isSuccess"><i class="glyphicon glyphicon-ok"></i></span>
<span *ngIf="item.isCancel"><i class="glyphicon glyphicon-ban-circle"></i></span>
<span *ngIf="item.isError"><i class="glyphicon glyphicon-remove"></i></span>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="row widget widget-flat widget-card-list">
<div class="widget-card" *ngFor="let item of this?.photos; let i = index" hoverable-group="widget-card-{{i}}">
<div class="card">
<a class="card-link" [href]="item.url" (click)="openModalPhoto(item, $event)">
<picture>
<source media="(min-width: 960px)" [srcset]="getSizedUrl(item, 960)">
<source media="(min-width: 575px)" [srcset]="getSizedUrl(item, 575)">
<img class="card-image img-thumbnail" [src]="getSizedUrl(item, 300)" [alt]="item.name">
</picture>
</a>
<div hoverable="widget-card-{{i}}" class="card-content">
<div class="btn-group" role="group" aria-label="image controls">
<button type="button" class="btn btn-default">
<i class="fa fa-thumbs-o-up" aria-hidden="true"></i>
<span class="sr-only">Godkänn</span>
</button>
<button type="button" class="btn btn-default">
<i class="fa fa-ban" aria-hidden="true"></i>
<span class="sr-only">Underkänn</span>
</button>
<button type="button" class="btn btn-default">
<i class="fa fa-trash" aria-hidden="true"></i>
<span class="sr-only">Radera</span>
</button>
</div>
</div>
</div>
</div>
<div bsModal #photoModal="bs-modal" class="modal fade modal-photo" tabindex="-1" role="dialog" aria-labelledby="photo modal" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close pull-right" aria-label="Close" (click)="closeModalPhoto()">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body" *ngIf="currentEditingPhoto != null">
<div [ngBusy]="{busy: this?.busy, message: 'Var god vänta...', backdrop: true, minDuration: 600, delay: 1000}"></div>
<fader class="modal-row" [(isVisible)]="currentPhotoIsVisible">
<picture>
<source media="(min-width: 960px)" [srcset]="getSizedUrl(currentEditingPhoto, 960)">
<source media="(min-width: 575px)" [srcset]="getSizedUrl(currentEditingPhoto, 575)">
<img class="img-responsive" [src]="getSizedUrl(currentEditingPhoto, 300)" [alt]="currentEditingPhoto.name">
</picture>
<div class="modal-nav">
<a class="nav-prev" (click)="prevPhoto()"></a>
<a class="nav-next" (click)="nextPhoto()"></a>
</div>
</fader>
<inline-editor-group class="row modal-row" [openInModal]="false" (onSave)="this.doSave()" (onCancel)="this.doCancel()" [(disableSave)]="this?.photosForm.invalid || !this?.photosForm.dirty">
<div class="col-xs-12">
<form class="form-horizontal" [formGroup]="photosForm">
<h3>{{ currentEditingPhoto.displayName }}</h3>
<div formArrayName="photoChanges">
<div *ngFor="let change of photosForm?.controls?.photoChanges?.controls; let i=index">
<!--<div>
<span>Bild {{i + 1}} av </span>
<span *ngIf="photosForm.controls.photoChanges.controls.length > 0"
(click)="removePhotoChange(change.photo)">
</span>
</div>-->
<div [formGroupName]="i">
<inline-text-editor style="display: inline-block;" formControlName="displayName" [focusThis]="true" type="text" name="Namn">
<presentation-state>
<template let-editor>
<div class="form-group">
<label>Namn</label>
<span>{{ editor?.value }}</span>
</div>
</template>
</presentation-state>
<edit-state>
<template let-editor>
<div class="row">
<div class="col-xs-12">
<label for="inline-editor-{{ editor.name }}" class="control-label">{{ editor.name }}</label>
<render-editor></render-editor>
</div>
</div>
</template>
</edit-state>
</inline-text-editor>
</div>
</div>
</div>
</form>
</div>
</inline-editor-group>
<div *ngIf="modalAlerts?.length > 0" class="row modal-row" style="padding-top: 1em;">
<div class="col-xs-12" *ngFor="let alert of this?.modalAlerts">
<alert [type]="alert.type"><span [innerHtml]="alert.msg"></span></alert>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<button type="button" [disabled]="this?.isLoading" (click)="doLoadMorePhotos()" class="btn btn-default btn-block">
Visa fler resultat
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment