|
@@ -63,6 +63,7 @@ class ClassPage {
|
|
Mixins: 'Mixins',
|
|
Mixins: 'Mixins',
|
|
Children: 'Children',
|
|
Children: 'Children',
|
|
MixedIn: 'MixedIn',
|
|
MixedIn: 'MixedIn',
|
|
|
|
+ Info: 'Info',
|
|
Contribution: 'Contribution'
|
|
Contribution: 'Contribution'
|
|
};
|
|
};
|
|
|
|
|
|
@@ -71,7 +72,8 @@ class ClassPage {
|
|
Base: 'base',
|
|
Base: 'base',
|
|
Overridden: 'overridden',
|
|
Overridden: 'overridden',
|
|
Dynamic: 'dynamic',
|
|
Dynamic: 'dynamic',
|
|
- Inherited: 'inherited'
|
|
|
|
|
|
+ Inherited: 'inherited',
|
|
|
|
+ ClassComment: 'ClassComment'
|
|
};
|
|
};
|
|
|
|
|
|
static PropertyLabel = {
|
|
static PropertyLabel = {
|
|
@@ -104,14 +106,11 @@ class ClassPage {
|
|
ShortName: 'shortName'
|
|
ShortName: 'shortName'
|
|
};
|
|
};
|
|
|
|
|
|
- static ContextMenuType = {
|
|
|
|
- PropertyItem: 'property-item'
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
static __static__ = '__static__';
|
|
static __static__ = '__static__';
|
|
|
|
+ static __self__ = '__self__';
|
|
|
|
|
|
start() {
|
|
start() {
|
|
- if(typeof Class === 'string') {
|
|
|
|
|
|
+ if(!Class.root) {
|
|
return this;
|
|
return this;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -122,7 +121,8 @@ class ClassPage {
|
|
[ClassPage.TabNames.Properties]: DOM.get('.tab.properties'),
|
|
[ClassPage.TabNames.Properties]: DOM.get('.tab.properties'),
|
|
[ClassPage.TabNames.Mixins]: DOM.get('.tab.mixins'),
|
|
[ClassPage.TabNames.Mixins]: DOM.get('.tab.mixins'),
|
|
[ClassPage.TabNames.Children]: DOM.get('.tab.children'),
|
|
[ClassPage.TabNames.Children]: DOM.get('.tab.children'),
|
|
- [ClassPage.TabNames.MixedIn]: DOM.get('.tab.mixedin')
|
|
|
|
|
|
+ [ClassPage.TabNames.MixedIn]: DOM.get('.tab.mixedin'),
|
|
|
|
+ [ClassPage.TabNames.Info]: DOM.get('.tab.info')
|
|
};
|
|
};
|
|
|
|
|
|
this.contentElements = {
|
|
this.contentElements = {
|
|
@@ -132,7 +132,8 @@ class ClassPage {
|
|
[ClassPage.TabNames.Properties]: DOM.get('.content-tab#properties'),
|
|
[ClassPage.TabNames.Properties]: DOM.get('.content-tab#properties'),
|
|
[ClassPage.TabNames.Mixins]: DOM.get('.content-tab#mixins'),
|
|
[ClassPage.TabNames.Mixins]: DOM.get('.content-tab#mixins'),
|
|
[ClassPage.TabNames.Children]: DOM.get('.content-tab#children'),
|
|
[ClassPage.TabNames.Children]: DOM.get('.content-tab#children'),
|
|
- [ClassPage.TabNames.MixedIn]: DOM.get('.content-tab#mixedin')
|
|
|
|
|
|
+ [ClassPage.TabNames.MixedIn]: DOM.get('.content-tab#mixedin'),
|
|
|
|
+ [ClassPage.TabNames.Info]: DOM.get('.content-tab#info')
|
|
};
|
|
};
|
|
|
|
|
|
if(isEditor) {
|
|
if(isEditor) {
|
|
@@ -159,10 +160,7 @@ class ClassPage {
|
|
const tabsModeButton = this.tabsModeButton = DOM.get('.display-mode-button.mode-tabs');
|
|
const tabsModeButton = this.tabsModeButton = DOM.get('.display-mode-button.mode-tabs');
|
|
const listModeButton = this.listModeButton = DOM.get('.display-mode-button.mode-list');
|
|
const listModeButton = this.listModeButton = DOM.get('.display-mode-button.mode-list');
|
|
|
|
|
|
- /* >>> Context menu */
|
|
|
|
- this.contextMenu = DOM.get('.context-menu');
|
|
|
|
- this.contextMenuItems = {};
|
|
|
|
- /* <<< Context menu */
|
|
|
|
|
|
+ this.contextMenu = ContextMenu.init();
|
|
|
|
|
|
(mode === ClassPage.Mode.Tabs ? tabsModeButton : listModeButton).addClass(ClassPage.StyleClasses.Selected);
|
|
(mode === ClassPage.Mode.Tabs ? tabsModeButton : listModeButton).addClass(ClassPage.StyleClasses.Selected);
|
|
|
|
|
|
@@ -189,7 +187,8 @@ class ClassPage {
|
|
|
|
|
|
this.rightContainer.addClass(mode);
|
|
this.rightContainer.addClass(mode);
|
|
|
|
|
|
- this.codeMirrorEditor.cmRefresh();
|
|
|
|
|
|
+ if(!Class.isPackage)
|
|
|
|
+ this.codeMirrorEditor.cmRefresh();
|
|
}
|
|
}
|
|
|
|
|
|
selectTab(tab) {
|
|
selectTab(tab) {
|
|
@@ -224,7 +223,8 @@ class ClassPage {
|
|
registerTabsEventListeners() {
|
|
registerTabsEventListeners() {
|
|
const tabElements = this.tabElements;
|
|
const tabElements = this.tabElements;
|
|
for(const tabName of Object.keys(tabElements)) {
|
|
for(const tabName of Object.keys(tabElements)) {
|
|
- tabElements[tabName].on(DOM.Events.Click, this.onTabClick.bind(this));
|
|
|
|
|
|
+ if(tabElements[tabName])
|
|
|
|
+ tabElements[tabName].on(DOM.Events.Click, this.onTabClick.bind(this));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -247,21 +247,26 @@ class ClassPage {
|
|
}
|
|
}
|
|
|
|
|
|
renderContent() {
|
|
renderContent() {
|
|
- this.renderEditor();
|
|
|
|
- this.renderParents();
|
|
|
|
- this.renderMixins();
|
|
|
|
- this.renderChildren();
|
|
|
|
- this.renderMixedIn();
|
|
|
|
- this.renderProperties();
|
|
|
|
- this.renderMethods();
|
|
|
|
- this.renderDocumentedPercentage();
|
|
|
|
- this.loadInheritedComments();
|
|
|
|
|
|
+ if(!Class.isPackage) {
|
|
|
|
+ this.renderEditor();
|
|
|
|
+ this.renderParents();
|
|
|
|
+ this.renderMixins();
|
|
|
|
+ this.renderChildren();
|
|
|
|
+ this.renderMixedIn();
|
|
|
|
+ this.renderProperties();
|
|
|
|
+ this.renderMethods();
|
|
|
|
+ this.renderDocumentedPercentage();
|
|
|
|
+ this.loadInheritedComments();
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+ this.renderInfo();
|
|
if(isEditor)
|
|
if(isEditor)
|
|
this.renderContribution();
|
|
this.renderContribution();
|
|
}
|
|
}
|
|
|
|
|
|
renderDocumentedPercentage() {
|
|
renderDocumentedPercentage() {
|
|
|
|
+ if(Class.isPackage)
|
|
|
|
+ return;
|
|
this.documentedPercentage.setInnerHTML(`${Math.round(this.documented/this.documentable * 10000) / 100}%`);
|
|
this.documentedPercentage.setInnerHTML(`${Math.round(this.documented/this.documentable * 10000) / 100}%`);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -354,15 +359,15 @@ class ClassPage {
|
|
}
|
|
}
|
|
|
|
|
|
for(const property of properties) {
|
|
for(const property of properties) {
|
|
- const key = isStatics ? `${ClassPage.__static__}${property.key}` : property.key;
|
|
|
|
- const propertyItem = DOM.create({ tag: DOM.Tags.Div, cls: 'property-item', attr: { [ClassPage.Attributes.DataPropertyName]: key, [ClassPage.Attributes.DataPropertyType]: property.type }}, propertiesList).on(DOM.Events.MouseDown, (e) => {
|
|
|
|
|
|
+ const onMouseDown = (e) => {
|
|
const element = CDElement.get(e.target);
|
|
const element = CDElement.get(e.target);
|
|
|
|
+ const key = isStatics ? `${ClassPage.__static__}${property.key}` : property.key;
|
|
|
|
|
|
if(e.buttons === DOM.MouseButtons.Right) {
|
|
if(e.buttons === DOM.MouseButtons.Right) {
|
|
if(element.hasClass('property-item-saving-filler'))
|
|
if(element.hasClass('property-item-saving-filler'))
|
|
return;
|
|
return;
|
|
setTimeout(() => {
|
|
setTimeout(() => {
|
|
- this.showContextMenu(ClassPage.ContextMenuType.PropertyItem, element, { x: e.pageX, y: e.pageY });
|
|
|
|
|
|
+ this.showContextMenu(element, { x: e.pageX, y: e.pageY });
|
|
}, 10);
|
|
}, 10);
|
|
} else if (e.buttons === DOM.MouseButtons.Left) {
|
|
} else if (e.buttons === DOM.MouseButtons.Left) {
|
|
if(propertyItemClickable(element))
|
|
if(propertyItemClickable(element))
|
|
@@ -373,142 +378,9 @@ class ClassPage {
|
|
this.searchPropertyInEditor(isMethods, property.dynamic, key);
|
|
this.searchPropertyInEditor(isMethods, property.dynamic, key);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- });
|
|
|
|
-
|
|
|
|
- const itemNameText = DOM.create({ tag: DOM.Tags.Span, innerHTML: isMethods ? 'Signature: ' : 'Name: ' });
|
|
|
|
- const itemNameValue = DOM.create({ tag: DOM.Tags.Span, cls: 'property-item-name-span', innerHTML: isMethods ? property.value : property.key });
|
|
|
|
- DOM.create({ tag: DOM.Tags.Div, cls: 'property-item-name', cn: [itemNameText, itemNameValue] }, propertyItem);
|
|
|
|
-
|
|
|
|
- if(type !== ClassPage.PropertyType.Dynamic && !isMethods) {
|
|
|
|
- const itemTypeText = DOM.create({ tag: DOM.Tags.Span, innerHTML: 'Type: ' });
|
|
|
|
- const itemTypeValue = DOM.create({ tag: DOM.Tags.Span, cls: 'property-item-type-span', innerHTML: property.type });
|
|
|
|
- DOM.create({ tag: DOM.Tags.Div, cls: 'property-item-type', cn: [itemTypeText, itemTypeValue] }, propertyItem);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if(type !== ClassPage.PropertyType.Dynamic && !isMethods && property.type !== 'undefined') {
|
|
|
|
- const itemValueText = DOM.create({ tag: DOM.Tags.Span, innerHTML: 'Default value: ' });
|
|
|
|
- const itemValueValue = DOM.create({ tag: DOM.Tags.Span, cls: 'property-item-default-value-span', innerHTML: property.type === 'string' ? `'${property.value}'` : property.value });
|
|
|
|
- DOM.create({ tag: DOM.Tags.Div, cls: 'property-item-default-value', cn: [itemValueText, itemValueValue] }, propertyItem);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if(type !== ClassPage.PropertyType.Dynamic && type !== ClassPage.PropertyType.Statics && type !== ClassPage.PropertyType.Base) {
|
|
|
|
- const itemParentText = DOM.create({ tag: DOM.Tags.Span, innerHTML: 'Nearest parent: ' });
|
|
|
|
- const itemParentValue = DOM.create({ tag: DOM.Tags.Span, cls: 'property-item-nearest-parent-span', innerHTML: property.nearestParent }).on('click', (e) => {
|
|
|
|
- Url.goTo(`/class/${property.nearestParent}`);
|
|
|
|
- });
|
|
|
|
- DOM.create({ tag: DOM.Tags.Div, cls: 'property-item-nearest-parent', cn: [itemParentText, itemParentValue] }, propertyItem);
|
|
|
|
- propertyItem.setAttribute(ClassPage.Attributes.DataPropertyParent, property.nearestParent);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if(type === ClassPage.PropertyType.Dynamic) {
|
|
|
|
- propertyItem.setAttribute(ClassPage.Attributes.DataPropertyDynamic, 'true');
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- const itemCommentText = DOM.create({ tag: DOM.Tags.Div, innerHTML: 'Comment:' });
|
|
|
|
- const itemCommentCn = [itemCommentText];
|
|
|
|
-
|
|
|
|
- const loadedComment = Comments[type === ClassPage.PropertyType.Statics ? `${ClassPage.__static__}${property.key}` : property.key];
|
|
|
|
- const loadedCommentText = loadedComment && typeof loadedComment === 'object' ? loadedComment.text : '';
|
|
|
|
-
|
|
|
|
- const hasComment = loadedComment && typeof loadedComment === 'object' && loadedCommentText.length > 0;
|
|
|
|
- const itemCommentStatic = DOM.create({ tag: DOM.Tags.Div, cls: `property-item-comment-static${!hasComment ? ' empty' : ''}`, innerHTML: hasComment ? CDUtils.nl2br(loadedCommentText) : 'Not commented yet...' });
|
|
|
|
- itemCommentCn.push(itemCommentStatic);
|
|
|
|
-
|
|
|
|
- if(type === ClassPage.PropertyType.Inherited) {
|
|
|
|
- this.inheritedCommentsFields[`${property.nearestParent}:${property.key}`] = itemCommentStatic;
|
|
|
|
- propertyItem.setAttribute(ClassPage.Attributes.DataPropertyInherited, 'true');
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- this.propertyItemElements[type === ClassPage.PropertyType.Statics ? `${ClassPage.__static__}${property.key}` : property.key] = propertyItem;
|
|
|
|
-
|
|
|
|
- if(isEditor) {
|
|
|
|
- const itemCommentInput = DOM.create({ tag: DOM.Tags.Textarea, cls: 'property-item-comment-input hidden', attr: { 'placeholder': 'Not commented yet...'} }).setValue(CDUtils.br2nl(loadedCommentText));
|
|
|
|
- itemCommentCn.push(itemCommentInput);
|
|
|
|
-
|
|
|
|
- if(type === ClassPage.PropertyType.Inherited) {
|
|
|
|
- itemCommentInput.addClass(ClassPage.StyleClasses.Readonly).setAttribute('readonly', 'true');
|
|
|
|
- } else {
|
|
|
|
- itemCommentStatic.addClass(ClassPage.StyleClasses.Clickable);
|
|
|
|
- itemCommentInput
|
|
|
|
- .on(DOM.Events.KeyDown, this.delayedAdjustCommentInputHeight.bind(this))
|
|
|
|
- .on(DOM.Events.Change, this.adjustCommentInputHeight.bind(this))
|
|
|
|
- .on(DOM.Events.Cut, this.delayedAdjustCommentInputHeight.bind(this))
|
|
|
|
- .on(DOM.Events.Paste, this.delayedAdjustCommentInputHeight.bind(this))
|
|
|
|
- .on(DOM.Events.Drop, this.delayedAdjustCommentInputHeight.bind(this));
|
|
|
|
-
|
|
|
|
- const onCommentSave = (e) => {
|
|
|
|
- const commentContent = itemCommentInput.getValue();
|
|
|
|
-
|
|
|
|
- if(commentContent === CDUtils.br2nl(itemCommentStatic.getValue()) || commentContent === '' && itemCommentStatic.hasClass('empty'))
|
|
|
|
- return;
|
|
|
|
-
|
|
|
|
- const propertyName = `${type === ClassPage.PropertyType.Statics ? ClassPage.__static__ : ''}${property.key}`;
|
|
|
|
- const className = Class[ClassPage.ClassProperties.Name];
|
|
|
|
- const classRoot = Class[ClassPage.ClassProperties.Root];
|
|
|
|
-
|
|
|
|
- propertyItem.addClass('saving');
|
|
|
|
- itemCommentInput.blur();
|
|
|
|
-
|
|
|
|
- fetch('/updateComment', {
|
|
|
|
- method: 'POST',
|
|
|
|
- headers: {
|
|
|
|
- 'Content-Type': 'application/x-www-form-urlencoded'
|
|
|
|
- },
|
|
|
|
- body: new URLSearchParams({
|
|
|
|
- 'root': classRoot,
|
|
|
|
- 'class': className,
|
|
|
|
- 'property': propertyName,
|
|
|
|
- 'comment': commentContent
|
|
|
|
- })
|
|
|
|
- }).then((res) => {
|
|
|
|
- if(res.status !== 202) {
|
|
|
|
- propertyItem.removeClass('saving');
|
|
|
|
- console.error(`Comment update failed (${res.status})`);
|
|
|
|
- }
|
|
|
|
- }).catch((e) => {
|
|
|
|
- propertyItem.removeClass('saving');
|
|
|
|
- console.error(`Comment update failed`);
|
|
|
|
- });
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- const itemCommentOkButton = DOM.create({ tag: DOM.Tags.Div, cls: 'property-item-comment-button hidden', innerHTML: 'OK' }).on(DOM.Events.Click, onCommentSave);
|
|
|
|
- itemCommentCn.push(itemCommentOkButton);
|
|
|
|
-
|
|
|
|
- itemCommentInput.on(DOM.Events.KeyDown, (e) => {
|
|
|
|
- if(e.key === DOM.Keys.Escape) {
|
|
|
|
- const inputScrollTop = itemCommentInput.get().scrollTop;
|
|
|
|
- itemCommentInput.switchClass(ClassPage.StyleClasses.Hidden);
|
|
|
|
- itemCommentOkButton.switchClass(ClassPage.StyleClasses.Hidden);
|
|
|
|
- itemCommentStatic.switchClass(ClassPage.StyleClasses.Hidden);
|
|
|
|
- itemCommentStatic.get().scrollTop = inputScrollTop;
|
|
|
|
- if(!itemCommentStatic.hasClass('empty'))
|
|
|
|
- itemCommentInput.setValue(CDUtils.br2nl(itemCommentStatic.getValue()));
|
|
|
|
- }
|
|
|
|
- if(e.key === DOM.Keys.Enter && !e.shiftKey) {
|
|
|
|
- onCommentSave();
|
|
|
|
- e.preventDefault();
|
|
|
|
- }
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- itemCommentStatic.on(DOM.Events.Click, (e) => {
|
|
|
|
- if(CDElement.get(e.target).getTag() === DOM.Tags.A)
|
|
|
|
- return;
|
|
|
|
- itemCommentInput.switchClass(ClassPage.StyleClasses.Hidden);
|
|
|
|
- itemCommentInput.focus();
|
|
|
|
- itemCommentInput.style('height', `${Math.min(422, itemCommentStatic.get().scrollHeight + 2)}px`);
|
|
|
|
- itemCommentInput.get().scrollTop = itemCommentStatic.get().scrollTop;
|
|
|
|
- itemCommentOkButton.switchClass(ClassPage.StyleClasses.Hidden);
|
|
|
|
- itemCommentStatic.switchClass(ClassPage.StyleClasses.Hidden);
|
|
|
|
- });
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- DOM.create({ tag: DOM.Tags.Div, cls: 'property-item-saving-filler' }, propertyItem);
|
|
|
|
}
|
|
}
|
|
-
|
|
|
|
- if(hasComment)
|
|
|
|
- itemCommentCn.push(this.createCommentDateElement(loadedComment.timestamp, loadedComment.author));
|
|
|
|
-
|
|
|
|
- DOM.create({ tag: DOM.Tags.Div, cls: 'property-item-comment', cn: itemCommentCn }, propertyItem);
|
|
|
|
|
|
+ const data = { type: property.type, nearestParent: property.nearestParent, static: isStatics, value: property.value };
|
|
|
|
+ this.createPropertyItem(property.key, data, type, propertiesList, isMethods, onMouseDown);
|
|
}
|
|
}
|
|
|
|
|
|
propertiesHeader.on(DOM.Events.Click, (e) => {
|
|
propertiesHeader.on(DOM.Events.Click, (e) => {
|
|
@@ -517,6 +389,21 @@ class ClassPage {
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ updateComment(classRoot, className, propertyName, commentContent) {
|
|
|
|
+ return fetch('/updateComment', {
|
|
|
|
+ method: 'POST',
|
|
|
|
+ headers: {
|
|
|
|
+ 'Content-Type': 'application/x-www-form-urlencoded'
|
|
|
|
+ },
|
|
|
|
+ body: new URLSearchParams({
|
|
|
|
+ 'root': classRoot,
|
|
|
|
+ 'class': className,
|
|
|
|
+ 'property': propertyName,
|
|
|
|
+ 'comment': commentContent
|
|
|
|
+ })
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+
|
|
createCommentDateElement(date, author) {
|
|
createCommentDateElement(date, author) {
|
|
const commentDateText = DOM.create({ tag: DOM.Tags.Span, cls: 'property-item-comment-date-text', innerHTML: `Commented by <b>${author}</b> on: ` });
|
|
const commentDateText = DOM.create({ tag: DOM.Tags.Span, cls: 'property-item-comment-date-text', innerHTML: `Commented by <b>${author}</b> on: ` });
|
|
const commentDateDate = DOM.create({ tag: DOM.Tags.Span, cls: 'property-item-comment-date-date', innerHTML: CDUtils.dateFormatUTC(date, 3, 'D.M.Y, H:I:S') });
|
|
const commentDateDate = DOM.create({ tag: DOM.Tags.Span, cls: 'property-item-comment-date-date', innerHTML: CDUtils.dateFormatUTC(date, 3, 'D.M.Y, H:I:S') });
|
|
@@ -603,6 +490,147 @@ class ClassPage {
|
|
this.renderClassItems(Class[ClassPage.ClassProperties.MixedIn], mixedInElement);
|
|
this.renderClassItems(Class[ClassPage.ClassProperties.MixedIn], mixedInElement);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ renderInfo() {
|
|
|
|
+ const infoContainer = this.contentElements[ClassPage.TabNames.Info];
|
|
|
|
+ //infoContainer.append(DOM.create({ tag: DOM.Tags.Div, innerHTML: 'abc test' }));
|
|
|
|
+ const propertiesList = DOM.create({ tag: DOM.Tags.Div, cls: 'properties-list' }, infoContainer);
|
|
|
|
+ this.createPropertyItem(ClassPage.__self__, { value: '' }, ClassPage.PropertyType.ClassComment, propertiesList);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ createPropertyItem(name, data, type, container, isMethod, onMouseDown) {
|
|
|
|
+ const key = data.static ? `${ClassPage.__static__}${name}` : name;
|
|
|
|
+ const propertyItem = DOM.create({ tag: DOM.Tags.Div, cls: 'property-item', attr: { [ClassPage.Attributes.DataPropertyName]: key, [ClassPage.Attributes.DataPropertyType]: data.type }}, container).on(DOM.Events.MouseDown, (e) => {
|
|
|
|
+ if(onMouseDown)
|
|
|
|
+ onMouseDown(e);
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ if(type !== ClassPage.PropertyType.ClassComment) {
|
|
|
|
+ const itemNameText = DOM.create({ tag: DOM.Tags.Span, innerHTML: isMethod ? 'Signature: ' : 'Name: ' });
|
|
|
|
+ const itemNameValue = DOM.create({ tag: DOM.Tags.Span, cls: 'property-item-name-span', innerHTML: isMethod ? data.value : name });
|
|
|
|
+ DOM.create({ tag: DOM.Tags.Div, cls: 'property-item-name', cn: [itemNameText, itemNameValue] }, propertyItem);
|
|
|
|
+
|
|
|
|
+ if(type !== ClassPage.PropertyType.Dynamic && !isMethod) {
|
|
|
|
+ const itemTypeText = DOM.create({ tag: DOM.Tags.Span, innerHTML: 'Type: ' });
|
|
|
|
+ const itemTypeValue = DOM.create({ tag: DOM.Tags.Span, cls: 'property-item-type-span', innerHTML: data.type });
|
|
|
|
+ DOM.create({ tag: DOM.Tags.Div, cls: 'property-item-type', cn: [itemTypeText, itemTypeValue] }, propertyItem);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if(type !== ClassPage.PropertyType.Dynamic && !isMethod && data.type !== 'undefined') {
|
|
|
|
+ const itemValueText = DOM.create({ tag: DOM.Tags.Span, innerHTML: 'Default value: ' });
|
|
|
|
+ const itemValueValue = DOM.create({ tag: DOM.Tags.Span, cls: 'property-item-default-value-span', innerHTML: data.type === 'string' ? `'${data.value}'` : data.value });
|
|
|
|
+ DOM.create({ tag: DOM.Tags.Div, cls: 'property-item-default-value', cn: [itemValueText, itemValueValue] }, propertyItem);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if(type !== ClassPage.PropertyType.Dynamic && type !== ClassPage.PropertyType.Statics && type !== ClassPage.PropertyType.Base) {
|
|
|
|
+ const itemParentText = DOM.create({ tag: DOM.Tags.Span, innerHTML: 'Nearest parent: ' });
|
|
|
|
+ const itemParentValue = DOM.create({ tag: DOM.Tags.Span, cls: 'property-item-nearest-parent-span', innerHTML: data.nearestParent }).on('click', (e) => {
|
|
|
|
+ Url.goTo(`/class/${data.nearestParent}`);
|
|
|
|
+ });
|
|
|
|
+ DOM.create({ tag: DOM.Tags.Div, cls: 'property-item-nearest-parent', cn: [itemParentText, itemParentValue] }, propertyItem);
|
|
|
|
+ propertyItem.setAttribute(ClassPage.Attributes.DataPropertyParent, data.nearestParent);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if(type === ClassPage.PropertyType.Dynamic) {
|
|
|
|
+ propertyItem.setAttribute(ClassPage.Attributes.DataPropertyDynamic, 'true');
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const itemCommentText = DOM.create({ tag: DOM.Tags.Div, innerHTML: 'Comment:' });
|
|
|
|
+ const itemCommentCn = [itemCommentText];
|
|
|
|
+
|
|
|
|
+ const loadedComment = Comments[type === ClassPage.PropertyType.Statics ? `${ClassPage.__static__}${name}` : name];
|
|
|
|
+ const loadedCommentText = loadedComment && typeof loadedComment === 'object' ? loadedComment.text : '';
|
|
|
|
+
|
|
|
|
+ const hasComment = loadedComment && typeof loadedComment === 'object' && loadedCommentText.length > 0;
|
|
|
|
+ const itemCommentStatic = DOM.create({ tag: DOM.Tags.Div, cls: `property-item-comment-static${!hasComment ? ' empty' : ''}`, innerHTML: hasComment ? CDUtils.nl2br(loadedCommentText) : 'Not commented yet...' });
|
|
|
|
+ itemCommentCn.push(itemCommentStatic);
|
|
|
|
+
|
|
|
|
+ if(type === ClassPage.PropertyType.Inherited) {
|
|
|
|
+ this.inheritedCommentsFields[`${data.nearestParent}:${name}`] = itemCommentStatic;
|
|
|
|
+ propertyItem.setAttribute(ClassPage.Attributes.DataPropertyInherited, 'true');
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ this.propertyItemElements[type === ClassPage.PropertyType.Statics ? `${ClassPage.__static__}${name}` : name] = propertyItem;
|
|
|
|
+
|
|
|
|
+ if(isEditor) {
|
|
|
|
+ const itemCommentInput = DOM.create({ tag: DOM.Tags.Textarea, cls: 'property-item-comment-input hidden', attr: { 'placeholder': 'Not commented yet...'} }).setValue(CDUtils.br2nl(loadedCommentText));
|
|
|
|
+ itemCommentCn.push(itemCommentInput);
|
|
|
|
+
|
|
|
|
+ if(type === ClassPage.PropertyType.Inherited) {
|
|
|
|
+ itemCommentInput.addClass(ClassPage.StyleClasses.Readonly).setAttribute('readonly', 'true');
|
|
|
|
+ } else {
|
|
|
|
+ itemCommentStatic.addClass(ClassPage.StyleClasses.Clickable);
|
|
|
|
+ itemCommentInput
|
|
|
|
+ .on(DOM.Events.KeyDown, this.delayedAdjustCommentInputHeight.bind(this))
|
|
|
|
+ .on(DOM.Events.Change, this.adjustCommentInputHeight.bind(this))
|
|
|
|
+ .on(DOM.Events.Cut, this.delayedAdjustCommentInputHeight.bind(this))
|
|
|
|
+ .on(DOM.Events.Paste, this.delayedAdjustCommentInputHeight.bind(this))
|
|
|
|
+ .on(DOM.Events.Drop, this.delayedAdjustCommentInputHeight.bind(this));
|
|
|
|
+
|
|
|
|
+ const onCommentSave = (e) => {
|
|
|
|
+ const commentContent = itemCommentInput.getValue();
|
|
|
|
+
|
|
|
|
+ if(commentContent === CDUtils.br2nl(itemCommentStatic.getValue()) || commentContent === '' && itemCommentStatic.hasClass('empty'))
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ const propertyName = `${type === ClassPage.PropertyType.Statics ? ClassPage.__static__ : ''}${name}`;
|
|
|
|
+ const className = Class[ClassPage.ClassProperties.Name];
|
|
|
|
+ const classRoot = Class[ClassPage.ClassProperties.Root];
|
|
|
|
+
|
|
|
|
+ propertyItem.addClass('saving');
|
|
|
|
+ itemCommentInput.blur();
|
|
|
|
+
|
|
|
|
+ this.updateComment(classRoot, className, propertyName, commentContent).then((res) => {
|
|
|
|
+ if(res.status !== 202) {
|
|
|
|
+ propertyItem.removeClass('saving');
|
|
|
|
+ console.error(`Comment update failed (${res.status})`);
|
|
|
|
+ }
|
|
|
|
+ }).catch((e) => {
|
|
|
|
+ propertyItem.removeClass('saving');
|
|
|
|
+ console.error(`Comment update failed`);
|
|
|
|
+ });
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ const itemCommentOkButton = DOM.create({ tag: DOM.Tags.Div, cls: 'property-item-comment-button hidden', innerHTML: 'OK' }).on(DOM.Events.Click, onCommentSave);
|
|
|
|
+ itemCommentCn.push(itemCommentOkButton);
|
|
|
|
+
|
|
|
|
+ itemCommentInput.on(DOM.Events.KeyDown, (e) => {
|
|
|
|
+ if(e.key === DOM.Keys.Escape) {
|
|
|
|
+ const inputScrollTop = itemCommentInput.get().scrollTop;
|
|
|
|
+ itemCommentInput.switchClass(ClassPage.StyleClasses.Hidden);
|
|
|
|
+ itemCommentOkButton.switchClass(ClassPage.StyleClasses.Hidden);
|
|
|
|
+ itemCommentStatic.switchClass(ClassPage.StyleClasses.Hidden);
|
|
|
|
+ itemCommentStatic.get().scrollTop = inputScrollTop;
|
|
|
|
+ if(!itemCommentStatic.hasClass('empty'))
|
|
|
|
+ itemCommentInput.setValue(CDUtils.br2nl(itemCommentStatic.getValue()));
|
|
|
|
+ }
|
|
|
|
+ if(e.key === DOM.Keys.Enter && !e.shiftKey) {
|
|
|
|
+ onCommentSave();
|
|
|
|
+ e.preventDefault();
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ itemCommentStatic.on(DOM.Events.Click, (e) => {
|
|
|
|
+ if(CDElement.get(e.target).getTag() === DOM.Tags.A)
|
|
|
|
+ return;
|
|
|
|
+ itemCommentInput.switchClass(ClassPage.StyleClasses.Hidden);
|
|
|
|
+ itemCommentInput.focus();
|
|
|
|
+ itemCommentInput.style('height', `${Math.min(422, itemCommentStatic.get().scrollHeight + 2)}px`);
|
|
|
|
+ itemCommentInput.get().scrollTop = itemCommentStatic.get().scrollTop;
|
|
|
|
+ itemCommentOkButton.switchClass(ClassPage.StyleClasses.Hidden);
|
|
|
|
+ itemCommentStatic.switchClass(ClassPage.StyleClasses.Hidden);
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ DOM.create({ tag: DOM.Tags.Div, cls: 'property-item-saving-filler' }, propertyItem);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if(hasComment)
|
|
|
|
+ itemCommentCn.push(this.createCommentDateElement(loadedComment.timestamp, loadedComment.author));
|
|
|
|
+
|
|
|
|
+ DOM.create({ tag: DOM.Tags.Div, cls: 'property-item-comment', cn: itemCommentCn }, propertyItem);
|
|
|
|
+ }
|
|
|
|
+
|
|
renderFullSourcePrompt() {
|
|
renderFullSourcePrompt() {
|
|
const editorContent = this.contentElements[ClassPage.TabNames.Editor];
|
|
const editorContent = this.contentElements[ClassPage.TabNames.Editor];
|
|
|
|
|
|
@@ -629,6 +657,9 @@ class ClassPage {
|
|
}
|
|
}
|
|
|
|
|
|
markContentInEditor() {
|
|
markContentInEditor() {
|
|
|
|
+ if(Class.isPackage)
|
|
|
|
+ return;
|
|
|
|
+
|
|
const staticsRange = this.getStaticsRange();
|
|
const staticsRange = this.getStaticsRange();
|
|
|
|
|
|
this.codeMirrorEditor.cmEachLine((lineHandle) => {
|
|
this.codeMirrorEditor.cmEachLine((lineHandle) => {
|
|
@@ -1035,8 +1066,8 @@ class ClassPage {
|
|
const tabElements = this.tabElements;
|
|
const tabElements = this.tabElements;
|
|
const contentElements = this.contentElements;
|
|
const contentElements = this.contentElements;
|
|
|
|
|
|
- const selectedTab = tabElements[hashTab] || tabElements[ClassPage.TabNames.Editor];
|
|
|
|
- const activeContent = contentElements[hashTab] || contentElements[ClassPage.TabNames.Editor];
|
|
|
|
|
|
+ const selectedTab = tabElements[hashTab] || (Class.isPackage ? tabElements[ClassPage.TabNames.Info] : tabElements[ClassPage.TabNames.Editor]);
|
|
|
|
+ const activeContent = contentElements[hashTab] || (Class.isPackage ? contentElements[ClassPage.TabNames.Info] : contentElements[ClassPage.TabNames.Editor]);
|
|
|
|
|
|
this.selectTab(selectedTab);
|
|
this.selectTab(selectedTab);
|
|
this.activateContent(activeContent);
|
|
this.activateContent(activeContent);
|
|
@@ -1122,87 +1153,51 @@ class ClassPage {
|
|
this.statistics = Statistics.init(contributionElement, Statistics.Modes.CLASS);
|
|
this.statistics = Statistics.init(contributionElement, Statistics.Modes.CLASS);
|
|
}
|
|
}
|
|
|
|
|
|
- /* >>> Context menu | TODO: move to a completely independent module? */
|
|
|
|
- showContextMenu(contextMenuType, target, pos) {
|
|
|
|
- while(!target.hasClass(contextMenuType))
|
|
|
|
|
|
+ /* >>> Context menu */
|
|
|
|
+ showContextMenu(target, pos) {
|
|
|
|
+ while(!target.hasClass('property-item'))
|
|
target = target.getParent();
|
|
target = target.getParent();
|
|
|
|
|
|
- switch(contextMenuType) {
|
|
|
|
- case ClassPage.ContextMenuType.PropertyItem:
|
|
|
|
- const propertyItemName = target.getAttribute(ClassPage.Attributes.DataPropertyName);
|
|
|
|
- const propertyItemType = target.getAttribute(ClassPage.Attributes.DataPropertyType);
|
|
|
|
- const propertyItemParent = target.getAttribute(ClassPage.Attributes.DataPropertyParent);
|
|
|
|
- const propertyItemDynamic = target.getAttribute(ClassPage.Attributes.DataPropertyDynamic);
|
|
|
|
- const propertyItemInhertied = target.getAttribute(ClassPage.Attributes.DataPropertyInherited);
|
|
|
|
- const propertyVisualName = target.getFirstChild('.property-item-name-span').getValue();
|
|
|
|
-
|
|
|
|
- if(propertyItemInhertied !== 'true') {
|
|
|
|
- this.createContextMenuItem('ShowInEditor', 'Show in Editor', () => {
|
|
|
|
- this.searchPropertyInEditor(propertyItemType === 'method', propertyItemDynamic === 'true', propertyItemName);
|
|
|
|
- });
|
|
|
|
- }
|
|
|
|
- if(propertyItemParent != null) {
|
|
|
|
- this.createContextMenuItem('MoveToParent', 'Move to parent', () => {
|
|
|
|
- Url.goTo(`/class/${propertyItemParent}#${propertyItemType === 'method' ? 'Methods' : 'Properties'}:${propertyItemName}`);
|
|
|
|
- });
|
|
|
|
- }
|
|
|
|
- if(isEditor && !target.getFirstChild('.property-item-comment-static').hasClass(ClassPage.StyleClasses.Hidden)) {
|
|
|
|
- this.createContextMenuDelimiter();
|
|
|
|
- this.createContextMenuItem('EditComment', 'Edit comment', () => {
|
|
|
|
- target.getFirstChild('.property-item-comment-static').click();
|
|
|
|
- target.getFirstChild('.property-item-comment-input').focus();
|
|
|
|
- });
|
|
|
|
- }
|
|
|
|
- this.createContextMenuDelimiter();
|
|
|
|
- this.createContextMenuItem('CopyLink', 'Copy link', () => {
|
|
|
|
- DOM.copyToClipboard(`${Url.getFullPath()}#${propertyItemType === 'method' ? 'Methods' : 'Properties'}:${propertyItemName}`);
|
|
|
|
|
|
+ const contextMenu = this.contextMenu;
|
|
|
|
+
|
|
|
|
+ const propertyItemName = target.getAttribute(ClassPage.Attributes.DataPropertyName);
|
|
|
|
+ const propertyItemType = target.getAttribute(ClassPage.Attributes.DataPropertyType);
|
|
|
|
+ const propertyItemParent = target.getAttribute(ClassPage.Attributes.DataPropertyParent);
|
|
|
|
+ const propertyItemDynamic = target.getAttribute(ClassPage.Attributes.DataPropertyDynamic);
|
|
|
|
+ const propertyItemInhertied = target.getAttribute(ClassPage.Attributes.DataPropertyInherited);
|
|
|
|
+ const propertyVisualName = target.getFirstChild('.property-item-name-span').getValue();
|
|
|
|
+
|
|
|
|
+ if(propertyItemInhertied !== 'true') {
|
|
|
|
+ contextMenu.addItem('ShowInEditor', 'Show in Editor', () => {
|
|
|
|
+ this.searchPropertyInEditor(propertyItemType === 'method', propertyItemDynamic === 'true', propertyItemName);
|
|
});
|
|
});
|
|
- this.createContextMenuDelimiter();
|
|
|
|
- this.createContextMenuItem('CopyHtmlLink', 'Copy HTML link', () => {
|
|
|
|
- let linkText = propertyVisualName;
|
|
|
|
- if(propertyItemName.startsWith(ClassPage.__static__))
|
|
|
|
- linkText = `${Class[ClassPage.ClassProperties.ShortName] || Class[ClassPage.ClassProperties.Name]}.${propertyVisualName}`;
|
|
|
|
- DOM.copyToClipboard(`<a href="${Url.getPath()}#${propertyItemType === 'method' ? 'Methods' : 'Properties'}:${propertyItemName}">${linkText}</a>`);
|
|
|
|
|
|
+ }
|
|
|
|
+ if(propertyItemParent != null) {
|
|
|
|
+ contextMenu.addItem('MoveToParent', 'Move to parent', () => {
|
|
|
|
+ Url.goTo(`/class/${propertyItemParent}#${propertyItemType === 'method' ? 'Methods' : 'Properties'}:${propertyItemName}`);
|
|
});
|
|
});
|
|
- break;
|
|
|
|
}
|
|
}
|
|
-
|
|
|
|
- this.contextMenu.style('left', `${pos.x}px`).style('top', `${pos.y}px`);
|
|
|
|
- this.contextMenu.removeClass(ClassPage.StyleClasses.Hidden);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- createContextMenuItem(name, text, action) {
|
|
|
|
- const itemAction = (e) => {
|
|
|
|
- action(e);
|
|
|
|
- this.hideContextMenu();
|
|
|
|
- };
|
|
|
|
- const item = DOM.create({ tag: DOM.Tags.Div, cls: 'context-menu-item', innerHTML: text, attr: { 'data-context-menu-item-name': name } }, this.contextMenu)
|
|
|
|
- .on(DOM.Events.Click, itemAction);
|
|
|
|
- this.contextMenuItems[name] = { item: item, action: itemAction };
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- createContextMenuDelimiter() {
|
|
|
|
- DOM.create({ tag: DOM.Tags.Div, cls: 'context-menu-delimiter' }, this.contextMenu);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- clearContextMenu() {
|
|
|
|
- for(const item of this.contextMenu.getChildren()) {
|
|
|
|
- const name = item.getAttribute('data-context-menu-item-name');
|
|
|
|
- if(name) {
|
|
|
|
- const action = this.contextMenuItems[name].action;
|
|
|
|
- item.un(DOM.Events.Click, action);
|
|
|
|
- this.contextMenuItems[name] = null;
|
|
|
|
- delete this.contextMenuItems[name];
|
|
|
|
- }
|
|
|
|
- item.remove();
|
|
|
|
|
|
+ if(isEditor && !target.getFirstChild('.property-item-comment-static').hasClass(ClassPage.StyleClasses.Hidden)) {
|
|
|
|
+ contextMenu.addDelimiter();
|
|
|
|
+ contextMenu.addItem('EditComment', 'Edit comment', () => {
|
|
|
|
+ target.getFirstChild('.property-item-comment-static').click();
|
|
|
|
+ target.getFirstChild('.property-item-comment-input').focus();
|
|
|
|
+ });
|
|
}
|
|
}
|
|
- }
|
|
|
|
|
|
+ contextMenu.addDelimiter();
|
|
|
|
+ contextMenu.addItem('CopyLink', 'Copy link', () => {
|
|
|
|
+ DOM.copyToClipboard(`${Url.getFullPath()}#${propertyItemType === 'method' ? 'Methods' : 'Properties'}:${propertyItemName}`);
|
|
|
|
+ });
|
|
|
|
+ contextMenu.addDelimiter();
|
|
|
|
+ contextMenu.addItem('CopyHtmlLink', 'Copy HTML link', () => {
|
|
|
|
+ let linkText = propertyVisualName;
|
|
|
|
+ if(propertyItemName.startsWith(ClassPage.__static__))
|
|
|
|
+ linkText = `${Class[ClassPage.ClassProperties.ShortName] || Class[ClassPage.ClassProperties.Name]}.${propertyVisualName}`;
|
|
|
|
+ DOM.copyToClipboard(`<a href="${Url.getPath()}#${propertyItemType === 'method' ? 'Methods' : 'Properties'}:${propertyItemName}">${linkText}</a>`);
|
|
|
|
+ });
|
|
|
|
|
|
- hideContextMenu() {
|
|
|
|
- this.contextMenu.addClass(ClassPage.StyleClasses.Hidden);
|
|
|
|
- this.clearContextMenu();
|
|
|
|
|
|
+ contextMenu.show(pos);
|
|
}
|
|
}
|
|
-
|
|
|
|
/* <<< Context menu */
|
|
/* <<< Context menu */
|
|
};
|
|
};
|
|
|
|
|
|
@@ -1211,6 +1206,8 @@ window_.on(DOM.Events.Load, (e) => {
|
|
});
|
|
});
|
|
|
|
|
|
window_.on(DOM.Events.KeyDown, (e) => {
|
|
window_.on(DOM.Events.KeyDown, (e) => {
|
|
|
|
+ if(Class.isPackage)
|
|
|
|
+ return;
|
|
if(window.page && e.key === DOM.Keys.Control)
|
|
if(window.page && e.key === DOM.Keys.Control)
|
|
window.page.codeMirrorEditorElement.addClass(ClassPage.StyleClasses.CtrlPressed);
|
|
window.page.codeMirrorEditorElement.addClass(ClassPage.StyleClasses.CtrlPressed);
|
|
if(window.page && e.key === DOM.Keys.Shift)
|
|
if(window.page && e.key === DOM.Keys.Shift)
|
|
@@ -1218,6 +1215,8 @@ window_.on(DOM.Events.KeyDown, (e) => {
|
|
});
|
|
});
|
|
|
|
|
|
window_.on(DOM.Events.KeyUp, (e) => {
|
|
window_.on(DOM.Events.KeyUp, (e) => {
|
|
|
|
+ if(Class.isPackage)
|
|
|
|
+ return;
|
|
if(window.page && e.key === DOM.Keys.Control)
|
|
if(window.page && e.key === DOM.Keys.Control)
|
|
window.page.codeMirrorEditorElement.removeClass(ClassPage.StyleClasses.CtrlPressed);
|
|
window.page.codeMirrorEditorElement.removeClass(ClassPage.StyleClasses.CtrlPressed);
|
|
if(window.page && e.key === DOM.Keys.Shift)
|
|
if(window.page && e.key === DOM.Keys.Shift)
|
|
@@ -1227,20 +1226,4 @@ window_.on(DOM.Events.KeyUp, (e) => {
|
|
window_.on(DOM.Events.HashChange, (e) => {
|
|
window_.on(DOM.Events.HashChange, (e) => {
|
|
if(window.page)
|
|
if(window.page)
|
|
window.page.applyHash();
|
|
window.page.applyHash();
|
|
-});
|
|
|
|
-
|
|
|
|
-window_.on(DOM.Events.MouseDown, (e) => {
|
|
|
|
- if(window.page) {
|
|
|
|
- let target = CDElement.get(e.target);
|
|
|
|
-
|
|
|
|
- while(target != null && !target.hasClass('context-menu')) {
|
|
|
|
- target = target.getParent();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if(target != null && target.hasClass('context-menu'))
|
|
|
|
- return;
|
|
|
|
-
|
|
|
|
- if(!window.page.contextMenu.hasClass(ClassPage.StyleClasses.Hidden))
|
|
|
|
- window.page.hideContextMenu();
|
|
|
|
- }
|
|
|
|
});
|
|
});
|