Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 59 additions & 8 deletions utils/docs/template/publish.js
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,16 @@ function buildSearchListForData() {
kind: item.kind
};

// Add sub-category for TSL items to improve search
if ( category === 'TSL' && item.meta && item.meta.filename ) {

const filename = item.meta.filename.replace( /\.js$/, '' );
// Remove "Node" suffix if present
const subCategory = filename.replace( /Node$/, '' );
entry.subCategory = subCategory;

}

categories[ category ].push( entry );

}
Expand Down Expand Up @@ -521,19 +531,38 @@ function buildGlobalsNav( globals, seen ) {

if ( globals.length ) {

// TSL
// TSL - organize by sub-category based on file name

let tslNav = '';
const tslBySubCategory = new Map();

globals.forEach( ( { kind, longname, name, tags } ) => {
globals.forEach( ( item ) => {

const { kind, longname, name, tags, meta } = item;

if ( kind !== 'typedef' && ! hasOwnProp.call( seen, longname ) ) {

const hasTslTag = Array.isArray( tags ) && tags.some( tag => tag.title === 'tsl' );

if ( hasTslTag ) {

tslNav += `\t\t\t\t\t\t<li>${linkto( longname, name )}</li>\n`;
// Extract sub-category from file name
let subCategory = 'Other';

if ( meta && meta.filename ) {

const filename = meta.filename.replace( /\.js$/, '' );
// Remove "Node" suffix if present
subCategory = filename.replace( /Node$/, '' );

}

if ( ! tslBySubCategory.has( subCategory ) ) {

tslBySubCategory.set( subCategory, [] );

}

tslBySubCategory.get( subCategory ).push( { longname, name } );

seen[ longname ] = true;

Expand All @@ -543,10 +572,32 @@ function buildGlobalsNav( globals, seen ) {

} );

nav += '\t\t\t\t\t<h2>TSL</h2>\n';
nav += '\t\t\t\t\t<ul>\n';
nav += tslNav;
nav += '\t\t\t\t\t</ul>\n';
if ( tslBySubCategory.size > 0 ) {

nav += '\t\t\t\t\t<h2>TSL</h2>\n';

// Sort sub-categories alphabetically
const sortedSubCategories = new Map( [ ...tslBySubCategory.entries() ].sort() );

for ( const [ subCategory, items ] of sortedSubCategories ) {

nav += `\t\t\t\t\t<h3>${subCategory}</h3>\n`;
nav += '\t\t\t\t\t<ul>\n';

// Sort items within each sub-category
items.sort( ( a, b ) => a.name.localeCompare( b.name ) );

items.forEach( ( { longname, name } ) => {

nav += `\t\t\t\t\t\t<li>${linkto( longname, name )}</li>\n`;

} );

nav += '\t\t\t\t\t</ul>\n';

}

}

// Globals

Expand Down
127 changes: 106 additions & 21 deletions utils/docs/template/static/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,14 @@ <h1><a href="https://threejs.org">three.js</a></h1>
for ( const item of items ) {

// Match against combined category and title for multi-word searches
const searchText = category + ' ' + item.title;
// For TSL items, also include the sub-category in the search
let searchText = category + ' ' + item.title;
if ( item.subCategory ) {

searchText = category + ' ' + item.subCategory + ' ' + item.title;

}

if ( searchText.match( regExp ) ) {

results.push( { ...item, category } );
Expand All @@ -354,7 +361,8 @@ <h1><a href="https://threejs.org">three.js</a></h1>
grouped[ className ] = {
class: null,
members: [],
category: item.category
category: item.category,
subCategory: item.subCategory
};

}
Expand Down Expand Up @@ -421,42 +429,119 @@ <h1><a href="https://threejs.org">three.js</a></h1>
const highlightedCategory = highlightMatch( category, highlightRegExp );
html += `<h2>${highlightedCategory}</h2>`;

for ( const className in byCategory[ category ] ) {
// For TSL category, group by sub-category
if ( category === 'TSL' ) {

const bySubCategory = {};

for ( const className in byCategory[ category ] ) {

const group = byCategory[ category ][ className ];
const group = byCategory[ category ][ className ];
const subCat = group.subCategory || 'Other';

if ( group.class ) {
if ( ! bySubCategory[ subCat ] ) {

html += '<div class="search-result-group">';
const selectedClass = group.class.hash === currentHash ? ' selected' : '';
const highlightedName = highlightMatch( group.class.name, highlightRegExp );
html += `<a href="#${group.class.hash}" class="search-result-class${selectedClass}">${highlightedName}</a>`;
bySubCategory[ subCat ] = {};

}

bySubCategory[ subCat ][ className ] = group;

}

if ( group.members.length > 0 ) {
// Sort sub-categories and render them
const sortedSubCategories = Object.keys( bySubCategory ).sort();

for ( const subCat of sortedSubCategories ) {

const highlightedSubCat = highlightMatch( subCat, highlightRegExp );
html += `<h3>${highlightedSubCat}</h3>`;

for ( const className in bySubCategory[ subCat ] ) {

const group = bySubCategory[ subCat ][ className ];

if ( group.class ) {

html += '<div class="search-result-group">';
const selectedClass = group.class.hash === currentHash ? ' selected' : '';
const highlightedName = highlightMatch( group.class.name, highlightRegExp );
html += `<a href="#${group.class.hash}" class="search-result-class${selectedClass}">${highlightedName}</a>`;

}

if ( group.members.length > 0 ) {

if ( ! group.class ) {

html += '<div class="search-result-group">';
html += `<a href="#${className}" class="search-result-class">${className}</a>`;

}

group.members.forEach( member => {

const selectedClass = member.hash === currentHash ? ' selected' : '';
const highlightedName = highlightMatch( member.name, highlightRegExp );
const suffix = member.kind === 'function' ? '()' : '';
html += `<a href="#${member.hash}" class="search-result-member${selectedClass}">.${highlightedName}${suffix}</a>`;

} );

if ( ! group.class ) {
}

if ( group.class || group.members.length > 0 ) {

html += '</div>';

}

}

}

} else {

// Regular category rendering (Core, Addons, Global)

for ( const className in byCategory[ category ] ) {

const group = byCategory[ category ][ className ];

if ( group.class ) {

html += '<div class="search-result-group">';
html += `<a href="#${className}" class="search-result-class">${className}</a>`;
const selectedClass = group.class.hash === currentHash ? ' selected' : '';
const highlightedName = highlightMatch( group.class.name, highlightRegExp );
html += `<a href="#${group.class.hash}" class="search-result-class${selectedClass}">${highlightedName}</a>`;

}

group.members.forEach( member => {
if ( group.members.length > 0 ) {

const selectedClass = member.hash === currentHash ? ' selected' : '';
const highlightedName = highlightMatch( member.name, highlightRegExp );
const suffix = member.kind === 'function' ? '()' : '';
html += `<a href="#${member.hash}" class="search-result-member${selectedClass}">.${highlightedName}${suffix}</a>`;
if ( ! group.class ) {

} );
html += '<div class="search-result-group">';
html += `<a href="#${className}" class="search-result-class">${className}</a>`;

}
}

group.members.forEach( member => {

const selectedClass = member.hash === currentHash ? ' selected' : '';
const highlightedName = highlightMatch( member.name, highlightRegExp );
const suffix = member.kind === 'function' ? '()' : '';
html += `<a href="#${member.hash}" class="search-result-member${selectedClass}">.${highlightedName}${suffix}</a>`;

if ( group.class || group.members.length > 0 ) {
} );

html += '</div>';
}

if ( group.class || group.members.length > 0 ) {

html += '</div>';

}

}

Expand Down
107 changes: 91 additions & 16 deletions utils/docs/template/tmpl/container.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -92,14 +92,7 @@
return isTSLPage ? hasTslTag : !hasTslTag;
});
}
if (members && members.length && members.forEach) {
?>
<h2 class="subsection-title">Properties</h2>
<?js members.forEach(function(p) { ?>
<?js= self.partial('members.tmpl', p) ?>
<?js }); ?>
<?js } ?>
<?js

var methods = self.find({kind: 'function', memberof: isGlobalPage ? {isUndefined: true} : doc.longname, ...ignoreInheritedSymbols});

// Filter methods for TSL vs Global
Expand All @@ -113,19 +106,101 @@
var staticMethods = methods.filter(function(m) { return m.scope === 'static'; });
var instanceMethods = methods.filter(function(m) { return m.scope !== 'static'; });

if (instanceMethods.length) {
// For TSL pages, group everything by sub-category
if (isTSLPage && ((members && members.length) || instanceMethods.length || staticMethods.length)) {
// Collect all items and group by sub-category
var allItemsBySubCategory = {};

function addToSubCategory(item, type) {
var subCategory = 'Other';
if (item.meta && item.meta.filename) {
var filename = item.meta.filename.replace(/\.js$/, '');
subCategory = filename.replace(/Node$/, '');
}
if (!allItemsBySubCategory[subCategory]) {
allItemsBySubCategory[subCategory] = {
properties: [],
methods: [],
staticMethods: []
};
}
item.isTSLItem = true;
allItemsBySubCategory[subCategory][type].push(item);
}

if (members && members.length) {
members.forEach(function(m) { addToSubCategory(m, 'properties'); });
}
if (instanceMethods.length) {
instanceMethods.forEach(function(m) { addToSubCategory(m, 'methods'); });
}
if (staticMethods.length) {
staticMethods.forEach(function(m) { addToSubCategory(m, 'staticMethods'); });
}

// Sort sub-categories and render
var sortedSubCategories = Object.keys(allItemsBySubCategory).sort();
?>
<h2 class="subsection-title">TSL Functions</h2>
<?js
sortedSubCategories.forEach(function(subCategory) {
var items = allItemsBySubCategory[subCategory];
?>
<h3><?js= subCategory ?></h3>
<?js
// Render properties first
items.properties.forEach(function(p) {
?>
<?js= self.partial('members.tmpl', p) ?>
<?js
});
// Then methods
items.methods.forEach(function(m) {
?>
<?js= self.partial('method.tmpl', m) ?>
<?js
});
// Then static methods
items.staticMethods.forEach(function(m) {
?>
<?js= self.partial('method.tmpl', m) ?>
<?js
});
});
} else {
// Regular rendering for non-TSL pages
if (members && members.length && members.forEach) {
?>
<h2 class="subsection-title">Properties</h2>
<?js
members.forEach(function(p) {
?>
<?js= self.partial('members.tmpl', p) ?>
<?js
});
}
if (instanceMethods.length) {
?>
<h2 class="subsection-title">Methods</h2>
<?js instanceMethods.forEach(function(m) { ?>
<?js
instanceMethods.forEach(function(m) {
?>
<?js= self.partial('method.tmpl', m) ?>
<?js }); ?>
<?js } ?>
<?js if (staticMethods.length) { ?>
<?js
});
}
if (staticMethods.length) {
?>
<h2 class="subsection-title">Static Methods</h2>
<?js staticMethods.forEach(function(m) { ?>
<?js
staticMethods.forEach(function(m) {
?>
<?js= self.partial('method.tmpl', m) ?>
<?js }); ?>
<?js } ?>
<?js
});
}
}
?>
<?js
var typedefs = self.find({kind: 'typedef', memberof: isGlobalPage ? {isUndefined: true} : doc.longname, ...ignoreInheritedSymbols});
if (typedefs && typedefs.length && typedefs.forEach) {
Expand Down
3 changes: 2 additions & 1 deletion utils/docs/template/tmpl/members.tmpl
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
<?js
var data = obj;
var self = this;
var prefix = (data.isTSLItem === true) ? '' : '.';
?>
<div class="member">
<h3 class="name" id="<?js= id ?>" translate="no">.<a href="#<?js= id ?>"><?js= name ?></a><?js= (data.signature ? data.signature : '') ?> <?js= data.attribs ?></h3>
<h3 class="name" id="<?js= id ?>" translate="no"><?js= prefix ?><a href="#<?js= id ?>"><?js= name ?></a><?js= (data.signature ? data.signature : '') ?> <?js= data.attribs ?></h3>
<?js if (data.summary) { ?>
<p class="summary"><?js= summary ?></p>
<?js } ?>
Expand Down
Loading