mirror of
https://github.com/silverstripe/silverstripe-tagfield
synced 2024-09-28 20:29:16 +02:00
Compare commits
16 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
f1a2e30a26 | ||
|
f2990cb03a | ||
|
1b97237abb | ||
|
315096c64d | ||
|
242f6bbb57 | ||
|
09212e406a | ||
|
69d64602dc | ||
|
b80f94f85e | ||
|
04234de836 | ||
|
dd7481a2bc | ||
|
8b8bd13097 | ||
|
249842fab8 | ||
|
6f203a36af | ||
|
5b26bd0739 | ||
|
28c41961a4 | ||
|
08d1646e4c |
@ -1,4 +0,0 @@
|
||||
mappings:
|
||||
StringTagField: SilverStripe\TagField\StringTagField
|
||||
TagField: SilverStripe\TagField\TagField
|
||||
TagField_Readonly: SilverStripe\TagField\TagField\Readonly
|
16
README.md
16
README.md
@ -5,6 +5,12 @@
|
||||
|
||||
Custom tag input field, for SilverStripe.
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
composer require silverstripe/tagfield
|
||||
```
|
||||
|
||||
## Overview
|
||||
|
||||
![Screenshot](docs/en/screenshot.png)
|
||||
@ -16,16 +22,6 @@ Note: The field is optimised for usage in the Silverstripe CMS UI.
|
||||
The form field class itself can be used outside of the CMS,
|
||||
but you'll need to build your own frontend to interpret the raw field data (`data-schema` attribute).
|
||||
|
||||
## Requirements
|
||||
|
||||
* Silverstripe 4.0
|
||||
|
||||
## Installing
|
||||
|
||||
```sh
|
||||
$ composer require silverstripe/tagfield
|
||||
```
|
||||
|
||||
## Using
|
||||
|
||||
### Relational Tags
|
||||
|
6
babel.config.json
Normal file
6
babel.config.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"presets": [
|
||||
"@babel/preset-env",
|
||||
"@babel/preset-react"
|
||||
]
|
||||
}
|
2
client/dist/js/bundle.js
vendored
2
client/dist/js/bundle.js
vendored
@ -1 +1 @@
|
||||
!function(e){function t(o){if(n[o])return n[o].exports;var r=n[o]={i:o,l:!1,exports:{}};return e[o].call(r.exports,r,r.exports,t),r.l=!0,r.exports}var n={};t.m=e,t.c=n,t.i=function(e){return e},t.d=function(e,n,o){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:o})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s="./client/src/bundles/bundle.js")}({"./client/src/boot/index.js":function(e,t,n){"use strict";var o=n("./client/src/boot/registerComponents.js"),r=function(e){return e&&e.__esModule?e:{default:e}}(o);window.document.addEventListener("DOMContentLoaded",function(){(0,r.default)()})},"./client/src/boot/registerComponents.js":function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var r=n(0),s=o(r),i=n("./client/src/components/TagField.js"),a=o(i);t.default=function(){s.default.component.registerMany({TagField:a.default})}},"./client/src/bundles/bundle.js":function(e,t,n){"use strict";n("./client/src/legacy/entwine/TagField.js"),n("./client/src/boot/index.js")},"./client/src/components/TagField.js":function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}function r(e,t){var n={};for(var o in e)t.indexOf(o)>=0||Object.prototype.hasOwnProperty.call(e,o)&&(n[o]=e[o]);return n}function s(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function a(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function u(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0}),t.Component=void 0;var l="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},h=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var o in n)Object.prototype.hasOwnProperty.call(n,o)&&(e[o]=n[o])}return e},c=function(){function e(e,t){for(var n=0;n<t.length;n++){var o=t[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(e,o.key,o)}}return function(t,n,o){return n&&e(t.prototype,n),o&&e(t,o),t}}(),f=n(1),p=o(f),d=n(5),m=o(d),v=n(3),y=o(v),b=n(2),g=o(b),j=n("./node_modules/url/url.js"),O=o(j),w=n("./node_modules/debounce-promise/dist/index.js"),C=o(w),x=n("./node_modules/prop-types/index.js"),_=o(x),S=function(e){function t(e){i(this,t);var n=a(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e));return n.selectComponentRef=null,n.setSelectComponentRef=function(e){n.selectComponentRef=e},n.state={initalState:e.value?e.value:[],hasChanges:!1},n.isControlled()||(n.state=h({},n.state,{value:e.value})),n.handleChange=n.handleChange.bind(n),n.handleOnBlur=n.handleOnBlur.bind(n),n.getOptions=n.getOptions.bind(n),n.fetchOptions=(0,C.default)(n.fetchOptions,500),n}return u(t,e),c(t,[{key:"componentDidUpdate",value:function(e,t){if(t.hasChanges!==this.state.hasChanges){var n=this.selectComponentRef.select.wrapper,o=new Event("change",{bubbles:!0});n.dispatchEvent(o)}}},{key:"getOptions",value:function(e){var t=this.props,n=t.lazyLoad,o=t.options;return n?e?this.fetchOptions(e):Promise.resolve({options:[]}):Promise.resolve({options:o})}},{key:"handleChange",value:function(e){if(this.setState({hasChanges:!1}),JSON.stringify(this.state.initalState)!==JSON.stringify(e)&&this.setState({hasChanges:!0}),this.isControlled())return void this.props.onChange(e);this.setState({value:e})}},{key:"isControlled",value:function(){return"function"==typeof this.props.onChange}},{key:"handleOnBlur",value:function(){}},{key:"fetchOptions",value:function(e){var t=this.props,n=t.optionUrl,o=t.labelKey,r=t.valueKey,i=O.default.parse(n,!0);return i.query.term=e,(0,y.default)(O.default.format(i),{credentials:"same-origin"}).then(function(e){return e.json()}).then(function(e){return{options:e.items.map(function(e){var t;return t={},s(t,o,e.Title),s(t,r,e.Value),s(t,"Selected",e.Selected),t})}})}},{key:"render",value:function(){var e=this.props,t=e.lazyLoad,n=e.options,o=e.creatable,s=r(e,["lazyLoad","options","creatable"]),i=t?{loadOptions:this.getOptions}:{options:n},a=m.default;if(t&&o?a=m.default.AsyncCreatable:t?a=m.default.Async:o&&(a=m.default.Creatable),this.isControlled()||(s.value=this.state.value),!s.multi&&s.value&&Object.keys(s.value).length>0){var u=s.value[Object.keys(s.value)[0]];"object"===(void 0===u?"undefined":l(u))&&(s.value=u)}var c=this.state.hasChanges?"":"no-change-track";return p.default.createElement(a,h({},s,{onChange:this.handleChange,onBlur:this.handleOnBlur},i,{className:c,ref:this.setSelectComponentRef}))}}]),t}(f.Component);S.propTypes={name:_.default.string.isRequired,labelKey:_.default.string.isRequired,valueKey:_.default.string.isRequired,lazyLoad:_.default.bool,creatable:_.default.bool,multi:_.default.bool,disabled:_.default.bool,options:_.default.arrayOf(_.default.object),optionUrl:_.default.string,value:_.default.any,onChange:_.default.func,onBlur:_.default.func},S.defaultProps={labelKey:"Title",valueKey:"Value",disabled:!1,lazyLoad:!1,creatable:!1,multi:!1},t.Component=S,t.default=(0,g.default)(S)},"./client/src/legacy/entwine/TagField.js":function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}var r=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var o in n)Object.prototype.hasOwnProperty.call(n,o)&&(e[o]=n[o])}return e},s=n(1),i=o(s),a=n(4),u=o(a),l=n(0);window.jQuery.entwine("ss",function(e){e(".js-injector-boot .ss-tag-field.entwine").entwine({onmatch:function(){var e=this,t=this.closest(".cms-content").attr("id"),n=t?{context:t}:{},o=(0,l.loadComponent)("TagField",n),s=r({},this.data("schema"),{onBlur:function(){e.parents(".cms-edit-form:first").trigger("change")}});u.default.render(i.default.createElement(o,r({noHolder:!0},s)),this[0])},onunmatch:function(){u.default.unmountComponentAtNode(this[0])}}),e(".cms-edit-form").entwine({getChangeTrackerOptions:function(){var t=void 0===this.entwineData("ChangeTrackerOptions"),n=this._super();return t&&(n=e.extend({},n),n.ignoreFieldSelector+=", .ss-tag-field .no-change-track :input",this.setChangeTrackerOptions(n)),n}})})},"./node_modules/debounce-promise/dist/index.js":function(e,t,n){"use strict";function o(e){return"function"==typeof e?e():e}function r(){var e={};return e.promise=new Promise(function(t,n){e.resolve=t,e.reject=n}),e}e.exports=function(e){function t(){var t=a;clearTimeout(u),Promise.resolve(s.accumulate?e.call(this,l):e.apply(this,l[l.length-1])).then(t.resolve,t.reject),l=[],a=null}var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,s=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},i=void 0,a=void 0,u=void 0,l=[];return function(){var h=o(n),c=(new Date).getTime(),f=!i||c-i>h;i=c;for(var p=arguments.length,d=Array(p),m=0;m<p;m++)d[m]=arguments[m];if(f&&s.leading)return s.accumulate?Promise.resolve(e.call(this,[d])).then(function(e){return e[0]}):Promise.resolve(e.call.apply(e,[this].concat(d)));if(a?clearTimeout(u):a=r(),l.push(d),u=setTimeout(t.bind(this),h),s.accumulate){var v=l.length-1;return a.promise.then(function(e){return e[v]})}return a.promise}}},"./node_modules/node-libs-browser/node_modules/punycode/punycode.js":function(e,t,n){(function(e,o){var r;!function(o){function s(e){throw new RangeError(R[e])}function i(e,t){for(var n=e.length,o=[];n--;)o[n]=t(e[n]);return o}function a(e,t){var n=e.split("@"),o="";return n.length>1&&(o=n[0]+"@",e=n[1]),e=e.replace(k,"."),o+i(e.split("."),t).join(".")}function u(e){for(var t,n,o=[],r=0,s=e.length;r<s;)t=e.charCodeAt(r++),t>=55296&&t<=56319&&r<s?(n=e.charCodeAt(r++),56320==(64512&n)?o.push(((1023&t)<<10)+(1023&n)+65536):(o.push(t),r--)):o.push(t);return o}function l(e){return i(e,function(e){var t="";return e>65535&&(e-=65536,t+=I(e>>>10&1023|55296),e=56320|1023&e),t+=I(e)}).join("")}function h(e){return e-48<10?e-22:e-65<26?e-65:e-97<26?e-97:g}function c(e,t){return e+22+75*(e<26)-((0!=t)<<5)}function f(e,t,n){var o=0;for(e=n?A(e/C):e>>1,e+=A(e/t);e>q*O>>1;o+=g)e=A(e/q);return A(o+(q+1)*e/(e+w))}function p(e){var t,n,o,r,i,a,u,c,p,d,m=[],v=e.length,y=0,w=_,C=x;for(n=e.lastIndexOf(S),n<0&&(n=0),o=0;o<n;++o)e.charCodeAt(o)>=128&&s("not-basic"),m.push(e.charCodeAt(o));for(r=n>0?n+1:0;r<v;){for(i=y,a=1,u=g;r>=v&&s("invalid-input"),c=h(e.charCodeAt(r++)),(c>=g||c>A((b-y)/a))&&s("overflow"),y+=c*a,p=u<=C?j:u>=C+O?O:u-C,!(c<p);u+=g)d=g-p,a>A(b/d)&&s("overflow"),a*=d;t=m.length+1,C=f(y-i,t,0==i),A(y/t)>b-w&&s("overflow"),w+=A(y/t),y%=t,m.splice(y++,0,w)}return l(m)}function d(e){var t,n,o,r,i,a,l,h,p,d,m,v,y,w,C,T=[];for(e=u(e),v=e.length,t=_,n=0,i=x,a=0;a<v;++a)(m=e[a])<128&&T.push(I(m));for(o=r=T.length,r&&T.push(S);o<v;){for(l=b,a=0;a<v;++a)(m=e[a])>=t&&m<l&&(l=m);for(y=o+1,l-t>A((b-n)/y)&&s("overflow"),n+=(l-t)*y,t=l,a=0;a<v;++a)if(m=e[a],m<t&&++n>b&&s("overflow"),m==t){for(h=n,p=g;d=p<=i?j:p>=i+O?O:p-i,!(h<d);p+=g)C=h-d,w=g-d,T.push(I(c(d+C%w,0))),h=A(C/w);T.push(I(c(h,0))),i=f(n,y,o==r),n=0,++o}++n,++t}return T.join("")}function m(e){return a(e,function(e){return T.test(e)?p(e.slice(4).toLowerCase()):e})}function v(e){return a(e,function(e){return P.test(e)?"xn--"+d(e):e})}var y,b=("object"==typeof t&&t&&t.nodeType,"object"==typeof e&&e&&e.nodeType,2147483647),g=36,j=1,O=26,w=38,C=700,x=72,_=128,S="-",T=/^xn--/,P=/[^\x20-\x7E]/,k=/[\x2E\u3002\uFF0E\uFF61]/g,R={overflow:"Overflow: input needs wider integers to process","not-basic":"Illegal input >= 0x80 (not a basic code point)","invalid-input":"Invalid input"},q=g-j,A=Math.floor,I=String.fromCharCode;y={version:"1.4.1",ucs2:{decode:u,encode:l},decode:p,encode:d,toASCII:v,toUnicode:m},void 0!==(r=function(){return y}.call(t,n,t,e))&&(e.exports=r)}()}).call(t,n("./node_modules/webpack/buildin/module.js")(e),n("./node_modules/webpack/buildin/global.js"))},"./node_modules/prop-types/factoryWithThrowingShims.js":function(e,t,n){"use strict";function o(){}function r(){}var s=n("./node_modules/prop-types/lib/ReactPropTypesSecret.js");r.resetWarningCache=o,e.exports=function(){function e(e,t,n,o,r,i){if(i!==s){var a=new Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw a.name="Invariant Violation",a}}function t(){return e}e.isRequired=e;var n={array:e,bigint:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,elementType:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t,checkPropTypes:r,resetWarningCache:o};return n.PropTypes=n,n}},"./node_modules/prop-types/index.js":function(e,t,n){e.exports=n("./node_modules/prop-types/factoryWithThrowingShims.js")()},"./node_modules/prop-types/lib/ReactPropTypesSecret.js":function(e,t,n){"use strict";e.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"},"./node_modules/querystring-es3/decode.js":function(e,t,n){"use strict";function o(e,t){return Object.prototype.hasOwnProperty.call(e,t)}e.exports=function(e,t,n,s){t=t||"&",n=n||"=";var i={};if("string"!=typeof e||0===e.length)return i;var a=/\+/g;e=e.split(t);var u=1e3;s&&"number"==typeof s.maxKeys&&(u=s.maxKeys);var l=e.length;u>0&&l>u&&(l=u);for(var h=0;h<l;++h){var c,f,p,d,m=e[h].replace(a,"%20"),v=m.indexOf(n);v>=0?(c=m.substr(0,v),f=m.substr(v+1)):(c=m,f=""),p=decodeURIComponent(c),d=decodeURIComponent(f),o(i,p)?r(i[p])?i[p].push(d):i[p]=[i[p],d]:i[p]=d}return i};var r=Array.isArray||function(e){return"[object Array]"===Object.prototype.toString.call(e)}},"./node_modules/querystring-es3/encode.js":function(e,t,n){"use strict";function o(e,t){if(e.map)return e.map(t);for(var n=[],o=0;o<e.length;o++)n.push(t(e[o],o));return n}var r=function(e){switch(typeof e){case"string":return e;case"boolean":return e?"true":"false";case"number":return isFinite(e)?e:"";default:return""}};e.exports=function(e,t,n,a){return t=t||"&",n=n||"=",null===e&&(e=void 0),"object"==typeof e?o(i(e),function(i){var a=encodeURIComponent(r(i))+n;return s(e[i])?o(e[i],function(e){return a+encodeURIComponent(r(e))}).join(t):a+encodeURIComponent(r(e[i]))}).join(t):a?encodeURIComponent(r(a))+n+encodeURIComponent(r(e)):""};var s=Array.isArray||function(e){return"[object Array]"===Object.prototype.toString.call(e)},i=Object.keys||function(e){var t=[];for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&t.push(n);return t}},"./node_modules/querystring-es3/index.js":function(e,t,n){"use strict";t.decode=t.parse=n("./node_modules/querystring-es3/decode.js"),t.encode=t.stringify=n("./node_modules/querystring-es3/encode.js")},"./node_modules/url/url.js":function(e,t,n){"use strict";function o(){this.protocol=null,this.slashes=null,this.auth=null,this.host=null,this.port=null,this.hostname=null,this.hash=null,this.search=null,this.query=null,this.pathname=null,this.path=null,this.href=null}function r(e,t,n){if(e&&l.isObject(e)&&e instanceof o)return e;var r=new o;return r.parse(e,t,n),r}function s(e){return l.isString(e)&&(e=r(e)),e instanceof o?e.format():o.prototype.format.call(e)}function i(e,t){return r(e,!1,!0).resolve(t)}function a(e,t){return e?r(e,!1,!0).resolveObject(t):t}var u=n("./node_modules/node-libs-browser/node_modules/punycode/punycode.js"),l=n("./node_modules/url/util.js");t.parse=r,t.resolve=i,t.resolveObject=a,t.format=s,t.Url=o;var h=/^([a-z0-9.+-]+:)/i,c=/:[0-9]*$/,f=/^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/,p=["<",">",'"',"`"," ","\r","\n","\t"],d=["{","}","|","\\","^","`"].concat(p),m=["'"].concat(d),v=["%","/","?",";","#"].concat(m),y=["/","?","#"],b=/^[+a-z0-9A-Z_-]{0,63}$/,g=/^([+a-z0-9A-Z_-]{0,63})(.*)$/,j={javascript:!0,"javascript:":!0},O={javascript:!0,"javascript:":!0},w={http:!0,https:!0,ftp:!0,gopher:!0,file:!0,"http:":!0,"https:":!0,"ftp:":!0,"gopher:":!0,"file:":!0},C=n("./node_modules/querystring-es3/index.js");o.prototype.parse=function(e,t,n){if(!l.isString(e))throw new TypeError("Parameter 'url' must be a string, not "+typeof e);var o=e.indexOf("?"),r=-1!==o&&o<e.indexOf("#")?"?":"#",s=e.split(r),i=/\\/g;s[0]=s[0].replace(i,"/"),e=s.join(r);var a=e;if(a=a.trim(),!n&&1===e.split("#").length){var c=f.exec(a);if(c)return this.path=a,this.href=a,this.pathname=c[1],c[2]?(this.search=c[2],this.query=t?C.parse(this.search.substr(1)):this.search.substr(1)):t&&(this.search="",this.query={}),this}var p=h.exec(a);if(p){p=p[0];var d=p.toLowerCase();this.protocol=d,a=a.substr(p.length)}if(n||p||a.match(/^\/\/[^@\/]+@[^@\/]+/)){var x="//"===a.substr(0,2);!x||p&&O[p]||(a=a.substr(2),this.slashes=!0)}if(!O[p]&&(x||p&&!w[p])){for(var _=-1,S=0;S<y.length;S++){var T=a.indexOf(y[S]);-1!==T&&(-1===_||T<_)&&(_=T)}var P,k;k=-1===_?a.lastIndexOf("@"):a.lastIndexOf("@",_),-1!==k&&(P=a.slice(0,k),a=a.slice(k+1),this.auth=decodeURIComponent(P)),_=-1;for(var S=0;S<v.length;S++){var T=a.indexOf(v[S]);-1!==T&&(-1===_||T<_)&&(_=T)}-1===_&&(_=a.length),this.host=a.slice(0,_),a=a.slice(_),this.parseHost(),this.hostname=this.hostname||"";var R="["===this.hostname[0]&&"]"===this.hostname[this.hostname.length-1];if(!R)for(var q=this.hostname.split(/\./),S=0,A=q.length;S<A;S++){var I=q[S];if(I&&!I.match(b)){for(var U="",E=0,F=I.length;E<F;E++)I.charCodeAt(E)>127?U+="x":U+=I[E];if(!U.match(b)){var L=q.slice(0,S),N=q.slice(S+1),M=I.match(g);M&&(L.push(M[1]),N.unshift(M[2])),N.length&&(a="/"+N.join(".")+a),this.hostname=L.join(".");break}}}this.hostname.length>255?this.hostname="":this.hostname=this.hostname.toLowerCase(),R||(this.hostname=u.toASCII(this.hostname));var z=this.port?":"+this.port:"",B=this.hostname||"";this.host=B+z,this.href+=this.host,R&&(this.hostname=this.hostname.substr(1,this.hostname.length-2),"/"!==a[0]&&(a="/"+a))}if(!j[d])for(var S=0,A=m.length;S<A;S++){var K=m[S];if(-1!==a.indexOf(K)){var D=encodeURIComponent(K);D===K&&(D=escape(K)),a=a.split(K).join(D)}}var H=a.indexOf("#");-1!==H&&(this.hash=a.substr(H),a=a.slice(0,H));var W=a.indexOf("?");if(-1!==W?(this.search=a.substr(W),this.query=a.substr(W+1),t&&(this.query=C.parse(this.query)),a=a.slice(0,W)):t&&(this.search="",this.query={}),a&&(this.pathname=a),w[d]&&this.hostname&&!this.pathname&&(this.pathname="/"),this.pathname||this.search){var z=this.pathname||"",$=this.search||"";this.path=z+$}return this.href=this.format(),this},o.prototype.format=function(){var e=this.auth||"";e&&(e=encodeURIComponent(e),e=e.replace(/%3A/i,":"),e+="@");var t=this.protocol||"",n=this.pathname||"",o=this.hash||"",r=!1,s="";this.host?r=e+this.host:this.hostname&&(r=e+(-1===this.hostname.indexOf(":")?this.hostname:"["+this.hostname+"]"),this.port&&(r+=":"+this.port)),this.query&&l.isObject(this.query)&&Object.keys(this.query).length&&(s=C.stringify(this.query));var i=this.search||s&&"?"+s||"";return t&&":"!==t.substr(-1)&&(t+=":"),this.slashes||(!t||w[t])&&!1!==r?(r="//"+(r||""),n&&"/"!==n.charAt(0)&&(n="/"+n)):r||(r=""),o&&"#"!==o.charAt(0)&&(o="#"+o),i&&"?"!==i.charAt(0)&&(i="?"+i),n=n.replace(/[?#]/g,function(e){return encodeURIComponent(e)}),i=i.replace("#","%23"),t+r+n+i+o},o.prototype.resolve=function(e){return this.resolveObject(r(e,!1,!0)).format()},o.prototype.resolveObject=function(e){if(l.isString(e)){var t=new o;t.parse(e,!1,!0),e=t}for(var n=new o,r=Object.keys(this),s=0;s<r.length;s++){var i=r[s];n[i]=this[i]}if(n.hash=e.hash,""===e.href)return n.href=n.format(),n;if(e.slashes&&!e.protocol){for(var a=Object.keys(e),u=0;u<a.length;u++){var h=a[u];"protocol"!==h&&(n[h]=e[h])}return w[n.protocol]&&n.hostname&&!n.pathname&&(n.path=n.pathname="/"),n.href=n.format(),n}if(e.protocol&&e.protocol!==n.protocol){if(!w[e.protocol]){for(var c=Object.keys(e),f=0;f<c.length;f++){var p=c[f];n[p]=e[p]}return n.href=n.format(),n}if(n.protocol=e.protocol,e.host||O[e.protocol])n.pathname=e.pathname;else{for(var d=(e.pathname||"").split("/");d.length&&!(e.host=d.shift()););e.host||(e.host=""),e.hostname||(e.hostname=""),""!==d[0]&&d.unshift(""),d.length<2&&d.unshift(""),n.pathname=d.join("/")}if(n.search=e.search,n.query=e.query,n.host=e.host||"",n.auth=e.auth,n.hostname=e.hostname||e.host,n.port=e.port,n.pathname||n.search){var m=n.pathname||"",v=n.search||"";n.path=m+v}return n.slashes=n.slashes||e.slashes,n.href=n.format(),n}var y=n.pathname&&"/"===n.pathname.charAt(0),b=e.host||e.pathname&&"/"===e.pathname.charAt(0),g=b||y||n.host&&e.pathname,j=g,C=n.pathname&&n.pathname.split("/")||[],d=e.pathname&&e.pathname.split("/")||[],x=n.protocol&&!w[n.protocol];if(x&&(n.hostname="",n.port=null,n.host&&(""===C[0]?C[0]=n.host:C.unshift(n.host)),n.host="",e.protocol&&(e.hostname=null,e.port=null,e.host&&(""===d[0]?d[0]=e.host:d.unshift(e.host)),e.host=null),g=g&&(""===d[0]||""===C[0])),b)n.host=e.host||""===e.host?e.host:n.host,n.hostname=e.hostname||""===e.hostname?e.hostname:n.hostname,n.search=e.search,n.query=e.query,C=d;else if(d.length)C||(C=[]),C.pop(),C=C.concat(d),n.search=e.search,n.query=e.query;else if(!l.isNullOrUndefined(e.search)){if(x){n.hostname=n.host=C.shift();var _=!!(n.host&&n.host.indexOf("@")>0)&&n.host.split("@");_&&(n.auth=_.shift(),n.host=n.hostname=_.shift())}return n.search=e.search,n.query=e.query,l.isNull(n.pathname)&&l.isNull(n.search)||(n.path=(n.pathname?n.pathname:"")+(n.search?n.search:"")),n.href=n.format(),n}if(!C.length)return n.pathname=null,n.search?n.path="/"+n.search:n.path=null,n.href=n.format(),n;for(var S=C.slice(-1)[0],T=(n.host||e.host||C.length>1)&&("."===S||".."===S)||""===S,P=0,k=C.length;k>=0;k--)S=C[k],"."===S?C.splice(k,1):".."===S?(C.splice(k,1),P++):P&&(C.splice(k,1),P--);if(!g&&!j)for(;P--;P)C.unshift("..");!g||""===C[0]||C[0]&&"/"===C[0].charAt(0)||C.unshift(""),T&&"/"!==C.join("/").substr(-1)&&C.push("");var R=""===C[0]||C[0]&&"/"===C[0].charAt(0);if(x){n.hostname=n.host=R?"":C.length?C.shift():"";var _=!!(n.host&&n.host.indexOf("@")>0)&&n.host.split("@");_&&(n.auth=_.shift(),n.host=n.hostname=_.shift())}return g=g||n.host&&C.length,g&&!R&&C.unshift(""),C.length?n.pathname=C.join("/"):(n.pathname=null,n.path=null),l.isNull(n.pathname)&&l.isNull(n.search)||(n.path=(n.pathname?n.pathname:"")+(n.search?n.search:"")),n.auth=e.auth||n.auth,n.slashes=n.slashes||e.slashes,n.href=n.format(),n},o.prototype.parseHost=function(){var e=this.host,t=c.exec(e);t&&(t=t[0],":"!==t&&(this.port=t.substr(1)),e=e.substr(0,e.length-t.length)),e&&(this.hostname=e)}},"./node_modules/url/util.js":function(e,t,n){"use strict";e.exports={isString:function(e){return"string"==typeof e},isObject:function(e){return"object"==typeof e&&null!==e},isNull:function(e){return null===e},isNullOrUndefined:function(e){return null==e}}},"./node_modules/webpack/buildin/global.js":function(e,t){var n;n=function(){return this}();try{n=n||Function("return this")()||(0,eval)("this")}catch(e){"object"==typeof window&&(n=window)}e.exports=n},"./node_modules/webpack/buildin/module.js":function(e,t){e.exports=function(e){return e.webpackPolyfill||(e.deprecate=function(){},e.paths=[],e.children||(e.children=[]),Object.defineProperty(e,"loaded",{enumerable:!0,get:function(){return e.l}}),Object.defineProperty(e,"id",{enumerable:!0,get:function(){return e.i}}),e.webpackPolyfill=1),e}},0:function(e,t){e.exports=Injector},1:function(e,t){e.exports=React},2:function(e,t){e.exports=FieldHolder},3:function(e,t){e.exports=IsomorphicFetch},4:function(e,t){e.exports=ReactDom},5:function(e,t){e.exports=ReactSelect}});
|
||||
!function(){"use strict";var e={274:function(e,t,n){var o,a=(o=n(521))&&o.__esModule?o:{default:o};window.document.addEventListener("DOMContentLoaded",(()=>{(0,a.default)()}))},521:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o=r(n(648)),a=r(n(157));function r(e){return e&&e.__esModule?e:{default:e}}t.default=()=>{o.default.component.registerMany({TagField:a.default})}},157:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.Component=void 0;var o=function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=y(t);if(n&&n.has(e))return n.get(e);var o={},a=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var r in e)if("default"!==r&&Object.prototype.hasOwnProperty.call(e,r)){var i=a?Object.getOwnPropertyDescriptor(e,r):null;i&&(i.get||i.set)?Object.defineProperty(o,r,i):o[r]=e[r]}o.default=e,n&&n.set(e,o);return o}(n(363)),a=v(n(967)),r=v(n(493)),i=v(n(198)),l=v(n(453)),s=v(n(78)),u=v(n(754)),c=v(n(875)),f=v(n(42)),d=v(n(872)),p=v(n(496)),h=v(n(86));function v(e){return e&&e.__esModule?e:{default:e}}function y(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(y=function(e){return e?n:t})(e)}function m(){return m=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var o in n)Object.prototype.hasOwnProperty.call(n,o)&&(e[o]=n[o])}return e},m.apply(this,arguments)}class O extends o.Component{constructor(e){super(e),this.isControlled()||(this.state={value:e.value}),this.handleChange=this.handleChange.bind(this),this.handleOnBlur=this.handleOnBlur.bind(this),this.isValidNewOption=this.isValidNewOption.bind(this),this.getOptions=this.getOptions.bind(this),this.fetchOptions=(0,p.default)(this.fetchOptions,500)}getOptions(e){const{lazyLoad:t,options:n}=this.props;return t?e?this.fetchOptions(e):Promise.resolve([]):Promise.resolve(n)}handleChange(e){this.isControlled()?this.props.onChange(e):this.setState({value:e})}isControlled(){return"function"==typeof this.props.onChange}handleOnBlur(){}fetchOptions(e){const{optionUrl:t,labelKey:n,valueKey:o}=this.props,a=d.default.parse(t,!0);return a.query.term=e,(0,c.default)(d.default.format(a),{credentials:"same-origin"}).then((e=>e.json())).then((e=>e.items.map((e=>({[n]:e.Title,[o]:e.Value,Selected:e.Selected})))))}isValidNewOption(e,t,n){const{valueKey:o}=this.props;if(!e)return!1;if(Array.isArray(t)){if(this.valueInOptions(e,t,o))return!1}else if(e===t[o])return!1;return!this.valueInOptions(e,n,o)}valueInOptions(e,t,n){for(const o of t)if(e===o[n])return!0;return!1}render(){const{lazyLoad:e,options:t,creatable:n,multi:a,disabled:r,labelKey:i,valueKey:l,SelectComponent:c,AsyncCreatableSelectComponent:f,AsyncSelectComponent:d,CreatableSelectComponent:p,...h}=this.props,v=e?{loadOptions:this.getOptions}:{options:t};let y=c;if(e&&n?y=f:e?y=d:n&&(y=p),this.isControlled()||(h.value=this.state.value),!a&&h.value&&Object.keys(h.value).length>0){const e=h.value[Object.keys(h.value)[0]];"object"==typeof e&&(h.value=e)}return o.default.createElement(s.default,null,o.default.createElement(y,m({},h,{isMulti:a,isDisabled:r,cacheOptions:!0,onChange:this.handleChange},v,{getOptionLabel:e=>e[i],getOptionValue:e=>e[l],noOptionsMessage:e=>{let{inputValue:t}=e;return t?u.default._t("TagField.NO_OPTIONS","No options"):u.default._t("TagField.TYPE_TO_SEARCH","Type to search")},isValidNewOption:this.isValidNewOption,getNewOptionData:(e,t)=>({[i]:t,[l]:e}),classNamePrefix:"ss-tag-field"})))}}t.Component=O,O.propTypes={name:h.default.string.isRequired,labelKey:h.default.string.isRequired,valueKey:h.default.string.isRequired,lazyLoad:h.default.bool,creatable:h.default.bool,multi:h.default.bool,disabled:h.default.bool,options:h.default.arrayOf(h.default.object),optionUrl:h.default.string,value:h.default.any,onChange:h.default.func,onBlur:h.default.func,SelectComponent:h.default.oneOfType([h.default.object,h.default.func]),AsyncCreatableSelectComponent:h.default.oneOfType([h.default.object,h.default.func]),AsyncSelectComponent:h.default.oneOfType([h.default.object,h.default.func]),CreatableSelectComponent:h.default.oneOfType([h.default.object,h.default.func])},O.defaultProps={labelKey:"Title",valueKey:"Value",disabled:!1,lazyLoad:!1,creatable:!1,multi:!1,SelectComponent:a.default,AsyncCreatableSelectComponent:i.default,AsyncSelectComponent:r.default,CreatableSelectComponent:l.default};var g=(0,f.default)(O);t.default=g},265:function(e,t,n){var o,a=(o=n(363))&&o.__esModule?o:{default:o},r=n(691),i=n(648);function l(){return l=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var o in n)Object.prototype.hasOwnProperty.call(n,o)&&(e[o]=n[o])}return e},l.apply(this,arguments)}window.jQuery.entwine("ss",(e=>{e(".js-injector-boot .ss-tag-field.entwine").entwine({ReactRoot:null,onmatch(){const e=this.closest(".cms-content").attr("id"),t=e?{context:e}:{},n=(0,i.loadComponent)("TagField",t),o={...this.data("schema"),onBlur:()=>{this.parents(".cms-edit-form:first").trigger("change")}};let s=this.getReactRoot();s||(s=(0,r.createRoot)(this[0]),this.setReactRoot(s)),s.render(a.default.createElement(n,l({noHolder:!0},o)))},onunmatch(){const e=this.getReactRoot();e&&(e.unmount(),this.setReactRoot(null))}}),e(".cms-edit-form").entwine({getChangeTrackerOptions(){const t=void 0===this.entwineData("ChangeTrackerOptions");let n=this._super();return t&&(n=e.extend({},n),n.ignoreFieldSelector+=", .ss-tag-field .Select :input",this.setChangeTrackerOptions(n)),n}})}))},496:function(e){function t(e){return"function"==typeof e?e():e}function n(){var e={};return e.promise=new Promise((function(t,n){e.resolve=t,e.reject=n})),e}e.exports=function(e){var o=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,a=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},r=void 0,i=void 0,l=void 0,s=[];return function(){var c=t(o),f=(new Date).getTime(),d=!r||f-r>c;r=f;for(var p=arguments.length,h=Array(p),v=0;v<p;v++)h[v]=arguments[v];if(d&&a.leading)return a.accumulate?Promise.resolve(e.call(this,[h])).then((function(e){return e[0]})):Promise.resolve(e.call.apply(e,[this].concat(h)));if(i?clearTimeout(l):i=n(),s.push(h),l=setTimeout(u.bind(this),c),a.accumulate){var y=s.length-1;return i.promise.then((function(e){return e[y]}))}return i.promise};function u(){var t=i;clearTimeout(l),Promise.resolve(a.accumulate?e.call(this,s):e.apply(this,s[s.length-1])).then(t.resolve,t.reject),s=[],i=null}}},78:function(e){e.exports=EmotionCssCacheProvider},42:function(e){e.exports=FieldHolder},648:function(e){e.exports=Injector},875:function(e){e.exports=IsomorphicFetch},872:function(e){e.exports=NodeUrl},86:function(e){e.exports=PropTypes},363:function(e){e.exports=React},691:function(e){e.exports=ReactDomClient},967:function(e){e.exports=ReactSelect},493:function(e){e.exports=ReactSelectAsync},198:function(e){e.exports=ReactSelectAsyncCreatable},453:function(e){e.exports=ReactSelectCreatable},754:function(e){e.exports=i18n}},t={};function n(o){var a=t[o];if(void 0!==a)return a.exports;var r=t[o]={exports:{}};return e[o](r,r.exports,n),r.exports}n(265),n(274)}();
|
2
client/dist/styles/bundle.css
vendored
2
client/dist/styles/bundle.css
vendored
@ -1 +1 @@
|
||||
.ss-tag-field .Select--multi .Select-value{margin-top:3px}
|
||||
.ss-tag-field__multi-value{margin-top:3px}.ss-tag-field__control{border-color:#ced5e1;box-shadow:none}.ss-tag-field__control--is-focused{border-color:#29abe2;box-shadow:none}.ss-tag-field__option+.ss-tag-field__option{border-top:1px solid #dbe0e9}.ss-tag-field__option-button{border:1px solid #dbe0e9;border-radius:.23rem;background:#fff;width:auto !important;max-width:25%;margin:-4px -5px -4px 5px;padding:4px 5px 4px 4px;cursor:pointer}.ss-tag-field__option-button:hover{background:#ced5e1}.ss-tag-field__option-button .font-icon-right-open-big{margin:2px 0 0 -1px;width:24px}.ss-tag-field__option-count-icon{padding:0 .6154rem;line-height:.8}.ss-tag-field__option-context{color:#566b8d;font-size:.923rem}.ss-tag-field__option--is-focused{background-color:#f5f5f5}.ss-tag-field__option--is-selected{background:#0071c4;color:#fff}.ss-tag-field__option--is-selected .ss-tag-field__option-button{border-color:#29abe2;background:none;color:#fff}.ss-tag-field__option--is-selected .ss-tag-field__option-button:hover{background:rgba(0,0,0,.2)}.ss-tag-field__option-title--highlighted{font-weight:bold}.ss-tag-field__indicator{cursor:pointer}.ss-tag-field__clear-indicator:hover,.ss-tag-field__clear-indicator:focus{color:#d40404}.ss-tag-field__dropdown-indicator:hover,.ss-tag-field__dropdown-indicator:focus{color:#303b4d}.ss-tag-field__multi-value{color:#43536d;background-color:#fff;border:1px solid #66afe9;border-radius:.23rem}.ss-tag-field__multi-value__remove{font-size:1.231rem;padding:0 5px 2px;border-left:1px solid #66afe9;border-radius:0}.ss-tag-field__multi-value__remove:focus,.ss-tag-field__multi-value__remove:hover{background-color:rgba(0,113,230,.08);color:#0071e6}
|
||||
|
@ -1,2 +1,2 @@
|
||||
require('legacy/entwine/TagField');
|
||||
require('boot');
|
||||
import 'legacy/entwine/TagField';
|
||||
import 'boot';
|
||||
|
@ -1,5 +1,10 @@
|
||||
import React, { Component } from 'react';
|
||||
import Select from 'react-select';
|
||||
import AsyncSelect from 'react-select/async';
|
||||
import AsyncCreatableSelect from 'react-select/async-creatable';
|
||||
import CreatableSelect from 'react-select/creatable';
|
||||
import EmotionCssCacheProvider from 'containers/EmotionCssCacheProvider/EmotionCssCacheProvider';
|
||||
import i18n from 'i18n';
|
||||
import fetch from 'isomorphic-fetch';
|
||||
import fieldHolder from 'components/FieldHolder/FieldHolder';
|
||||
import url from 'url';
|
||||
@ -10,38 +15,19 @@ class TagField extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.selectComponentRef = null;
|
||||
|
||||
this.setSelectComponentRef = ref => {
|
||||
this.selectComponentRef = ref;
|
||||
};
|
||||
|
||||
this.state = {
|
||||
initalState: props.value ? props.value : [],
|
||||
hasChanges: false,
|
||||
};
|
||||
|
||||
if (!this.isControlled()) {
|
||||
this.state = {
|
||||
...this.state,
|
||||
value: props.value,
|
||||
};
|
||||
}
|
||||
|
||||
this.handleChange = this.handleChange.bind(this);
|
||||
this.handleOnBlur = this.handleOnBlur.bind(this);
|
||||
this.isValidNewOption = this.isValidNewOption.bind(this);
|
||||
this.getOptions = this.getOptions.bind(this);
|
||||
this.fetchOptions = debounce(this.fetchOptions, 500);
|
||||
}
|
||||
|
||||
componentDidUpdate(previousProps, previousState) {
|
||||
if (previousState.hasChanges !== this.state.hasChanges) {
|
||||
const element = this.selectComponentRef.select.wrapper;
|
||||
const event = new Event('change', { bubbles: true });
|
||||
element.dispatchEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the options that should be shown to the user for this tagfield, optionally filtering by the
|
||||
* given string input
|
||||
@ -53,13 +39,12 @@ class TagField extends Component {
|
||||
const { lazyLoad, options } = this.props;
|
||||
|
||||
if (!lazyLoad) {
|
||||
return Promise.resolve({ options });
|
||||
return Promise.resolve(options);
|
||||
}
|
||||
|
||||
if (!input) {
|
||||
return Promise.resolve({ options: [] });
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
|
||||
return this.fetchOptions(input);
|
||||
}
|
||||
|
||||
@ -70,16 +55,6 @@ class TagField extends Component {
|
||||
* @param {string} value
|
||||
*/
|
||||
handleChange(value) {
|
||||
this.setState({
|
||||
hasChanges: false
|
||||
});
|
||||
|
||||
if (JSON.stringify(this.state.initalState) !== JSON.stringify(value)) {
|
||||
this.setState({
|
||||
hasChanges: true
|
||||
});
|
||||
}
|
||||
|
||||
if (this.isControlled()) {
|
||||
this.props.onChange(value);
|
||||
return;
|
||||
@ -121,30 +96,87 @@ class TagField extends Component {
|
||||
|
||||
return fetch(url.format(fetchURL), { credentials: 'same-origin' })
|
||||
.then((response) => response.json())
|
||||
.then((json) => ({
|
||||
options: json.items.map((item) => ({
|
||||
.then((json) => json.items.map(
|
||||
(item) => ({
|
||||
[labelKey]: item.Title,
|
||||
[valueKey]: item.Value,
|
||||
Selected: item.Selected,
|
||||
})),
|
||||
}));
|
||||
})
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a new option can be created based on a given input
|
||||
* @param {string} inputValue
|
||||
* @param {array|object} value
|
||||
* @param {array} currentOptions
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isValidNewOption(inputValue, value, currentOptions) {
|
||||
const { valueKey } = this.props;
|
||||
|
||||
// Don't allow empty options
|
||||
if (!inputValue) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Don't repeat the currently selected option
|
||||
if (Array.isArray(value)) {
|
||||
if (this.valueInOptions(inputValue, value, valueKey)) {
|
||||
return false;
|
||||
}
|
||||
} else if (inputValue === value[valueKey]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Don't repeat any existing option
|
||||
return !this.valueInOptions(inputValue, currentOptions, valueKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a value is in an array of options already
|
||||
* @param {string} value
|
||||
* @param {array} options
|
||||
* @param {string} valueKey
|
||||
* @returns {boolean}
|
||||
*/
|
||||
valueInOptions(value, options, valueKey) {
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
for (const item of options) {
|
||||
if (value === item[valueKey]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { lazyLoad, options, creatable, ...passThroughAttributes } =
|
||||
this.props;
|
||||
const {
|
||||
lazyLoad,
|
||||
options,
|
||||
creatable,
|
||||
multi,
|
||||
disabled,
|
||||
labelKey,
|
||||
valueKey,
|
||||
SelectComponent,
|
||||
AsyncCreatableSelectComponent,
|
||||
AsyncSelectComponent,
|
||||
CreatableSelectComponent,
|
||||
...passThroughAttributes
|
||||
} = this.props;
|
||||
|
||||
const optionAttributes = lazyLoad
|
||||
? { loadOptions: this.getOptions }
|
||||
: { options };
|
||||
|
||||
let SelectComponent = Select;
|
||||
let DynamicSelect = SelectComponent;
|
||||
if (lazyLoad && creatable) {
|
||||
SelectComponent = Select.AsyncCreatable;
|
||||
DynamicSelect = AsyncCreatableSelectComponent;
|
||||
} else if (lazyLoad) {
|
||||
SelectComponent = Select.Async;
|
||||
DynamicSelect = AsyncSelectComponent;
|
||||
} else if (creatable) {
|
||||
SelectComponent = Select.Creatable;
|
||||
DynamicSelect = CreatableSelectComponent;
|
||||
}
|
||||
|
||||
// Update the value to passthrough with the kept state provided this component is not
|
||||
@ -154,7 +186,7 @@ class TagField extends Component {
|
||||
}
|
||||
|
||||
// if this is a single select then we just need the first value
|
||||
if (!passThroughAttributes.multi && passThroughAttributes.value) {
|
||||
if (!multi && passThroughAttributes.value) {
|
||||
if (Object.keys(passThroughAttributes.value).length > 0) {
|
||||
const value =
|
||||
passThroughAttributes.value[
|
||||
@ -167,17 +199,23 @@ class TagField extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
const changedClassName = this.state.hasChanges ? '' : 'no-change-track';
|
||||
|
||||
return (
|
||||
<SelectComponent
|
||||
{...passThroughAttributes}
|
||||
onChange={this.handleChange}
|
||||
onBlur={this.handleOnBlur}
|
||||
{...optionAttributes}
|
||||
className={changedClassName}
|
||||
ref={this.setSelectComponentRef}
|
||||
/>
|
||||
<EmotionCssCacheProvider>
|
||||
<DynamicSelect
|
||||
{...passThroughAttributes}
|
||||
isMulti={multi}
|
||||
isDisabled={disabled}
|
||||
cacheOptions
|
||||
onChange={this.handleChange}
|
||||
{...optionAttributes}
|
||||
getOptionLabel={(option) => option[labelKey]}
|
||||
getOptionValue={(option) => option[valueKey]}
|
||||
noOptionsMessage={({ inputValue }) => (inputValue ? i18n._t('TagField.NO_OPTIONS', 'No options') : i18n._t('TagField.TYPE_TO_SEARCH', 'Type to search'))}
|
||||
isValidNewOption={this.isValidNewOption}
|
||||
getNewOptionData={(inputValue, label) => ({ [labelKey]: label, [valueKey]: inputValue })}
|
||||
classNamePrefix="ss-tag-field"
|
||||
/>
|
||||
</EmotionCssCacheProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -195,6 +233,10 @@ TagField.propTypes = {
|
||||
value: PropTypes.any,
|
||||
onChange: PropTypes.func,
|
||||
onBlur: PropTypes.func,
|
||||
SelectComponent: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
|
||||
AsyncCreatableSelectComponent: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
|
||||
AsyncSelectComponent: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
|
||||
CreatableSelectComponent: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
|
||||
};
|
||||
|
||||
TagField.defaultProps = {
|
||||
@ -204,6 +246,10 @@ TagField.defaultProps = {
|
||||
lazyLoad: false,
|
||||
creatable: false,
|
||||
multi: false,
|
||||
SelectComponent: Select,
|
||||
AsyncCreatableSelectComponent: AsyncCreatableSelect,
|
||||
AsyncSelectComponent: AsyncSelect,
|
||||
CreatableSelectComponent: CreatableSelect,
|
||||
};
|
||||
|
||||
export { TagField as Component };
|
||||
|
@ -1,3 +1,110 @@
|
||||
.ss-tag-field .Select--multi .Select-value {
|
||||
.ss-tag-field__multi-value {
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
/* Styles below here are duplicates of the treedropdownfield styles in silverstripe/admin, but with the appropriate classnames for tagfield. */
|
||||
.ss-tag-field__control {
|
||||
border-color: $gray-200;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.ss-tag-field__control--is-focused {
|
||||
border-color: $brand-primary;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.ss-tag-field__option+.ss-tag-field__option {
|
||||
border-top: 1px solid $border-color-light;
|
||||
}
|
||||
|
||||
.ss-tag-field__option-button {
|
||||
border: 1px solid $border-color-light;
|
||||
border-radius: $border-radius;
|
||||
background: $white;
|
||||
// needed to override the width rule in .fill-width
|
||||
width: auto !important; // sass-lint:disable-line no-important
|
||||
max-width: 25%;
|
||||
margin: -4px -5px -4px 5px;
|
||||
padding: 4px 5px 4px 4px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background: $gray-200;
|
||||
}
|
||||
|
||||
.font-icon-right-open-big {
|
||||
margin: 2px 0 0 -1px;
|
||||
width: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.ss-tag-field__option-count-icon {
|
||||
padding: 0 ($spacer / 2);
|
||||
line-height: 0.8;
|
||||
}
|
||||
|
||||
.ss-tag-field__option-context {
|
||||
color: $gray-600;
|
||||
font-size: $font-size-sm;
|
||||
}
|
||||
|
||||
.ss-tag-field__option--is-focused {
|
||||
background-color: $list-group-hover-bg;
|
||||
}
|
||||
|
||||
.ss-tag-field__option--is-selected {
|
||||
background: $link-color;
|
||||
color: $white;
|
||||
|
||||
.ss-tag-field__option-button {
|
||||
border-color: $brand-primary;
|
||||
background: none;
|
||||
color: $white;
|
||||
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ss-tag-field__option-title--highlighted {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.ss-tag-field__indicator {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.ss-tag-field__clear-indicator {
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: $brand-danger;
|
||||
}
|
||||
}
|
||||
|
||||
.ss-tag-field__dropdown-indicator {
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: $body-color-dark;
|
||||
}
|
||||
}
|
||||
|
||||
.ss-tag-field__multi-value {
|
||||
color: $body-color;
|
||||
background-color: $white;
|
||||
border: 1px solid $input-focus-border-color;
|
||||
border-radius: $border-radius;
|
||||
}
|
||||
|
||||
.ss-tag-field__multi-value__remove {
|
||||
font-size: $font-size-lg;
|
||||
padding: 0 5px 2px;
|
||||
border-left: 1px solid $input-focus-border-color;
|
||||
border-radius: 0;
|
||||
|
||||
&:focus,
|
||||
&:hover {
|
||||
background-color: rgba(0, 113, 230, .08);
|
||||
color: #0071e6;
|
||||
}
|
||||
}
|
||||
|
@ -1,85 +1,64 @@
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
/* global jest, describe, beforeEach, it, expect, setTimeout, document */
|
||||
|
||||
jest.mock('isomorphic-fetch');
|
||||
/* global jest, test, describe, beforeEach, it, expect, setTimeout, document */
|
||||
|
||||
import React from 'react';
|
||||
import Enzyme, { shallow } from 'enzyme';
|
||||
import Adapter from 'enzyme-adapter-react-15.4';
|
||||
import { Component as TagField } from '../TagField';
|
||||
import Select from 'react-select';
|
||||
import fetch from 'isomorphic-fetch';
|
||||
import { render } from '@testing-library/react';
|
||||
|
||||
Enzyme.configure({ adapter: new Adapter() });
|
||||
function makeProps(obj = {}) {
|
||||
return {
|
||||
name: 'Test',
|
||||
labelKey: 'label',
|
||||
valueKey: 'value',
|
||||
lazyLoad: false,
|
||||
creatable: false,
|
||||
multi: true,
|
||||
SelectComponent: () => <div className="test-dynamic test-select" />,
|
||||
CreatableSelectComponent: () => <div className="test-dynamic test-creatable-select" />,
|
||||
AsyncSelectComponent: () => <div className="test-dynamic test-async-select" />,
|
||||
AsyncCreatableSelectComponent: () => <div className="test-dynamic test-async-creatable-select" />,
|
||||
...obj,
|
||||
};
|
||||
}
|
||||
|
||||
describe('TagField', () => {
|
||||
let props;
|
||||
|
||||
beforeEach(() => {
|
||||
props = {
|
||||
name: 'Test',
|
||||
labelKey: 'label',
|
||||
valueKey: 'value',
|
||||
lazyLoad: false,
|
||||
creatable: false,
|
||||
multi: true,
|
||||
};
|
||||
});
|
||||
|
||||
describe('should render a Select component with type', () => {
|
||||
it('Select', () => {
|
||||
const wrapper = shallow(
|
||||
<TagField {...props} />
|
||||
);
|
||||
expect(wrapper.find(Select).length).toBe(1);
|
||||
});
|
||||
it('Select.Creatable with creatable option', () => {
|
||||
props.creatable = true;
|
||||
const wrapper = shallow(
|
||||
<TagField {...props} />
|
||||
);
|
||||
expect(wrapper.find(Select.Creatable).length).toBe(1);
|
||||
});
|
||||
it('Select.Async with lazyLoad option', () => {
|
||||
props.lazyLoad = true;
|
||||
const wrapper = shallow(
|
||||
<TagField {...props} />
|
||||
);
|
||||
expect(wrapper.find(Select.Async).length).toBe(1);
|
||||
});
|
||||
it('Select.AsyncCreatable with both creatable and lazyLoad options', () => {
|
||||
props.creatable = true;
|
||||
props.lazyLoad = true;
|
||||
const wrapper = shallow(
|
||||
<TagField {...props} />
|
||||
);
|
||||
expect(wrapper.find(Select.AsyncCreatable).length).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with lazyLoad on and given a URL', () => {
|
||||
let wrapper;
|
||||
|
||||
beforeEach(() => {
|
||||
props.lazyLoad = true;
|
||||
props.optionUrl = 'localhost/some-fetch-url';
|
||||
|
||||
wrapper = shallow(
|
||||
<TagField {...props} />
|
||||
);
|
||||
|
||||
fetch.mockImplementation(() => Promise.resolve({
|
||||
json: () => ({}),
|
||||
}));
|
||||
});
|
||||
|
||||
it('should fetch the URL for results', done => {
|
||||
wrapper.instance().getOptions('a');
|
||||
|
||||
setTimeout(() => {
|
||||
expect(fetch).toBeCalledWith('localhost/some-fetch-url?term=a', expect.anything());
|
||||
done();
|
||||
}, 500);
|
||||
});
|
||||
});
|
||||
test('TagField should render a Select component by default', () => {
|
||||
const { container } = render(
|
||||
<TagField {...makeProps()}/>
|
||||
);
|
||||
expect(container.querySelectorAll('.test-dynamic')).toHaveLength(1);
|
||||
expect(container.querySelector('.test-select')).not.toBeNull();
|
||||
});
|
||||
|
||||
test('TagField should render a CreatableSelect with creatable option', () => {
|
||||
const { container } = render(
|
||||
<TagField {...makeProps({
|
||||
creatable: true
|
||||
})}
|
||||
/>
|
||||
);
|
||||
expect(container.querySelectorAll('.test-dynamic')).toHaveLength(1);
|
||||
expect(container.querySelector('.test-creatable-select')).not.toBeNull();
|
||||
});
|
||||
|
||||
test('Tagfiled should render an AsyncSelect with lazy load option', () => {
|
||||
const { container } = render(
|
||||
<TagField {...makeProps({
|
||||
lazyLoad: true
|
||||
})}
|
||||
/>
|
||||
);
|
||||
expect(container.querySelectorAll('.test-dynamic')).toHaveLength(1);
|
||||
expect(container.querySelector('.test-async-select')).not.toBeNull();
|
||||
});
|
||||
|
||||
test('Tagfiled should render a AsyncCreatableSelect with lazy load and creatable options', () => {
|
||||
const { container } = render(
|
||||
<TagField {...makeProps({
|
||||
lazyLoad: true,
|
||||
creatable: true
|
||||
})}
|
||||
/>
|
||||
);
|
||||
expect(container.querySelectorAll('.test-dynamic')).toHaveLength(1);
|
||||
expect(container.querySelector('.test-async-creatable-select')).not.toBeNull();
|
||||
});
|
||||
|
@ -1,10 +1,12 @@
|
||||
/* global window */
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import { loadComponent } from 'lib/Injector';
|
||||
|
||||
window.jQuery.entwine('ss', ($) => {
|
||||
$('.js-injector-boot .ss-tag-field.entwine').entwine({
|
||||
ReactRoot: null,
|
||||
|
||||
onmatch() {
|
||||
const cmsContent = this.closest('.cms-content').attr('id');
|
||||
const context = (cmsContent)
|
||||
@ -18,17 +20,25 @@ window.jQuery.entwine('ss', ($) => {
|
||||
}
|
||||
};
|
||||
|
||||
ReactDOM.render(
|
||||
let root = this.getReactRoot();
|
||||
if (!root) {
|
||||
root = createRoot(this[0]);
|
||||
this.setReactRoot(root);
|
||||
}
|
||||
root.render(
|
||||
<TagField
|
||||
noHolder
|
||||
{...dataSchema}
|
||||
/>,
|
||||
this[0]
|
||||
/>
|
||||
);
|
||||
},
|
||||
|
||||
onunmatch() {
|
||||
ReactDOM.unmountComponentAtNode(this[0]);
|
||||
const root = this.getReactRoot();
|
||||
if (root) {
|
||||
root.unmount();
|
||||
this.setReactRoot(null);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -44,7 +54,7 @@ window.jQuery.entwine('ss', ($) => {
|
||||
// clone the object (so we don't modify the original),
|
||||
opts = $.extend({}, opts);
|
||||
// modify it,
|
||||
opts.ignoreFieldSelector += ', .ss-tag-field .no-change-track :input';
|
||||
opts.ignoreFieldSelector += ', .ss-tag-field .Select :input';
|
||||
// then set the clone as the value on this element
|
||||
// (so next call to this method gets this same clone)
|
||||
this.setChangeTrackerOptions(opts);
|
||||
|
@ -19,13 +19,13 @@
|
||||
"issues": "http://github.com/silverstripe/silverstripe-tagfield/issues"
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.4 || ^8.0",
|
||||
"silverstripe/framework": "^4.13",
|
||||
"silverstripe/versioned": "^1.3"
|
||||
"php": "^8.1",
|
||||
"silverstripe/framework": "^5",
|
||||
"silverstripe/versioned": "^2"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.5",
|
||||
"squizlabs/php_codesniffer": "^3.0"
|
||||
"squizlabs/php_codesniffer": "^3"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
68
package.json
68
package.json
@ -1,8 +1,6 @@
|
||||
{
|
||||
"name": "silverstripe-tagfield",
|
||||
"version": "2.2.0",
|
||||
"description": "Tag field for SilverStripe",
|
||||
"main": "./client/src/boot/index.js",
|
||||
"license": "BSD-3-Clause",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -14,10 +12,10 @@
|
||||
},
|
||||
"author": "SilverStripe Ltd.",
|
||||
"engines": {
|
||||
"node": ">=6.x"
|
||||
"node": "^18.x"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "yarn && yarn lint && yarn test && NODE_ENV=production webpack -p --bail --progress",
|
||||
"build": "yarn && yarn lint && yarn test && rm -rf client/dist/* && NODE_ENV=production webpack --mode production --bail --progress",
|
||||
"dev": "NODE_ENV=development webpack --progress",
|
||||
"watch": "NODE_ENV=development webpack --watch --progress",
|
||||
"css": "WEBPACK_CHILD=css npm run build",
|
||||
@ -29,7 +27,35 @@
|
||||
"lint-js-fix": "eslint client/src --fix",
|
||||
"lint-sass": "sass-lint client/src"
|
||||
},
|
||||
"dependencies": {
|
||||
"classnames": "^2.3.2",
|
||||
"debounce-promise": "^3.1.2",
|
||||
"isomorphic-fetch": "^3.0.0",
|
||||
"prop-types": "^15.8.1",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"url": "^0.11.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@silverstripe/eslint-config": "^1.0.0",
|
||||
"@silverstripe/webpack-config": "^2.0.0",
|
||||
"@testing-library/react": "^14.0.0",
|
||||
"babel-jest": "^29.2.2",
|
||||
"copy-webpack-plugin": "^11.0.0",
|
||||
"html-loader": "^4.2.0",
|
||||
"jest-cli": "^29.2.2",
|
||||
"jest-environment-jsdom": "^29.3.1",
|
||||
"webpack": "^5.74.0",
|
||||
"webpack-cli": "^5.0.0"
|
||||
},
|
||||
"resolutions": {
|
||||
"colors": "1.4.0"
|
||||
},
|
||||
"browserslist": [
|
||||
"defaults"
|
||||
],
|
||||
"jest": {
|
||||
"testEnvironment": "jsdom",
|
||||
"roots": [
|
||||
"client/src"
|
||||
],
|
||||
@ -46,39 +72,5 @@
|
||||
"transform": {
|
||||
".*": "babel-jest"
|
||||
}
|
||||
},
|
||||
"babel": {
|
||||
"presets": [
|
||||
"env",
|
||||
"react"
|
||||
],
|
||||
"plugins": [
|
||||
"transform-object-rest-spread"
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@silverstripe/eslint-config": "^0.0.6",
|
||||
"@silverstripe/webpack-config": "^0.10.0",
|
||||
"@storybook/react": "^3.2.19",
|
||||
"babel-jest": "^23.6.0",
|
||||
"copy-webpack-plugin": "^4.2.0",
|
||||
"enzyme": "^3.3.0",
|
||||
"enzyme-adapter-react-15.4": "^1.0.5",
|
||||
"html-loader": "^0.5.1",
|
||||
"jest-cli": "^23.6.0",
|
||||
"react-addons-test-utils": "15.3.1",
|
||||
"webpack": "^2"
|
||||
},
|
||||
"dependencies": {
|
||||
"babel-polyfill": "6.7.4",
|
||||
"classnames": "^2.2.5",
|
||||
"debounce-promise": "^3.1.0",
|
||||
"isomorphic-fetch": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz",
|
||||
"jquery": "^3.5.0",
|
||||
"prop-types": "^15.7.2",
|
||||
"react": "15.3.1",
|
||||
"react-dom": "15.3.1",
|
||||
"react-select": "^1.2.1",
|
||||
"url": "^0.11.0"
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ use Iterator;
|
||||
use SilverStripe\Control\Controller;
|
||||
use SilverStripe\Control\HTTPRequest;
|
||||
use SilverStripe\Control\HTTPResponse;
|
||||
use SilverStripe\Dev\Deprecation;
|
||||
use SilverStripe\Forms\DropdownField;
|
||||
use SilverStripe\Forms\Validator;
|
||||
use SilverStripe\ORM\ArrayList;
|
||||
@ -34,13 +33,6 @@ class StringTagField extends DropdownField
|
||||
'suggest',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var bool Triggers a write call within the saveInto function if enabled
|
||||
*
|
||||
* @deprecated 3.0.0 Will be removed without equivalent functionality to replace it
|
||||
*/
|
||||
private static $immediate_write_enabled = true;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
@ -66,7 +58,6 @@ class StringTagField extends DropdownField
|
||||
*/
|
||||
protected $isMultiple = true;
|
||||
|
||||
/** @skipUpgrade */
|
||||
protected $schemaComponent = 'TagField';
|
||||
|
||||
/**
|
||||
@ -281,13 +272,6 @@ class StringTagField extends DropdownField
|
||||
$name = $this->getName();
|
||||
|
||||
$record->$name = $this->dataValue();
|
||||
|
||||
$immediate_write_enabled = Deprecation::withNoReplacement(function () {
|
||||
return self::config()->get('immediate_write_enabled');
|
||||
});
|
||||
if ($immediate_write_enabled) {
|
||||
$record->write();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -395,7 +379,7 @@ class StringTagField extends DropdownField
|
||||
*/
|
||||
public function validate($validator)
|
||||
{
|
||||
return true;
|
||||
return $this->extendValidationResult(true, $validator);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -63,7 +63,6 @@ class TagField extends MultiSelectField
|
||||
*/
|
||||
protected $isMultiple = true;
|
||||
|
||||
/** @skipUpgrade */
|
||||
protected $schemaComponent = 'TagField';
|
||||
|
||||
/**
|
||||
@ -497,7 +496,7 @@ class TagField extends MultiSelectField
|
||||
}
|
||||
|
||||
// Create new instance if not yet saved
|
||||
if ($this->getCanCreate()) {
|
||||
if ($this->getCanCreate() && $value) {
|
||||
$dataClass = $source->dataClass();
|
||||
$record = Injector::inst()->create($dataClass);
|
||||
$record->{$titleField} = $value;
|
||||
@ -573,7 +572,7 @@ class TagField extends MultiSelectField
|
||||
*/
|
||||
public function validate($validator)
|
||||
{
|
||||
return true;
|
||||
return $this->extendValidationResult(true, $validator);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -8,7 +8,6 @@ use SilverStripe\Forms\FieldList;
|
||||
use SilverStripe\Forms\Form;
|
||||
use SilverStripe\TagField\StringTagField;
|
||||
use SilverStripe\TagField\Tests\Stub\StringTagFieldTestBlogPost;
|
||||
use SilverStripe\Dev\Deprecation;
|
||||
|
||||
class StringTagFieldTest extends SapphireTest
|
||||
{
|
||||
@ -62,44 +61,6 @@ class StringTagFieldTest extends SapphireTest
|
||||
$this->assertEquals('Tag1,Tag2', $record->Tags);
|
||||
}
|
||||
|
||||
public function testImmediateWriteEnabled()
|
||||
{
|
||||
if (Deprecation::isEnabled()) {
|
||||
$this->markTestSkipped('Test calls deprecated code');
|
||||
}
|
||||
$record = $this->getNewStringTagFieldTestBlogPost('BlogPost1');
|
||||
$record->write();
|
||||
|
||||
StringTagField::config()->set('immediate_write_enabled', true);
|
||||
|
||||
$field = new StringTagField('Tags');
|
||||
$field->setValue(['Tag1', 'Tag2']);
|
||||
$field->saveInto($record);
|
||||
|
||||
$this->assertEquals('Tag1,Tag2', StringTagFieldTestBlogPost::get()->byID($record->ID)->Tags);
|
||||
}
|
||||
|
||||
public function testImmediateWriteDisabled()
|
||||
{
|
||||
if (Deprecation::isEnabled()) {
|
||||
$this->markTestSkipped('Test calls deprecated code');
|
||||
}
|
||||
$record = $this->getNewStringTagFieldTestBlogPost('BlogPost1');
|
||||
$record->write();
|
||||
|
||||
StringTagField::config()->set('immediate_write_enabled', false);
|
||||
|
||||
$field = new StringTagField('Tags');
|
||||
$field->setValue(['Tag1', 'Tag2']);
|
||||
$field->saveInto($record);
|
||||
|
||||
$this->assertNull(StringTagFieldTestBlogPost::get()->byID($record->ID)->Tags);
|
||||
|
||||
$record->write();
|
||||
|
||||
$this->assertEquals('Tag1,Tag2', StringTagFieldTestBlogPost::get()->byID($record->ID)->Tags);
|
||||
}
|
||||
|
||||
public function testItSuggestsTags()
|
||||
{
|
||||
$field = new StringTagField('SomeField', 'Some field', ['Tag1', 'Tag2'], []);
|
||||
|
@ -1,60 +1,31 @@
|
||||
const Path = require('path');
|
||||
const webpackConfig = require('@silverstripe/webpack-config');
|
||||
const {
|
||||
resolveJS,
|
||||
externalJS,
|
||||
moduleJS,
|
||||
pluginJS,
|
||||
moduleCSS,
|
||||
pluginCSS,
|
||||
} = webpackConfig;
|
||||
const { JavascriptWebpackConfig, CssWebpackConfig } = require('@silverstripe/webpack-config');
|
||||
|
||||
const ENV = process.env.NODE_ENV;
|
||||
const PATHS = {
|
||||
MODULES: 'node_modules',
|
||||
FILES_PATH: '../',
|
||||
ROOT: Path.resolve(),
|
||||
SRC: Path.resolve('client/src'),
|
||||
DIST: Path.resolve('client/dist'),
|
||||
};
|
||||
|
||||
const externals = externalJS(ENV, PATHS);
|
||||
delete externals.reactstrap;
|
||||
|
||||
const config = [
|
||||
{
|
||||
name: 'js',
|
||||
entry: {
|
||||
// Main JS bundle
|
||||
new JavascriptWebpackConfig('js', PATHS, 'silverstripe/tagfield')
|
||||
.setEntry({
|
||||
bundle: `${PATHS.SRC}/bundles/bundle.js`,
|
||||
},
|
||||
output: {
|
||||
path: PATHS.DIST,
|
||||
filename: 'js/[name].js',
|
||||
},
|
||||
devtool: (ENV !== 'production') ? 'source-map' : '',
|
||||
resolve: resolveJS(ENV, PATHS),
|
||||
externals,
|
||||
module: moduleJS(ENV, PATHS),
|
||||
plugins: pluginJS(ENV, PATHS),
|
||||
},
|
||||
{
|
||||
name: 'css',
|
||||
entry: {
|
||||
})
|
||||
.getConfig(),
|
||||
// sass to css
|
||||
new CssWebpackConfig('css', PATHS)
|
||||
.setEntry({
|
||||
bundle: `${PATHS.SRC}/styles/bundle.scss`,
|
||||
},
|
||||
output: {
|
||||
path: PATHS.DIST,
|
||||
filename: 'styles/[name].css',
|
||||
},
|
||||
devtool: (ENV !== 'production') ? 'source-map' : '',
|
||||
module: moduleCSS(ENV, PATHS),
|
||||
plugins: pluginCSS(ENV, PATHS),
|
||||
},
|
||||
})
|
||||
.getConfig(),
|
||||
];
|
||||
|
||||
// Use WEBPACK_CHILD=js or WEBPACK_CHILD=css env var to run a single config
|
||||
module.exports = (process.env.WEBPACK_CHILD)
|
||||
? config.find((entry) => entry.name === process.env.WEBPACK_CHILD)
|
||||
: module.exports = config;
|
||||
: config;
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user