Merge pull request #4472 from romanroe/performance_improvements

Reduced Watcher Count
pull/4491/head
Roman Roelofsen 9 years ago
commit f901cb88a8
  1. 21
      frontend/app/components/work-packages/wp-display-attr/wp-display-attr.directive.html
  2. 50
      frontend/app/components/work-packages/wp-display-attr/wp-display-attr.directive.ts
  3. 32
      frontend/app/components/work-packages/wp-single-view/wp-single-view.directive.html
  4. 4
      frontend/app/components/work-packages/wp-subject/wp-subject.directive.html
  5. 0
      frontend/app/components/wp-display/field-types/____RR____delete____wp-display-default-field.directive.html
  6. 3
      frontend/app/components/wp-display/field-types/wp-display-boolean-field.module.ts
  7. 3
      frontend/app/components/wp-display/field-types/wp-display-date-field.module.ts
  8. 3
      frontend/app/components/wp-display/field-types/wp-display-datetime-field.module.ts
  9. 3
      frontend/app/components/wp-display/field-types/wp-display-duration-field.module.ts
  10. 3
      frontend/app/components/wp-display/field-types/wp-display-resource-field.module.ts
  11. 3
      frontend/app/components/wp-display/field-types/wp-display-string-object-field.module.ts
  12. 3
      frontend/app/components/wp-display/field-types/wp-display-text-field.module.ts
  13. 49
      frontend/app/components/wp-display/wp-display-field/wp-display-field.module.ts
  14. 18
      frontend/app/components/wp-edit/wp-edit-field/wp-edit-field.directive.html
  15. 4
      frontend/app/components/wp-edit/wp-edit-field/wp-edit-field.directive.ts
  16. 21
      frontend/app/components/wp-table/wp-table.directive.html
  17. 107
      frontend/app/components/wp-table/wp-virtual-scroll.directive.ts
  18. 1
      frontend/app/typings/open-project.typings.js
  19. 1
      frontend/app/typings/open-project.typings.js.map

@ -1,17 +1,16 @@
<span class="inplace-edit--read-value--container"> <span class="inplace-edit--read-value--container">
<span class="hidden-for-sighted"
ng-attr-id="{{$ctrl.labelId}}"> <span class="hidden-for-sighted __d__hidden-for-sighted"></span>
{{ ::$ctrl.label }} {{ $ctrl.displayText }}
</span> <span class="wp-table--cell-span inplace-edit--read-value--value __d__cell"
<span class="wp-table--cell-span inplace-edit--read-value--value"
ng-switch="$ctrl.displayType"
ng-click="$ctrl.activateIfEditable($event)" ng-click="$ctrl.activateIfEditable($event)"
data-click-on-keypress="[13, 32]" data-click-on-keypress="[13, 32]"
focus="$ctrl.shouldFocus()" focus="$ctrl.shouldFocus()">
ng-attr-tabindex="{{$ctrl.isEditable() ? '0' : '-1'}}"
ng-class="{ '-placeholder' : $ctrl.isEmpty }" <span class="__d__renderer">
aria-labelledby="{{$ctrl.labelId}}"> <ng-include ng-if="::!$ctrl.field.isManualRenderer"
src="::$ctrl.field.template"></ng-include>
</span>
<ng-include src="$ctrl.field.template"></ng-include>
</span> </span>
</span> </span>

@ -30,22 +30,27 @@ import {HalResource} from "../../api/api-v3/hal-resources/hal-resource.service";
import {wpDirectivesModule} from "../../../angular-modules"; import {wpDirectivesModule} from "../../../angular-modules";
import {WorkPackageEditFieldController} from "../../wp-edit/wp-edit-field/wp-edit-field.directive"; import {WorkPackageEditFieldController} from "../../wp-edit/wp-edit-field/wp-edit-field.directive";
import {WorkPackageCacheService} from "../work-package-cache.service"; import {WorkPackageCacheService} from "../work-package-cache.service";
import {scopedObservable} from "../../../helpers/angular-rx-utils";
import {WorkPackageResource} from "../../api/api-v3/hal-resources/work-package-resource.service";
import {DisplayField} from "../../wp-display/wp-display-field/wp-display-field.module"; import {DisplayField} from "../../wp-display/wp-display-field/wp-display-field.module";
import {WorkPackageDisplayFieldService} from "../../wp-display/wp-display-field/wp-display-field.service"; import {WorkPackageDisplayFieldService} from "../../wp-display/wp-display-field/wp-display-field.service";
export class WorkPackageDisplayAttributeController { export class WorkPackageDisplayAttributeController {
public wpEditField:WorkPackageEditFieldController;
public attribute:string; public wpEditField: WorkPackageEditFieldController;
public placeholderOptional:string; public attribute: string;
public workPackage:any; public placeholderOptional: string;
public customSchema:HalResource; public workPackage: any;
public customSchema: HalResource;
public field: DisplayField; public field: DisplayField;
public label: string;
private __d__hiddenForSighted: JQuery;
private __d__cell: JQuery;
private __d__renderer: JQuery;
constructor(protected wpDisplayField: WorkPackageDisplayFieldService, constructor(protected $element: JQuery,
protected wpCacheService:WorkPackageCacheService, protected wpDisplayField: WorkPackageDisplayFieldService,
protected $scope:ng.IScope) { protected wpCacheService: WorkPackageCacheService,
protected $scope: ng.IScope) {
// Update the attribute initially // Update the attribute initially
if (this.workPackage) { if (this.workPackage) {
@ -72,7 +77,7 @@ export class WorkPackageDisplayAttributeController {
return this.wpEditField && this.wpEditField.shouldFocus(); return this.wpEditField && this.wpEditField.shouldFocus();
} }
public get labelId():string { public get labelId(): string {
return 'wp-' + this.workPackage.id + '-display-attr-' + this.attribute + '-aria-label'; return 'wp-' + this.workPackage.id + '-display-attr-' + this.attribute + '-aria-label';
} }
@ -101,17 +106,30 @@ export class WorkPackageDisplayAttributeController {
this.workPackage = wp; this.workPackage = wp;
this.schema.$load().then(() => { this.schema.$load().then(() => {
this.field = <DisplayField>this.wpDisplayField.getField(this.workPackage, this.attribute, this.schema[this.attribute]); this.field = <DisplayField>this.wpDisplayField.getField(this.workPackage, this.attribute, this.schema[this.attribute]);
if (this.field.isManualRenderer) {
this.__d__renderer = this.__d__renderer || this.$element.find(".__d__renderer");
this.field.render(this.__d__renderer, this);
}
this.__d__hiddenForSighted = this.__d__hiddenForSighted || this.$element.find(".__d__hidden-for-sighted");
this.__d__hiddenForSighted.attr("id", this.labelId);
this.__d__hiddenForSighted.text(this.label + " " + this.displayText);
this.__d__cell = this.__d__cell || this.$element.find(".__d__cell");
this.__d__cell.attr("tabindex", this.isEditable() ? "0" : "-1");
this.__d__cell.attr("aria-labelledby", this.labelId);
this.__d__cell.toggleClass("-placeholder", this.isEmpty);
}); });
} }
} }
function wpDisplayAttrDirective() { function wpDisplayAttrDirective() {
function wpTdLink( function wpTdLink(scope,
scope, element,
element, attr,
attr, controllers) {
controllers) {
scope.$ctrl.wpEditField = controllers[0]; scope.$ctrl.wpEditField = controllers[0];

@ -16,12 +16,8 @@
<div <div
wp-edit-field="'description'" wp-edit-field="'description'"
wp-edit-field-wrapper-classes="'-no-label'" wp-edit-field-wrapper-classes="'-no-label'"
display-placeholder="$ctrl.I18n.t('js.work_packages.placeholders.description')"
class="single-attribute wiki"> class="single-attribute wiki">
<wp-display-attr
work-package="$ctrl.workPackage"
attribute="'description'"
placeholder="$ctrl.I18n.t('js.work_packages.placeholders.description')">
</wp-display-attr>
</div> </div>
</div> </div>
@ -62,11 +58,6 @@
wp-edit-field-label="$ctrl.singleViewWp.getLabel(field)" wp-edit-field-label="$ctrl.singleViewWp.getLabel(field)"
wp-edit-field-wrapper-classes="'-small'" wp-edit-field-wrapper-classes="'-small'"
class="attributes-key-value--value-container"> class="attributes-key-value--value-container">
<wp-display-attr
work-package="$ctrl.workPackage"
attribute="field"
label="$ctrl.singleViewWp.getLabel(field)">
</wp-display-attr>
</div> </div>
<div <div
@ -95,29 +86,16 @@
<div <div
wp-edit-field="field.fields[0]" wp-edit-field="field.fields[0]"
wp-edit-field-label="$ctrl.singleViewWp.getLabel(field.fields[0])" wp-edit-field-label="$ctrl.singleViewWp.getLabel(field.fields[0])"
wp-edit-field-wrapper-classes="'-small -shrink'"> wp-edit-field-wrapper-classes="'-small -shrink'"
display-placeholder="::$ctrl.text.fields[field.label][field.fields[0]]">
<wp-display-attr
work-package="$ctrl.workPackage"
attribute="field.fields[0]"
placeholder="::$ctrl.text.fields[field.label][field.fields[0]]"
label="$ctrl.singleViewWp.getLabel(field.fields[0])">
</wp-display-attr>
</div>
<span class="attributes-key-value--value-separator"></span> <span class="attributes-key-value--value-separator"></span>
<div <div
wp-edit-field="field.fields[1]" wp-edit-field="field.fields[1]"
wp-edit-field-label="$ctrl.singleViewWp.getLabel(field.fields[1])" wp-edit-field-label="$ctrl.singleViewWp.getLabel(field.fields[1])"
wp-edit-field-wrapper-classes="'-small -shrink'"> wp-edit-field-wrapper-classes="'-small -shrink'"
display-placeholder="::$ctrl.text.fields[field.label][field.fields[1]]">
<wp-display-attr
work-package="$ctrl.workPackage"
attribute="field.fields[1]"
placeholder="::$ctrl.text.fields[field.label][field.fields[1]]"
label="$ctrl.singleViewWp.getLabel(field.fields[1])">
</wp-display-attr>
</div> </div>
</div> </div>
</div> </div>

@ -4,10 +4,6 @@
wp-edit-field="'subject'" wp-edit-field="'subject'"
wp-edit-field-wrapper-classes="'-no-label'" wp-edit-field-wrapper-classes="'-no-label'"
class="work-packages--details--subject"> class="work-packages--details--subject">
<wp-display-attr
work-package="$ctrl.workPackage"
attribute="'subject'">
</wp-display-attr>
</div> </div>
</div> </div>

@ -30,6 +30,9 @@ import {DisplayField} from "../wp-display-field/wp-display-field.module";
import {HalResource} from "../../api/api-v3/hal-resources/hal-resource.service" import {HalResource} from "../../api/api-v3/hal-resources/hal-resource.service"
export class BooleanDisplayField extends DisplayField { export class BooleanDisplayField extends DisplayField {
isManualRenderer = true;
public WorkPackagesHelper:op.WorkPackagesHelper; public WorkPackagesHelper:op.WorkPackagesHelper;
constructor(public resource:HalResource, constructor(public resource:HalResource,

@ -29,7 +29,8 @@
import {DisplayField} from "../wp-display-field/wp-display-field.module"; import {DisplayField} from "../wp-display-field/wp-display-field.module";
export class DateDisplayField extends DisplayField { export class DateDisplayField extends DisplayField {
public template:string = '/components/wp-display/field-types/wp-display-default-field.directive.html';
isManualRenderer = true;
public get valueString() { public get valueString() {
const WorkPackagesHelper:any = this.$injector.get('WorkPackagesHelper'); const WorkPackagesHelper:any = this.$injector.get('WorkPackagesHelper');

@ -29,7 +29,8 @@
import {DisplayField} from "../wp-display-field/wp-display-field.module"; import {DisplayField} from "../wp-display-field/wp-display-field.module";
export class DateTimeDisplayField extends DisplayField { export class DateTimeDisplayField extends DisplayField {
public template:string = '/components/wp-display/field-types/wp-display-default-field.directive.html';
isManualRenderer = true;
public get valueString() { public get valueString() {
const WorkPackagesHelper:any = this.$injector.get('WorkPackagesHelper'); const WorkPackagesHelper:any = this.$injector.get('WorkPackagesHelper');

@ -29,6 +29,9 @@
import {DisplayField} from "../wp-display-field/wp-display-field.module"; import {DisplayField} from "../wp-display-field/wp-display-field.module";
export class DurationDisplayField extends DisplayField { export class DurationDisplayField extends DisplayField {
isManualRenderer = true;
public get valueString() { public get valueString() {
const WorkPackagesHelper:any = this.$injector.get('WorkPackagesHelper'); const WorkPackagesHelper:any = this.$injector.get('WorkPackagesHelper');

@ -29,6 +29,9 @@
import {DisplayField} from "../wp-display-field/wp-display-field.module"; import {DisplayField} from "../wp-display-field/wp-display-field.module";
export class ResourceDisplayField extends DisplayField { export class ResourceDisplayField extends DisplayField {
isManualRenderer = true;
public get value() { public get value() {
if(this.schema) { if(this.schema) {
return this.resource[this.name] && this.resource[this.name].name; return this.resource[this.name] && this.resource[this.name].name;

@ -29,6 +29,9 @@
import {DisplayField} from "../wp-display-field/wp-display-field.module"; import {DisplayField} from "../wp-display-field/wp-display-field.module";
export class StringObjectDisplayField extends DisplayField { export class StringObjectDisplayField extends DisplayField {
isManualRenderer = true;
public get value() { public get value() {
if(this.schema) { if(this.schema) {
return this.resource[this.name] && this.resource[this.name].value; return this.resource[this.name] && this.resource[this.name].value;

@ -29,6 +29,9 @@
import {DisplayField} from "../wp-display-field/wp-display-field.module"; import {DisplayField} from "../wp-display-field/wp-display-field.module";
export class TextDisplayField extends DisplayField { export class TextDisplayField extends DisplayField {
isManualRenderer = true;
public get valueString() { public get valueString() {
return this.value; return this.value;
} }

@ -26,18 +26,20 @@
// See doc/COPYRIGHT.rdoc for more details. // See doc/COPYRIGHT.rdoc for more details.
// ++ // ++
import {HalResource} from '../../api/api-v3/hal-resources/hal-resource.service'; import {HalResource} from "../../api/api-v3/hal-resources/hal-resource.service";
import {Field} from '../../wp-field/wp-field.module' import {Field, FieldFactory} from "../../wp-field/wp-field.module";
import {FieldFactory} from '../../wp-field/wp-field.module' import {WorkPackageDisplayAttributeController} from "../../work-packages/wp-display-attr/wp-display-attr.directive";
export class DisplayField extends Field{ export class DisplayField extends Field {
public static type:string;
public static $injector:ng.auto.IInjectorService; public isManualRenderer: boolean = false;
public template:string = '/components/wp-display/field-types/wp-display-default-field.directive.html' public static type: string;
public I18n:op.I18n; public static $injector: ng.auto.IInjectorService;
public template: string = null;
public I18n: op.I18n;
public get value() { public get value() {
if(this.schema) { if (this.schema) {
return this.resource[this.name]; return this.resource[this.name];
} }
else { else {
@ -45,32 +47,37 @@ export class DisplayField extends Field{
} }
} }
public get type():string { public get type(): string {
return (this.constructor as typeof DisplayField).type; return (this.constructor as typeof DisplayField).type;
} }
public get required():boolean { public get required(): boolean {
return this.schema.required; return this.schema.required;
} }
public isEmpty():boolean { public isEmpty(): boolean {
return !this.value; return !this.value;
} }
public get placeholder():string { public get placeholder(): string {
return this.I18n.t('js.work_packages.placeholders.default'); return this.I18n.t('js.work_packages.placeholders.default');
} }
public get valueString():string { public get valueString(): string {
return this.value; return this.value;
} }
protected get $injector():ng.auto.IInjectorService { protected get $injector(): ng.auto.IInjectorService {
return (this.constructor as typeof DisplayField).$injector; return (this.constructor as typeof DisplayField).$injector;
} }
constructor(public resource:HalResource, public render(element: JQuery, fieldDisplay: WorkPackageDisplayAttributeController): void {
public name:string, element.attr("title", fieldDisplay.displayText);
element.text(fieldDisplay.displayText);
}
constructor(public resource: HalResource,
public name: string,
public schema) { public schema) {
super(resource, name, schema); super(resource, name, schema);
@ -83,9 +90,9 @@ export class DisplayFieldFactory extends FieldFactory {
protected static fields = {}; protected static fields = {};
protected static classes = {}; protected static classes = {};
public static create(workPackage:HalResource, public static create(workPackage: HalResource,
fieldName:string, fieldName: string,
schema:op.FieldSchema):DisplayField { schema: op.FieldSchema): DisplayField {
let type = DisplayFieldFactory.getSpecificType(fieldName) || let type = DisplayFieldFactory.getSpecificType(fieldName) ||
schema && DisplayFieldFactory.getType(schema.type) || schema && DisplayFieldFactory.getType(schema.type) ||
DisplayFieldFactory.defaultType; DisplayFieldFactory.defaultType;
@ -94,7 +101,7 @@ export class DisplayFieldFactory extends FieldFactory {
return <DisplayField>(new fieldClass(workPackage, fieldName, schema)); return <DisplayField>(new fieldClass(workPackage, fieldName, schema));
} }
protected static getSpecificType(type:string):string { protected static getSpecificType(type: string): string {
let fields = DisplayFieldFactory.fields; let fields = DisplayFieldFactory.fields;
return fields[type]; return fields[type];

@ -1,4 +1,6 @@
<div class="wp-edit-field inplace-edit" <div class="wp-edit-field inplace-edit"
ng-if="::vm.workPackage"
ng-switch="vm.active"
ng-class="[ ng-class="[
vm.errorenous && '-error' || '', vm.errorenous && '-error' || '',
vm.isEditable && '-editable' || '', vm.isEditable && '-editable' || '',
@ -7,13 +9,13 @@
vm.wrapperClasses === undefined ? '-small' : vm.wrapperClasses vm.wrapperClasses === undefined ? '-small' : vm.wrapperClasses
]"> ]">
<form ng-if="vm.workPackage && vm.active" <form ng-switch-when="true"
ng-click="vm.haltUserFormClick($event)" ng-click="vm.haltUserFormClick($event)"
ng-dblclick="vm.haltUserFormClick($event)" ng-dblclick="vm.haltUserFormClick($event)"
name="vm.fieldForm" name="vm.fieldForm"
ng-submit="vm.submit()"> ng-submit="vm.submit()">
<label for="{{vm.htmlId}}" <label for="{{::vm.htmlId}}"
class="hidden-for-sighted"> class="hidden-for-sighted">
{{::vm.fieldLabel}} {{::vm.fieldLabel}}
</label> </label>
@ -22,7 +24,13 @@
</form> </form>
<ng-transclude class="-hidden-overflow inplace-edit--read-value" <wp-display-attr ng-switch-when="false"
ng-hide="vm.active"> attribute="::vm.fieldName"
</ng-transclude> schema="vm.workPackage.schema"
work-package="::vm.workPackage"
placeholder="::vm.displayPlaceholder"
label="vm.fieldLabel"
class="-hidden-overflow inplace-edit--read-value"
ng-class="vm.displayClasses">
</wp-display-attr>
</div> </div>

@ -257,7 +257,9 @@ function wpEditField() {
fieldLabel: '=?wpEditFieldLabel', fieldLabel: '=?wpEditFieldLabel',
fieldIndex: '=', fieldIndex: '=',
columns: '=', columns: '=',
wrapperClasses: '=wpEditFieldWrapperClasses' wrapperClasses: '=wpEditFieldWrapperClasses',
displayPlaceholder: '=?',
displayClasses: '=?',
}, },
require: ['^wpEditForm', 'wpEditField'], require: ['^wpEditForm', 'wpEditField'],

@ -94,7 +94,7 @@
<!-- Work package rows --> <!-- Work package rows -->
<tr wp-row <tr wp-row
id="work-package-{{ row.object.id }}" id="work-package-{{ ::row.object.id }}"
class="wp--row" class="wp--row"
has-dropdown-menu has-dropdown-menu
trigger-on-event="contextmenu" trigger-on-event="contextmenu"
@ -123,14 +123,14 @@
<accessible-checkbox name="ids[]" <accessible-checkbox name="ids[]"
checkbox-id="work_package{{row.object.id}}" checkbox-id="work_package{{row.object.id}}"
checkbox-value="row.object.id" checkbox-value="row.object.id"
checkbox-title="{{checkboxTitle}}" checkbox-title="{{::checkboxTitle}}"
model="row.checked"> model="row.checked">
</accessible-checkbox> </accessible-checkbox>
<span> <span>
<a class="wp-table--details-link" <a class="wp-table--details-link"
ui-sref="work-packages.list.details.overview({workPackageId: row.object.id})"> ui-sref="work-packages.list.details.overview({workPackageId: row.object.id})">
<i class="icon icon-view-split"></i> <i class="icon icon-view-split"></i>
<span ng-bind="I18n.t('js.button_open_details')"/> <span ng-bind="::I18n.t('js.button_open_details')"/>
</a> </a>
</span> </span>
</td> </td>
@ -146,17 +146,14 @@
</td> </td>
<td ng-repeat="column in columns" <td ng-repeat="column in columns"
lang="{{column.custom_field && column.custom_field.name_locale || locale}}" lang="::{{column.custom_field && column.custom_field.name_locale || locale}}"
wp-edit-field="getTableColumnName(row.object, column.name)" wp-edit-field="::getTableColumnName(row.object, column.name)"
wp-edit-field-wrapper-classes="'-small -shrink'" wp-edit-field-wrapper-classes="'-small -shrink'"
columns="columns" display-classes="::[row.level > 0 && column.name == 'subject' && 'icon-context icon-arrow-right5 icon-small']"
field-index="$index" columns="::columns"
field-index="::$index"
class="wp-table--cell" class="wp-table--cell"
ng-class="{ '-short': column.name == 'id' }"> ng-class="::{ '-short': column.name == 'id' }">
<wp-display-attr attribute="getTableColumnName(row.object, column.name)"
work-package="row.object"
ng-class="[row.level > 0 && column.name == 'subject' && 'icon-context icon-arrow-right5 icon-small']">
</wp-display-attr>
</td> </td>
</tr> </tr>

@ -0,0 +1,107 @@
// -- copyright
// OpenProject is a project management system.
// Copyright (C) 2012-2015 the OpenProject Foundation (OPF)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License version 3.
//
// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
// Copyright (C) 2006-2013 Jean-Philippe Lang
// Copyright (C) 2010-2013 the ChiliProject Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// See doc/COPYRIGHT.rdoc for more details.
// ++
import IScope = angular.IScope;
import IRootElementService = angular.IRootElementService;
angular
.module('openproject.workPackages.directives')
.directive('wpVirtualScroll', wpVirtualScroll);
function getBlockNodes(nodes) {
var node = nodes[0];
var endNode = nodes[nodes.length - 1];
var blockNodes = [node];
do {
node = node.nextSibling;
if (!node) break;
blockNodes.push(node);
} while (node !== endNode);
return $(blockNodes);
}
function wpVirtualScroll($window, $animate) {
return {
multiElement: true,
transclude: 'element',
// priority: 600,
terminal: true,
restrict: 'A',
// $$tlb: true,
link: ($scope, $element: IRootElementService, $attr, ctrl, $transclude) => {
const parent = $element.parent();
let block: any;
let childScope: IScope;
let previousElements: any;
let tr = document.createElement("tr");
let td = document.createElement("td");
td.innerHTML = "&nbsp;";
tr.appendChild(td);
const value = true;
if (value) {
if (!childScope) {
$transclude(function (clone, newScope) {
childScope = newScope;
block = {
clone: clone
};
$animate.enter(clone, parent, $element);
});
}
} else {
if (previousElements) {
previousElements.remove();
previousElements = null;
}
if (childScope) {
childScope.$destroy();
childScope = null;
}
if (block) {
previousElements = getBlockNodes(block.clone);
$animate.leave(previousElements).then(function () {
previousElements = null;
});
block = null;
}
// adding dummy row
parent.append(tr);
}
}
};
}

@ -0,0 +1 @@
//# sourceMappingURL=open-project.typings.js.map

@ -0,0 +1 @@
{"version":3,"file":"open-project.typings.js","sourceRoot":"","sources":["open-project.typings.ts"],"names":[],"mappings":""}
Loading…
Cancel
Save