123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517 |
- import { BaseView } from "./base-view";
- import { PouchService } from "../services/pouch-service";
- import { EventsManager } from "../base/events/event-manager";
- /**
- *
- * ██████╗ █████╗ ███████╗███████╗██╗ ██╗███████╗████████╗██╗ ██╗██╗███████╗██╗ ██╗
- * ██╔══██╗██╔══██╗██╔════╝██╔════╝██║ ██║██╔════╝╚══██╔══╝██║ ██║██║██╔════╝██║ ██║
- * ██████╔╝███████║███████╗█████╗ ██║ ██║███████╗ ██║ ██║ ██║██║█████╗ ██║ █╗ ██║
- * ██╔══██╗██╔══██║╚════██║██╔══╝ ██║ ██║╚════██║ ██║ ╚██╗ ██╔╝██║██╔══╝ ██║███╗██║
- * ██████╔╝██║ ██║███████║███████╗███████╗██║███████║ ██║ ╚████╔╝ ██║███████╗╚███╔███╔╝
- * ╚═════╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚══════╝╚═╝╚══════╝ ╚═╝ ╚═══╝ ╚═╝╚══════╝ ╚══╝╚══╝
- *
- * Clase que reúne todas las capacidades para mostrar e interactuar con una vista de lista.
- *
- */
- export abstract class BaseListView<T> extends BaseView<T>{
- items: T[];
- itemsShown: T[];
- itemsMatched: T[];
- selectedItem: T;
- filters: Array<[string, string, any]>;
- search: boolean;
- range: { start: number, end: number };
- constructor(c: { new (): T; }, ...filters: Array<[string, string, any]>) {
- super(c, PouchService);
- this.items = [];
- this.itemsShown = [];
- this.itemsMatched = [];
- this.selectedItem = null;
- this.filters = filters;
- this.search = false;
- this.range = { start: 0, end: 10 }
-
- this.initialize();
- }
- // ------------------------------------------------------------
- // ██████╗ ███████╗████████╗████████╗███████╗██████╗ ███████╗
- // ██╔════╝ ██╔════╝╚══██╔══╝╚══██╔══╝██╔════╝██╔══██╗██╔════╝
- // ██║ ███╗█████╗ ██║ ██║ █████╗ ██████╔╝███████╗
- // ██║ ██║██╔══╝ ██║ ██║ ██╔══╝ ██╔══██╗╚════██║
- // ╚██████╔╝███████╗ ██║ ██║ ███████╗██║ ██║███████║
- // ╚═════╝ ╚══════╝ ╚═╝ ╚═╝ ╚══════╝╚═╝ ╚═╝╚══════╝
- // ------------------------------------------------------------
- /**
- *
- */
- getItems(): T[] {
- return this.items;
- }
- /**
- *
- */
- getItemsShown(): T[] {
- return this.itemsShown;
- }
- /**
- *
- */
- getItemsMatched(): T[] {
- return this.itemsMatched;
- }
- /**
- *
- */
- getSelectedItem(): T {
- return this.selectedItem;
- }
- /**
- *
- */
- getFilters(): Array<[string, string, any]> {
- return this.filters;
- }
- /**
- *
- */
- getRange(): { start: number, end: number } {
- return this.range;
- }
-
- // -----------------------------------------------------------
- // ███████╗███████╗████████╗████████╗███████╗██████╗ ███████╗
- // ██╔════╝██╔════╝╚══██╔══╝╚══██╔══╝██╔════╝██╔══██╗██╔════╝
- // ███████╗█████╗ ██║ ██║ █████╗ ██████╔╝███████╗
- // ╚════██║██╔══╝ ██║ ██║ ██╔══╝ ██╔══██╗╚════██║
- // ███████║███████╗ ██║ ██║ ███████╗██║ ██║███████║
- // ╚══════╝╚══════╝ ╚═╝ ╚═╝ ╚══════╝╚═╝ ╚═╝╚══════╝
- // -----------------------------------------------------------
-
- /**
- *
- * @param items
- */
- setItems(items: T[]): void {
- this.items = items;
- this.setItemsShown(this.getItems().slice(this.getRange().start, this.getRange().end));
- }
-
- /**
- *
- * @param itemsShown
- */
- setItemsShown(itemsShown: T[]): void {
- this.itemsShown = itemsShown;
- }
-
- /**
- *
- * @param itemsMatched
- */
- setItemsMatched(itemsMatched: T[]): void {
- this.itemsMatched = itemsMatched;
- }
- /**
- *
- * @param item
- */
- setSelectedItem(item: T): void {
- this.selectedItem = item;
- }
- /**
- *
- * @param filters
- */
- setFilters(filters: Array<[string, string, any]>): void {
- this.filters = filters;
- this.applyFilter(this.getItems());
- }
- /**
- *
- */
- isSearch(): boolean {
- return this.search;
- }
-
- /**
- *
- * @param search
- */
- setSearch(search: boolean): void {
- this.search = search;
- }
- /**
- *
- * @param range
- */
- setRange(range: { start: number, end: number }): void {
- this.range = range;
- }
- // -------------------------------------------------------------------------------------------------------------------
- // ███████╗██████╗ ███████╗ ██████╗██╗ █████╗ ██╗ ██████╗ ███████╗████████╗████████╗███████╗██████╗ ███████╗
- // ██╔════╝██╔══██╗██╔════╝██╔════╝██║██╔══██╗██║ ██╔════╝ ██╔════╝╚══██╔══╝╚══██╔══╝██╔════╝██╔══██╗██╔════╝
- // ███████╗██████╔╝█████╗ ██║ ██║███████║██║ ██║ ███╗█████╗ ██║ ██║ █████╗ ██████╔╝███████╗
- // ╚════██║██╔═══╝ ██╔══╝ ██║ ██║██╔══██║██║ ██║ ██║██╔══╝ ██║ ██║ ██╔══╝ ██╔══██╗╚════██║
- // ███████║██║ ███████╗╚██████╗██║██║ ██║███████╗ ╚██████╔╝███████╗ ██║ ██║ ███████╗██║ ██║███████║
- // ╚══════╝╚═╝ ╚══════╝ ╚═════╝╚═╝╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚══════╝ ╚═╝ ╚═╝ ╚══════╝╚═╝ ╚═╝╚══════╝
- // -------------------------------------------------------------------------------------------------------------------
-
- /**
- *
- */
- getStartRange(): number {
- return this.getRange().start;
- }
- /**
- *
- */
- getEndRange(): number {
- return this.getRange().end;
- }
- /**
- *
- */
- hasItems(): boolean {
- return this.getItems().length > 0;
- }
- /**
- *
- */
- hasItemsShown(): boolean {
- return this.getItemsShown().length > 0;
- }
- /**
- *
- */
- isExpandableRange(): boolean {
- return this.getRange().end < this.getItemsShown().length;
- }
- /**
- *
- */
- getSelectedIndexInAll(): number {
- if (!this.getSelectedItem()) {
- return -1;
- }
- return this.getItems().indexOf(this.getSelectedItem());
- }
- /**
- *
- */
- getSelectedIndexInShown(): number {
- if (!this.getSelectedItem()) {
- return -1;
- }
- return this.getItemsShown().indexOf(this.getSelectedItem());
- }
- /**
- *
- */
- getSelectedIndexInMatched(): number {
- if (!this.getSelectedItem()) {
- return -1;
- }
- return this.getItemsMatched().indexOf(this.getSelectedItem());
- }
- // ------------------------------------------------------------------------------------------------------------------
- // ███████╗██████╗ ███████╗ ██████╗██╗ █████╗ ██╗ ███████╗███████╗████████╗████████╗███████╗██████╗ ███████╗
- // ██╔════╝██╔══██╗██╔════╝██╔════╝██║██╔══██╗██║ ██╔════╝██╔════╝╚══██╔══╝╚══██╔══╝██╔════╝██╔══██╗██╔════╝
- // ███████╗██████╔╝█████╗ ██║ ██║███████║██║ ███████╗█████╗ ██║ ██║ █████╗ ██████╔╝███████╗
- // ╚════██║██╔═══╝ ██╔══╝ ██║ ██║██╔══██║██║ ╚════██║██╔══╝ ██║ ██║ ██╔══╝ ██╔══██╗╚════██║
- // ███████║██║ ███████╗╚██████╗██║██║ ██║███████╗ ███████║███████╗ ██║ ██║ ███████╗██║ ██║███████║
- // ╚══════╝╚═╝ ╚══════╝ ╚═════╝╚═╝╚═╝ ╚═╝╚══════╝ ╚══════╝╚══════╝ ╚═╝ ╚═╝ ╚══════╝╚═╝ ╚═╝╚══════╝
- // ------------------------------------------------------------------------------------------------------------------
-
- /**
- *
- * @param start
- */
- setStartRange(start: number): void {
- this.setRange({ start: start, end: this.getRange().end });
- }
- /**
- *
- * @param end
- */
- setEndRange(end: number): void {
- this.setRange({ start: this.getRange().start, end: end });
- }
- //---------------------------------------------------------------
- // ███████╗███████╗██████╗ ██╗ ██╗██╗ ██████╗███████╗███████╗
- // ██╔════╝██╔════╝██╔══██╗██║ ██║██║██╔════╝██╔════╝██╔════╝
- // ███████╗█████╗ ██████╔╝██║ ██║██║██║ █████╗ ███████╗
- // ╚════██║██╔══╝ ██╔══██╗╚██╗ ██╔╝██║██║ ██╔══╝ ╚════██║
- // ███████║███████╗██║ ██║ ╚████╔╝ ██║╚██████╗███████╗███████║
- // ╚══════╝╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚═╝ ╚═════╝╚══════╝╚══════╝
- //---------------------------------------------------------------
- /**
- * Inicializa la lista.
- * Emite una evento al empezar y terminar el proceso.
- */
- initialize() {
- EventsManager.publish("app:loading", true);
- super.getInjectable(PouchService).getAll(this.getModelName()).subscribe(result => {
- this.applyFilter(result.docs);
- this.subcribeToEvents();
- EventsManager.publish("app:loading", false);
- }, error => {
- console.log(error);
- EventsManager.publish("app:loading", false);
- EventsManager.publish("app:error", error);
- });
- }
- /**
- * Aplica los filtros correspondientes a la lista
- */
- applyFilter(records: T[]): void {
- if (records.length == 0) {
- return;
- }
-
- if (this.getFilters().length == 0) {
- this.setItems(records);
- return;
- }
- this.setItems(records.filter(record => {
- let expressions = this.getFilters().map(filter => {
- let operator = "===";
- let leftOperand = "record." + filter[0];
- let rightOperand = typeof(filter[2]) === "string" ? "'" + filter[2] + "'" : filter[2];
- if (filter[1] === "!=") {
- operator = "!==";
- }
- if (filter[1] === ">") {
- operator = ">";
- }
- if (filter[1] === "<") {
- operator = "<";
- }
- if (filter[1] === ">=") {
- operator = "<=";
- }
- if (filter[1] === "<=") {
- operator = "<=";
- }
- return leftOperand + operator + rightOperand;
- });
- return eval(expressions.join("&&"));
- }));
- }
- /**
- * Suscribe a los eventos de la lista
- */
- private subcribeToEvents(): void {
- EventsManager.subscribe("app:changed", data => {
- if (data.action === "add") {
- this.add(data.item);
- }
- if (data.action === "update") {
- this.update(data.item);
- }
- if (data.action === "delete") {
- this.remove();
- }
- this.unselectItem();
- });
- }
- /**
- * Adicioana a la lista un nuevo objeto guardado
- * @param obj
- */
- add(item: T): void {
- this.items.unshift(item);
- this.itemsShown.unshift(item);
- }
- /**
- * Actualiza el objeto modificado
- * @param item
- */
- update(item: T): void {
- this.itemsShown[this.getSelectedIndexInShown()] = item;
- if (this.isSearch()) {
- this.itemsMatched[this.getSelectedIndexInShown()] = item;
- }
- this.items[this.getSelectedIndexInAll()] = item;
- }
- /**
- * Quita el objeto borrado de la lista
- */
- remove(): void {
- this.itemsShown.splice(this.getSelectedIndexInShown(), 1);
- if (this.isSearch()) {
- this.itemsMatched.splice(this.getSelectedIndexInShown(), 1);
- }
- this.items.splice(this.getSelectedIndexInAll(), 1);
- }
- /**
- * Deselecciona el elemento que haya sido previamente seleccionado.
- */
- unselectItem(): void {
- this.setSelectedItem(null);
- }
- /**
- * Limpia las coincidencias de búsqueda.
- */
- clearItemsMatched(): void {
- this.setItemsMatched([]);
- }
- /**
- * Alterna entre el modo de lista y el modo de búsqueda de la lista.
- */
- toggleSearch(): void {
- this.setSearch(!this.isSearch());
- this.setRange({ start: 0, end: 10 });
- if (!this.isSearch()) {
- this.setItemsMatched([]);
- this.setItemsShown(this.getItems().slice(this.getRange().start, this.getRange().end));
- }
- }
- /**
- * Realiza la expansión del rango para la vista.
- */
- expandRange(): void {
- this.setRange({ start: this.getRange().end, end: this.getRange().end + 10 });
- if (this.isSearch()) {
- this.setItemsShown(this.getItemsShown().concat(this.getItemsMatched().slice(this.getRange().start, this.getRange().end)));
- } else {
- this.setItemsShown(this.getItemsShown().concat(this.getItems().slice(this.getRange().start, this.getRange().end)));
- }
- }
-
- /**
- * Realiza la expasión de la vista de la lista.
- *
- * @param event
- */
- expand(event: any): void {
- this.expandRange();
- if (this.isExpandableRange()) {
- event.enable(false);
- }
- event.complete();
- }
- /**
- * Realiza la busqueda cada campo de los objetos en la lista de items mientras este campo sea de tipo string.
- * Emite un evento cuando comienza y termina el proceso.
- * @param text
- */
- performSearch(event: any): void {
- let value: string = event.target.value;
- if (!value || value.length < 3) {
- return;
- }
-
- EventsManager.publish("app:loading", true);
- this.clearItemsMatched();
-
- let regExp = new RegExp(value, "g");
- let item: T = null;
- let keys: Array<any> = null;
- for (let i = 0; i < this.getItems().length; i++) {
- item = this.getItems()[i];
- keys = Object.keys(item);
- for (let j = 0; j < keys.length; j++) {
- if (typeof item[keys[j]] !== "string") {
- continue;
- }
- if (!!item[keys[j]].toLowerCase().match(regExp)) {
- this.getItemsMatched().push(item);
- break;
- }
- }
- }
- this.setItemsShown(this.getItemsMatched().slice(this.getRange().start, this.getRange().end));
-
- EventsManager.publish("app:loading", false);
- }
- /**
- * Realiza el borrado del item seleccionado.
- * Emite un evento al terminar el proceso.
- */
- performDelete(): void {
- super.getInjectable(PouchService).remove(this.getSelectedItem()).subscribe(result => {
- EventsManager.publish("app:changed", {
- action: "delete",
- details: result
- });
- }, error => {
- EventsManager.publish("app:error", error);
- });
- }
- }
|