Skip to content

Commit

Permalink
Added landing page functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
dm-p committed Jun 23, 2020
1 parent 057f814 commit 67c5875
Show file tree
Hide file tree
Showing 10 changed files with 244 additions and 17 deletions.
7 changes: 7 additions & 0 deletions assets/background.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 12 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,19 @@
"unit": "karma start"
},
"devDependencies": {
"@babel/polyfill": "^7.2.5",
"@babel/runtime": "7.6.0",
"@babel/runtime-corejs3": "7.6.0",
"@types/d3": "5.7.2",
"@types/overlayscrollbars": "^1.12.0",
"core-js": "3.2.1",
"d3": "5.12.0",
"overlayscrollbars": "^1.12.0",
"powerbi-visuals-api": "~2.6.1",
"powerbi-visuals-utils-dataviewutils": "2.2.1",
"ts-loader": "6.1.0",
"tslint": "^5.18.0",
"tslint-microsoft-contrib": "^6.2.0",
"typescript": "3.6.3",
"@babel/polyfill": "^7.2.5",
"@types/jasmine": "^3.5.0",
"@types/jasmine-jquery": "^1.5.33",
"@types/jquery": "^3.3.31",
"@types/karma": "^3.0.5",
"@types/lodash-es": "^4.17.3",
"@types/overlayscrollbars": "^1.12.0",
"core-js": "3.2.1",
"coveralls": "3.0.2",
"d3": "5.12.0",
"istanbul-instrumenter-loader": "^3.0.1",
"jasmine": "2.5.2",
"jasmine-core": "2.5.2",
Expand All @@ -43,13 +36,21 @@
"karma-typescript": "^4.1.1",
"karma-typescript-preprocessor": "^0.4.0",
"karma-webpack": "^3.0.5",
"overlayscrollbars": "^1.12.0",
"powerbi-visuals-api": "~2.6.1",
"powerbi-visuals-utils-dataviewutils": "2.2.1",
"powerbi-visuals-utils-testutils": "^2.2.1",
"prettier": "^1.19.1",
"prettier-tslint": "^0.4.2",
"puppeteer": "^1.20.0",
"style-loader": "0.23.1",
"ts-loader": "6.1.0",
"ts-node": "7.0.1",
"tslint": "^5.18.0",
"tslint-microsoft-contrib": "^6.2.0",
"tslint-plugin-prettier": "^2.1.0",
"typescript": "3.6.3",
"w3-css": "^4.1.0",
"webpack": "^4.41.4"
}
}
2 changes: 1 addition & 1 deletion pbiviz.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"displayName": "HTML Display",
"guid": "htmlDisplay443BE3AD55E043BF878BED274D3A6855",
"visualClassName": "Visual",
"version": "1.0.0.5",
"version": "1.0.0.6",
"description": "A replacement Power BI custom visual for the HTML Viewer, which has recently been removed from the marketplace.",
"supportUrl": "https://github.com/dm-p/powerbi-visuals-html-display",
"gitHubUrl": "https://github.com/dm-p/powerbi-visuals-html-display"
Expand Down
145 changes: 145 additions & 0 deletions src/LandingPageHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
// Power BI API references
import powerbiVisualsApi from 'powerbi-visuals-api';
import powerbi = powerbiVisualsApi;
import IVisualHost = powerbi.extensibility.visual.IVisualHost;
import ILocalizationManager = powerbi.extensibility.ILocalizationManager;

// External dependencies
import * as d3 from 'd3';

// Internal dependencies
import { VisualConstants } from './VisualConstants';
import { DomainUtils } from './DomainUtils';

/**
* Manages the handling and placement of the visual landing page if no data is present.
*/
export default class LandingPageHandler {

// Specifies that the landing page is currently on.
landingPageEnabled: boolean = false;
// Specifies that the landing page has been removed since being displayed.
landingPageRemoved: boolean = false;
// Element to bind the landing page to.
private element: d3.Selection<any, any, any, any>;
// Handle localisation of visual text.
private localisationManager: ILocalizationManager;

/**
* @param element - main visual element
* @param localisationManager - Power BI localisation manager instance
*/
constructor(
element: d3.Selection<any, any, any, any>,
localisationManager: ILocalizationManager
) {
this.element = element;
this.localisationManager = localisationManager;
}

/**
* Handles the display or removal of the landing page elements
* @param options - visual update options
* @param host - Power BI visual host services
*/
handleLandingPage(viewModelIsValid: boolean, host: IVisualHost) {

// Conditions for showing landing page
if (!viewModelIsValid) {
if (!this.landingPageEnabled) {
this.landingPageEnabled = true;
this.render(host);
}
} else {
this.clear();
}
}

/**
* Clears down the landing page of elements
*/
clear() {
this.element.selectAll('*').remove();
if (this.landingPageEnabled && !this.landingPageRemoved) {
this.landingPageRemoved = true;
}
this.landingPageEnabled = false;
}

/**
* Renders the landing page content
*
* @param host - Power BI visual host services
*/
render(host: IVisualHost) {

// Top-level elements
let container = this.element
.append('div')
.classed(`${VisualConstants.dom.landingPageClassPrefix}-landing-page`, true)
.classed('w3-card-4', true);

let heading = container
.append('div')
.classed('w3-container', true)
.classed('w3-theme', true);

let version = container
.append('div')
.classed('w3-container', true)
.classed('w3-theme-l3', true)
.classed('w3-small', true);

let helpBox = container
.append('div')
.classed('w3-container', true)
.classed('w3-theme-l5', true)
.classed(`${VisualConstants.dom.landingPageClassPrefix}-watermark`, true)
.classed(`${VisualConstants.dom.landingPageClassPrefix}-help`, true);

// Add title
heading
.append('h5')
.text(VisualConstants.pbiviz.visual.displayName);

// Add version number
version
.text(VisualConstants.pbiviz.visual.version);

// Help box content

// Button / remote link
helpBox
.append('button')
.classed('w3-button', true)
.classed('w3-theme-action', true)
.classed('w3-circle', true)
.style('position', 'fixed')
.style('top', '24px')
.style('right', '12px')
.on('click', () => host.launchUrl(VisualConstants.pbiviz.visual.supportUrl))
.text('?');

// Overview
helpBox
.append('p')
.classed('w3-small', true)
.text(this.localisationManager.getDisplayName('Landing_Page_Overview_1'));
helpBox
.append('p')
.classed('w3-small', true)
.text(this.localisationManager.getDisplayName('Landing_Page_Overview_2'));
helpBox
.append('p')
.classed('w3-small', true)
.text(this.localisationManager.getDisplayName('Landing_Page_Overview_3'));
helpBox
.append('p')
.classed('w3-small', true)
.text(this.localisationManager.getDisplayName('Landing_Page_Overview_4'));

DomainUtils.resolveScrollableContent(container.node());

}

}
8 changes: 7 additions & 1 deletion src/VisualConstants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
// Internal dependencies
import * as pbivizMetadata from '../pbiviz.json';

export const VisualConstants = {
pbiviz: pbivizMetadata,
contentFormatting: {
showRawHtml: false,
font: {
Expand All @@ -14,6 +18,8 @@ export const VisualConstants = {
viewerIdSelector: 'htmlViewer',
entryClassSelector: 'htmlViewerEntry',
statusIdSelector: 'statusMessage',
contentIdSelector: 'htmlContent'
contentIdSelector: 'htmlContent',
landingIdSelector: 'landingPage',
landingPageClassPrefix: 'html-display'
}
}
17 changes: 14 additions & 3 deletions src/visual.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,14 @@
ViewModelHandler
} from './ViewModel';
import DomainUtils from './DomainUtils';
import LandingPageHandler from './LandingPageHandler';

export class Visual implements IVisual {

// The root element for the entire visual
private container: d3.Selection<HTMLDivElement, any, any, any>;
// Used for displaying landing page
private landingContainer: d3.Selection<HTMLDivElement, any, any, any>;
// Used for handling issues in the visual
private statusContainer: d3.Selection<HTMLDivElement, any, any, any>;
// USed for HTML content from data model
Expand All @@ -47,21 +50,27 @@
private localisationManager: ILocalizationManager;
// Visual view model
private viewModelHandler = new ViewModelHandler();
// Handles landing page
private landingPageHandler: LandingPageHandler;

// Runs when the visual is initialised
constructor(options: VisualConstructorOptions) {

this.container = d3Select.select(options.element)
.append('div')
.attr('id', VisualConstants.dom.viewerIdSelector);
this.host = options.host;
this.localisationManager = this.host.createLocalizationManager();
this.landingContainer = this.container
.append('div')
.attr('id', VisualConstants.dom.landingIdSelector);
this.statusContainer = this.container
.append('div')
.attr('id', VisualConstants.dom.statusIdSelector);
this.contentContainer = this.container
.append('div')
.attr('id', VisualConstants.dom.contentIdSelector);
this.host = options.host;
this.localisationManager = this.host.createLocalizationManager();
this.landingPageHandler = new LandingPageHandler(this.landingContainer, this.localisationManager);
this.events = this.host.eventService;
this.viewModelHandler.reset();

Expand Down Expand Up @@ -97,6 +106,8 @@
}
}

this.landingPageHandler.handleLandingPage(this.viewModelHandler.viewModel.isValid, this.host);

// Do checks on potential outcomes and handle accordingly
if (!viewModel.isValid) {
throw new Error('View model mapping error');
Expand Down Expand Up @@ -130,7 +141,7 @@
// Signal that we've encountered an error
this.events.renderingFailed(options, e);
this.contentContainer.selectAll('*').remove();
this.updateStatus(this.localisationManager.getDisplayName('Status_Invalid_View_Model'));
this.updateStatus();

}

Expand Down
4 changes: 4 additions & 0 deletions stringResources/en-US/resources.resjson
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
{
"Landing_Page_Overview_1": "Thanks very much for using this visual!",
"Landing_Page_Overview_2": "To get started you simply need to add a measure or field that contains your HTML to the HTML Content field in the properties pane, and the visual will attempt to render it for you.",
"Landing_Page_Overview_3": "Please note that there are some limitations to this, due to the security limitations imposed upon Power BI custom visuals.",
"Landing_Page_Overview_4": "You can visit the visual's home page by clicking the question mark icon in the top-right of this page.",
"Roles_HTML_Content": "HTML Content",
"Roles_HTML_Content_Description": "Field values or measures containing the desired HTML data to render.",
"Objects_ContentFormatting": "Content Formatting",
Expand Down
46 changes: 46 additions & 0 deletions style/visual.less
Original file line number Diff line number Diff line change
@@ -1,7 +1,53 @@
@import (less) "node_modules/overlayscrollbars/css/OverLayScrollbars.min.css";
@import (less) "node_modules/w3-css/w3.css";

#htmlViewer {
width: 100vw;
height: 100vh;
overflow: auto;
}

.w3-theme-l5 {color:#000 !important; background-color:#fcfcfc !important}
.w3-theme-l4 {color:#000 !important; background-color:#f6f6f6 !important}
.w3-theme-l3 {color:#000 !important; background-color:#eceded !important}
.w3-theme-l2 {color:#000 !important; background-color:#e3e4e4 !important}
.w3-theme-l1 {color:#000 !important; background-color:#d9dbdb !important}
.w3-theme-d1 {color:#000 !important; background-color:#babdbe !important}
.w3-theme-d2 {color:#000 !important; background-color:#a5a8aa !important}
.w3-theme-d3 {color:#fff !important; background-color:#8f9396 !important}
.w3-theme-d4 {color:#fff !important; background-color:#7a7f81 !important}
.w3-theme-d5 {color:#fff !important; background-color:#656a6c !important}

.w3-theme-light {color:#000 !important; background-color:#fcfcfc !important}
.w3-theme-dark {color:#fff !important; background-color:#656a6c !important}
.w3-theme-action {color:#fff !important; background-color:#656a6c !important}

.w3-theme {color:#000 !important; background-color:#d0d2d3 !important}
.w3-text-theme {color:#d0d2d3 !important}
.w3-border-theme {border-color:#d0d2d3 !important}

.w3-hover-theme:hover {color:#000 !important; background-color:#d0d2d3 !important}
.w3-hover-text-theme:hover {color:#d0d2d3 !important}
.w3-hover-border-theme:hover {border-color:#d0d2d3 !important}

.html-display-landing-page {
width: 100vw;
height: 100vh;
overflow: auto;
}

.html-display-watermark {
background-image: url("data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgNTEyIDUxMiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgb3ZlcmZsb3c9ImhpZGRlbiI+PHBhdGggZD0iTTcxIDQ2MCAzMCAwIDQ4MSAwIDQ0MCA0NjAgMjU1IDUxMiIgZmlsbD0iI0UzNEYyNiIvPjxwYXRoIGQ9Ik0yNTYgNDcyIDQwNSA0MzEgNDQwIDM3IDI1NiAzNyIgZmlsbD0iI0VGNjUyQSIvPjxwYXRoIGQ9Ik0yNTYgMjA4IDE4MSAyMDggMTc2IDE1MCAyNTYgMTUwIDI1NiA5NCAyNTUgOTQgMTE0IDk0IDExNSAxMDkgMTI5IDI2NSAyNTYgMjY1Wk0yNTYgMzU1IDI1NSAzNTUgMTkyIDMzOCAxODggMjkzIDE1OCAyOTMgMTMyIDI5MyAxMzkgMzgyIDI1NSA0MTQgMjU2IDQxNFoiIGZpbGw9IiNFQkVCRUIiLz48cGF0aCBkPSJNMjU1IDIwOCAyNTUgMjY1IDMyNSAyNjUgMzE4IDMzOCAyNTUgMzU1IDI1NSA0MTQgMzcxIDM4MiAzNzIgMzcyIDM4NSAyMjMgMzg3IDIwOCAzNzEgMjA4Wk0yNTUgOTQgMjU1IDEyOSAyNTUgMTUwIDI1NSAxNTAgMzkyIDE1MCAzOTIgMTUwIDM5MiAxNTAgMzkzIDEzOCAzOTYgMTA5IDM5NyA5NFoiIGZpbGw9IiNGRkZGRkYiLz48L3N2Zz4=");
background-repeat: no-repeat;
background-position: center;
background-size: auto 85%;
}

.html-display-minimised {
width: 100vw;
height: 100vh;
}

.html-display-help {
height: 60%;
}
3 changes: 2 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"es2015",
"dom"
],
"alwaysStrict": true
"alwaysStrict": true,
"resolveJsonModule": true
},
"files": [
"./src/visual.ts"
Expand Down

0 comments on commit 67c5875

Please sign in to comment.