Created separate version for on-prem backwards compat.

This commit is contained in:
Mikael Svenson 2020-03-13 11:19:50 +01:00
parent 90a98a3ec4
commit 316155fce4
31 changed files with 31245 additions and 0 deletions

View File

@ -0,0 +1,25 @@
# EditorConfig helps developers define and maintain consistent
# coding styles between different editors and IDEs
# editorconfig.org
root = true
[*]
# change these settings to your own preference
indent_style = space
indent_size = 2
# we recommend you to keep these unchanged
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
[{package,bower}.json]
indent_style = space
indent_size = 2

View File

@ -0,0 +1 @@
* text=auto

View File

@ -0,0 +1,32 @@
# Logs
logs
*.log
npm-debug.log*
# Dependency directories
node_modules
# Build generated files
dist
lib
solution
temp
*.sppkg
# Coverage directory used by tools like istanbul
coverage
# OSX
.DS_Store
# Visual Studio files
.ntvs_analysis.dat
.vs
bin
obj
# Resx Generated Code
*.resx.ts
# Styles Generated Code
*.scss.ts

View File

@ -0,0 +1,14 @@
# Folders
.vscode
coverage
node_modules
sharepoint
src
temp
# Files
*.csproj
.git*
.yo-rc.json
gulpfile.js
tsconfig.json

View File

@ -0,0 +1,11 @@
{
"@microsoft/generator-sharepoint": {
"libraryName": "pnp-script-editor",
"framework": "react",
"version": "1.4.1",
"libraryId": "1425175f-3ed8-44d2-8fc4-dd1497191294",
"isCreatingSolution": true,
"packageManager": "npm",
"componentType": "webpart"
}
}

View File

@ -0,0 +1,174 @@
---
page_type: sample
products:
- office-sp
languages:
- javascript
- typescript
extensions:
contentType: samples
technologies:
- SharePoint Framework
platforms:
- react
createdDate: 3/1/2017 12:00:00 AM
---
# Script editor web part for modern pages built in React
This version is built on SPFx v1.4.1 and also support SharePoint on-premises. If you want a version for SPO only go to [react-script-editor](../react-script-editor).
## Summary
Coming from old classic SharePoint pages you might have existing script solutions you want to re-use on a modern page
without having to repackage it as a new SharePoint Framework web part. This web part is similar to the classic
Script Editor Web Part, and allows you do drop arbitrary script or html on a modern page.
> Notice. All client-side web parts are deployed or enabled to be available in site level by tenant administrator using tenant app catalog. If there are concerns on enabling script options in a tenant, this web part or a approach should not be approved by tenant administrators.
As an example add the following scripts to the web part in order to show stock ticker info on your page. First *tv.js* is loaded, and then the script block is executed to show the ticker information.
```html
<!-- TradingView Widget BEGIN -->
<div class="tradingview-widget-container">
<div id="tradingview_ab4e5"></div>
<div class="tradingview-widget-copyright"><a href="https://www.tradingview.com/symbols/NASDAQ-MSFT/" rel="noopener" target="_blank"><span class="blue-text">MSFT chart</span></a> by TradingView</div>
</div>
<script type="text/javascript" src="https://s3.tradingview.com/tv.js"></script>
<script type="text/javascript">
new TradingView.widget({
"width": 400,
"height": 200,
"symbol": "NASDAQ:MSFT",
"interval": "D",
"timezone": "Etc/UTC",
"theme": "Light",
"style": "1",
"locale": "en",
"toolbar_bg": "#f1f3f6",
"enable_publishing": false,
"allow_symbol_change": true,
"container_id": "tradingview_ab4e5"
});
</script>
<!-- TradingView Widget END -->
```
The web part works by loading each script in a `<script src>` tag sequentially in the order they are specified, then any other `<script>` block is executed.
![site page header configurator web part](./assets/modern-script-editor-wp.gif)
If all you want is to add markup on the page, you can do that as well. Adding the following html would show a headline and a list.
```html
<h2>My header</h2>
<ul>
<li>One
<li>Two
<li>Three
</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>
```
## 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.1-green.svg)
## Applies to
* [SharePoint Framework Release GA](https://blogs.office.com/2017/02/23/sharepoint-framework-reaches-general-availability-build-and-deploy-engaging-web-parts-today/)
* [Office 365 tenant](https://dev.office.com/sharepoint/docs/spfx/set-up-your-development-environment)
## Solution
Solution|Author(s)
--------|---------
react-script-editor | Mikael Svenson ([@mikaelsvenson](http://www.twitter.com/mikaelsvenson), [techmikael.com](techmikael.com))
## Version history
Version|Date|Comments
-------|----|--------
1.0|March 10th, 2017|Initial release
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
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.
1.0.0.6|March 26th, 2018|Fixed so that AMD modules don't detect `define`, and load as non-modules.
1.0.0.7|May 23rd, 2018|Added supportsFullBleed to manifest.
1.0.0.8|May 23rd, 2018|Updated SPFx to v1.5.1, made editor load dynamically to reduce runtime bundle size, fixed white space issue.
1.0.0.9|Aug 22, 2018|Improved bundle size
1.0.0.10|Jan 16th, 2019|Fix for removing of web part padding
1.0.0.11|March 18th, 2019|Fix for re-loading of script on smart navigation
1.0.0.12|April 15th, 2019|Re-fix for pad removal of web part
1.0.0.13|July 1th, 2019|Downgrade to SPFx v1.4.1 to support SP2019
1.0.0.14|Oct 13th, 2019|Added resolve to fix pnpm issue. Updated author info.
## 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.**
---
## Minimal Path to Awesome
### Local testing
- Clone this repository
- In the command line run:
- `npm install`
- `gulp serve`
### Deploy
* gulp clean
* gulp bundle --ship
* gulp package-solution --ship
* Upload .sppkg file from sharepoint\solution to your tenant App Catalog
* E.g.: https://&lt;tenant&gt;.sharepoint.com/sites/AppCatalog/AppCatalog
* Add the web part to a site collection, and test it on a page
### Deploy to non-script sites / modern team sites
By default this web part is not allowed on no-script sites, as it allows execution of arbitrary script. This is by design as from a security and governance perspective you might not want arbitrary script added to your pages. This is typically something you want control over.
If you however want to allow the web part for non-script sites like Office 365 Group modern team sites you have to edit `ScriptEditorWebPart.manifest.json` with the following change:
```
"requiresCustomScript": false
```
### Deploy tenant wide
By default you have to install this web part per site collection where you want it availble. If you want it enabled by default on all sites you have to edit `package-solution.json` with the following change:
```
"skipFeatureDeployment": true
```
In order to make it availble to absolutely all sites you need apply the _Deploy to non-script sites / modern team site_ change as well.
## Features
This web part illustrates the following concepts on top of the SharePoint Framework:
- Re-use existing JavaScript solutions on a modern page
- Office UI Fabric
- React
<img src="https://telemetry.sharepointpnp.com/sp-dev-fx-webparts/samples/react-script-editor" />

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 MiB

View File

@ -0,0 +1,14 @@
{
"$schema": "https://developer.microsoft.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"
}
]
}
}
}

View File

@ -0,0 +1,4 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/copy-assets.schema.json",
"deployCdnPath": "temp/deploy"
}

View File

@ -0,0 +1,7 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/deploy-azure-storage.schema.json",
"workingDir": "./temp/deploy/",
"account": "<!-- STORAGE ACCOUNT NAME -->",
"container": "pnp-script-editor",
"accessKey": "<!-- ACCESS KEY -->"
}

View File

@ -0,0 +1,13 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json",
"solution": {
"name": "Modern Script Editor web part by mikaelsvenson",
"id": "1425175f-3ed8-44d2-8fc4-dd1497191294",
"version": "1.0.0.14",
"includeClientSideAssets": true,
"skipFeatureDeployment": false
},
"paths": {
"zippedPackage": "solution/pnp-script-editor.sppkg"
}
}

View File

@ -0,0 +1,10 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/core-build/serve.schema.json",
"port": 4321,
"initialPage": "https://localhost:5432/workbench",
"https": true,
"api": {
"port": 5432,
"entryPath": "node_modules/@microsoft/sp-webpart-workbench/lib/api/"
}
}

View File

@ -0,0 +1,46 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/core-build/tslint.schema.json",
// Display errors as warnings
"displayAsWarning": true,
// The TSLint task may have been configured with several custom lint rules
// before this config file is read (for example lint rules from the tslint-microsoft-contrib
// project). If true, this flag will deactivate any of these rules.
"removeExistingRules": true,
// When true, the TSLint task is configured with some default TSLint "rules.":
"useDefaultConfigAsBase": false,
// Since removeExistingRules=true and useDefaultConfigAsBase=false, there will be no lint rules
// which are active, other than the list of rules below.
"lintConfig": {
// Opt-in to Lint rules which help to eliminate bugs in JavaScript
"rules": {
"class-name": false,
"export-name": false,
"forin": false,
"label-position": false,
"member-access": true,
"no-arg": false,
"no-console": false,
"no-construct": false,
"no-duplicate-case": true,
"no-duplicate-variable": true,
"no-eval": false,
"no-function-expression": true,
"no-internal-module": true,
"no-shadowed-variable": true,
"no-switch-case-fall-through": true,
"no-unnecessary-semicolons": true,
"no-unused-expression": true,
"no-use-before-declare": true,
"no-with-statement": true,
"semicolon": true,
"trailing-comma": false,
"typedef": false,
"typedef-whitespace": false,
"use-named-parameter": true,
"valid-typeof": true,
"variable-name": false,
"whitespace": false,
"prefer-const": true
}
}
}

View File

@ -0,0 +1,4 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/write-manifests.schema.json",
"cdnBasePath": "<!-- PATH TO CDN -->"
}

View File

@ -0,0 +1,25 @@
'use strict';
const gulp = require('gulp');
const path = require('path');
const build = require('@microsoft/sp-build-web');
const bundleAnalyzer = require('webpack-bundle-analyzer');
build.configureWebpack.mergeConfig({
additionalConfiguration: (generatedConfiguration) => {
const lastDirName = path.basename(__dirname);
const dropPath = path.join(__dirname, 'temp', 'stats');
generatedConfiguration.plugins.push(new bundleAnalyzer.BundleAnalyzerPlugin({
openAnalyzer: false,
analyzerMode: 'static',
reportFilename: path.join(dropPath, `${lastDirName}.stats.html`),
generateStatsFile: true,
statsFilename: path.join(dropPath, `${lastDirName}.stats.json`),
logLevel: 'error'
}));
return generatedConfiguration;
}
});
build.initialize(gulp);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,41 @@
{
"name": "pnp-script-editor",
"version": "1.0.0",
"private": true,
"engines": {
"node": ">=0.10.0"
},
"resolutions": {
"natives": "1.1.3",
"@types/react": "15.6.6"
},
"dependencies": {
"@microsoft/load-themed-styles": "^1.4.1",
"@microsoft/sp-core-library": "1.4.1",
"@microsoft/sp-loader": "^1.4.1",
"@microsoft/sp-webpart-base": "1.4.1",
"@types/es6-promise": "0.0.33",
"@types/react": "15.6.6",
"@types/react-dom": "15.5.6",
"@types/webpack-env": "1.13.1",
"office-ui-fabric-react": "^5.118.3",
"react": "15.6.2",
"react-dom": "15.6.2"
},
"devDependencies": {
"@microsoft/sp-build-web": "1.4.1",
"@microsoft/sp-module-interfaces": "1.4.1",
"@microsoft/sp-webpart-workbench": "1.4.1",
"@types/chai": "3.4.34",
"@types/mocha": "2.2.38",
"@types/prop-types": "ts2.4",
"ajv": "~5.2.2",
"gulp": "~3.9.1",
"webpack-bundle-analyzer": "^2.13.1"
},
"scripts": {
"build": "gulp bundle",
"clean": "gulp clean",
"test": "gulp test"
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,6 @@
export interface IScriptEditorWebPartProps {
script: string;
title: string;
removePadding: boolean;
spPageContextInfo: boolean;
}

View File

@ -0,0 +1,26 @@
import {
IPropertyPaneField,
PropertyPaneFieldType,
IPropertyPaneCustomFieldProps
} from '@microsoft/sp-webpart-base';
export class PropertyPaneLogo implements IPropertyPaneField<IPropertyPaneCustomFieldProps> {
public type: PropertyPaneFieldType = PropertyPaneFieldType.Custom;
public targetProperty: string;
public properties: IPropertyPaneCustomFieldProps;
constructor() {
this.properties = {
key: "Logo",
onRender: this.onRender.bind(this)
};
}
private onRender(elem: HTMLElement): void {
elem.innerHTML = `
<div style="margin-top: 30px">
<div style="float:right">Author: <a href="https://twitter.com/mikaelsvenson" tabindex="-1">Mikael Svenson</a></div>
</div>`;
}
}
export default PropertyPaneLogo;

View File

@ -0,0 +1,29 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx/client-side-web-part-manifest.schema.json",
"id": "3a328f0a-99c4-4b28-95ab-fe0847f657a3",
"alias": "ScriptEditorWebPart",
"componentType": "WebPart",
"version": "*",
"supportsFullBleed": true,
"manifestVersion": 2,
"requiresCustomScript": true,
"preconfiguredEntries": [{
"groupId": "3a328f0a-99c4-4b28-95ab-fe0847f657a3",
"group": {
"default": "mAdcOW deZign"
},
"title": {
"default": "Modern Script Editor"
},
"description": {
"default": "Add arbitrary script to a page"
},
"officeFabricIconFontName": "JS",
"properties": {
"script": "",
"title": "The Modern Script Editor web part!",
"removePadding": false,
"spPageContextInfo": false
}
}]
}

View File

@ -0,0 +1,198 @@
import * as React from 'react';
import * as ReactDom from 'react-dom';
import { Version, DisplayMode } from '@microsoft/sp-core-library';
import { SPComponentLoader } from '@microsoft/sp-loader';
import {
BaseClientSideWebPart,
IPropertyPaneConfiguration,
PropertyPaneToggle,
PropertyPaneTextField
} from '@microsoft/sp-webpart-base';
import { IScriptEditorProps } from './components/IScriptEditorProps';
import { IScriptEditorWebPartProps } from './IScriptEditorWebPartProps';
import PropertyPaneLogo from './PropertyPaneLogo';
export default class ScriptEditorWebPart extends BaseClientSideWebPart<IScriptEditorWebPartProps> {
public save: (script: string) => void = (script: string) => {
this.properties.script = script;
this.render();
}
public render(): void {
if (this.displayMode == DisplayMode.Read) {
if (this.properties.removePadding) {
let element = this.domElement.parentElement;
// check up to 5 levels up for padding and exit once found
for (let i = 0; i < 5; i++) {
const style = window.getComputedStyle(element);
const hasPadding = style.paddingTop !== "0px";
if (hasPadding) {
element.style.paddingTop = "0px";
element.style.paddingBottom = "0px";
element.style.marginTop = "0px";
element.style.marginBottom = "0px";
}
element = element.parentElement;
}
}
this.domElement.innerHTML = this.properties.script;
this.executeScript(this.domElement);
} else {
this.renderEditor();
}
}
private async renderEditor(){
// Dynamically load the editor pane to reduce overall bundle size
const editorPopUp = await import(
/* webpackChunkName: 'scripteditor' */
'./components/ScriptEditor'
);
const element: React.ReactElement<IScriptEditorProps> = React.createElement(
editorPopUp.default,
{
script: this.properties.script,
title: this.properties.title,
save: this.save
}
);
ReactDom.render(element, this.domElement);
}
protected get dataVersion(): Version {
return Version.parse('1.0');
}
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
groups: [
{
groupFields: [
PropertyPaneTextField("title", {
label: "Title to show in edit mode",
value: this.properties.title
}),
PropertyPaneToggle("removePadding", {
label: "Remove top/bottom padding of web part container",
checked: this.properties.removePadding,
onText: "Remove padding",
offText: "Keep padding"
}),
PropertyPaneToggle("spPageContextInfo", {
label: "Enable classic _spPageContextInfo",
checked: this.properties.spPageContextInfo,
onText: "Enabled",
offText: "Disabled"
}),
new PropertyPaneLogo()
]
}
]
}
]
};
}
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.
//
// Argument element is an element in the dom.
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
const scripts = [];
const children_nodes = element.childNodes;
for (let 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);
}
}
const urls = [];
const onLoads = [];
for (let i = 0; scripts[i]; i++) {
const scriptTag = scripts[i];
if (scriptTag.src && scriptTag.src.length > 0) {
urls.push(scriptTag.src);
}
if (scriptTag.onload && scriptTag.onload.length > 0) {
onLoads.push(scriptTag.onload);
}
}
let oldamd = null;
if (window["define"] && window["define"].amd) {
oldamd = window["define"].amd;
window["define"].amd = null;
}
for (let i = 0; i < urls.length; i++) {
try {
let scriptUrl = urls[i];
const prefix = scriptUrl.indexOf('?') === -1 ? '?' : '&';
scriptUrl += prefix + 'cow=' + new Date().getTime();
await SPComponentLoader.loadScript(scriptUrl, { globalExportsName: "ScriptGlobal" });
} catch (error) {
if (console.error) {
console.error(error);
}
}
}
if (oldamd) {
window["define"].amd = oldamd;
}
for (let i = 0; scripts[i]; i++) {
const scriptTag = scripts[i];
if (scriptTag.parentNode) { scriptTag.parentNode.removeChild(scriptTag); }
this.evalScript(scripts[i]);
}
// execute any onload people have added
for (let i = 0; onLoads[i]; i++) {
onLoads[i]();
}
}
}

View File

@ -0,0 +1,5 @@
export interface IScriptEditorProps {
script: string;
title: string;
save(script: string): void;
}

View File

@ -0,0 +1,13 @@
@import '~office-ui-fabric-react/dist/sass/References.scss';
.scriptEditor {
.container {
max-width: 700px;
margin: 0px auto;
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
}
.row {
padding: 20px;
}
}

View File

@ -0,0 +1,85 @@
import * as React from 'react';
import styles from './ScriptEditor.module.scss';
import { IScriptEditorProps } from './IScriptEditorProps';
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._showDialog = this._showDialog.bind(this);
this._closeDialog = this._closeDialog.bind(this);
this._cancelDialog = this._cancelDialog.bind(this);
this._onScriptEditorTextChanged = this._onScriptEditorTextChanged.bind(this);
const uiFabricCSS: string = `
.pnp-bgColor-themeDark, .pnp-bgColor-themeDark--hover:hover {
background-color: "[theme:themeDark, default:#005a9e]";
}
`;
loadStyles(uiFabricCSS);
this.state = {
showDialog: false
};
}
public componentDidMount(): void {
this.setState({ script: this.props.script, loaded: this.props.script });
}
private _showDialog() {
this.setState({ showDialog: true });
}
private _closeDialog() {
this.setState({ showDialog: false });
this.props.save(this.state.script);
}
private _cancelDialog() {
this.props.save(this.state.loaded);
this.setState({ showDialog: false, script: this.state.loaded });
}
private _onScriptEditorTextChanged(text: string) {
this.setState({ script: text });
}
public render(): React.ReactElement<IScriptEditorProps> {
const viewMode = <span dangerouslySetInnerHTML={{ __html: this.state.script }}></span>;
return (
<div >
<div className={styles.scriptEditor}>
<div className={styles.container}>
<div className={`ms-Grid-row pnp-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">{this.props.title}</span>
<p className="ms-font-l ms-fontColor-white"></p>
<DefaultButton description='Opens the snippet dialog' onClick={this._showDialog}>Edit snippet</DefaultButton>
</div>
</div>
</div>
</div>
<Dialog
isOpen={this.state.showDialog}
type={DialogType.normal}
onDismiss={this._closeDialog}
title='Embed'
subText='Paste your script, markup or embed code below. Note that scripts will only run in view mode.'
isBlocking={true}
className={'ScriptPart'}
>
<TextField multiline rows={15} onChanged={this._onScriptEditorTextChanged} value={this.state.script} />
<DialogFooter>
<PrimaryButton onClick={this._closeDialog}>Save</PrimaryButton>
<DefaultButton onClick={this._cancelDialog}>Cancel</DefaultButton>
</DialogFooter>
{viewMode}
</Dialog>
</div >);
}
}

View File

@ -0,0 +1,4 @@
.ScriptPart .ms-Dialog-main {
width: 65%;
max-width: 65%;
}

View File

@ -0,0 +1,9 @@
/// <reference types="mocha" />
import { assert } from 'chai';
describe('ScriptEditorWebPart', () => {
it('should do something', () => {
assert.ok(true);
});
});

View File

@ -0,0 +1,26 @@
{
"compilerOptions": {
"target": "es5",
"forceConsistentCasingInFileNames": true,
"module": "esnext",
"jsx": "react",
"declaration": true,
"sourceMap": true,
"experimentalDecorators": true,
"skipLibCheck": true,
"moduleResolution": "node",
"typeRoots": [
"./node_modules/@types",
"./node_modules/@microsoft"
],
"types": [
"es6-promise",
"webpack-env"
],
"lib": [
"es5",
"dom",
"es2015.collection"
]
}
}

View File

@ -0,0 +1,3 @@
{
"rulesDirectory": "./config"
}

View File

@ -0,0 +1,8 @@
// Type definitions for Microsoft ODSP projects
// Project: ODSP
/* Global definition for UNIT_TEST builds
Code that is wrapped inside an if(UNIT_TEST) {...}
block will not be included in the final bundle when the
--ship flag is specified */
declare const UNIT_TEST: boolean;

View File

@ -0,0 +1 @@
/// <reference path="@ms/odsp.d.ts" />