Bundle all CSS and Office UI Fabric in the part (#321)

* Updated to drop 1.3

* Changed to dynamic office ui fabric loading
Bundled needed CSS, and depend on oob CSS for layout

* Refactored from javascript to typescript.
This commit is contained in:
Mikael Svenson 2017-10-09 04:46:50 -04:00 committed by Vesa Juvonen
parent 5f9d97ca53
commit 2e629e111d
7 changed files with 83 additions and 7863 deletions

View File

@ -48,7 +48,7 @@ If all you want is to add markup on the page, you can do that as well. Adding th
```
## Used SharePoint Framework Version
![drop](https://img.shields.io/badge/version-GA-green.svg)
![drop](https://img.shields.io/badge/drop-1.3.0-green.svg)
## Applies to
@ -66,7 +66,8 @@ react-script-editor | Mikael Svenson ([@mikaelsvenson](http://www.twitter.com/mi
Version|Date|Comments
-------|----|--------
1.0|March 10th, 2017|Initial release
1.0.1|August 8th, 2017|Updated SPFx version and CSS loading
1.0.0.1|August 8th, 2017|Updated SPFx version and CSS loading
1.0.0.2|October 4th, 2017|Updated SPFx version, bundle Office UI Fabric and CSS in webpart
## Disclaimer
**THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.**

View File

@ -1,12 +1,14 @@
{
"entries": [
{
"entry": "./lib/webparts/scriptEditor/ScriptEditorWebPart.js",
"manifest": "./src/webparts/scriptEditor/ScriptEditorWebPart.manifest.json",
"outputPath": "./dist/script-editor.bundle.js"
"$schema": "https://dev.office.com/json-schemas/spfx-build/config.2.0.schema.json",
"version": "2.0",
"bundles": {
"script-editor-bundle": {
"components": [
{
"entrypoint": "./lib/webparts/scriptEditor/ScriptEditorWebPart.js",
"manifest": "./src/webparts/scriptEditor/ScriptEditorWebPart.manifest.json"
}
]
}
],
"externals": {
"office-ui-fabric-react": "https://publiccdn.sharepointonline.com/techmikael.sharepoint.com/11510075fe4212d19d3e6d07c91981263dd697bf111cb1e5f0efb15de0ec08b382cde399/2.34.2/office-ui-fabric-react.bundle.min.js"
}
}

View File

@ -2,7 +2,7 @@
"solution": {
"name": "Modern Script Editor web part by Puzzlepart",
"id": "1425175f-3ed8-44d2-8fc4-dd1497191294",
"version": "1.0.0.1"
"version": "1.0.0.2"
},
"paths": {
"zippedPackage": "solution/pzl-script-editor.sppkg"

View File

@ -6,23 +6,22 @@
"node": ">=0.10.0"
},
"dependencies": {
"@microsoft/sp-client-base": "~1.0.0",
"@microsoft/sp-core-library": "~1.1.0",
"@microsoft/sp-webpart-base": "~1.1.0",
"@types/react": "0.14.46",
"@microsoft/sp-core-library": "~1.3.0",
"@microsoft/sp-webpart-base": "~1.3.0",
"@types/react": "15.0.38",
"@types/react-addons-shallow-compare": "0.14.17",
"@types/react-addons-test-utils": "0.14.15",
"@types/react-addons-update": "0.14.14",
"@types/react-dom": "0.14.18",
"@types/webpack-env": ">=1.12.1 <1.14.0",
"office-ui-fabric-react": "2.34.2",
"office-ui-fabric-react": "^4.40.1",
"react": "15.4.2",
"react-dom": "15.4.2"
},
"devDependencies": {
"@microsoft/sp-build-web": "~1.1.0",
"@microsoft/sp-module-interfaces": "~1.1.0",
"@microsoft/sp-webpart-workbench": "~1.1.0",
"@microsoft/sp-build-web": "~1.3.0",
"@microsoft/sp-module-interfaces": "~1.3.0",
"@microsoft/sp-webpart-workbench": "~1.3.0",
"gulp": "~3.9.1",
"@types/chai": ">=3.4.34 <3.6.0",
"@types/mocha": ">=2.2.33 <2.6.0"

View File

@ -68,6 +68,37 @@ export default class ScriptEditorWebPart extends BaseClientSideWebPart<IScriptEd
};
}
private evalScript(elem) {
const data = (elem.text || elem.textContent || elem.innerHTML || "");
const headTag = document.getElementsByTagName("head")[0] || document.documentElement;
const scriptTag = document.createElement("script");
scriptTag.type = "text/javascript";
if (elem.src && elem.src.length > 0) {
return;
}
if (elem.onload && elem.onload.length > 0) {
scriptTag.onload = elem.onload;
}
try {
// doesn't work on ie...
scriptTag.appendChild(document.createTextNode(data));
} catch (e) {
// IE has funky script nodes
scriptTag.text = data;
}
headTag.insertBefore(scriptTag, headTag.firstChild);
headTag.removeChild(scriptTag);
}
private nodeName(elem, name) {
return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();
}
// Finds and executes scripts in a newly added element's body.
// Needed since innerHTML does not run scripts.
//
@ -76,46 +107,13 @@ export default class ScriptEditorWebPart extends BaseClientSideWebPart<IScriptEd
// Define global name to tack scripts on in case script to be loaded is not AMD/UMD
(<any>window).ScriptGlobal = {};
function nodeName(elem, name) {
return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();
}
function evalScript(elem) {
var data = (elem.text || elem.textContent || elem.innerHTML || ""),
head = document.getElementsByTagName("head")[0] ||
document.documentElement,
script = document.createElement("script");
script.type = "text/javascript";
if (elem.src && elem.src.length > 0) {
return;
}
if (elem.onload && elem.onload.length > 0) {
script.onload = elem.onload;
}
try {
// doesn't work on ie...
script.appendChild(document.createTextNode(data));
} catch (e) {
// IE has funky script nodes
script.text = data;
}
head.insertBefore(script, head.firstChild);
head.removeChild(script);
}
// main section of function
var scripts = [],
script,
children_nodes = element.childNodes,
child,
i;
const scripts = [];
const children_nodes = element.childNodes;
for (i = 0; children_nodes[i]; i++) {
child = children_nodes[i];
if (nodeName(child, "script") &&
for (var i = 0; children_nodes[i]; i++) {
const child: any = children_nodes[i];
if (this.nodeName(child, "script") &&
(!child.type || child.type.toLowerCase() === "text/javascript")) {
scripts.push(child);
}
@ -123,13 +121,13 @@ export default class ScriptEditorWebPart extends BaseClientSideWebPart<IScriptEd
const urls = [];
const onLoads = [];
for (i = 0; scripts[i]; i++) {
script = scripts[i];
if (script.src && script.src.length > 0) {
urls.push(script.src);
for (var j = 0; scripts[j]; j++) {
const scriptTag = scripts[j];
if (scriptTag.src && scriptTag.src.length > 0) {
urls.push(scriptTag.src);
}
if (script.onload && script.onload.length > 0) {
onLoads.push(script.onload);
if (scriptTag.onload && scriptTag.onload.length > 0) {
onLoads.push(scriptTag.onload);
}
}
@ -146,15 +144,15 @@ export default class ScriptEditorWebPart extends BaseClientSideWebPart<IScriptEd
promiseSerial(allFuncs)
.then(() => {
// execute any onload people have added
for (i = 0; onLoads[i]; i++) {
onLoads[i]();
for (j = 0; onLoads[j]; j++) {
onLoads[j]();
}
// execute script blocks
for (i = 0; scripts[i]; i++) {
script = scripts[i];
if (script.parentNode) { script.parentNode.removeChild(script); }
evalScript(scripts[i]);
for (j = 0; scripts[j]; j++) {
const scriptTag = scripts[j];
if (scriptTag.parentNode) { scriptTag.parentNode.removeChild(scriptTag); }
this.evalScript(scripts[j]);
}
}).catch(console.error);
};
}
}

View File

@ -1,35 +1,26 @@
import * as React from 'react';
import styles from './ScriptEditor.module.scss';
import { IScriptEditorProps } from './IScriptEditorProps';
import { Dialog, DialogType, DialogFooter } from 'office-ui-fabric-react';
import { DefaultButton, PrimaryButton } from 'office-ui-fabric-react';
import { TextField } from 'office-ui-fabric-react';
import { Dialog, DialogType, DialogFooter } from 'office-ui-fabric-react/lib/Dialog';
import { DefaultButton, PrimaryButton } from 'office-ui-fabric-react/lib/Button';
import { TextField } from 'office-ui-fabric-react/lib/TextField';
import { loadStyles } from '@microsoft/load-themed-styles';
require('./overrides.css');
export default class ScriptEditor extends React.Component<IScriptEditorProps, any> {
constructor() {
super();
this.loadCss();
const uiFabricCSS: string = `
.pzl-bgColor-themeDark, .pzl-bgColor-themeDark--hover:hover {
background-color: "[theme:themeDark, default:#005a9e]";
}
`;
loadStyles(uiFabricCSS);
this.state = {
showDialog: false
};
}
public async loadCss() {
if (window["UIFabricLoaded"]) {
return;
}
const response = await fetch("https://publiccdn.sharepointonline.com/techmikael.sharepoint.com/11510075fe4212d19d3e6d07c91981263dd697bf111cb1e5f0efb15de0ec08b382cde399/5.0.1/office-ui-fabric.min.css");
if (response.ok) {
response.text().then((data: any) => {
loadStyles(data);
window["UIFabricLoaded"] = true;
this.forceUpdate();
});
}
}
public componentDidMount(): void {
this.setState({ script: this.props.script, loaded: this.props.script });
}
@ -52,19 +43,16 @@ export default class ScriptEditor extends React.Component<IScriptEditorProps, an
}
public render(): React.ReactElement<IScriptEditorProps> {
if (!window["UIFabricLoaded"]) {
return <span />;
}
const viewMode = <span dangerouslySetInnerHTML={{ __html: this.state.script }}></span>;
return (
<div >
<div className={styles.scriptEditor}>
<div className={styles.container}>
<div className={`pzl-Grid-row pzl-bgColor-themeDark pzl-fontColor-white ${styles.row}`}>
<div className="pzl-Grid-col pzl-u-lg10 pzl-u-xl8 pzl-u-xlPush2 pzl-u-lgPush1">
<span className="pzl-font-xl pzl-fontColor-white">The Modern Script Editor web part!</span>
<p className="pzl-font-l pzl-fontColor-white"></p>
<div className={`ms-Grid-row pzl-bgColor-themeDark ms-fontColor-white ${styles.row}`}>
<div className="ms-Grid-col ms-lg10 ms-xl8 ms-xlPush2 ms-lgPush1">
<span className="ms-font-xl ms-fontColor-white">The Modern Script Editor web part!</span>
<p className="ms-font-l ms-fontColor-white"></p>
<DefaultButton description='Opens the Sample Dialog' onClick={this._showDialog.bind(this)}>Edit snippet</DefaultButton>
</div>
</div>