Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expand/collapse description on click on the app title #38 #43

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
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
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import NamesAndIconViewSize = api.app.NamesAndIconViewSize;
import i18n = api.util.i18n;
import {MarketApplication} from '../../market/MarketApplication';

export class MarketAppViewer extends api.ui.Viewer<MarketApplication> {
Expand All @@ -25,7 +26,7 @@ export class MarketAppViewer extends api.ui.Viewer<MarketApplication> {
}

resolveDisplayName(object: MarketApplication): string {
let appLink = new api.dom.AEl().setUrl(object.getUrl(), '_blank').setHtml(object.getDisplayName(), false);
const appLink = new api.dom.AEl('app-name').setUrl('#').setHtml(object.getDisplayName(), false);
return appLink.toString();
}

Expand Down Expand Up @@ -58,10 +59,10 @@ export class MarketAppViewer extends api.ui.Viewer<MarketApplication> {
}

if (object) {
let displayName = this.resolveDisplayName(object);
let subName = this.resolveSubName(object, this.relativePath);
let subTitle = this.resolveSubTitle(object);
let iconUrl = this.resolveIconUrl(object);
const displayName = this.resolveDisplayName(object);
const subName = this.resolveSubName(object, this.relativePath);
const subTitle = this.resolveSubTitle(object);
const iconUrl = this.resolveIconUrl(object);

this.namesAndIconView.getNamesView().setMainName(displayName, false).setSubName(subName, subTitle);
if (!!subTitle) {
Expand All @@ -76,6 +77,14 @@ export class MarketAppViewer extends api.ui.Viewer<MarketApplication> {
this.namesAndIconView.setIconClass('icon-puzzle icon-large');
this.namesAndIconView.getIconImageEl().setSrc('');
});

const isReadMoreSectionAdded: boolean = this.namesAndIconView.getNamesView().getChildren().length > 2;
if (!isReadMoreSectionAdded) {
const readMoreSection: api.dom.Element = new api.dom.DivEl('app-more');
readMoreSection.appendChild(
new api.dom.AEl().setUrl(object.getUrl(), '_blank').setHtml(i18n('market.app.readmore'), false));
this.namesAndIconView.getNamesView().appendChild(readMoreSection);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,22 +32,22 @@ export class MarketAppsTreeGrid extends TreeGrid<MarketApplication> {

constructor() {

let nameColumn = new GridColumnBuilder<TreeNode<MarketApplication>>()
const nameColumn = new GridColumnBuilder<TreeNode<MarketApplication>>()
.setName('Name')
.setId('displayName')
.setField('displayName')
.setCssClass('app-name-and-icon')
.setMinWidth(170)
.setFormatter(MarketAppsTreeGrid.nameFormatter)
.build();
let versionColumn = new GridColumnBuilder<TreeNode<MarketApplication>>()
const versionColumn = new GridColumnBuilder<TreeNode<MarketApplication>>()
.setName('Version')
.setId('version')
.setField('latestVersion')
.setCssClass('version')
.setMinWidth(40)
.build();
let appStatusColumns = new GridColumnBuilder<TreeNode<MarketApplication>>()
const appStatusColumns = new GridColumnBuilder<TreeNode<MarketApplication>>()
.setName('AppStatus')
.setId('appStatus')
.setField('status')
Expand Down Expand Up @@ -77,7 +77,7 @@ export class MarketAppsTreeGrid extends TreeGrid<MarketApplication> {
this.installApplications = [];
this.gridDataLoaded = false;

this.subscribeAndManageInstallClick();
this.subscribeAndManageClick();
this.subscribeOnUninstallEvent();
this.subscribeOnInstallEvent();

Expand All @@ -101,7 +101,7 @@ export class MarketAppsTreeGrid extends TreeGrid<MarketApplication> {
}

private initDataLoadListener() {
let firstLoadListener = () => {
const firstLoadListener = () => {
if (this.getGrid().getDataView().getLength() > 0) {
this.unLoaded(firstLoadListener);
setTimeout(() => {
Expand All @@ -125,7 +125,7 @@ export class MarketAppsTreeGrid extends TreeGrid<MarketApplication> {
private subscribeOnUninstallEvent() { // set status of market app to NOT_INSTALLED if it was uninstalled
api.application.ApplicationEvent.on((event: ApplicationEvent) => {
if (ApplicationEventType.UNINSTALLED === event.getEventType()) {
let nodeToUpdate = this.getRoot().getCurrentRoot().findNode(event.getApplicationKey().toString());
const nodeToUpdate = this.getRoot().getCurrentRoot().findNode(event.getApplicationKey().toString());
if (!!nodeToUpdate) {
(<MarketApplication>nodeToUpdate.getData()).setStatus(MarketAppStatus.NOT_INSTALLED);
this.refresh();
Expand All @@ -135,9 +135,9 @@ export class MarketAppsTreeGrid extends TreeGrid<MarketApplication> {
}

private findNodeByAppUrl(url: string): TreeNode<MarketApplication> {
let nodes: TreeNode<MarketApplication>[] = this.getGrid().getDataView().getItems();
const nodes: TreeNode<MarketApplication>[] = this.getGrid().getDataView().getItems();
for (let i = 0; i < nodes.length; i++) {
let node = nodes[i];
const node = nodes[i];
if (node.getData().getLatestVersionDownloadUrl() === url) {
return node;
}
Expand Down Expand Up @@ -165,12 +165,12 @@ export class MarketAppsTreeGrid extends TreeGrid<MarketApplication> {
console.debug('MarketAppsTreeGrid: progress', event.getApplicationUrl(), event.getProgress());
}

let app = <MarketApplication>nodeToUpdate.getData();
const app = <MarketApplication>nodeToUpdate.getData();
app.setProgress(event.getProgress());

let row = this.getGrid().getDataView().getRowById(nodeToUpdate.getId());
const row = this.getGrid().getDataView().getRowById(nodeToUpdate.getId());
if (row > -1) {
let cell = this.getGrid().getColumnIndex('appStatus');
const cell = this.getGrid().getColumnIndex('appStatus');
this.getGrid().updateCell(row, cell);
}
}
Expand All @@ -184,20 +184,20 @@ export class MarketAppsTreeGrid extends TreeGrid<MarketApplication> {
console.debug('MarketAppsTreeGrid: installed', event.getApplicationUrl(), event.getProgress());
}

let app = <MarketApplication>nodeToUpdate.getData();
const app = <MarketApplication>nodeToUpdate.getData();
app.setStatus(MarketAppStatus.INSTALLED);

new api.application.GetApplicationRequest(event.getApplicationKey(), true).sendAndParse()
.then((application: api.application.Application)=> {
if (!!application) {
let marketApplication: MarketApplication = <MarketApplication>nodeToUpdate.getData();
const marketApplication: MarketApplication = <MarketApplication>nodeToUpdate.getData();

if (MarketApplicationsFetcher.installedAppCanBeUpdated(marketApplication, application)) {
marketApplication.setStatus(MarketAppStatus.OLDER_VERSION_INSTALLED);
} else {
marketApplication.setStatus(MarketAppStatus.INSTALLED);
}
let row = this.getGrid().getDataView().getRowById(nodeToUpdate.getId());
const row = this.getGrid().getDataView().getRowById(nodeToUpdate.getId());
if (row > -1) {
this.getGrid().updateRow(row);
}
Expand All @@ -209,47 +209,70 @@ export class MarketAppsTreeGrid extends TreeGrid<MarketApplication> {
});
}

private subscribeAndManageInstallClick() {
private subscribeAndManageClick() {
this.getGrid().subscribeOnClick((event, data) => {
let node = this.getItem(data.row);
let app = <MarketApplication>node.getData();
let url = app.getLatestVersionDownloadUrl();
let elem = new Element(new ElementFromHelperBuilder().setHelper(new ElementHelper(event.target)));
let status = app.getStatus();
const isInstallClicked: boolean = event.target.classList.contains(MarketAppStatusFormatter.statusInstallCssClass) ||
event.target.classList.contains(MarketAppStatusFormatter.statusUpdateCssClass);
const isAppNameClicked = event.target.classList.contains('app-name');

if (isInstallClicked) {
this.handleInstallClicked(event, data);
} else if (isAppNameClicked) {
this.toggleFullDescriptionForClickedItem(event);
}
});
}

if ((elem.hasClass(MarketAppStatusFormatter.statusInstallCssClass) ||
elem.hasClass(MarketAppStatusFormatter.statusUpdateCssClass))) {
private handleInstallClicked(event: any, data: any) {
const node = this.getItem(data.row);
const app = <MarketApplication>node.getData();
const url = app.getLatestVersionDownloadUrl();
const elem = new Element(new ElementFromHelperBuilder().setHelper(new ElementHelper(event.target)));
const status = app.getStatus();

app.setStatus(MarketAppStatus.INSTALLING);
app.setStatus(MarketAppStatus.INSTALLING);

let row = this.getGrid().getDataView().getRowById(node.getId());
if (row > -1) {
this.getGrid().updateCell(row, this.getGrid().getColumnIndex('appStatus'));
}
const row = this.getGrid().getDataView().getRowById(node.getId());
if (row > -1) {
this.getGrid().updateCell(row, this.getGrid().getColumnIndex('appStatus'));
}

if (MarketAppsTreeGrid.debug) {
console.debug('MarketAppsTreeGrid: starting install', url, elem);
}
if (MarketAppsTreeGrid.debug) {
console.debug('MarketAppsTreeGrid: starting install', url, elem);
}

new InstallUrlApplicationRequest(url).sendAndParse().then((result: ApplicationInstallResult) => {
if (!result.getFailure()) {
elem.removeClass(MarketAppStatusFormatter.statusInstallCssClass + ' ' + MarketAppStatusFormatter.statusUpdateCssClass);
elem.addClass(MarketAppStatusFormatter.getStatusCssClass(MarketAppStatus.INSTALLED));
} else {
elem.setHtml(MarketAppStatusFormatter.formatStatus(status));
}
}).catch((reason: any) => {
elem.setHtml(MarketAppStatusFormatter.formatStatus(status));
api.DefaultErrorHandler.handle(reason);
});
}

new InstallUrlApplicationRequest(url)
.sendAndParse().then((result: ApplicationInstallResult) => {
// api.application.ApplicationEvent.un(progressHandler);
if (!result.getFailure()) {
private toggleFullDescriptionForClickedItem(event: any) {
let rowElem = event.target;
while (!rowElem.classList.contains('slick-row')) {
rowElem = rowElem.parentElement;
}

elem.removeClass(MarketAppStatusFormatter.statusInstallCssClass + ' ' +
MarketAppStatusFormatter.statusUpdateCssClass);
elem.addClass(MarketAppStatusFormatter.getStatusCssClass(MarketAppStatus.INSTALLED));
const currentRowHeight: number = rowElem.children[0].offsetHeight;
rowElem.classList.toggle('maximized');
const newRowHeight: number = rowElem.children[0].offsetHeight;
const diff: number = newRowHeight - currentRowHeight;

} else {
elem.setHtml(MarketAppStatusFormatter.formatStatus(status));
}
// updating grid's height to fit new row's height
rowElem.parentElement.style.height = (+rowElem.parentElement.style.height.replace('px', '') + diff) + 'px';

}).catch((reason: any) => {
elem.setHtml(MarketAppStatusFormatter.formatStatus(status));
api.DefaultErrorHandler.handle(reason);
});
}
});
// updating row's siblings to shift ahead with respect to new row's height
while (rowElem.nextSibling) {
rowElem = rowElem.nextSibling;
rowElem.style.top = (+rowElem.style.top.replace('px', '') + diff) + 'px';
}
}

public static nameFormatter(row: number, cell: number, value: any, columnDef: any, node: TreeNode<MarketApplication>) {
Expand All @@ -274,13 +297,13 @@ export class MarketAppsTreeGrid extends TreeGrid<MarketApplication> {
}

public static appStatusFormatter(row: number, cell: number, value: any, columnDef: any, node: TreeNode<MarketApplication>) {
let app = <MarketApplication>node.getData();
let statusWrapper = new api.dom.AEl();
const app = <MarketApplication>node.getData();
const statusWrapper = new api.dom.AEl();

if (!!app.getAppKey()) {

let status = app.getStatus();
let progress = app.getProgress();
const status = app.getStatus();
const progress = app.getProgress();

statusWrapper.setHtml(MarketAppStatusFormatter.formatStatus(status, progress), false);
statusWrapper.addClass(MarketAppStatusFormatter.getStatusCssClass(status));
Expand All @@ -302,8 +325,8 @@ export class MarketAppsTreeGrid extends TreeGrid<MarketApplication> {
}

fetchChildren(): wemQ.Promise<MarketApplication[]> {
let root = this.getRoot().getCurrentRoot();
let children = root.getChildren();
const root = this.getRoot().getCurrentRoot();
const children = root.getChildren();
let from = root.getChildren().length;
if (from > 0 && !children[from - 1].getData().getAppKey()) {
children.pop();
Expand All @@ -318,19 +341,19 @@ export class MarketAppsTreeGrid extends TreeGrid<MarketApplication> {
return MarketApplicationsFetcher.fetchChildren(this.getVersion(), this.installApplications, from,
MarketAppsTreeGrid.MAX_FETCH_SIZE).then(
(data: MarketApplicationResponse) => {
let meta = data.getMetadata();
let applications = children.map((el) => {
const meta = data.getMetadata();
const applications = children.map((el) => {
return el.getData();
}).slice(0, from).concat(data.getApplications());
root.setMaxChildren(meta.getTotalHits());
if (from + meta.getHits() < meta.getTotalHits()) {
let emptyApplication = new MarketApplicationBuilder().setLatestVersion('').build();
const emptyApplication = new MarketApplicationBuilder().setLatestVersion('').build();
applications.push(emptyApplication);
}
return applications;
}).catch((reason: any) => {
let status500Message = i18n('market.error.500');
let defaultErrorMessage = i18n('market.error.default');
const status500Message = i18n('market.error.500');
const defaultErrorMessage = i18n('market.error.default');
this.handleError(reason, reason.getStatusCode() === 500 ? status500Message : defaultErrorMessage);
return [];
});
Expand All @@ -344,11 +367,11 @@ export class MarketAppsTreeGrid extends TreeGrid<MarketApplication> {
}

private getVersion(): string {
let version: string = CONFIG.xpVersion;
const version: string = CONFIG.xpVersion;
if (!version) {
return '';
}
let parts = version.split('.');
const parts = version.split('.');
if (parts.length > 3) {
parts.pop(); // remove '.snapshot'
return parts.join('.');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,35 @@
}

}

.slick-row.maximized {
height: auto;

.slick-cell.app-name-and-icon {
height: auto;

.@{_COMMON_PREFIX}sub-name {
overflow: visible;
white-space: normal;
text-overflow: clip;
}

.app-more {
padding-top: 2px;

a {
cursor: pointer;
text-decoration: none;
font-size: 14px;
color: @admin-dark-gray;

&:hover {
text-decoration: underline;
}
}
}
}
}
}

.version {
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/i18n/phrases.properties
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,4 @@ market.noAppsFound = No applications found
market.loadAppList = Loading application list
market.error.500 = Woops... The server seems to be experiencing problems. Please try again later.
market.error.default = Enonic Market is temporarily unavailable. Please try again later.
market.app.readmore=Read more on Enonic Market...
1 change: 1 addition & 0 deletions src/main/resources/i18n/phrases_ru.properties
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,4 @@ market.noAppsFound = Приложения не найдены
market.loadAppList = Загрузка списка приложений
market.error.500 = Не удается подключиться к серверу. Повторите попытку позже.
market.error.default = Enonic Market временно недоступен. Повторите попытку позже.
market.app.readmore=Узнайте больше на Enonic Market...