Adding the riot-list sample webpart (#184)
* Adding the riot-list sample webpart * Adding the latest Animated Gif file
This commit is contained in:
parent
cf2dd21984
commit
f3669414d9
|
@ -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
|
|
@ -0,0 +1 @@
|
|||
* text=auto
|
|
@ -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
|
|
@ -0,0 +1,14 @@
|
|||
# Folders
|
||||
.vscode
|
||||
coverage
|
||||
node_modules
|
||||
sharepoint
|
||||
src
|
||||
temp
|
||||
|
||||
# Files
|
||||
*.csproj
|
||||
.git*
|
||||
.yo-rc.json
|
||||
gulpfile.js
|
||||
tsconfig.json
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"@microsoft/generator-sharepoint": {
|
||||
"libraryName": "spfx-riot-list",
|
||||
"framework": "none",
|
||||
"version": "1.0.2",
|
||||
"libraryId": "6e137a70-041c-49e1-aa9e-470b704180a0"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
# List RiotJS Client-Side Web Part
|
||||
|
||||
## Summary
|
||||
Simplistic sample Web Part that demonstrates the use of RiotJS in creating a SharePoint Framework web part. The properties pane for this web part display a drop down list of lists in the current web. Once the user selects one of the lists, the web part display the contents of the list.
|
||||
|
||||
|
||||
![Screeshot of the Display List web part](./assets/riot-list-preview.gif)
|
||||
|
||||
> Does only show data when hosted in SharePoint. No mock data at this point for local testing the rendering.
|
||||
|
||||
## Used SharePoint Framework Version
|
||||
![drop](https://img.shields.io/badge/drop-ga-green.svg)
|
||||
|
||||
## Applies to
|
||||
|
||||
* [SharePoint Framework General Availability](http://dev.office.com/sharepoint/docs/spfx/sharepoint-framework-overview)
|
||||
* [Office 365 developer tenant](http://dev.office.com/sharepoint/docs/spfx/set-up-your-developer-tenant)
|
||||
|
||||
|
||||
## Solution
|
||||
|
||||
Solution|Author(s)
|
||||
--------|---------
|
||||
spfx-riot-list|Sébastien Levert (MVP, Valo Intranet, @sebastienlevert)
|
||||
|
||||
|
||||
## Version history
|
||||
|
||||
Version|Date|Comments
|
||||
-------|----|--------
|
||||
1.0|April 26, 2017|Initial release
|
||||
|
||||
|
||||
## 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
|
||||
|
||||
- Clone this repository
|
||||
- in the command line run:
|
||||
- `npm install`
|
||||
- `gulp serve`
|
||||
- `Open the *workbench* on your Office 365 Developer tenant`
|
||||
- Basic functionality can be tested locally, data is only shown when used in context of SharePoint
|
||||
|
||||
## Features
|
||||
The spfx-riot-webpart web part displays the content of the list specified in the web part properties pane.
|
||||
|
||||
This Web Part illustrates the following concepts on top of the SharePoint Framework:
|
||||
|
||||
* Using RiotJS as the component rendering engine
|
||||
* The use of modular CSS
|
||||
* The use of PnP JS Core with async/await support in TypeScript
|
Binary file not shown.
After Width: | Height: | Size: 726 KiB |
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"entries": [
|
||||
{
|
||||
"entry": "./lib/webparts/listViewer/ListViewerWebPart.js",
|
||||
"manifest": "./src/webparts/listViewer/ListViewerWebPart.manifest.json",
|
||||
"outputPath": "./dist/list-viewer.bundle.js"
|
||||
}
|
||||
],
|
||||
"externals": {},
|
||||
"localizedResources": {
|
||||
"listViewerStrings": "webparts/listViewer/loc/{locale}.js"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"deployCdnPath": "temp/deploy"
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"workingDir": "./temp/deploy/",
|
||||
"account": "<!-- STORAGE ACCOUNT NAME -->",
|
||||
"container": "spfx-riot-list",
|
||||
"accessKey": "<!-- ACCESS KEY -->"
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"solution": {
|
||||
"name": "riot-list-client-side-solution",
|
||||
"id": "6e137a70-041c-49e1-aa9e-470b704180a0",
|
||||
"version": "1.0.0.0"
|
||||
},
|
||||
"paths": {
|
||||
"zippedPackage": "solution/riot-list.sppkg"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"port": 4321,
|
||||
"initialPage": "https://localhost:5432/workbench",
|
||||
"https": true,
|
||||
"api": {
|
||||
"port": 5432,
|
||||
"entryPath": "node_modules/@microsoft/sp-webpart-workbench/lib/api/"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
{
|
||||
// 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-unused-imports": 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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"cdnBasePath": "<!-- PATH TO CDN -->"
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
const gulp = require('gulp');
|
||||
const build = require('@microsoft/sp-build-web');
|
||||
|
||||
build.initialize(gulp);
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"name": "riot-list",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@microsoft/sp-client-base": "~1.0.0",
|
||||
"@microsoft/sp-core-library": "~1.0.0",
|
||||
"@microsoft/sp-webpart-base": "~1.0.0",
|
||||
"@types/webpack-env": ">=1.12.1 <1.14.0",
|
||||
"office-ui-fabric-core": "5.0.1",
|
||||
"office-ui-fabric-js": "^1.4.0",
|
||||
"riot": "^3.4.2",
|
||||
"riot-typescript": "^1.0.10",
|
||||
"sp-client-custom-fields": "^1.3.3",
|
||||
"sp-pnp-js": "^2.0.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@microsoft/sp-build-web": "~1.0.1",
|
||||
"@microsoft/sp-module-interfaces": "~1.0.0",
|
||||
"@microsoft/sp-webpart-workbench": "~1.0.0",
|
||||
"gulp": "~3.9.1",
|
||||
"@types/chai": ">=3.4.34 <3.6.0",
|
||||
"@types/mocha": ">=2.2.33 <2.6.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "gulp bundle",
|
||||
"clean": "gulp clean",
|
||||
"test": "gulp test"
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
export * from './ListViewer/ListViewer.Index';
|
|
@ -0,0 +1,4 @@
|
|||
export interface IListViewerProps {
|
||||
styles: any;
|
||||
listId: string;
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
export * from './ListViewer';
|
||||
export * from './IListViewerProps';
|
|
@ -0,0 +1,26 @@
|
|||
<list-viewer>
|
||||
|
||||
<div class="Placeholder">
|
||||
<div class="Placeholder-container ms-Grid">
|
||||
<div class="Placeholder-head ms-Grid-row">
|
||||
<div class="ms-Grid-col ms-u-hiddenSm ms-u-md3">
|
||||
</div>
|
||||
<div class="Placeholder-headContainer ms-Grid-col ms-u-sm12 ms-u-md6">
|
||||
<i class="Placeholder-icon ms-fontSize-su ms-Icon ms-Icon--GroupedList"></i>
|
||||
<span class="Placeholder-text ms-fontWeight-light ms-fontSize-xxl">RiotJS List Viewer</span>
|
||||
</div>
|
||||
<div class="ms-Grid-col ms-u-hiddenSm ms-u-md3">
|
||||
</div>
|
||||
</div>
|
||||
<div class="Placeholder-description ms-Grid-row" if="{ listId }">
|
||||
<span class="Placeholder-descriptionText">{ list.Title }</span>
|
||||
</div>
|
||||
<div class="Placeholder-description ms-Grid-row" if="{ !listId }">
|
||||
<span class="Placeholder-descriptionText">Please configure your webpart to select a list</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<office-ui-fabric-table is-loading="{ isLoading }" items="{ items }" styles="{ styles }" if="{ listId }"></office-ui-fabric-table>
|
||||
|
||||
</list-viewer>
|
|
@ -0,0 +1,45 @@
|
|||
import * as riot from "riot/riot+compiler";
|
||||
import * as Riot from "./../../core/riot/Riot";
|
||||
import pnp, { ODataEntityArray, ODataEntity } from "sp-pnp-js";
|
||||
import { IListViewerProps } from "./IListViewerProps";
|
||||
import { ItemObject, ListObject } from "./Models";
|
||||
import { Table } from "./../../office-ui-fabric-riot/Components";
|
||||
|
||||
@Riot.template(require("./ListViewer.html") as string)
|
||||
export class ListViewer extends Riot.Element {
|
||||
private listId: string;
|
||||
private styles: any;
|
||||
private listTitle: string;
|
||||
private items: ItemObject[] = new Array<ItemObject>();
|
||||
private list: ListObject;
|
||||
private isLoading: boolean = false;
|
||||
|
||||
constructor(options: IListViewerProps) {
|
||||
super();
|
||||
|
||||
if(options) {
|
||||
this.styles = options.styles;
|
||||
this.listId = options.listId;
|
||||
}
|
||||
}
|
||||
|
||||
protected getSubComponentTypes(): any {
|
||||
return [Table];
|
||||
}
|
||||
|
||||
protected async mounted() {
|
||||
await this.init();
|
||||
}
|
||||
|
||||
protected async init() {
|
||||
if(this.listId) {
|
||||
this.isLoading = true;
|
||||
this.update();
|
||||
|
||||
this.list = await pnp.sp.web.lists.getById(this.listId).getAs(ODataEntity(ListObject));
|
||||
this.items = await pnp.sp.web.lists.getById(this.listId).items.getAs(ODataEntityArray(ItemObject));
|
||||
this.isLoading = false;
|
||||
this.update();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
import { List, Item } from "sp-pnp-js";
|
||||
|
||||
export class ItemObject extends Item {
|
||||
public Id: number;
|
||||
public Title: string;
|
||||
}
|
||||
|
||||
export class ListObject extends List {
|
||||
public Id: string;
|
||||
public Title: string;
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
import * as riot from "riot/riot+compiler";
|
||||
|
||||
export class Observable {
|
||||
public on(events: string, callback: Function) {}
|
||||
public one(events: string, callback: Function) {}
|
||||
public off(events: string) {}
|
||||
public trigger(eventName: string, ...args) {}
|
||||
|
||||
constructor() {
|
||||
riot.observable(this);
|
||||
}
|
||||
}
|
||||
|
||||
export interface LifeCycle
|
||||
{
|
||||
mounted?(F: Function);
|
||||
unmounted?(F: Function);
|
||||
beforeMount?(F: Function);
|
||||
beforeUnmount?(F: Function);
|
||||
updating?(F: Function);
|
||||
updated?(F: Function);
|
||||
}
|
||||
|
||||
export interface HTMLRiotElement extends HTMLElement
|
||||
{
|
||||
_tag: Element;
|
||||
}
|
||||
|
||||
export abstract class Element implements Observable, LifeCycle {
|
||||
public opts: any;
|
||||
public parent: Element;
|
||||
public root: HTMLElement;
|
||||
public tags: any;
|
||||
public tagName: string;
|
||||
public template: string;
|
||||
public isMounted: boolean;
|
||||
public element: HTMLElement;
|
||||
|
||||
public update(data?: any) { }
|
||||
public unmount(keepTheParent?: boolean) { }
|
||||
public on(eventName: string,fun: Function) { }
|
||||
public one(eventName: string,fun: Function) { }
|
||||
public off(events: string) {}
|
||||
public trigger(eventName: string,...args) {}
|
||||
public mixin(mixinObject: Object|Function|string, instance?: any) {}
|
||||
|
||||
protected abstract getSubComponentTypes() : any;
|
||||
|
||||
public static createElement(options?:any): HTMLRiotElement {
|
||||
var tagName = (this.prototype as any).tagName;
|
||||
var el = document.createElement(tagName);
|
||||
riot.mount(el, tagName, options);
|
||||
let riotElement = el as any as HTMLRiotElement;
|
||||
return riotElement;
|
||||
}
|
||||
}
|
||||
|
||||
// new extend, works with getters and setters
|
||||
function extend(d, element) {
|
||||
var map = Object.keys(element.prototype).reduce((descriptors, key) => {
|
||||
descriptors[key] = Object.getOwnPropertyDescriptor(element.prototype, key);
|
||||
return descriptors;
|
||||
},{}) as PropertyDescriptorMap;
|
||||
Object.defineProperties(d, map);
|
||||
}
|
||||
|
||||
export var precompiledTags: { [fileName: string]: CompilerResult } = {};
|
||||
|
||||
export function registerClass(element: Function) {
|
||||
|
||||
function registerTag(compiledTag: CompilerResult) {
|
||||
|
||||
var transformFunction = function (opts) {
|
||||
extend(this,element); // copies prototype into "this"
|
||||
element.apply(this, [opts]); // calls class constructor applying it on "this"
|
||||
|
||||
if(element.prototype.mounted !== undefined) this.on("mount" , this.mounted);
|
||||
if(element.prototype.unmounted !== undefined) this.on("unmount" , this.unmounted);
|
||||
if(element.prototype.updating !== undefined) this.on("update" , this.updating);
|
||||
if(element.prototype.updated !== undefined) this.on("updated" , this.updated);
|
||||
if(element.prototype.beforeMount !== undefined) this.on("before-mount" , this.beforeMount);
|
||||
if(element.prototype.beforeUnmount !== undefined) this.on("before-unmount" , this.beforeUnmount);
|
||||
};
|
||||
|
||||
riot.tag(compiledTag.tagName, compiledTag.html, compiledTag.css, compiledTag.attribs, transformFunction, riot.settings.brackets);
|
||||
|
||||
return compiledTag.tagName;
|
||||
}
|
||||
|
||||
let compiled: CompilerResult;
|
||||
|
||||
// gets string template
|
||||
if(element.prototype.template !== undefined) {
|
||||
const tagTemplate: string = (element.prototype.template as string).replace(/\r\n/g, '');
|
||||
compiled = riot.compile(tagTemplate, true, {entities: true})[0];
|
||||
element.prototype.tagName = registerTag(compiled);
|
||||
}
|
||||
else throw "template property not specified";
|
||||
}
|
||||
|
||||
// @template decorator
|
||||
export function template(template: string) {
|
||||
return (target: Function) => {
|
||||
target.prototype["template"] = template;
|
||||
registerClass(target);
|
||||
};
|
||||
}
|
||||
|
||||
export interface Router {
|
||||
(callback: Function): void;
|
||||
(filter: string, callback: Function): void;
|
||||
(to: string, title?: string): void;
|
||||
|
||||
create(): Router;
|
||||
start(autoExec?: boolean): void;
|
||||
stop(): void;
|
||||
exec(): void;
|
||||
query(): any;
|
||||
|
||||
base(base: string): any;
|
||||
parser(parser: (path: string)=>string, secondParser?: Function ): any;
|
||||
}
|
||||
|
||||
export interface CompilerResult {
|
||||
tagName: string;
|
||||
html: string;
|
||||
css: string;
|
||||
attribs: string;
|
||||
js: string;
|
||||
}
|
||||
|
||||
export interface Settings {
|
||||
brackets: string;
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
import {
|
||||
BaseClientSideWebPart
|
||||
} from '@microsoft/sp-webpart-base';
|
||||
import * as riot from "riot/riot+compiler";
|
||||
|
||||
export abstract class RiotClientSideWebPart<TProperties> extends BaseClientSideWebPart<TProperties> {
|
||||
protected abstract get tagName(): string;
|
||||
protected abstract get webPartOptions(): any;
|
||||
protected abstract get rootComponentType(): any;
|
||||
|
||||
public render(): void {
|
||||
this.domElement.innerHTML = `<${this.tagName}></${this.tagName}>`;
|
||||
riot.mount(this.domElement, this.tagName, this.webPartOptions);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
export * from './Table/Table.Index';
|
||||
export * from './Spinner/Spinner.Index';
|
|
@ -0,0 +1,3 @@
|
|||
@import '~office-ui-fabric-core/dist/sass/Fabric';
|
||||
@import '~office-ui-fabric-js/dist/components/Table/Table';
|
||||
@import '~office-ui-fabric-js/dist/components/Spinner/Spinner';
|
|
@ -0,0 +1 @@
|
|||
export * from './Spinner';
|
|
@ -0,0 +1,7 @@
|
|||
<office-ui-fabric-spinner>
|
||||
<div class="{ opts.styles['ms-Spinner'] }">
|
||||
<div class="{ opts.styles['ms-Spinner-label'] }" if="{ opts.label }">
|
||||
{ opts.label }
|
||||
</div>
|
||||
</div>
|
||||
</office-ui-fabric-spinner>
|
|
@ -0,0 +1,128 @@
|
|||
import * as riot from "riot/riot+compiler";
|
||||
import * as Riot from "./../../core/riot/Riot";
|
||||
|
||||
@Riot.template(require("./Spinner.html") as string)
|
||||
export class Spinner extends Riot.Element {
|
||||
private eightSize: number = 0.2;
|
||||
private animationSpeed: number = 90;
|
||||
private interval: number;
|
||||
private spinner: HTMLElement;
|
||||
private numCircles: number;
|
||||
private offsetSize: number;
|
||||
private parentSize: number = 20;
|
||||
private fadeIncrement: number = 0;
|
||||
private circleObjects: Array<CircleObject> = [];
|
||||
|
||||
protected getSubComponentTypes(): any[] {
|
||||
return [];
|
||||
}
|
||||
|
||||
protected mounted() {
|
||||
this.init();
|
||||
}
|
||||
|
||||
public start(): void {
|
||||
this.stop();
|
||||
this.interval = setInterval(() => {
|
||||
let i = this.circleObjects.length;
|
||||
while (i--) {
|
||||
this._fade(this.circleObjects[i]);
|
||||
}
|
||||
}, this.animationSpeed);
|
||||
}
|
||||
|
||||
public stop(): void {
|
||||
clearInterval(this.interval);
|
||||
}
|
||||
|
||||
private init(): void {
|
||||
this._setTargetElement();
|
||||
this._setPropertiesForSize();
|
||||
this._createCirclesAndArrange();
|
||||
this._initializeOpacities();
|
||||
this.start();
|
||||
}
|
||||
|
||||
private _setPropertiesForSize(): void {
|
||||
if (this.spinner.className.indexOf("large") > -1) {
|
||||
this.parentSize = 28;
|
||||
this.eightSize = 0.179;
|
||||
}
|
||||
|
||||
this.offsetSize = this.eightSize;
|
||||
this.numCircles = 8;
|
||||
}
|
||||
|
||||
private _setTargetElement(): void {
|
||||
this.spinner = this.root.getElementsByClassName(this.opts.styles['ms-Spinner'])[0] as HTMLElement;
|
||||
}
|
||||
|
||||
private _initializeOpacities(): void {
|
||||
let i = 0;
|
||||
let j = 1;
|
||||
let opacity;
|
||||
this.fadeIncrement = 1 / this.numCircles;
|
||||
|
||||
for (i; i < this.numCircles; i++) {
|
||||
let circleObject = this.circleObjects[i];
|
||||
opacity = (this.fadeIncrement * j++);
|
||||
this._setOpacity(circleObject.element, opacity);
|
||||
}
|
||||
}
|
||||
|
||||
private _fade(circleObject: CircleObject): void {
|
||||
let opacity = this._getOpacity(circleObject.element) - this.fadeIncrement;
|
||||
|
||||
if (opacity <= 0) {
|
||||
opacity = 1;
|
||||
}
|
||||
|
||||
this._setOpacity(circleObject.element, opacity);
|
||||
}
|
||||
|
||||
private _getOpacity(element: HTMLElement): number {
|
||||
return parseFloat(window.getComputedStyle(element).getPropertyValue("opacity"));
|
||||
}
|
||||
|
||||
private _setOpacity(element: HTMLElement, opacity: number): void {
|
||||
element.style.opacity = opacity.toString();
|
||||
}
|
||||
|
||||
private _createCircle(): HTMLElement {
|
||||
let circle = document.createElement("div");
|
||||
circle.className = this.opts.styles['ms-Spinner-circle'];
|
||||
circle.style.width = circle.style.height = this.parentSize * this.offsetSize + "px";
|
||||
return circle;
|
||||
}
|
||||
|
||||
private _createCirclesAndArrange(): void {
|
||||
let angle = 0;
|
||||
let offset = this.parentSize * this.offsetSize;
|
||||
let step = (2 * Math.PI) / this.numCircles;
|
||||
let i = this.numCircles;
|
||||
let circleObject;
|
||||
let radius = (this.parentSize - offset) * 0.5;
|
||||
|
||||
while (i--) {
|
||||
let circle = this._createCircle();
|
||||
let x = Math.round(this.parentSize * 0.5 + radius * Math.cos(angle) - circle.clientWidth * 0.5) - offset * 0.5;
|
||||
let y = Math.round(this.parentSize * 0.5 + radius * Math.sin(angle) - circle.clientHeight * 0.5) - offset * 0.5;
|
||||
this.spinner.appendChild(circle);
|
||||
circle.style.left = x + "px";
|
||||
circle.style.top = y + "px";
|
||||
angle += step;
|
||||
circleObject = new CircleObject(circle, i);
|
||||
this.circleObjects.push(circleObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class CircleObject {
|
||||
public element: HTMLElement;
|
||||
public j: number;
|
||||
|
||||
constructor(element, j) {
|
||||
this.element = element;
|
||||
this.j = j;
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
export * from './Table';
|
|
@ -0,0 +1,22 @@
|
|||
<office-ui-fabric-table>
|
||||
<table class="{ opts.styles['ms-Table'] }">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Title</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr if="{ opts.isLoading }">
|
||||
<td><office-ui-fabric-spinner label="Loading..." styles="{ opts.styles }"></office-ui-fabric-spinner></td>
|
||||
</tr>
|
||||
<tr if="{ !opts.isLoading && (!opts.items || opts.items.length == 0) }">
|
||||
<td>No record found.</td>
|
||||
</tr>
|
||||
<tr each="{ item in opts.items }" if="{ opts.items && opts.items.length > 0 }">
|
||||
<td>{ item.Id }</td>
|
||||
<td>{ item.Title }</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</office-ui-fabric-table>
|
|
@ -0,0 +1,10 @@
|
|||
import * as riot from "riot/riot+compiler";
|
||||
import * as Riot from "./../../core/riot/Riot";
|
||||
import { Spinner } from "./../Spinner/Spinner.Index";
|
||||
|
||||
@Riot.template(require("./Table.html") as string)
|
||||
export class Table extends Riot.Element {
|
||||
protected getSubComponentTypes(): any[] {
|
||||
return [Spinner];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
export interface IListViewerWebPartProps {
|
||||
listId: string;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
@import '../../office-ui-fabric-riot/Fabric.Components';
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"$schema": "../../../node_modules/@microsoft/sp-module-interfaces/lib/manifestSchemas/jsonSchemas/clientSideComponentManifestSchema.json",
|
||||
|
||||
"id": "482dd760-ae6d-4d63-ae5a-3e28dfea1007",
|
||||
"alias": "ListViewerWebPart",
|
||||
"componentType": "WebPart",
|
||||
"version": "0.0.1",
|
||||
"manifestVersion": 2,
|
||||
|
||||
"preconfiguredEntries": [{
|
||||
"groupId": "482dd760-ae6d-4d63-ae5a-3e28dfea1007",
|
||||
"group": { "default": "Under Development" },
|
||||
"title": { "default": "List Viewer" },
|
||||
"description": { "default": "List Viewer of a selected SharePoint List of Document Library using RiotJS" },
|
||||
"officeFabricIconFontName": "Page",
|
||||
"properties": {
|
||||
}
|
||||
}]
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
import { Version } from '@microsoft/sp-core-library';
|
||||
import {
|
||||
IWebPartContext,
|
||||
IPropertyPaneConfiguration
|
||||
} from '@microsoft/sp-webpart-base';
|
||||
import { PropertyFieldSPListPicker, PropertyFieldSPListPickerOrderBy } from 'sp-client-custom-fields/lib/PropertyFieldSPListPicker';
|
||||
import styles from './ListViewer.module.scss';
|
||||
import { IListViewerWebPartProps } from './IListViewerWebPartProps';
|
||||
import { RiotClientSideWebPart } from './../../core/riot/RiotClientSideWebPart';
|
||||
import { ListViewer, IListViewerProps } from './../../components/Components';
|
||||
|
||||
export default class ListViewerWebPart extends RiotClientSideWebPart<IListViewerWebPartProps> {
|
||||
|
||||
public constructor(context?: IWebPartContext) {
|
||||
super();
|
||||
this.onPropertyPaneFieldChanged = this.onPropertyPaneFieldChanged.bind(this);
|
||||
}
|
||||
|
||||
protected get webPartOptions(): any {
|
||||
var properties: IListViewerProps = {
|
||||
styles: styles,
|
||||
listId: this.properties.listId
|
||||
};
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
protected get rootComponentType(): any {
|
||||
return ListViewer;
|
||||
}
|
||||
|
||||
protected get tagName(): any {
|
||||
return "list-viewer";
|
||||
}
|
||||
|
||||
protected get dataVersion(): Version {
|
||||
return Version.parse('1.0');
|
||||
}
|
||||
|
||||
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
|
||||
return {
|
||||
pages: [
|
||||
{
|
||||
header: {
|
||||
description: "Use this webpart to display the content of the selected list using RiotJS"
|
||||
},
|
||||
groups: [
|
||||
{
|
||||
groupName: "List Configuration",
|
||||
groupFields: [
|
||||
PropertyFieldSPListPicker('listId', {
|
||||
label: 'Select a list',
|
||||
selectedList: this.properties.listId,
|
||||
includeHidden: false,
|
||||
orderBy: PropertyFieldSPListPickerOrderBy.Title,
|
||||
disabled: false,
|
||||
onPropertyChange: this.onPropertyPaneFieldChanged.bind(this),
|
||||
properties: this.properties,
|
||||
context: this.context,
|
||||
onGetErrorMessage: null,
|
||||
deferredValidationTime: 0,
|
||||
key: 'listPickerFieldId'
|
||||
})
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
define([], function() {
|
||||
return {
|
||||
"PropertyPaneDescription": "Description",
|
||||
"BasicGroupName": "Group Name",
|
||||
"DescriptionFieldLabel": "Description Field"
|
||||
}
|
||||
});
|
|
@ -0,0 +1,10 @@
|
|||
declare interface IListViewerStrings {
|
||||
PropertyPaneDescription: string;
|
||||
BasicGroupName: string;
|
||||
DescriptionFieldLabel: string;
|
||||
}
|
||||
|
||||
declare module 'listViewerStrings' {
|
||||
const strings: IListViewerStrings;
|
||||
export = strings;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
/// <reference types="mocha" />
|
||||
|
||||
import { assert } from 'chai';
|
||||
|
||||
describe('ListViewerWebPart', () => {
|
||||
it('should do something', () => {
|
||||
assert.ok(true);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"module": "commonjs",
|
||||
"jsx": "react",
|
||||
"declaration": true,
|
||||
"sourceMap": true,
|
||||
"experimentalDecorators": true,
|
||||
"types": [
|
||||
"es6-promise",
|
||||
"es6-collections",
|
||||
"webpack-env"
|
||||
]
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue