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

@ -30,22 +30,27 @@ import {HalResource} from "../../api/api-v3/hal-resources/hal-resource.service";
import {wpDirectivesModule} from "../../../angular-modules";
import {WorkPackageEditFieldController} from "../../wp-edit/wp-edit-field/wp-edit-field.directive";
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 {WorkPackageDisplayFieldService} from "../../wp-display/wp-display-field/wp-display-field.service";
export class WorkPackageDisplayAttributeController {
public wpEditField:WorkPackageEditFieldController;
public attribute:string;
public placeholderOptional:string;
public workPackage:any;
public customSchema:HalResource;
public wpEditField: WorkPackageEditFieldController;
public attribute: string;
public placeholderOptional: string;
public workPackage: any;
public customSchema: HalResource;
public field: DisplayField;
public label: string;
private __d__hiddenForSighted: JQuery;
private __d__cell: JQuery;
private __d__renderer: JQuery;
constructor(protected wpDisplayField: WorkPackageDisplayFieldService,
protected wpCacheService:WorkPackageCacheService,
protected $scope:ng.IScope) {
constructor(protected $element: JQuery,
protected wpDisplayField: WorkPackageDisplayFieldService,
protected wpCacheService: WorkPackageCacheService,
protected $scope: ng.IScope) {
// Update the attribute initially
if (this.workPackage) {
@ -72,7 +77,7 @@ export class WorkPackageDisplayAttributeController {
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';
}
@ -101,17 +106,30 @@ export class WorkPackageDisplayAttributeController {
this.workPackage = wp;
this.schema.$load().then(() => {
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 wpTdLink(
scope,
element,
attr,
controllers) {
function wpTdLink(scope,
element,
attr,
controllers) {
scope.$ctrl.wpEditField = controllers[0];

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

@ -4,10 +4,6 @@
wp-edit-field="'subject'"
wp-edit-field-wrapper-classes="'-no-label'"
class="work-packages--details--subject">
<wp-display-attr
work-package="$ctrl.workPackage"
attribute="'subject'">
</wp-display-attr>
</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"
export class BooleanDisplayField extends DisplayField {
isManualRenderer = true;
public WorkPackagesHelper:op.WorkPackagesHelper;
constructor(public resource:HalResource,

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

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

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

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

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

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

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

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

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

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