Merge pull request #445 from wobba/ModernScriptImproveLoading

Support for AMD/UMD modules
This commit is contained in:
Mikael Svenson 2018-03-08 14:21:54 -08:00 committed by GitHub
commit de679bcfa3
5 changed files with 83 additions and 24 deletions

View File

@ -47,8 +47,47 @@ If all you want is to add markup on the page, you can do that as well. Adding th
</ul>
```
You may add CSS via style tags or `link` tags.
```html
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<style>
#container h1 {
color: red;
}
</style>
<div id="container">
<h1>Headline</h1>
</div>
<div class="row">
<div class="col-md-8">.col-md-8</div>
<div class="col-md-4">.col-md-4</div>
</div>
<div class="row">
<div class="col-md-4">.col-md-4</div>
<div class="col-md-4">.col-md-4</div>
<div class="col-md-4">.col-md-4</div>
</div>
```
## Notes for AMD/UMD modules
If the library you load is an AMD/UMD module you have to add the custom attribute `module` on the script tag, specifying the global name which should hold the module.
```html
<div id="time"></div>
<script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js" module="mymoment"></script>
<script>
var m = mymoment();
document.getElementById("time").innerHTML = m.format('MMMM Do YYYY, HH:mm:ss');
</script>
```
## Support for classic _spPageContextInfo
If your scripts rely on the classic _spPageContextInfo, you can enable that in the web part property pane.
## Used SharePoint Framework Version
![drop](https://img.shields.io/badge/drop-1.4.0-green.svg)
![drop](https://img.shields.io/badge/drop-1.4.1-green.svg)
## Applies to
@ -70,6 +109,7 @@ Version|Date|Comments
1.0.0.2|October 4th, 2017|Updated SPFx version, bundle Office UI Fabric and CSS in webpart
1.0.0.3|January 10th, 2018|Updated SPFx version, added remove padding property and refactoring
1.0.0.4|February 14th, 2018|Added title property for edit mode and documentation for enabling the web part on Group sites / tenant wide
1.0.0.5|March 8th, 2018|Added support for loading scripts which are AMD/UMD modules. Added support for classic _spPageContextInfo. Refactoring.
## 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

@ -2,7 +2,7 @@
"solution": {
"name": "Modern Script Editor web part by Puzzlepart",
"id": "1425175f-3ed8-44d2-8fc4-dd1497191294",
"version": "1.0.0.4",
"version": "1.0.0.5",
"includeClientSideAssets": true,
"skipFeatureDeployment": false
},

View File

@ -2,4 +2,5 @@ export interface IScriptEditorWebPartProps {
script: string;
title: string;
removePadding: boolean;
spPageContextInfo: boolean;
}

View File

@ -22,7 +22,8 @@
"properties": {
"script": "",
"title" : "The Modern Script Editor web part!",
"removePadding": false
"removePadding": false,
"spPageContextInfo" : false
}
}
]

View File

@ -63,7 +63,7 @@ export default class ScriptEditorWebPart extends BaseClientSideWebPart<IScriptEd
groups: [
{
groupFields: [
PropertyPaneTextField("title",{
PropertyPaneTextField("title", {
label: "Title to show in edit mode",
value: this.properties.title
}),
@ -73,6 +73,12 @@ export default class ScriptEditorWebPart extends BaseClientSideWebPart<IScriptEd
onText: "Remove padding",
offText: "Keep padding"
}),
PropertyPaneToggle("spPageContextInfo", {
label: "Enable classic _spPageContextInfo",
checked: this.properties.spPageContextInfo,
onText: "Enabled",
offText: "Disabled"
}),
PropertyPaneCustomField({
onRender: this.renderLogo,
key: "logo"
@ -120,8 +126,13 @@ export default class ScriptEditorWebPart extends BaseClientSideWebPart<IScriptEd
// Needed since innerHTML does not run scripts.
//
// Argument element is an element in the dom.
private executeScript(element: HTMLElement) {
private async executeScript(element: HTMLElement) {
// Define global name to tack scripts on in case script to be loaded is not AMD/UMD
if(this.properties.spPageContextInfo && !window["_spPageContextInfo"]){
window["_spPageContextInfo"] = this.context.pageContext.legacyPageContext;
}
(<any>window).ScriptGlobal = {};
// main section of function
@ -138,10 +149,14 @@ export default class ScriptEditorWebPart extends BaseClientSideWebPart<IScriptEd
const urls = [];
const onLoads = [];
const moduleMap = [];
for (var j = 0; scripts[j]; j++) {
const scriptTag = scripts[j];
if (scriptTag.src && scriptTag.src.length > 0) {
urls.push(scriptTag.src);
if (scriptTag.attributes["module"] && scriptTag.attributes["module"].value.length > 0) {
moduleMap[scriptTag.src] = scriptTag.attributes["module"].value;
}
}
if (scriptTag.onload && scriptTag.onload.length > 0) {
onLoads.push(scriptTag.onload);
@ -150,26 +165,28 @@ export default class ScriptEditorWebPart extends BaseClientSideWebPart<IScriptEd
// Execute promises in sequentially - https://hackernoon.com/functional-javascript-resolving-promises-sequentially-7aac18c4431e
// Use "ScriptGlobal" as the global namein case script is AMD/UMD
const allFuncs = urls.map(url => () => SPComponentLoader.loadScript(url, { globalExportsName: "ScriptGlobal" }));
const promiseSerial = funcs =>
funcs.reduce((promise, func) =>
promise.then(result => func().then(Array.prototype.concat.bind(result))),
Promise.resolve([]));
for (let i = 0; i < urls.length; i++) {
try {
let m: any = await SPComponentLoader.loadScript(urls[i], { globalExportsName: "ScriptGlobal" });
let moduleName = moduleMap[urls[i]];
if (moduleName) {
//If it's a AMD/UMD module, then assign to that global variable
window[moduleName] = m;
}
} catch (error) {
console.error(error);
}
}
// execute Promises in serial
promiseSerial(allFuncs)
.then(() => {
// execute any onload people have added
for (j = 0; onLoads[j]; j++) {
onLoads[j]();
}
// execute script blocks
for (j = 0; scripts[j]; j++) {
const scriptTag = scripts[j];
if (scriptTag.parentNode) { scriptTag.parentNode.removeChild(scriptTag); }
this.evalScript(scripts[j]);
}
}).catch(console.error);
for (j = 0; scripts[j]; j++) {
const scriptTag = scripts[j];
if (scriptTag.parentNode) { scriptTag.parentNode.removeChild(scriptTag); }
this.evalScript(scripts[j]);
}
// execute any onload people have added
for (j = 0; onLoads[j]; j++) {
onLoads[j]();
}
}
}