Updated the WebPart with inline template editing

Added inline template editing within the toolpane, automatic template
generation and fixed a bug related to the "Me" checkbox while filtering
user fields.
This commit is contained in:
Simon-Pierre Plante 2017-04-24 22:56:15 -04:00
parent 024cf6cfe8
commit f189d73480
26 changed files with 740 additions and 119 deletions

2
.gitignore vendored
View File

@ -9,8 +9,8 @@ node_modules
# Build generated files
dist
lib
solution
temp
solution/debug
# Coverage directory used by tools like istanbul
coverage

View File

@ -1,3 +1,3 @@
{
"cdnBasePath": "https://publiccdn.sharepointonline.com/spptechnologies.sharepoint.com/110700492eeea162ee5bad0f35b1f0061ded8bf436ce0199efe2a4d24109e1c0df1ec594/react-content-query"
"cdnBasePath": "https://publiccdn.sharepointonline.com/spptechnologies.sharepoint.com/110700492eeea162ee5bad0f35b1f0061ded8bf436ce0199efe2a4d24109e1c0df1ec594/react-content-query-1.0.0"
}

View File

@ -6,12 +6,23 @@ const build = require('@microsoft/sp-build-web');
/********************************************************************************************
* Adds an alias for handlebars in order to avoid errors while gulping the project
* https://github.com/wycats/handlebars.js/issues/1174
* Adds a loader and a node setting for webpacking the handlebars-helpers correctly
* https://github.com/helpers/handlebars-helpers/issues/263
********************************************************************************************/
build.configureWebpack.mergeConfig({
additionalConfiguration: (generatedConfiguration) => {
generatedConfiguration.resolve.alias = { handlebars: 'handlebars/dist/handlebars.min.js' };
return generatedConfiguration;
}
build.configureWebpack.mergeConfig({
additionalConfiguration: (generatedConfiguration) => {
generatedConfiguration.resolve.alias = { handlebars: 'handlebars/dist/handlebars.min.js' };
generatedConfiguration.module.loaders.push({
test: /\.js$/, loader: 'unlazy'
});
generatedConfiguration.node = {
fs: 'empty'
}
return generatedConfiguration;
}
});
build.initialize(gulp);
build.initialize(gulp);

423
npm-shrinkwrap.json generated
View File

@ -1,6 +1,6 @@
{
"name": "react-content-query",
"version": "0.0.1",
"version": "1.0.0",
"dependencies": {
"@microsoft/api-extractor": {
"version": "1.1.15",
@ -737,14 +737,12 @@
"ansi-regex": {
"version": "2.1.1",
"from": "ansi-regex@>=2.0.0 <3.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"dev": true
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz"
},
"ansi-styles": {
"version": "2.2.1",
"from": "ansi-styles@>=2.2.1 <3.0.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
"dev": true
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz"
},
"anymatch": {
"version": "1.3.0",
@ -779,14 +777,24 @@
"arr-diff": {
"version": "2.0.0",
"from": "arr-diff@>=2.0.0 <3.0.0",
"resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz",
"dev": true
"resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz"
},
"arr-filter": {
"version": "1.1.2",
"from": "arr-filter@>=1.1.1 <2.0.0",
"resolved": "https://registry.npmjs.org/arr-filter/-/arr-filter-1.1.2.tgz",
"dependencies": {
"make-iterator": {
"version": "1.0.0",
"from": "make-iterator@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.0.tgz"
}
}
},
"arr-flatten": {
"version": "1.0.1",
"from": "arr-flatten@>=1.0.1 <2.0.0",
"resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.0.1.tgz",
"dev": true
"resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.0.1.tgz"
},
"array-differ": {
"version": "1.0.0",
@ -812,6 +820,18 @@
"resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz",
"dev": true
},
"array-sort": {
"version": "0.1.2",
"from": "array-sort@>=0.1.2 <0.2.0",
"resolved": "https://registry.npmjs.org/array-sort/-/array-sort-0.1.2.tgz",
"dependencies": {
"kind-of": {
"version": "2.0.1",
"from": "kind-of@>=2.0.0 <3.0.0",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-2.0.1.tgz"
}
}
},
"array-union": {
"version": "1.0.2",
"from": "array-union@>=1.0.1 <2.0.0",
@ -827,8 +847,7 @@
"array-unique": {
"version": "0.2.1",
"from": "array-unique@>=0.2.1 <0.3.0",
"resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz",
"dev": true
"resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz"
},
"arraybuffer.slice": {
"version": "0.0.6",
@ -897,6 +916,11 @@
"from": "asynckit@>=0.4.0 <0.5.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz"
},
"autolinker": {
"version": "0.15.3",
"from": "autolinker@>=0.15.0 <0.16.0",
"resolved": "https://registry.npmjs.org/autolinker/-/autolinker-0.15.3.tgz"
},
"autoprefixer": {
"version": "6.3.7",
"from": "autoprefixer@6.3.7",
@ -1185,8 +1209,7 @@
"braces": {
"version": "1.8.5",
"from": "braces@>=1.8.2 <2.0.0",
"resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz",
"dev": true
"resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz"
},
"browserify-mime": {
"version": "1.2.9",
@ -1311,8 +1334,7 @@
"chalk": {
"version": "1.1.3",
"from": "chalk@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"dev": true
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz"
},
"charenc": {
"version": "0.0.2",
@ -1703,6 +1725,23 @@
"resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz",
"dev": true
},
"create-frame": {
"version": "1.0.0",
"from": "create-frame@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/create-frame/-/create-frame-1.0.0.tgz",
"dependencies": {
"isobject": {
"version": "3.0.0",
"from": "isobject@>=3.0.0 <4.0.0",
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.0.tgz"
},
"lazy-cache": {
"version": "2.0.2",
"from": "lazy-cache@^2.0.2",
"resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-2.0.2.tgz"
}
}
},
"cross-spawn": {
"version": "3.0.1",
"from": "cross-spawn@>=3.0.0 <4.0.0",
@ -1866,6 +1905,18 @@
"resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz",
"dev": true
},
"date.js": {
"version": "0.3.1",
"from": "date.js@>=0.3.1 <0.4.0",
"resolved": "https://registry.npmjs.org/date.js/-/date.js-0.3.1.tgz",
"dependencies": {
"debug": {
"version": "0.7.4",
"from": "debug@>=0.7.2 <0.8.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz"
}
}
},
"dateformat": {
"version": "2.0.0",
"from": "dateformat@>=2.0.0 <3.0.0",
@ -1941,6 +1992,11 @@
"resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz",
"dev": true
},
"define-property": {
"version": "0.2.5",
"from": "define-property@>=0.2.5 <0.3.0",
"resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz"
},
"defined": {
"version": "1.0.0",
"from": "defined@>=1.0.0 <2.0.0",
@ -2182,8 +2238,7 @@
"ent": {
"version": "2.2.0",
"from": "ent@>=2.2.0 <2.3.0",
"resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz",
"dev": true
"resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz"
},
"envify": {
"version": "3.4.1",
@ -2234,8 +2289,7 @@
"escape-string-regexp": {
"version": "1.0.5",
"from": "escape-string-regexp@>=1.0.2 <2.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"dev": true
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz"
},
"escodegen": {
"version": "1.8.1",
@ -2320,14 +2374,12 @@
"expand-brackets": {
"version": "0.1.5",
"from": "expand-brackets@>=0.1.4 <0.2.0",
"resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz",
"dev": true
"resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz"
},
"expand-range": {
"version": "1.8.2",
"from": "expand-range@>=1.8.1 <2.0.0",
"resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz",
"dev": true
"resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz"
},
"expand-tilde": {
"version": "1.2.2",
@ -2413,14 +2465,12 @@
"extend-shallow": {
"version": "2.0.1",
"from": "extend-shallow@>=2.0.1 <3.0.0",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
"dev": true
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz"
},
"extglob": {
"version": "0.3.2",
"from": "extglob@>=0.3.1 <0.4.0",
"resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz",
"dev": true
"resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz"
},
"extract-zip": {
"version": "1.5.0",
@ -2503,14 +2553,12 @@
"filename-regex": {
"version": "2.0.0",
"from": "filename-regex@>=2.0.0 <3.0.0",
"resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.0.tgz",
"dev": true
"resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.0.tgz"
},
"fill-range": {
"version": "2.2.3",
"from": "fill-range@>=2.1.0 <3.0.0",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz",
"dev": true
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz"
},
"filled-array": {
"version": "1.1.0",
@ -2577,14 +2625,12 @@
"for-in": {
"version": "1.0.2",
"from": "for-in@>=1.0.1 <2.0.0",
"resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
"dev": true
"resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz"
},
"for-own": {
"version": "0.1.5",
"from": "for-own@>=0.1.4 <0.2.0",
"resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz",
"dev": true
"resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz"
},
"forever-agent": {
"version": "0.6.1",
@ -2629,8 +2675,7 @@
"fs-exists-sync": {
"version": "0.1.0",
"from": "fs-exists-sync@>=0.1.0 <0.2.0",
"resolved": "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz",
"dev": true
"resolved": "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz"
},
"fs-extra": {
"version": "0.26.7",
@ -2692,12 +2737,29 @@
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz",
"dev": true
},
"get-object": {
"version": "0.2.0",
"from": "get-object@>=0.2.0 <0.3.0",
"resolved": "https://registry.npmjs.org/get-object/-/get-object-0.2.0.tgz",
"dependencies": {
"isobject": {
"version": "0.2.0",
"from": "isobject@>=0.2.0 <0.3.0",
"resolved": "https://registry.npmjs.org/isobject/-/isobject-0.2.0.tgz"
}
}
},
"get-stdin": {
"version": "4.0.1",
"from": "get-stdin@>=4.0.1 <5.0.0",
"resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz",
"dev": true
},
"get-value": {
"version": "2.0.6",
"from": "get-value@>=2.0.6 <3.0.0",
"resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz"
},
"getpass": {
"version": "0.1.6",
"from": "getpass@>=0.1.1 <0.2.0",
@ -2719,8 +2781,7 @@
"glob-base": {
"version": "0.3.0",
"from": "glob-base@>=0.3.0 <0.4.0",
"resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz",
"dev": true
"resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz"
},
"glob-escape": {
"version": "0.0.2",
@ -2731,8 +2792,7 @@
"glob-parent": {
"version": "2.0.0",
"from": "glob-parent@>=2.0.0 <3.0.0",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz",
"dev": true
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz"
},
"glob-stream": {
"version": "3.1.18",
@ -3657,6 +3717,38 @@
}
}
},
"handlebars-helpers": {
"version": "0.8.2",
"from": "handlebars-helpers@latest",
"resolved": "https://registry.npmjs.org/handlebars-helpers/-/handlebars-helpers-0.8.2.tgz",
"dependencies": {
"for-in": {
"version": "0.1.8",
"from": "for-in@>=0.1.6 <0.2.0",
"resolved": "https://registry.npmjs.org/for-in/-/for-in-0.1.8.tgz"
},
"is-extglob": {
"version": "2.1.1",
"from": "is-extglob@>=2.1.0 <3.0.0",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz"
},
"is-glob": {
"version": "3.1.0",
"from": "is-glob@>=3.1.0 <4.0.0",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz"
},
"is-number": {
"version": "3.0.0",
"from": "is-number@>=3.0.0 <4.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz"
},
"lazy-cache": {
"version": "2.0.2",
"from": "lazy-cache@>=2.0.2 <3.0.0",
"resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-2.0.2.tgz"
}
}
},
"har-schema": {
"version": "1.0.5",
"from": "har-schema@>=1.0.5 <2.0.0",
@ -3676,8 +3768,7 @@
"has-ansi": {
"version": "2.0.0",
"from": "has-ansi@>=2.0.0 <3.0.0",
"resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
"dev": true
"resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz"
},
"has-binary": {
"version": "0.1.7",
@ -3726,6 +3817,21 @@
"resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz",
"dev": true
},
"helper-date": {
"version": "0.2.3",
"from": "helper-date@>=0.2.3 <0.3.0",
"resolved": "https://registry.npmjs.org/helper-date/-/helper-date-0.2.3.tgz"
},
"helper-markdown": {
"version": "0.2.1",
"from": "helper-markdown@>=0.2.1 <0.3.0",
"resolved": "https://registry.npmjs.org/helper-markdown/-/helper-markdown-0.2.1.tgz"
},
"helper-md": {
"version": "0.2.2",
"from": "helper-md@>=0.2.2 <0.3.0",
"resolved": "https://registry.npmjs.org/helper-md/-/helper-md-0.2.2.tgz"
},
"hoek": {
"version": "2.16.3",
"from": "hoek@>=2.0.0 <3.0.0",
@ -3783,6 +3889,18 @@
}
}
},
"html-tag": {
"version": "1.0.0",
"from": "html-tag@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/html-tag/-/html-tag-1.0.0.tgz",
"dependencies": {
"isobject": {
"version": "3.0.0",
"from": "isobject@^3.0.0",
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.0.tgz"
}
}
},
"http-browserify": {
"version": "1.7.0",
"from": "http-browserify@>=1.3.2 <2.0.0",
@ -3847,6 +3965,11 @@
"resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz",
"dev": true
},
"index-of": {
"version": "0.2.0",
"from": "index-of@>=0.2.0 <0.3.0",
"resolved": "https://registry.npmjs.org/index-of/-/index-of-0.2.0.tgz"
},
"indexes-of": {
"version": "1.0.1",
"from": "indexes-of@>=1.0.1 <2.0.0",
@ -3919,6 +4042,11 @@
"resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz",
"dev": true
},
"is-accessor-descriptor": {
"version": "0.1.6",
"from": "is-accessor-descriptor@>=0.1.6 <0.2.0",
"resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz"
},
"is-arrayish": {
"version": "0.2.1",
"from": "is-arrayish@>=0.2.1 <0.3.0",
@ -3942,29 +4070,54 @@
"resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz",
"dev": true
},
"is-data-descriptor": {
"version": "0.1.4",
"from": "is-data-descriptor@>=0.1.4 <0.2.0",
"resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz"
},
"is-descriptor": {
"version": "0.1.5",
"from": "is-descriptor@>=0.1.0 <0.2.0",
"resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.5.tgz",
"dependencies": {
"lazy-cache": {
"version": "2.0.2",
"from": "lazy-cache@^2.0.2",
"resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-2.0.2.tgz"
}
}
},
"is-dotfile": {
"version": "1.0.2",
"from": "is-dotfile@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.2.tgz",
"dev": true
"resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.2.tgz"
},
"is-equal-shallow": {
"version": "0.1.3",
"from": "is-equal-shallow@>=0.1.3 <0.2.0",
"resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz",
"dev": true
"resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz"
},
"is-even": {
"version": "0.1.1",
"from": "is-even@>=0.1.1 <0.2.0",
"resolved": "https://registry.npmjs.org/is-even/-/is-even-0.1.1.tgz",
"dependencies": {
"is-number": {
"version": "1.1.2",
"from": "is-number@>=1.1.0 <2.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-1.1.2.tgz"
}
}
},
"is-extendable": {
"version": "0.1.1",
"from": "is-extendable@>=0.1.1 <0.2.0",
"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
"dev": true
"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz"
},
"is-extglob": {
"version": "1.0.0",
"from": "is-extglob@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
"dev": true
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz"
},
"is-finite": {
"version": "1.0.2",
@ -3981,8 +4134,7 @@
"is-glob": {
"version": "2.0.1",
"from": "is-glob@>=2.0.1 <3.0.0",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
"dev": true
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz"
},
"is-my-json-valid": {
"version": "2.16.0",
@ -3999,8 +4151,7 @@
"is-number": {
"version": "2.1.0",
"from": "is-number@>=2.1.0 <3.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz",
"dev": true
"resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz"
},
"is-obj": {
"version": "1.0.1",
@ -4008,6 +4159,18 @@
"resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz",
"dev": true
},
"is-odd": {
"version": "0.1.1",
"from": "is-odd@>=0.1.1 <0.2.0",
"resolved": "https://registry.npmjs.org/is-odd/-/is-odd-0.1.1.tgz",
"dependencies": {
"is-number": {
"version": "1.1.2",
"from": "is-number@>=1.1.0 <2.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-1.1.2.tgz"
}
}
},
"is-path-cwd": {
"version": "1.0.0",
"from": "is-path-cwd@>=1.0.0 <2.0.0",
@ -4035,14 +4198,12 @@
"is-posix-bracket": {
"version": "0.1.1",
"from": "is-posix-bracket@>=0.1.0 <0.2.0",
"resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz",
"dev": true
"resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz"
},
"is-primitive": {
"version": "2.0.0",
"from": "is-primitive@>=2.0.0 <3.0.0",
"resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz",
"dev": true
"resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz"
},
"is-property": {
"version": "1.0.2",
@ -4130,13 +4291,11 @@
"version": "2.1.0",
"from": "isobject@>=2.0.0 <3.0.0",
"resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
"dev": true,
"dependencies": {
"isarray": {
"version": "1.0.0",
"from": "isarray@1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"dev": true
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz"
}
}
},
@ -4742,11 +4901,31 @@
"resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz",
"dev": true
},
"lodash.filter": {
"version": "4.6.0",
"from": "lodash.filter@>=4.2.0 <5.0.0",
"resolved": "https://registry.npmjs.org/lodash.filter/-/lodash.filter-4.6.0.tgz"
},
"lodash.findkey": {
"version": "4.6.0",
"from": "lodash.findkey@>=4.2.0 <5.0.0",
"resolved": "https://registry.npmjs.org/lodash.findkey/-/lodash.findkey-4.6.0.tgz"
},
"lodash.foreach": {
"version": "4.5.0",
"from": "lodash.foreach@>=4.1.0 <5.0.0",
"resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz"
},
"lodash.get": {
"version": "4.4.2",
"from": "lodash.get@>=4.1.2 <5.0.0",
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz"
},
"lodash.includes": {
"version": "4.3.0",
"from": "lodash.includes@>=4.1.0 <5.0.0",
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz"
},
"lodash.isarguments": {
"version": "3.1.0",
"from": "lodash.isarguments@>=3.0.0 <4.0.0",
@ -4762,8 +4941,7 @@
"lodash.isempty": {
"version": "4.4.0",
"from": "lodash.isempty@>=4.2.1 <5.0.0",
"resolved": "https://registry.npmjs.org/lodash.isempty/-/lodash.isempty-4.4.0.tgz",
"dev": true
"resolved": "https://registry.npmjs.org/lodash.isempty/-/lodash.isempty-4.4.0.tgz"
},
"lodash.isequal": {
"version": "4.5.0",
@ -4819,6 +4997,11 @@
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.3.5.tgz",
"dev": true
},
"lodash.partition": {
"version": "4.6.0",
"from": "lodash.partition@>=4.2.0 <5.0.0",
"resolved": "https://registry.npmjs.org/lodash.partition/-/lodash.partition-4.6.0.tgz"
},
"lodash.pick": {
"version": "4.4.0",
"from": "lodash.pick@>=4.2.1 <5.0.0",
@ -4855,6 +5038,11 @@
"resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz",
"dev": true
},
"lodash.trim": {
"version": "4.5.1",
"from": "lodash.trim@>=4.2.0 <5.0.0",
"resolved": "https://registry.npmjs.org/lodash.trim/-/lodash.trim-4.5.1.tgz"
},
"lodash.uniq": {
"version": "4.5.0",
"from": "lodash.uniq@>=4.3.0 <5.0.0",
@ -4907,6 +5095,11 @@
}
}
},
"logging-helpers": {
"version": "0.4.0",
"from": "logging-helpers@>=0.4.0 <0.5.0",
"resolved": "https://registry.npmjs.org/logging-helpers/-/logging-helpers-0.4.0.tgz"
},
"lolex": {
"version": "1.4.0",
"from": "lolex@>=1.4.0 <1.5.0",
@ -4953,6 +5146,11 @@
"resolved": "https://registry.npmjs.org/macaddress/-/macaddress-0.2.8.tgz",
"dev": true
},
"make-iterator": {
"version": "0.3.1",
"from": "make-iterator@>=0.3.0 <0.4.0",
"resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-0.3.1.tgz"
},
"map-cache": {
"version": "0.2.2",
"from": "map-cache@>=0.2.0 <0.3.0",
@ -5076,8 +5274,7 @@
"micromatch": {
"version": "2.3.11",
"from": "micromatch@>=2.3.7 <3.0.0",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz",
"dev": true
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz"
},
"mime": {
"version": "1.3.4",
@ -5107,6 +5304,11 @@
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"dev": true
},
"mixin-deep": {
"version": "1.2.0",
"from": "mixin-deep@>=1.1.3 <2.0.0",
"resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.2.0.tgz"
},
"mkdirp": {
"version": "0.5.1",
"from": "mkdirp@>=0.5.0 <0.6.0",
@ -5356,8 +5558,7 @@
"normalize-path": {
"version": "2.0.1",
"from": "normalize-path@>=2.0.1 <3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.0.1.tgz",
"dev": true
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.0.1.tgz"
},
"normalize-range": {
"version": "0.1.2",
@ -5414,8 +5615,7 @@
"object.omit": {
"version": "2.0.1",
"from": "object.omit@>=2.0.0 <3.0.0",
"resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz",
"dev": true
"resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz"
},
"object.pick": {
"version": "1.2.0",
@ -5578,8 +5778,7 @@
"parse-glob": {
"version": "3.0.4",
"from": "parse-glob@>=3.0.4 <4.0.0",
"resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz",
"dev": true
"resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz"
},
"parse-json": {
"version": "2.2.0",
@ -6033,8 +6232,7 @@
"preserve": {
"version": "0.2.0",
"from": "preserve@>=0.2.0 <0.3.0",
"resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz",
"dev": true
"resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz"
},
"pretty-hrtime": {
"version": "1.0.3",
@ -6158,8 +6356,7 @@
"randomatic": {
"version": "1.1.6",
"from": "randomatic@>=1.1.3 <2.0.0",
"resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.6.tgz",
"dev": true
"resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.6.tgz"
},
"range-parser": {
"version": "1.2.0",
@ -6312,8 +6509,7 @@
"regex-cache": {
"version": "0.4.3",
"from": "regex-cache@>=0.4.2 <0.5.0",
"resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.3.tgz",
"dev": true
"resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.3.tgz"
},
"regexpu-core": {
"version": "1.0.0",
@ -6351,11 +6547,37 @@
"resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz",
"dev": true
},
"relative": {
"version": "3.0.2",
"from": "relative@>=3.0.2 <4.0.0",
"resolved": "https://registry.npmjs.org/relative/-/relative-3.0.2.tgz"
},
"remarkable": {
"version": "1.7.1",
"from": "remarkable@>=1.6.0 <2.0.0",
"resolved": "https://registry.npmjs.org/remarkable/-/remarkable-1.7.1.tgz",
"dependencies": {
"argparse": {
"version": "0.1.16",
"from": "argparse@>=0.1.15 <0.2.0",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-0.1.16.tgz"
},
"underscore": {
"version": "1.7.0",
"from": "underscore@>=1.7.0 <1.8.0",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz"
},
"underscore.string": {
"version": "2.4.0",
"from": "underscore.string@>=2.4.0 <2.5.0",
"resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.4.0.tgz"
}
}
},
"repeat-element": {
"version": "1.1.2",
"from": "repeat-element@>=1.1.2 <2.0.0",
"resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz",
"dev": true
"resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz"
},
"repeat-string": {
"version": "1.6.1",
@ -6423,6 +6645,12 @@
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
"dev": true
},
"requires-regex": {
"version": "0.3.3",
"from": "requires-regex@>=0.3.3 <0.4.0",
"resolved": "https://registry.npmjs.org/requires-regex/-/requires-regex-0.3.3.tgz",
"dev": true
},
"resolve": {
"version": "1.3.2",
"from": "resolve@>=1.1.7 <2.0.0",
@ -6603,6 +6831,11 @@
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
"dev": true
},
"set-getter": {
"version": "0.1.0",
"from": "set-getter@>=0.1.0 <0.2.0",
"resolved": "https://registry.npmjs.org/set-getter/-/set-getter-0.1.0.tgz"
},
"set-immediate-shim": {
"version": "1.0.1",
"from": "set-immediate-shim@>=1.0.1 <2.0.0",
@ -6904,8 +7137,7 @@
"strip-ansi": {
"version": "3.0.1",
"from": "strip-ansi@>=3.0.0 <4.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"dev": true
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz"
},
"strip-bom": {
"version": "1.0.0",
@ -6939,6 +7171,11 @@
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
"dev": true
},
"striptags": {
"version": "2.2.1",
"from": "striptags@>=2.1.1 <3.0.0",
"resolved": "https://registry.npmjs.org/striptags/-/striptags-2.2.1.tgz"
},
"sudo": {
"version": "1.0.3",
"from": "sudo@>=1.0.3 <1.1.0",
@ -6948,8 +7185,7 @@
"supports-color": {
"version": "2.0.0",
"from": "supports-color@>=2.0.0 <3.0.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
"dev": true
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz"
},
"svgo": {
"version": "0.7.2",
@ -7163,12 +7399,22 @@
"resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz",
"dev": true
},
"to-gfm-code-block": {
"version": "0.1.1",
"from": "to-gfm-code-block@>=0.1.1 <0.2.0",
"resolved": "https://registry.npmjs.org/to-gfm-code-block/-/to-gfm-code-block-0.1.1.tgz"
},
"to-iso-string": {
"version": "0.0.2",
"from": "to-iso-string@0.0.2",
"resolved": "https://registry.npmjs.org/to-iso-string/-/to-iso-string-0.0.2.tgz",
"dev": true
},
"to-object-path": {
"version": "0.3.0",
"from": "to-object-path@>=0.3.0 <0.4.0",
"resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz"
},
"tough-cookie": {
"version": "2.3.2",
"from": "tough-cookie@>=2.3.0 <2.4.0",
@ -7374,6 +7620,12 @@
"resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-1.0.0.tgz",
"dev": true
},
"unlazy-loader": {
"version": "0.1.2",
"from": "unlazy-loader@latest",
"resolved": "https://registry.npmjs.org/unlazy-loader/-/unlazy-loader-0.1.2.tgz",
"dev": true
},
"unpipe": {
"version": "1.0.0",
"from": "unpipe@1.0.0",
@ -7588,8 +7840,7 @@
"void-elements": {
"version": "2.0.1",
"from": "void-elements@>=2.0.0 <3.0.0",
"resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz",
"dev": true
"resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz"
},
"watchpack": {
"version": "0.2.9",

View File

@ -17,6 +17,7 @@
"@types/react-dom": "0.14.18",
"@types/webpack-env": ">=1.12.1 <1.14.0",
"handlebars": "^4.0.6",
"handlebars-helpers": "^0.8.2",
"moment": "^2.18.1",
"office-ui-fabric-react": "1.14.3",
"react": "15.4.2",
@ -30,7 +31,8 @@
"@types/microsoft-ajax": "0.0.31",
"@types/mocha": ">=2.2.33 <2.6.0",
"@types/sharepoint": "^2013.1.4",
"gulp": "~3.9.1"
"gulp": "~3.9.1",
"unlazy-loader": "^0.1.2"
},
"scripts": {
"build": "gulp bundle",

Binary file not shown.

View File

@ -4,13 +4,15 @@ export class ContentQueryConstants {
/**************************************************************
* WebPart Properties
**************************************************************/
public static readonly propertyWebUrl = "webUrl";
public static readonly propertyListTitle = "listTitle";
public static readonly propertyOrderBy = "orderBy";
public static readonly propertOrderByDirection = "orderByDirection";
public static readonly propertyLimitEnabled = "limitEnabled";
public static readonly propertyItemLimit = "itemLimit";
public static readonly propertyFilters = "filters";
public static readonly propertyViewFields = "viewFields";
public static readonly propertyTemplateUrl = "templateUrl";
public static readonly propertyWebUrl = "webUrl";
public static readonly propertyListTitle = "listTitle";
public static readonly propertyOrderBy = "orderBy";
public static readonly propertOrderByDirection = "orderByDirection";
public static readonly propertyLimitEnabled = "limitEnabled";
public static readonly propertyItemLimit = "itemLimit";
public static readonly propertyFilters = "filters";
public static readonly propertyViewFields = "viewFields";
public static readonly propertyTemplateText = "templateText";
public static readonly propertyTemplateUrl = "templateUrl";
public static readonly propertyhasDefaultTemplateBeenUpdated = "hasDefaultTemplateBeenUpdated";
}

View File

@ -151,11 +151,11 @@ export class CamlQueryHelper {
let filterOutput = '';
let filterUsers = filter.value as IPersonaProps[];
if(isEmpty(filter.value)) {
return '';
if(filter.me) {
filterOutput = Text.format("<Eq><FieldRef Name='{0}' /><Value Type='Integer'><UserID /></Value></Eq>", filter.field.internalName);
}
else if(filter.me) {
filterOutput = Text.format("<In><FieldRef Name='{0}' LookupId='TRUE' /><Values><Value Type='Integer'><UserID /></Value></Values></In>", filter.field.internalName);
else if(isEmpty(filter.value)) {
return '';
}
else if (filter.operator == QueryFilterOperator.ContainsAny || filterUsers == null)
{

View File

@ -403,6 +403,51 @@ export class ContentQueryService implements IContentQueryService {
}
/*************************************************************************************************
* Generates a default handlebars template based on the view fields selected by the user
* @param viewFields : The view fields that have been selected by the user
*************************************************************************************************/
public generateDefaultTemplate(viewFields: string[]): string {
let viewFieldsStr = viewFields.map((field) => { return Text.format(" <span><b>{0} : </b>\{\{{0}.textValue\}\}</span>", field); }).join("\n");
let template = Text.format(`<style type="text/css">
.dynamic-template .dynamic-items .dynamic-item {
background: #ffffff;
box-shadow: 0px 0px 6px #bfbebe;
margin-bottom: 15px;
}
.dynamic-template .dynamic-items .dynamic-item h3 {
background: #47b4de;
color: #fff;
padding: 5px 5px 7px 10px;
margin: 0px;
}
.dynamic-template .dynamic-items .dynamic-item .dynamic-item-fields {
padding: 10px;
}
.dynamic-template .dynamic-items .dynamic-item .dynamic-item-fields span {
display: block;
font-size: 12px;
}
</style>
<div class="dynamic-template">
<h2>{0}</h2>
<div class="dynamic-items">
{{#each items}}
<div class="dynamic-item">
<h3>Result #{{@index}}</h3>
<div class="dynamic-item-fields">
{1}
</div>
</div>
{{/each}}
</div>
</div>`, strings.DynamicallyGeneratedTemplate ,viewFieldsStr);
return template;
}
/***************************************************************************
* Resets the stored 'list title' options
***************************************************************************/

View File

@ -17,6 +17,7 @@ export interface IContentQueryService {
getTaxonomyPickerSuggestions: (webUrl: string, listTitle: string, field: IQueryFilterField, filterText: string, currentTerms: ITag[]) => Promise<IPersonaProps[]>;
ensureFileResolves: (filePath: string) => Promise<{}>;
isValidTemplateFile: (filePath: string) => boolean;
generateDefaultTemplate: (viewFields: string[]) => string;
clearCachedListTitleOptions: () => void;
clearCachedOrderByOptions: () => void;
clearCachedFilterFields: () => void;

View File

@ -0,0 +1,6 @@
import { IPropertyPaneCustomFieldProps } from '@microsoft/sp-webpart-base';
import { IPropertyPaneTextDialogProps } from './IPropertyPaneTextDialogProps';
export interface IPropertyPaneTextDialogInternalProps extends IPropertyPaneTextDialogProps, IPropertyPaneCustomFieldProps {
}

View File

@ -0,0 +1,8 @@
import { ITextDialogStrings } from "./components/TextDialog/ITextDialogStrings";
export interface IPropertyPaneTextDialogProps {
dialogTextFieldValue?: string;
onPropertyChange: (propertyPath: string, text: string) => void;
disabled?: boolean;
strings: ITextDialogStrings;
}

View File

@ -0,0 +1,74 @@
import * as React from 'react';
import * as ReactDom from 'react-dom';
import { IPropertyPaneField, PropertyPaneFieldType } from '@microsoft/sp-webpart-base';
import { IPropertyPaneTextDialogProps } from './IPropertyPaneTextDialogProps';
import { IPropertyPaneTextDialogInternalProps } from './IPropertyPaneTextDialogInternalProps';
import { TextDialog } from './components/TextDialog/TextDialog';
import { ITextDialogProps } from './components/TextDialog/ITextDialogProps';
export class PropertyPaneTextDialog implements IPropertyPaneField<IPropertyPaneTextDialogProps> {
public type: PropertyPaneFieldType = PropertyPaneFieldType.Custom;
public targetProperty: string;
public properties: IPropertyPaneTextDialogInternalProps;
private elem: HTMLElement;
/*****************************************************************************************
* Property pane's contructor
* @param targetProperty
* @param properties
*****************************************************************************************/
constructor(targetProperty: string, properties: IPropertyPaneTextDialogProps) {
this.targetProperty = targetProperty;
this.properties = {
dialogTextFieldValue: properties.dialogTextFieldValue,
onPropertyChange: properties.onPropertyChange,
disabled: properties.disabled,
strings: properties.strings,
onRender: this.onRender.bind(this),
key: targetProperty
};
}
/*****************************************************************************************
* Renders the QueryFilterPanel property pane
*****************************************************************************************/
public render(): void {
if (!this.elem) {
return;
}
this.onRender(this.elem);
}
/*****************************************************************************************
* Renders the QueryFilterPanel property pane
*****************************************************************************************/
private onRender(elem: HTMLElement): void {
if (!this.elem) {
this.elem = elem;
}
const textDialog: React.ReactElement<ITextDialogProps> = React.createElement(TextDialog, {
dialogTextFieldValue: this.properties.dialogTextFieldValue,
onChanged: this.onChanged.bind(this),
disabled: this.properties.disabled,
strings: this.properties.strings,
// required to allow the component to be re-rendered by calling this.render() externally
stateKey: new Date().toString()
});
ReactDom.render(textDialog, elem);
}
/*****************************************************************************************
* Call the property pane's onPropertyChange when the TextDialog changes
*****************************************************************************************/
private onChanged(text: string): void {
this.properties.onPropertyChange(this.targetProperty, text);
}
}

View File

@ -0,0 +1,9 @@
import { ITextDialogStrings } from "./ITextDialogStrings";
export interface ITextDialogProps {
dialogTextFieldValue?: string;
onChanged?: (text: string) => void;
disabled?: boolean;
strings: ITextDialogStrings;
stateKey?: string;
}

View File

@ -0,0 +1,4 @@
export interface ITextDialogState {
dialogText: string;
showDialog: boolean;
}

View File

@ -0,0 +1,9 @@
export interface ITextDialogStrings {
dialogTitle: string;
dialogSubText?: string;
dialogButtonLabel?: string;
dialogButtonText: string;
dialogTextBoxPlaceholder?: string;
saveButtonText: string;
cancelButtonText: string;
}

View File

@ -0,0 +1,3 @@
.textDialog {
max-width: 100%;
}

View File

@ -0,0 +1,100 @@
import * as React from 'react';
import { Dialog, DialogType, DialogFooter } from 'office-ui-fabric-react';
import { Button, ButtonType, Label } from 'office-ui-fabric-react';
import { TextField } from 'office-ui-fabric-react';
import { ITextDialogProps } from './ITextDialogProps';
import { ITextDialogState } from './ITextDialogState';
import styles from './TextDialog.module.scss';
export class TextDialog extends React.Component<ITextDialogProps, ITextDialogState> {
/*************************************************************************************
* Component's constructor
* @param props
* @param state
*************************************************************************************/
constructor(props: ITextDialogProps, state: ITextDialogState) {
super(props);
this.state = { dialogText: this.props.dialogTextFieldValue, showDialog: false };
}
/*************************************************************************************
* Shows the dialog
*************************************************************************************/
private showDialog() {
this.setState({ dialogText: this.state.dialogText, showDialog: true });
}
/*************************************************************************************
* Notifies the parent with the dialog's latest value, then closes the dialog
*************************************************************************************/
private saveDialog() {
this.setState({ dialogText: this.state.dialogText, showDialog: false });
if(this.props.onChanged) {
this.props.onChanged(this.state.dialogText);
}
}
/*************************************************************************************
* Closes the dialog without notifying the parent for any changes
*************************************************************************************/
private cancelDialog() {
this.setState({ dialogText: this.state.dialogText, showDialog: false });
}
/*************************************************************************************
* Updates the dialog's value each time the textfield changes
*************************************************************************************/
private onDialogTextChanged(newValue: string) {
this.setState({ dialogText: newValue, showDialog: this.state.showDialog });
}
/*************************************************************************************
* Called immediately after updating occurs
*************************************************************************************/
public componentDidUpdate(prevProps: ITextDialogProps, prevState: ITextDialogState): void {
if (this.props.disabled !== prevProps.disabled || this.props.stateKey !== prevProps.stateKey) {
this.setState({ dialogText: this.props.dialogTextFieldValue, showDialog: this.state.showDialog });
}
}
/*************************************************************************************
* Renders the the TextDialog component
*************************************************************************************/
public render() {
return (
<div>
<Label>{ this.props.strings.dialogButtonLabel }</Label>
<Button label={ this.props.strings.dialogButtonLabel } onClick={ this.showDialog.bind(this) }>{ this.props.strings.dialogButtonText }</Button>
<Dialog type={ DialogType.normal }
isOpen={ this.state.showDialog }
onDismiss={ this.cancelDialog.bind(this) }
title={ this.props.strings.dialogTitle }
subText={ this.props.strings.dialogSubText }
isBlocking={ true }
containerClassName={ 'ms-dialogMainOverride ' + styles.textDialog }>
<TextField placeholder={ this.props.strings.dialogTextBoxPlaceholder }
value={ this.state.dialogText }
multiline rows={ 20 }
resizable={ true }
onChanged={ this.onDialogTextChanged.bind(this) } />
<DialogFooter>
<Button buttonType={ ButtonType.primary } onClick={ this.saveDialog.bind(this) }>{ this.props.strings.saveButtonText }</Button>
<Button onClick={ this.cancelDialog.bind(this) }>{ this.props.strings.cancelButtonText }</Button>
</DialogFooter>
</Dialog>
</div>
);
}
}

View File

@ -9,15 +9,15 @@
"preconfiguredEntries": [{
"groupId": "46edf08f-95c7-4ca7-9146-6471f9f471be",
"group": { "default": "Under Development" },
"title": { "default": "Content by Query WebPart" },
"group": { "default": "SPP Technologies" },
"title": { "default": "React Content Query WebPart" },
"description": {
"default": "A react content by query WebPart for querying items within a site and easily displaying them using a simple yet powerfull HandleBars templating engine.",
"fr-FR": "Un composante React permettant d'effectuer des requêtes sur les items et de facilement afficher les résultat à l'aide de gabarits HandleBars fournit par l'utilisateur"
},
"officeFabricIconFontName": "Page",
"properties": {
"description": "Content by Query WebPart"
"description": "React Content Query WebPart"
}
}]
}

View File

@ -16,6 +16,7 @@ import { IContentQueryWebPartProps }
import { PropertyPaneAsyncDropdown } from '../../controls/PropertyPaneAsyncDropdown/PropertyPaneAsyncDropdown';
import { PropertyPaneQueryFilterPanel } from '../../controls/PropertyPaneQueryFilterPanel/PropertyPaneQueryFilterPanel';
import { PropertyPaneAsyncChecklist } from '../../controls/PropertyPaneAsyncChecklist/PropertyPaneAsyncChecklist';
import { PropertyPaneTextDialog } from '../../controls/PropertyPaneTextDialog/PropertyPaneTextDialog';
import { IQueryFilter } from '../../controls/PropertyPaneQueryFilterPanel/components/QueryFilter/IQueryFilter';
import { IQueryFilterField } from '../../controls/PropertyPaneQueryFilterPanel/components/QueryFilter/IQueryFilterField';
import { IChecklistItem } from '../../controls/PropertyPaneAsyncChecklist/components/AsyncChecklist/IChecklistItem';
@ -46,6 +47,7 @@ export default class ContentQueryWebPart extends BaseClientSideWebPart<IContentQ
private itemLimitTextField: IPropertyPaneField<IPropertyPaneTextFieldProps>;
private filtersPanel: PropertyPaneQueryFilterPanel;
private viewFieldsChecklist: PropertyPaneAsyncChecklist;
private templateTextDialog: PropertyPaneTextDialog;
private templateUrlTextField: IPropertyPaneField<IPropertyPaneTextFieldProps>;
@ -88,6 +90,7 @@ export default class ContentQueryWebPart extends BaseClientSideWebPart<IContentQ
onLoadTemplate: this.loadTemplate.bind(this),
onLoadTemplateContext: this.loadTemplateContext.bind(this),
querySettings: querySettings,
templateText: this.properties.templateText,
templateUrl: this.properties.templateUrl,
strings: strings.contentQueryStrings,
stateKey: new Date().toString()
@ -158,6 +161,14 @@ export default class ContentQueryWebPart extends BaseClientSideWebPart<IContentQ
strings: strings.viewFieldsChecklistStrings
});
// Creates a custom PropertyPaneTextDialog for the templateText property
this.templateTextDialog = new PropertyPaneTextDialog(ContentQueryConstants.propertyTemplateText, {
dialogTextFieldValue: this.properties.templateText,
onPropertyChange: this.onTemplateTextChange.bind(this),
disabled: false,
strings: strings.templateTextStrings
});
// Creates a PropertyPaneChoiceGroup for the orderByDirection property
this.orderByDirectionChoiceGroup = PropertyPaneChoiceGroup(ContentQueryConstants.propertOrderByDirection, {
options: [
@ -227,6 +238,17 @@ export default class ContentQueryWebPart extends BaseClientSideWebPart<IContentQ
groupName: strings.DisplayGroupName,
groupFields: [
this.viewFieldsChecklist,
this.templateTextDialog
]
}
]
},
{
header: { description: strings.ExternalPageDescription },
groups: [
{
groupName: strings.ExternalGroupName,
groupFields: [
this.templateUrlTextField
]
}
@ -397,11 +419,39 @@ export default class ContentQueryWebPart extends BaseClientSideWebPart<IContentQ
// Stores the new value in web part properties
update(this.properties, propertyPath, (): any => { return checkedKeys; });
// Updates the default template text if it hasn't been altered by the user
if(!this.properties.hasDefaultTemplateBeenUpdated) {
let generatedTemplate = this.ContentQueryService.generateDefaultTemplate(checkedKeys);
update(this.properties, ContentQueryConstants.propertyTemplateText, (): any => { return generatedTemplate; });
this.templateTextDialog.properties.dialogTextFieldValue = generatedTemplate;
this.templateTextDialog.render();
}
// refresh web part
this.onPropertyPaneFieldChanged(propertyPath, oldValue, checkedKeys);
}
/***************************************************************************
* Handles the change of the viewFields property
***************************************************************************/
private onTemplateTextChange(propertyPath: string, text: string) {
Log.verbose(this.logSource, "WebPart property 'templateText' has changed, refreshing WebPart...", this.context.serviceScope);
const oldValue = get(this.properties, propertyPath);
// Stores the new value in web part properties
update(this.properties, propertyPath, (): any => { return text; });
// Updates the "hasDefaultTemplateBeenUpdated" to true so the WebPart doesn't override the user template after updating view fields
if(!this.properties.hasDefaultTemplateBeenUpdated) {
update(this.properties, ContentQueryConstants.propertyhasDefaultTemplateBeenUpdated, (): any => { return true; });
}
// refresh web part
this.onPropertyPaneFieldChanged(propertyPath, oldValue, text);
}
/***************************************************************************
* Validates the templateUrl property
***************************************************************************/
@ -505,4 +555,4 @@ export default class ContentQueryWebPart extends BaseClientSideWebPart<IContentQ
this.viewFieldsChecklist.properties.disable = isEmpty(this.properties.webUrl) || isEmpty(this.properties.listTitle);
this.viewFieldsChecklist.render();
}
}
}

View File

@ -9,5 +9,7 @@ export interface IContentQueryWebPartProps {
orderByDirection: string;
filters: IQueryFilter[];
viewFields: string[];
templateText: string;
templateUrl: string;
hasDefaultTemplateBeenUpdated: boolean;
}

View File

@ -28,9 +28,14 @@ export default class ContentQuery extends React.Component<IContentQueryProps, IC
constructor(props: IContentQueryProps, state: IContentQueryState) {
super(props);
// Imports the handlebars-helpers
let helpers = require<any>('handlebars-helpers')({
handlebars: Handlebars
});
this.onGoingAsyncCalls = [];
this.state = { loading: true, processedTemplateResult: null, error: null };
}
}
/*************************************************************************************
@ -65,7 +70,7 @@ export default class ContentQuery extends React.Component<IContentQueryProps, IC
this.props.onLoadTemplateContext(this.props.querySettings, currentCallTimeStamp).then((templateContext: IContentQueryTemplateContext) => {
// Loads the handlebars template
this.props.onLoadTemplate(this.props.templateUrl).then((templateContent: string) => {
this.loadTemplate().then((templateContent: string) => {
// Only process the result of the current async call if it's the last in the ordered queue
if(this.isLastExecutedCall(templateContext.callTimeStamp)) {
@ -91,6 +96,26 @@ export default class ContentQuery extends React.Component<IContentQueryProps, IC
}
/*************************************************************************************
* Loads the template from url if available, otherwise returns the inline template
*************************************************************************************/
private loadTemplate(): Promise<string> {
// Resolves the template content if no template url
if(isEmpty(this.props.templateUrl)) {
return Promise.resolve(this.props.templateText);
}
return new Promise<string>((resolve,reject) => {
this.props.onLoadTemplate(this.props.templateUrl).then((templateContent: string) => {
resolve(templateContent);
})
.catch((error: string) => {
reject(error);
});
});
}
/*************************************************************************************
* Process the specified handlebars template with the given template context
* @param templateContent : The handlebars template that needs to be compiled
@ -120,7 +145,7 @@ export default class ContentQuery extends React.Component<IContentQueryProps, IC
return !isEmpty(this.props.querySettings.webUrl) &&
!isEmpty(this.props.querySettings.listTitle) &&
!isEmpty(this.props.querySettings.viewFields) &&
!isEmpty(this.props.templateUrl);
(!isEmpty(this.props.templateUrl) || !isEmpty(this.props.templateText));
}
@ -170,12 +195,12 @@ export default class ContentQuery extends React.Component<IContentQueryProps, IC
{/* Shows the validation checklist if mandatory properties aren't all configured */}
{ !mandatoryFieldsConfigured && !this.state.loading && !this.state.error &&
<div className={styles.cqwpValidations}>
Configure the following mandatory properties in order to display results :
{ this.props.strings.mandatoryProperties }
<Checkbox label={strings.WebUrlFieldLabel} checked={!isEmpty(this.props.querySettings.webUrl)} />
<Checkbox label={strings.ListTitleFieldLabel} checked={!isEmpty(this.props.querySettings.listTitle)} />
<Checkbox label={strings.viewFieldsChecklistStrings.label} checked={!isEmpty(this.props.querySettings.viewFields)} />
<Checkbox label={strings.TemplateUrlFieldLabel} checked={!isEmpty(this.props.templateUrl)} />
<Checkbox label={strings.templateTextStrings.dialogButtonLabel + " / " + strings.TemplateUrlFieldLabel} checked={(!isEmpty(this.props.templateUrl) || !isEmpty(this.props.templateText))} />
</div>
}

View File

@ -7,7 +7,8 @@ export interface IContentQueryProps {
onLoadTemplate: (templateUrl: string) => Promise<string>;
onLoadTemplateContext: (querySettings: IQuerySettings, callTimeStamp: number) => Promise<IContentQueryTemplateContext>;
querySettings: IQuerySettings;
templateUrl: string;
templateText?: string;
templateUrl?: string;
strings: IContentQueryStrings;
stateKey: string;
}

View File

@ -1,5 +1,6 @@
export interface IContentQueryStrings {
loadingItems: string;
mandatoryProperties: string;
errorLoadingQuery: string;
errorLoadingTemplate: string;
errorProcessingTemplate: string;

View File

@ -2,10 +2,12 @@ define([], function() {
return {
SourcePageDescription: "Specify where the WebPart should get the results from.",
QueryPageDescription: "If needed, choose the sorting behavior, limit the results, or add filters in order to narrow the query down.",
DisplayPageDescription: "Finally, specify which fields should be available for rendering within the HandleBars template, and specify the URL of the said template.",
DisplayPageDescription: "Specify which fields should be available for rendering within the HandleBars template, and edit your handlebars template.",
ExternalPageDescription: "Optionally, externalize the properties below by specifying valid sharepoint urls.",
SourceGroupName: "Source",
QueryGroupName: "Query",
DisplayGroupName: "Display",
ExternalGroupName: "External Resources",
WebUrlFieldLabel: "Web Url",
WebUrlFieldPlaceholder: "Select the source web...",
WebUrlFieldLoadingLabel: "Loading webs from current site...",
@ -29,6 +31,7 @@ define([], function() {
ErrorProcessingTemplate: "An error occured while processing the handlebars template : {0}",
ShowItemsAscending: "Show items in ascending order",
ShowItemsDescending: "Show items in descending order",
DynamicallyGeneratedTemplate: "Dynamically generated template",
queryFilterPanelStrings: {
filtersLabel: "Filters",
addFilterLabel: "Add filter",
@ -80,8 +83,18 @@ define([], function() {
loading: 'Loading fields from specified list...',
errorFormat: 'An error occured while loading fields : {0}'
},
templateTextStrings: {
dialogTitle: "Edit template content",
dialogSubText: "Edit your handlebars template in this dialog. Note that the inline template specified within this dialog will be ignored if a template url is specified.",
dialogButtonLabel: "Template",
dialogButtonText: "Edit template content",
dialogTextBoxPlaceholder: "Edit your handlebars template here...",
saveButtonText: 'Save',
cancelButtonText: 'Cancel'
},
contentQueryStrings: {
loadingItems: 'Processing query',
mandatoryProperties: 'Configure the following mandatory properties in order to display results :',
errorLoadingQuery: 'An error occured while processing the query : {0}',
errorLoadingTemplate: 'An error occured while loading the template: {0}',
errorProcessingTemplate: 'An error occured while processing the handlebars template : {0}'

View File

@ -2,9 +2,11 @@ declare interface IContentQueryStrings {
SourcePageDescription: string;
QueryPageDescription: string;
DisplayPageDescription: string;
ExternalPageDescription: string;
SourceGroupName: string;
QueryGroupName: string;
DisplayGroupName: string;
ExternalGroupName: string;
WebUrlFieldLabel: string;
WebUrlFieldPlaceholder: string;
WebUrlFieldLoadingLabel: string;
@ -27,8 +29,10 @@ declare interface IContentQueryStrings {
ErrorWebNotFound: string;
ShowItemsAscending: string;
ShowItemsDescending: string;
DynamicallyGeneratedTemplate: string;
queryFilterPanelStrings: any;
viewFieldsChecklistStrings: any;
templateTextStrings: any;
contentQueryStrings: any;
}