1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255 |
- class ClassPage {
- static ModeCookieName = 'doczilla-js-docs-class-page-mode';
- static Mode = {
- Tabs: 'mode-tabs',
- List: 'mode-list'
- };
- static StyleClasses = {
- Selected: 'selected',
- Active: 'active',
- CtrlPressed: 'ctrl-pressed',
- ShiftPressed: 'shift-pressed',
- ParentsBranch: 'parents-branch',
- ClassItem: 'class-item',
- ClassName: 'class-name',
- ClassIcon: 'class-icon',
- Filler: 'filler',
- FullSourcePrompt: 'full-source-prompt',
- FullSourcePromptText: 'full-source-prompt-text',
- FullSourcePromptButton: 'full-source-prompt-button',
- Spacing: 'spacing',
- CmLink: 'cm-link',
- Z8Locale: 'z8-locale',
- Hidden: 'hidden',
- Collapsed: 'collapsed',
- Highlighted: 'highlighted',
- Readonly: 'readonly',
- Clickable: 'clickable',
- Empty: 'empty',
- White: 'white'
- };
- static Attributes = {
- DataTab: 'data-tab',
- DataDisplayMode: 'data-display-mode',
- DataClassName: 'data-class-name',
- OnClick: 'onclick',
- DataPropertyName: 'data-property-name',
- DataPropertyType: 'data-property-type',
- DataPropertyParent: 'data-property-parent',
- DataPropertyInherited: 'data-property-inherited',
- DataPropertyDynamic: 'data-property-dynamic'
- };
- static Messages = {
- NoMixins: 'This class has no mixins.',
- NoChildren: 'This class has no child classes.',
- NoMixedIn: 'This class is not mixed in any classes.',
- NoParents: 'This is a base class, which has no parent classes.',
- ShowFullSourceText: 'There were found another entities in the source file of this class. Would you like to see full source file?',
- HideFullSourceText: 'Full source file shown. Would you like to hide all entities except the target class?',
- PromptButtonText: 'OK',
- CmLinkTipPrefix: 'Ctrl+Click to go to class'
- };
- static TabNames = {
- Editor: 'Editor',
- Methods: 'Methods',
- Parents: 'Parents',
- Properties: 'Properties',
- Mixins: 'Mixins',
- Children: 'Children',
- MixedIn: 'MixedIn',
- Info: 'Info',
- Contribution: 'Contribution'
- };
- static PropertyType = {
- Statics: 'statics',
- Base: 'base',
- Overridden: 'overridden',
- Dynamic: 'dynamic',
- Inherited: 'inherited',
- ClassComment: 'ClassComment'
- };
- static PropertyLabel = {
- Statics: 'Static properties',
- Base: 'Base properties',
- Overridden: 'Overridden properties',
- Dynamic: 'Dynamic properties',
- Inherited: 'Inherited properties'
- };
- static MethodLabel = {
- Statics: 'Static methods',
- Base: 'Base methods',
- Overridden: 'Overridden methods',
- Dynamic: 'Dynamic methods',
- Inherited: 'Inherited methods'
- };
- static ClassProperties = {
- Name: 'name',
- Methods: 'methods',
- Properties: 'properties',
- Children: 'children',
- Mixins: 'mixins',
- MixedIn: 'mixedIn',
- ParentsBranch: 'parentsBranch',
- Statics: 'statics',
- DynamicProperties: 'dynamicProperties',
- Root: 'root',
- ShortName: 'shortName'
- };
- static __static__ = '__static__';
- static __self__ = '__self__';
- start() {
- if(!Class[ClassPage.ClassProperties.Root]) {
- return this;
- }
- this.tabElements = {
- [ClassPage.TabNames.Editor]: DOM.get('.tab.editor'),
- [ClassPage.TabNames.Methods]: DOM.get('.tab.methods'),
- [ClassPage.TabNames.Parents]: DOM.get('.tab.parents'),
- [ClassPage.TabNames.Properties]: DOM.get('.tab.properties'),
- [ClassPage.TabNames.Mixins]: DOM.get('.tab.mixins'),
- [ClassPage.TabNames.Children]: DOM.get('.tab.children'),
- [ClassPage.TabNames.MixedIn]: DOM.get('.tab.mixedin'),
- [ClassPage.TabNames.Info]: DOM.get('.tab.info')
- };
-
- this.contentElements = {
- [ClassPage.TabNames.Editor]: DOM.get('.content-tab#editor'),
- [ClassPage.TabNames.Methods]: DOM.get('.content-tab#methods'),
- [ClassPage.TabNames.Parents]: DOM.get('.content-tab#parents'),
- [ClassPage.TabNames.Properties]: DOM.get('.content-tab#properties'),
- [ClassPage.TabNames.Mixins]: DOM.get('.content-tab#mixins'),
- [ClassPage.TabNames.Children]: DOM.get('.content-tab#children'),
- [ClassPage.TabNames.MixedIn]: DOM.get('.content-tab#mixedin'),
- [ClassPage.TabNames.Info]: DOM.get('.content-tab#info')
- };
- if(isEditor) {
- this.tabElements[ClassPage.TabNames.Contribution] = DOM.get('.tab.contribution');
- this.contentElements[ClassPage.TabNames.Contribution] = DOM.get('.content-tab#contribution');
- }
- this.documented = 0; //Object.keys(Comments).filter((key) => { return Comments[key].text.length > 0; }).length;
- this.documentable = 1; // __self__ property is always included
- this.inheritedCommentsQuery = {};
- this.inheritedCommentsFields = {};
- this.propertyItemElements = {};
- this.documentedPercentage = DOM.get('.class-documented-percentage');
- const rightContainer = this.rightContainer = DOM.get('.right');
- const modeCookieValue = DOM.getCookieProperty(App.CookieName, ClassPage.ModeCookieName);
-
- if(!modeCookieValue)
- DOM.setCookieProperty(App.CookieName, ClassPage.ModeCookieName, ClassPage.Mode.Tabs);
- const mode = this.mode = modeCookieValue || ClassPage.Mode.Tabs;
- const tabsModeButton = this.tabsModeButton = DOM.get('.display-mode-button.mode-tabs');
- const listModeButton = this.listModeButton = DOM.get('.display-mode-button.mode-list');
- this.contextMenu = ContextMenu.init();
- (mode === ClassPage.Mode.Tabs ? tabsModeButton : listModeButton).addClass(ClassPage.StyleClasses.Selected);
- rightContainer.addClass(mode);
- this.loadDocumentedInfo();
- this.renderContent();
- this.markContentInEditor();
- this.registerEventListeners();
- this.applyHash();
- this.openSocket();
- return this;
- }
- switchMode(mode) {
- this.rightContainer.removeClass(this.mode);
- this.mode = mode;
- DOM.setCookieProperty(App.CookieName, ClassPage.ModeCookieName, mode);
- this.rightContainer.addClass(mode);
- if(!Class.isPackage)
- this.codeMirrorEditor.cmRefresh();
- }
- selectTab(tab) {
- tab = typeof tab === 'string' ? this.tabElements[tab] : tab;
- const selectedTab = this.selectedTab;
- let filler = selectedTab ? selectedTab.getFirstChild('.filler') : null;
- if(!filler)
- filler = DOM.create({ tag: DOM.Tags.Div, cls: ClassPage.StyleClasses.Filler });
- selectedTab && selectedTab.removeClass(ClassPage.StyleClasses.Selected);
- this.selectedTab = tab.addClass(ClassPage.StyleClasses.Selected);
- this.selectedTab.append(filler);
- }
- activateContent(content) {
- content = typeof content === 'string' ? this.contentElements[content] : content;
- if(this.activeContent)
- this.activeContent.removeClass(ClassPage.StyleClasses.Active);
- this.activeContent = content.addClass(ClassPage.StyleClasses.Active);
- if(content === this.contentElements[ClassPage.TabNames.Editor])
- this.codeMirrorEditor.cmRefresh();
- if(content === this.contentElements[ClassPage.TabNames.Properties] || content === this.contentElements[ClassPage.TabNames.Methods])
- DOM.getAll('.property-item-comment-input').forEach((item) => {
- item.style('height', `${Math.min(422, item.get().scrollHeight + 2)}px`);
- });
- }
- registerEventListeners() {
- this.registerTabsEventListeners();
- this.registerModeButtonsEventListeners();
- }
- registerTabsEventListeners() {
- const tabElements = this.tabElements;
- for(const tabName of Object.keys(tabElements)) {
- if(tabElements[tabName])
- tabElements[tabName].on(DOM.Events.Click, this.onTabClick.bind(this));
- }
- }
- registerModeButtonsEventListeners() {
- this.tabsModeButton.on(DOM.Events.Click, this.onModeButtonClick.bind(this));
- this.listModeButton.on(DOM.Events.Click, this.onModeButtonClick.bind(this));
- }
- prepareSource() {
- const className = Class[ClassPage.ClassProperties.Name].replaceAll('.', '\\.');
- const classRx = new RegExp(`Z8\\.define\\(\'${className}\',\\s*\\{(?:.|[\r\n])+?^\\}\\);?`, 'gm');
- const classSourceMatch = ClassSource.match(classRx);
- if(!classSourceMatch) { // remove after `}\n);` issue fixed...
- this.sourceHasAnotherEntities = false;
- return this.classSource = ClassSource;
- }
- const classSource = this.classSource = classSourceMatch[0];
- this.sourceHasAnotherEntities = ClassSource.trim() !== classSource;
- return classSource;
- }
- renderContent() {
- if(!Class.isPackage) {
- this.renderEditor();
- this.renderParents();
- this.renderMixins();
- this.renderChildren();
- this.renderMixedIn();
- this.renderProperties();
- this.renderMethods();
- this.loadInheritedComments();
- if(isEditor)
- this.renderContribution();
- }
- this.renderDocumentedPercentage();
- this.renderInfo();
- }
- renderDocumentedPercentage() {
- this.documentedPercentage.setInnerHTML(`${Math.round(this.documented/this.documentable * 10000) / 100}%`);
- }
- renderEditor() {
- this.codeMirrorEditor = CodeMirror(DOM.get('#editor').get(), {
- [App.CodeMirrorProperties.Value]: this.prepareSource(ClassSource),
- [App.CodeMirrorProperties.Mode]: 'javascript',
- [App.CodeMirrorProperties.Theme]: 'darcula',
- [App.CodeMirrorProperties.Readonly]: true,
- [App.CodeMirrorProperties.LineNumbers]: true,
- [App.CodeMirrorProperties.MatchBrackets]: true,
- [App.CodeMirrorProperties.ScrollbarStyle]: 'overlay',
- [App.CodeMirrorProperties.ConfigureMouse]: (cm, repeat, ev) => {
- return { 'addNew': false };
- },
- });
- if(this.sourceHasAnotherEntities)
- this.renderFullSourcePrompt();
- this.codeMirrorEditorElement = DOM.get('.CodeMirror');
- }
- renderProperties() {
- const propertiesElement = this.contentElements[ClassPage.TabNames.Properties];
- const properties = this.getProperties(false);
-
- this.renderPropertiesType(properties, ClassPage.PropertyType.Statics, ClassPage.PropertyLabel.Statics, propertiesElement, false, false);
- this.renderPropertiesType(properties, ClassPage.PropertyType.Base, ClassPage.PropertyLabel.Base, propertiesElement, false, false);
- this.renderPropertiesType(properties, ClassPage.PropertyType.Overridden, ClassPage.PropertyLabel.Overridden, propertiesElement, false, false);
- this.renderPropertiesType(properties, ClassPage.PropertyType.Dynamic, ClassPage.PropertyLabel.Dynamic, propertiesElement, false, false);
- this.renderPropertiesType(properties, ClassPage.PropertyType.Inherited, ClassPage.PropertyLabel.Inherited, propertiesElement, true, false);
- }
- renderMethods() {
- const methodsElement = this.contentElements[ClassPage.TabNames.Methods];
- const properties = this.getProperties(true);
- this.renderPropertiesType(properties, ClassPage.PropertyType.Statics, ClassPage.MethodLabel.Statics, methodsElement, false, true);
- this.renderPropertiesType(properties, ClassPage.PropertyType.Base, ClassPage.MethodLabel.Base, methodsElement, false, true);
- this.renderPropertiesType(properties, ClassPage.PropertyType.Overridden, ClassPage.MethodLabel.Overridden, methodsElement, false, true);
- this.renderPropertiesType(properties, ClassPage.PropertyType.Dynamic, ClassPage.MethodLabel.Dynamic, methodsElement, false, true);
- this.renderPropertiesType(properties, ClassPage.PropertyType.Inherited, ClassPage.MethodLabel.Inherited, methodsElement, true, true);
- }
- // TODO: refactor! Make PropertyItem class
- renderPropertiesType(properties, type, headerText, container, initiallyHidden, isMethods) {
- const isStatics = type === ClassPage.PropertyType.Statics;
- const isInherited = type === ClassPage.PropertyType.Inherited;
- properties = properties[type];
- if(!properties || properties.length == 0)
- return;
- const propertyItemClickable = (element) => {
- let el = element;
- while(!el.hasClass('property-item-comment-static') && !el.hasClass('property-item'))
- el = el.getParent();
- return element.hasClass('property-item-nearest-parent-span')
- || element.hasClass('property-item-comment-input')
- || element.hasClass('property-item-comment-button')
- || element.hasClass('property-item-saving-filler')
- || (el.hasClass('property-item-comment-static') && el.hasClass(ClassPage.StyleClasses.Clickable))
- || element.getTag() === DOM.Tags.A;
- };
- if(!isInherited) {
- this.documentable += properties.length;
- } else {
- const inheritedCommentsQuery = this.inheritedCommentsQuery;
- properties.forEach((prop) => {
- if(inheritedCommentsQuery[prop.nearestParent]) {
- inheritedCommentsQuery[prop.nearestParent].properties.push(prop.key);
- } else {
- inheritedCommentsQuery[prop.nearestParent] = { root: prop.nearestParentRoot, className: prop.nearestParent, properties: [prop.key] };
- }
- });
- }
- const propertiesHeaderText = DOM.create({ tag: DOM.Tags.Span, cls: 'properties-header-text', innerHTML: headerText });
- const propertiesHeaderCollapsedIcon = DOM.create({ tag: DOM.Tags.Div, cls: 'properties-header-collapsed-icon' });
- const propertiesHeader = DOM.create({ tag: DOM.Tags.Div, cls: 'properties-header', cn: [propertiesHeaderText, propertiesHeaderCollapsedIcon] }, container);
- const propertiesList = DOM.create({ tag: DOM.Tags.Div, cls: 'properties-list' }, container);
-
- if(initiallyHidden) {
- propertiesList.addClass(ClassPage.StyleClasses.Hidden);
- propertiesHeader.addClass(ClassPage.StyleClasses.Collapsed);
- }
- for(const property of properties) {
- const onMouseDown = (e) => {
- const element = CDElement.get(e.target);
- const key = isStatics ? `${ClassPage.__static__}${property.key}` : property.key;
- if(e.buttons === DOM.MouseButtons.Right) {
- if(element.hasClass('property-item-saving-filler'))
- return;
- setTimeout(() => {
- this.showContextMenu(element, { x: e.pageX, y: e.pageY });
- }, 10);
- } else if (e.buttons === DOM.MouseButtons.Left) {
- if(propertyItemClickable(element))
- return;
- if(type === ClassPage.PropertyType.Inherited) {
- Url.goTo(`/class/${property.nearestParent}#${isMethods ? 'Methods' : 'Properties'}:${key}`);
- } else {
- this.searchPropertyInEditor(isMethods, property.dynamic, key);
- }
- }
- }
- 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) => {
- propertiesList.switchClass(ClassPage.StyleClasses.Hidden);
- propertiesHeader.switchClass(ClassPage.StyleClasses.Collapsed);
- });
- }
- 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) {
- 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') });
- return DOM.create({ tag: DOM.Tags.Div, cls: 'property-item-comment-date', cn: [commentDateText, commentDateDate] });
- }
- loadInheritedComments() {
- if(Object.keys(this.inheritedCommentsQuery).length === 0 || Object.keys(this.inheritedCommentsFields).length === 0)
- return;
- fetch('/getInheritedComments', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/x-www-form-urlencoded'
- },
- body: new URLSearchParams({
- query: JSON.stringify(this.inheritedCommentsQuery)
- })
- }).then(res => res.json()).then((inheritedComments) => {
- for(const cls of Object.keys(inheritedComments)) {
- const props = inheritedComments[cls];
- for(const prop of Object.keys(props)) {
- const element = this.inheritedCommentsFields[`${cls}:${prop}`];
- if(element) {
- element.setInnerHTML(props[prop].text);
- element.removeClass(ClassPage.StyleClasses.Empty);
- element.getParent().append(this.createCommentDateElement(props[prop].timestamp, props[prop].author));
- }
- }
- }
- });
- }
- getProperties(methods) {
- const filter = methods ? (item) => item.type === 'method' : (item) => item.type !== 'method';
- const statics = Class[ClassPage.ClassProperties.Statics].filter(filter);
- const properties = Class[ClassPage.ClassProperties.Properties].sort((a, b) => a.key.toLowerCase().localeCompare(b.key.toLowerCase())).sort((a, b) => {
- return Class[ClassPage.ClassProperties.ParentsBranch].indexOf(a.nearestParent) > Class[ClassPage.ClassProperties.ParentsBranch].indexOf(b.nearestParent) ? -1 : 1;
- }).filter(filter);
- const dynamicProperties = methods ? [] : Class[ClassPage.ClassProperties.DynamicProperties];
- const result = {
- [ClassPage.PropertyType.Statics]: statics,
- [ClassPage.PropertyType.Base]: properties.filter((item) => !item.inherited),
- [ClassPage.PropertyType.Overridden]: properties.filter((item) => item.overridden),
- [ClassPage.PropertyType.Inherited]: properties.filter((item) => item.inherited && !item.overridden),
- [ClassPage.PropertyType.Dynamic]: dynamicProperties
- };
- return result;
- }
- renderMixins() {
- const mixinsElement = this.contentElements[ClassPage.TabNames.Mixins];
- if(Class[ClassPage.ClassProperties.Mixins].length == 0) {
- DOM.create({ tag: DOM.Tags.Div, style: 'font-size: 24px;', innerHTML: ClassPage.Messages.NoMixins }, mixinsElement);
- mixinsElement.addClass(ClassPage.StyleClasses.Empty);
- return;
- }
- this.renderClassItems(Class[ClassPage.ClassProperties.Mixins], mixinsElement);
- }
- renderChildren() {
- const childrenElement = this.contentElements[ClassPage.TabNames.Children];
- if(Class[ClassPage.ClassProperties.Children].length == 0) {
- DOM.create({ tag: DOM.Tags.Div, style: 'font-size: 24px;', innerHTML: ClassPage.Messages.NoChildren }, childrenElement);
- childrenElement.addClass(ClassPage.StyleClasses.Empty);
- return;
- }
- this.renderClassItems(Class[ClassPage.ClassProperties.Children], childrenElement);
- }
- renderMixedIn() {
- const mixedInElement = this.contentElements[ClassPage.TabNames.MixedIn];
- if(Class[ClassPage.ClassProperties.MixedIn].length == 0) {
- DOM.create({ tag: DOM.Tags.Div, style: 'font-size: 24px;', innerHTML: ClassPage.Messages.NoMixedIn }, mixedInElement);
- mixedInElement.addClass(ClassPage.StyleClasses.Empty);
- return;
- }
- this.renderClassItems(Class[ClassPage.ClassProperties.MixedIn], mixedInElement);
- }
- renderInfo() {
- const infoContainer = this.contentElements[ClassPage.TabNames.Info];
- 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() {
- const editorContent = this.contentElements[ClassPage.TabNames.Editor];
- const prompt = DOM.create({ tag: DOM.Tags.Div, cls: ClassPage.StyleClasses.FullSourcePrompt }, editorContent);
- const text = this.fullSourcePromptText = DOM.create({ tag: DOM.Tags.Div, cls: ClassPage.StyleClasses.FullSourcePromptText, innerHTML: ClassPage.Messages.ShowFullSourceText }, prompt);
- const button = DOM.create({ tag: DOM.Tags.Div, cls: ClassPage.StyleClasses.FullSourcePromptButton, innerHTML: ClassPage.Messages.PromptButtonText }, prompt);
- const onButtonClick = (e) => {
- this.switchFullSource();
- };
- button.on(DOM.Events.Click, onButtonClick.bind(this));
- }
- switchFullSource(show) {
- const shown = this.fullSourceCodeShown = show !== undefined ? !show : !this.fullSourceCodeShown;
- this.codeMirrorEditor.cmSetValue(shown ? ClassSource : this.classSource);
- if(shown)
- this.findAndScrollToTargetClass();
- this.codeMirrorEditor.cmRefresh();
- this.markContentInEditor();
- this.fullSourcePromptText && this.fullSourcePromptText.setInnerHTML(shown ? ClassPage.Messages.HideFullSourceText : ClassPage.Messages.ShowFullSourceText);
- return shown;
- }
- markContentInEditor() {
- if(Class.isPackage)
- return;
- const staticsRange = this.getStaticsRange();
- this.codeMirrorEditor.cmEachLine((lineHandle) => {
- this.markExtend(lineHandle);
- this.markMixins(lineHandle);
- this.markZ8Locales(lineHandle);
- this.markNew(lineHandle);
- this.markThis(lineHandle);
- this.markProperties(lineHandle, staticsRange);
- });
- }
- findAndScrollToTargetClass() {
- const className = Class[ClassPage.ClassProperties.Name].replaceAll('.', '\\.');
- const editor = this.codeMirrorEditor;
- const defineRx = new RegExp(`Z8\\.define\\(\'${className}\',`);
- editor.cmEachLine((lineHandle) => {
- const text = lineHandle.text;
- const match = text.match(defineRx);
- if(match) {
- editor.scrollIntoView({ line: lineHandle.lineNo(), ch: 0 }, 100);
- return;
- }
- });
- }
- renderParents() {
- const parentsContent = this.contentElements[ClassPage.TabNames.Parents];
- const parentsContainer = DOM.create({ tag: DOM.Tags.Div, cls: ClassPage.StyleClasses.ParentsBranch }, parentsContent);
- if(Class[ClassPage.ClassProperties.ParentsBranch].length == 0) {
- DOM.create({ tag: DOM.Tags.Div, style: 'font-size: 24px;', innerHTML: ClassPage.Messages.NoParents }, parentsContent);
- parentsContent.addClass(ClassPage.StyleClasses.Empty);
- return;
- }
- this.renderClassItems(Class[ClassPage.ClassProperties.ParentsBranch], parentsContainer, true);
- }
- renderClassItems(itemsList, container, withIndent) {
- let indent = 0;
- if(!withIndent)
- itemsList = itemsList.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
- for(const cls of itemsList) {
- const icon = DOM.create({ tag: DOM.Tags.Div, cls: ClassPage.StyleClasses.ClassIcon });
- const name = DOM.create({ tag: DOM.Tags.Div, cls: ClassPage.StyleClasses.ClassName, innerHTML: cls });
- const cn = [icon, name];
- if(indent > 0 && withIndent)
- cn.unshift(DOM.create({ tag: DOM.Tags.Div, cls: ClassPage.StyleClasses.Spacing, style: `width: ${10 * indent}px;` }));
- DOM.create({ tag: DOM.Tags.Div, cls: `${ClassPage.StyleClasses.ClassItem}${ withIndent ? ' indent' : '' }`, attr: { [ClassPage.Attributes.DataClassName]: cls }, cn: cn }, container).on(DOM.Events.Click, this.onClassClick.bind(this));
- indent++;
- }
- }
- markExtend(lineHandle) {
- const editor = this.codeMirrorEditor;
- const text = lineHandle.text;
- const match = text.match(/extend:\s*['"]?([\w\.]+)['"]?/);
- if (match) {
- const className = match[1];
- const from = { line: lineHandle.lineNo(), ch: match.index + 8 };
- const to = { line: lineHandle.lineNo(), ch: match.index + match[0].length };
- editor.markText(from, to, {
- className: ClassPage.StyleClasses.CmLink,
- title: `${ClassPage.Messages.CmLinkTipPrefix} ${className}`,
- attributes: {
- [ClassPage.Attributes.DataClassName]: className,
- [ClassPage.Attributes.OnClick]: 'window.page.onClassLinkClick(this);'
- }
- });
- }
- }
- markMixins(lineHandle) {
- const editor = this.codeMirrorEditor;
- const text = lineHandle.text;
- const match = text.match(/mixins:\s*(\[.*?\]|\w+)/);
- if (match) {
- let mixins = match[1].replace(/\[|\]/g, "").split(/\s*,\s*/);
- const mixinsStr = match[1].replace(/\[|\]/g, "");
- mixins = mixinsStr.split(/\s*,\s*/);
- const startIndex = match.index + match[0].indexOf(mixinsStr);
- for (var i = 0; i < mixins.length; i++) {
- const className = mixins[i].trim().replace(/^['"]|['"]$/g, "");
- const classIndex = mixinsStr.indexOf(className);
- const from = { line: lineHandle.lineNo(), ch: startIndex + classIndex };
- const to = { line: lineHandle.lineNo(), ch: startIndex + classIndex + className.length };
- editor.markText(from, to, {
- className: ClassPage.StyleClasses.CmLink,
- title: `${ClassPage.Messages.CmLinkTipPrefix} ${className}`,
- attributes: {
- [ClassPage.Attributes.DataClassName]: className,
- [ClassPage.Attributes.OnClick]: 'window.page.onClassLinkClick(this);'
- }
- });
- }
- }
- }
- markZ8Locales(lineHandle) {
- const editor = this.codeMirrorEditor;
- const text = lineHandle.text;
- const regexp = /Z8\.\$\('([\S]+)'(?:\s*,\s*.*)?\)/g;
- let match;
- while ((match = regexp.exec(text)) !== null) {
- const messageId = match[1];
- const from = { line: lineHandle.lineNo(), ch: match.index };
- const to = { line: lineHandle.lineNo(), ch: match.index + match[0].length };
- editor.markText(from, to, {
- className: ClassPage.StyleClasses.Z8Locale,
- title: `RU: ${Z8Locales['ru'][messageId]}\nEN: ${Z8Locales['en'][messageId]}`
- });
- }
- }
- markNew(lineHandle) {
- const editor = this.codeMirrorEditor;
- const text = lineHandle.text;
- const regexp = /new\s+([\w\.]+)/g;
- let match;
- while ((match = regexp.exec(text)) !== null) {
- const className = match[1];
- const from = { line: lineHandle.lineNo(), ch: match.index + 4 };
- const to = { line: lineHandle.lineNo(), ch: match.index + match[0].length };
-
- if(!ClassList[className] && !this.shortNameExists(className))
- continue;
-
- editor.markText(from, to, {
- className: ClassPage.StyleClasses.CmLink,
- title: `${ClassPage.Messages.CmLinkTipPrefix} ${className}`,
- attributes: {
- [ClassPage.Attributes.DataClassName]: className,
- [ClassPage.Attributes.OnClick]: 'window.page.onClassLinkClick(this);'
- }
- });
- }
- }
- markThis(lineHandle) {
- const editor = this.codeMirrorEditor;
- const text = lineHandle.text;
- const regexp = /this\.([\w]+)/g;
- let match;
- while ((match = regexp.exec(text)) !== null) {
- const propertyName = match[1];
- const from = { line: lineHandle.lineNo(), ch: match.index + 5 };
- const to = { line: lineHandle.lineNo(), ch: match.index + match[0].length };
-
- const foundProperty = this.findClassProperty(propertyName);
- if(!foundProperty)
- continue;
-
- editor.markText(from, to, {
- className: 'cm-this-prop',
- title: `Ctrl+Click to go to ${foundProperty.type === 'method' ? 'method' : 'property'} '${propertyName}'`,
- attributes: {
- [ClassPage.Attributes.DataPropertyName]: propertyName,
- [ClassPage.Attributes.DataPropertyType]: foundProperty.type === 'method' ? 'Methods' : 'Properties',
- [ClassPage.Attributes.DataPropertyParent]: foundProperty.inherited ? foundProperty.nearestParent : '',
- [ClassPage.Attributes.OnClick]: 'window.page.onPropertyClick(this);'
- }
- });
- }
- }
- markProperties(lineHandle, staticsRange) {
- const editor = this.codeMirrorEditor;
- const text = lineHandle.text;
- const lineNo = lineHandle.lineNo();
- const regexp = /\t([\w]+):/g;
- const isStatic = lineNo >= staticsRange.from && lineNo <= staticsRange.to;
- let match;
- while ((match = regexp.exec(text)) !== null) {
- const propertyName = isStatic ? `${ClassPage.__static__}${match[1]}` : match[1];
- const from = { line: lineNo, ch: match.index + 1 };
- const to = { line: lineNo, ch: match.index + match[0].length - 1 };
-
- const foundProperty = this.findClassProperty(propertyName);
- if(!foundProperty)
- continue;
- const titlePropertyName = isStatic ? `${Class[ClassPage.ClassProperties.ShortName] || Class[ClassPage.ClassProperties.Name]}.${propertyName.replace(ClassPage.__static__, '')}` : propertyName;
- editor.markText(from, to, {
- className: 'cm-this-prop',
- title: `Ctrl+Click to go to ${foundProperty.type === 'method' ? 'method' : 'property'} '${titlePropertyName}'`,
- attributes: {
- [ClassPage.Attributes.DataPropertyName]: propertyName,
- [ClassPage.Attributes.DataPropertyType]: foundProperty.type === 'method' ? 'Methods' : 'Properties',
- [ClassPage.Attributes.DataPropertyParent]: foundProperty.inherited && !foundProperty.overridden ? foundProperty.nearestParent : '',
- [ClassPage.Attributes.OnClick]: 'window.page.onPropertyClick(this);'
- }
- });
- }
- }
- getStaticsRange() {
- const range = { from: -1, to: -1 };
- let staticsParenthesisFlag = -1;
- let found = false;
- this.codeMirrorEditor.cmEachLine((lineHandle) => {
- if(found)
- return;
- const text = lineHandle.text;
- let ignoreFirstParenthesis = false;
- if(staticsParenthesisFlag === -1 && text.match(/statics:\s*\{/)) {
- staticsParenthesisFlag = 1;
- ignoreFirstParenthesis = true;
- range.from = lineHandle.lineNo();
- }
- if(staticsParenthesisFlag > 0) {
- for(let i = 0; i < text.length; i++) {
- if(text.charAt(i) === '{' && ignoreFirstParenthesis)
- ignoreFirstParenthesis = false;
- else if (text.charAt(i) === '{')
- staticsParenthesisFlag++;
- else if(text.charAt(i) === '}')
- staticsParenthesisFlag--;
- }
- }
- if(staticsParenthesisFlag === 0) {
- range.to = lineHandle.lineNo();
- found = true;
- }
- });
- return range;
- }
- shortNameExists(shortName) {
- return Object.keys(ClassList).map((key) => ClassList[key]).filter((item) => item[ClassPage.ClassProperties.ShortName] === shortName).length > 0;
- }
- findClassProperty(propertyName) {
- if(propertyName.startsWith(ClassPage.__static__)) {
- propertyName = propertyName.slice(10);
- const statics = Class[ClassPage.ClassProperties.Statics];
- const foundStatic = statics.filter((prop) => prop.key === propertyName)[0];
- return foundStatic;
- }
- const dynamicProperties = Class[ClassPage.ClassProperties.DynamicProperties];
- const properties = Class[ClassPage.ClassProperties.Properties];
- const foundDynamic = dynamicProperties.filter((prop) => prop.key === propertyName)[0];
- const foundProperty = properties.filter((prop) => prop.key === propertyName)[0];
- return foundDynamic || foundProperty;
- }
- onClassLinkClick(fragment) {
- const codeMirrorEditorElement = this.codeMirrorEditorElement;
- if(codeMirrorEditorElement.hasClass(ClassPage.StyleClasses.CtrlPressed))
- Url.goTo(`/class/${fragment.getAttribute(ClassPage.Attributes.DataClassName)}`, codeMirrorEditorElement.hasClass(ClassPage.StyleClasses.ShiftPressed));
- }
- onPropertyClick(fragment) {
- const codeMirrorEditorElement = this.codeMirrorEditorElement;
- if(codeMirrorEditorElement.hasClass(ClassPage.StyleClasses.CtrlPressed)) {
- const parentClassName = fragment.getAttribute(ClassPage.Attributes.DataPropertyParent);
- const propertyType = fragment.getAttribute(ClassPage.Attributes.DataPropertyType);
- const propertyName = fragment.getAttribute(ClassPage.Attributes.DataPropertyName);
- if(parentClassName.length > 0)
- Url.goTo(`/class/${parentClassName}#${propertyType}:${propertyName}`);
- else
- Url.setHash(`${propertyType}:${propertyName}`).updateLocation();
- }
- }
- onTabClick(e) {
- const element = CDElement.get(e.target);
- if(element.hasClass(ClassPage.StyleClasses.Selected))
- return;
- this.openTab(element.getAttribute(ClassPage.Attributes.DataTab));
- }
- openTab(tabName) {
- this.selectTab(tabName);
- this.activateContent(tabName);
- Url.setHash(tabName).updateLocation();
- }
- onClassClick(e) {
- let element = CDElement.get(e.target);
- while(!element.hasClass(ClassPage.StyleClasses.ClassItem))
- element = element.getParent();
- Url.goTo(`/class/${element.getAttribute(ClassPage.Attributes.DataClassName)}`);
- }
- onModeButtonClick(e) {
- const button = CDElement.get(e.target);
- const mode = button.getAttribute(ClassPage.Attributes.DataDisplayMode);
- this.switchMode(mode);
- button.addClass(ClassPage.StyleClasses.Selected);
- (mode === ClassPage.Mode.Tabs ? this.listModeButton : this.tabsModeButton).removeClass(ClassPage.StyleClasses.Selected);
- }
- searchInEditor(isStatic, ...queries) {
- this.switchFullSource(true);
- const editor = this.codeMirrorEditor;
- const staticsRange = this.getStaticsRange();
- const staticsStart = staticsRange.from;
- const staticsEnd = staticsRange.to;
- for(const query of queries) {
- const cursor = editor.getSearchCursor(query, CodeMirror.Pos(editor.cmFirstLine(), 0), { caseFold: false, multiline: true });
- while(cursor.find()) {
- const from = cursor.from();
- const to = cursor.to();
- const lineIndex = from.line;
- if((isStatic && lineIndex >= staticsStart && lineIndex <= staticsEnd) || (!isStatic && (lineIndex < staticsStart || lineIndex > staticsEnd))) {
- this.openTab('Editor');
- editor.setSelection(from, to);
- editor.scrollIntoView({ from: from, to: to }, 100);
- return;
- }
- }
- }
- }
- searchPropertyInEditor(isMethod, isDynamic, propertyName) {
- const isStatic = propertyName.startsWith(ClassPage.__static__);
- propertyName = isStatic ? propertyName.slice(10) : propertyName;
- if(isMethod) {
- this.searchInEditor(isStatic, `${propertyName}: function`);
- } else {
- if(isDynamic)
- this.searchInEditor(false, `this.${propertyName} =`, `this.${propertyName}`);
- else
- this.searchInEditor(isStatic, `${propertyName}: `);
- }
- }
- scrollToProperty(hashTab, hashProp) {
- if(!hashProp)
- return;
-
- const item = this.contentElements[hashTab].getFirstChild(`.property-item[data-property-name="${hashProp}"]`);
-
- if(!item)
- return;
- const categoryList = item.getParent();
- const categoryHeader = categoryList.previousSibling();
-
- if(categoryList.hasClass(ClassPage.StyleClasses.Hidden))
- categoryList.removeClass(ClassPage.StyleClasses.Hidden);
- if(categoryHeader.hasClass(ClassPage.StyleClasses.Collapsed))
- categoryHeader.removeClass(ClassPage.StyleClasses.Collapsed);
- item.addClass(ClassPage.StyleClasses.Highlighted);
- item.addClass(ClassPage.StyleClasses.White);
- if(this.mode === ClassPage.Mode.Tabs)
- this.contentElements[hashTab].scrollTo(`.property-item[data-property-name="${hashProp}"]`);
- else
- item.scrollIntoView();
- setTimeout(() => {
- item.removeClass(ClassPage.StyleClasses.White);
- }, 1000);
- setTimeout(() => {
- item.removeClass(ClassPage.StyleClasses.Highlighted);
- }, 2000);
- }
- delayedAdjustCommentInputHeight(e) {
- setTimeout(() => { this.adjustCommentInputHeight(e) }, 0);
- }
- adjustCommentInputHeight(e) {
- const textArea = e.target;
- if(textArea.scrollHeight < 422 || e.key === DOM.Keys.Backspace) {
- textArea.style.height = 'auto';
- textArea.style.height = `${Math.min(422, textArea.scrollHeight + 2)}px`;
- }
-
- textArea.scrollTop = textArea.scrollHeight;
- }
- applyHash() {
- const hash = (Url.getHash() || '').split(':');
- const hashTab = hash[0];
- const hashProp = hash[1];
- const tabElements = this.tabElements;
- const contentElements = this.contentElements;
- 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.activateContent(activeContent);
- this.scrollToProperty(hashTab, hashProp);
- }
- openSocket() {
- this.socket = new Socket('/ws').onMessage(this.onSocketMessage.bind(this));
- }
- onSocketMessage(e) {
- const changes = JSON.parse(e.data) || [];
- changes.forEach((changedComment) => {
- this.processChange(changedComment);
- });
- if(this.statistics)
- this.statistics.load();
- }
- processChange(changedComment) {
- if(changedComment.root !== Class[ClassPage.ClassProperties.Root] || changedComment.className !== Class[ClassPage.ClassProperties.Name])
- return;
- const propertyItem = this.propertyItemElements[changedComment.propertyName];
- propertyItem.removeClass('saving');
- switch(changedComment.action) {
- case 'create':
- this.documented++;
- this.renderDocumentedPercentage();
- Comments[changedComment.propertyName] = changedComment;
- propertyItem.getFirstChild('.property-item-comment').append(this.createCommentDateElement(changedComment.timestamp, changedComment.author));
- break;
- case 'update':
- if(Comments[changedComment.propertyName].text.length === 0) {
- this.documented++;
- this.renderDocumentedPercentage();
- }
-
- Comments[changedComment.propertyName].text = changedComment.text;
- const dateElement = propertyItem.getFirstChild('.property-item-comment-date > .property-item-comment-date-date');
- if(dateElement) {
- dateElement.setInnerHTML(CDUtils.dateFormatUTC(changedComment.timestamp, 3, 'D.M.Y, H:I:S'));
- } else {
- propertyItem.getFirstChild('.property-item-comment').append(this.createCommentDateElement(changedComment.timestamp, changedComment.author));
- }
- break;
- case 'remove':
- this.documented--;
- if(Comments[changedComment.propertyName])
- Comments[changedComment.propertyName].text = '';
- this.renderDocumentedPercentage();
- propertyItem.getFirstChild('.property-item-comment-date').remove();
- break;
- }
- const commentContent = changedComment.text;
- const itemCommentStatic = propertyItem.getFirstChild('.property-item-comment-static');
- const itemCommentInput = propertyItem.getFirstChild('.property-item-comment-input');
- const itemCommentOkButton = propertyItem.getFirstChild('.property-item-comment-button');
- if(itemCommentInput) {
- itemCommentInput.setValue(commentContent);
- itemCommentInput.addClass(ClassPage.StyleClasses.Hidden);
- itemCommentOkButton.addClass(ClassPage.StyleClasses.Hidden);
- }
-
- itemCommentStatic.setInnerHTML(commentContent.length > 0 ? CDUtils.nl2br(commentContent) : 'Not commented yet...');
- itemCommentStatic.switchClass(ClassPage.StyleClasses.Empty, commentContent.length === 0);
- itemCommentStatic.removeClass(ClassPage.StyleClasses.Hidden);
- }
- renderContribution() {
- const contributionElement = this.contentElements[ClassPage.TabNames.Contribution];
- this.statistics = Statistics.init(contributionElement, Statistics.Modes.CLASS);
- }
- /* >>> Context menu */
- showContextMenu(target, pos) {
- while(!target.hasClass('property-item'))
- target = target.getParent();
- 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);
- });
- }
- if(propertyItemParent != null) {
- contextMenu.addItem('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)) {
- 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>`);
- });
- contextMenu.show(pos);
- }
- /* <<< Context menu */
- loadDocumentedInfo() {
- let requestBody;
- if(Class.isPackage) {
- requestBody = new URLSearchParams({
- 'root': Class[ClassPage.ClassProperties.Root],
- 'packageName': Class[ClassPage.ClassProperties.Name]
- });
- } else {
- requestBody = new URLSearchParams({
- 'className': Class[ClassPage.ClassProperties.Name]
- });
- }
- fetch(`/docinfo`, {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/x-www-form-urlencoded'
- },
- body: requestBody
- }).then(res => res.json()).then((res) => {
- this.documented = res['documented'];
- this.documentable = res['documentable'];
- this.renderDocumentedPercentage();
- });
- }
- };
- window_.on(DOM.Events.Load, (e) => {
- window.page = new ClassPage().start();
- });
- window_.on(DOM.Events.KeyDown, (e) => {
- if(Class.isPackage)
- return;
- if(window.page && (e.key === DOM.Keys.Control || e.key === DOM.Keys.Meta))
- window.page.codeMirrorEditorElement.addClass(ClassPage.StyleClasses.CtrlPressed);
- if(window.page && e.key === DOM.Keys.Shift)
- window.page.codeMirrorEditorElement.addClass(ClassPage.StyleClasses.ShiftPressed);
- });
- window_.on(DOM.Events.KeyUp, (e) => {
- if(Class.isPackage)
- return;
- if(window.page && (e.key === DOM.Keys.Control || e.key === DOM.Keys.Meta))
- window.page.codeMirrorEditorElement.removeClass(ClassPage.StyleClasses.CtrlPressed);
- if(window.page && e.key === DOM.Keys.Shift)
- window.page.codeMirrorEditorElement.removeClass(ClassPage.StyleClasses.ShiftPressed);
- });
- window_.on(DOM.Events.HashChange, (e) => {
- if(window.page)
- window.page.applyHash();
- });
|