├── .gitignore ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── composer.json ├── dist ├── css │ └── field.css └── js │ └── field.js ├── mix-manifest.json ├── package.json ├── phpunit.xml.dist ├── resources ├── js │ ├── components │ │ ├── DetailField.vue │ │ ├── FormField.vue │ │ ├── IndexField.vue │ │ └── list-items │ │ │ ├── CheckedItem.vue │ │ │ └── UncheckedItem.vue │ ├── field.js │ └── mixins │ │ └── CheckboxDisplay.js └── sass │ └── field.scss ├── screenshot-detail.png ├── screenshot-form.png ├── screenshot-index.png ├── src ├── Checkboxes.php └── FieldServiceProvider.php ├── tests ├── TestCase.php └── Unit │ ├── CheckboxesFieldTest.php │ ├── CheckedOptionsForVueFormFieldTest.php │ └── SaveFormatsTest.php └── webpack.mix.js /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | /vendor 3 | /node_modules 4 | package-lock.json 5 | composer.phar 6 | composer.lock 7 | phpunit.xml 8 | .phpunit.result.cache 9 | .DS_Store 10 | Thumbs.db 11 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fourstacks/nova-checkboxes/73de263bfb500e5ab9159dba120818995f4605dc/CHANGELOG.md -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Four Stacks Ltd 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | *NOTE* 2 | 3 | There is now a native field in Nova called Boolean Group that replicates this field when using the `saveUncheckedValues` option. It is recommended that if you are using this package with that option enabled that you switch to the native Nova field as this package is only sporadically maintained. 4 | 5 | --- 6 | 7 | 8 | # A checkbox field for Nova apps 9 | 10 | This package contains a Laravel Nova field to add an array of checkboxes to your Nova resource forms and display the input from these fields. 11 | 12 | 13 | ## Installation 14 | 15 | You can install this package in to a Laravel app that uses [Nova](https://nova.laravel.com) via composer: 16 | 17 | ```bash 18 | composer require fourstacks/nova-checkboxes 19 | ``` 20 | ## Examples 21 | 22 | ![Nova checkboxes on Nova index view (with displayUncheckedValuesOnIndex option)](https://raw.githubusercontent.com/fourstacks/nova-checkboxes/master/screenshot-index.png) 23 | Nova checkboxes on Nova index view (with `displayUncheckedValuesOnIndex` option) 24 | 25 | ![Nova checkboxes on Nova detail view](https://raw.githubusercontent.com/fourstacks/nova-checkboxes/master/screenshot-detail.png) 26 | Nova checkboxes on Nova detail view 27 | 28 | ![Nova checkboxes on Nova form view](https://raw.githubusercontent.com/fourstacks/nova-checkboxes/master/screenshot-form.png) 29 | Nova checkboxes on Nova form 30 | 31 | 32 | ## Usage 33 | 34 | To add a checkbox field, use the `Fourstacks\NovaCheckboxes\Checkboxes` field in your Nova resource: 35 | 36 | ```php 37 | namespace App\Nova; 38 | 39 | use Fourstacks\NovaCheckboxes\Checkboxes; 40 | 41 | // ... 42 | 43 | class Member extends Resource 44 | { 45 | // ... 46 | 47 | public function fields(Request $request) 48 | { 49 | return [ 50 | // ... 51 | 52 | Checkboxes::make('Hobbies'), 53 | 54 | // ... 55 | ]; 56 | } 57 | } 58 | ``` 59 | If you wish to use this package in it's default configuration then you should also ensure the Eloquent model that your Nova resource represents is casting the attribute you wish to use a checkbox field for, to an array: 60 | 61 | ```php 62 | namespace App; 63 | 64 | // ... 65 | 66 | class Member extends Model 67 | { 68 | protected $casts = [ 69 | 'hobbies' => 'array' 70 | ] 71 | } 72 | ``` 73 | The exception to this is if you choose to use the `saveAsString` option (see configuration below), in which case you should make sure that you are not casting this attribute to an array. 74 | 75 | ## Configuration 76 | 77 | This package comes with various options that you can use to customise how the values from checkbox fields are saved and displayed: 78 | 79 | #### options 80 | 81 | Parameters: `array` 82 | 83 | Every checkbox field you create should contain `options`. These control the checkboxes that appear on your form and are comprised of a label and an underlying value: 84 | 85 | ```php 86 | 87 | Checkboxes::make('Hobbies') 88 | ->options([ 89 | 'sailing' => 'Sailing', 90 | 'rock_climbing' => 'Rock Climbing', 91 | 'archery' => 'Archery' 92 | ]) 93 | 94 | ``` 95 | 96 | #### saveAsString 97 | 98 | By default, this package will save checked items from this field to an array, in the attributes column in your database: 99 | 100 | `[sailing,rock_climbing]` 101 | 102 | This requires that you have set the `$casts` property on your eloquent model to an array (see Usage). 103 | 104 | However if you wish you can instead save checked items as a simple comma separated string: 105 | 106 | `sailing,rock_climbing` 107 | 108 | Use the following option to achieve this: 109 | 110 | ```php 111 | 112 | Checkboxes::make('Hobbies') 113 | ->options([ 114 | 'sailing' => 'Sailing', 115 | 'rock_climbing' => 'Rock Climbing', 116 | 'archery' => 'Archery' 117 | ]) 118 | ->saveAsString() 119 | 120 | ``` 121 | 122 | #### saveUncheckedValues 123 | 124 | By default, this field will only save checked items to the database. However if you wish to save all options that you have set along with whether they are checked or not you can do so by adding this option: 125 | 126 | ```php 127 | 128 | Checkboxes::make('Hobbies') 129 | ->options([ 130 | 'sailing' => 'Sailing', 131 | 'rock_climbing' => 'Rock Climbing', 132 | 'archery' => 'Archery' 133 | ]) 134 | ->saveUncheckedValues() 135 | 136 | ``` 137 | 138 | This will save results to your database as an object: 139 | 140 | `{sailing:true,rock_climbing:false,archery:true}` 141 | 142 | Note that in order to use this option you cannot also use the `saveAsString` option - it's one or the other. Also you must ensure that you have set the `$casts` property on your eloquent model to an array (see Usage). 143 | 144 | #### displayUncheckedValuesOnIndex 145 | 146 | By default, only the checked options will display on the index. If you wish to display all the options for this field along with their checked/unchecked status you can add this option: 147 | 148 | ```php 149 | Checkboxes::make('Hobbies') 150 | ->options([ 151 | 'sailing' => 'Sailing', 152 | 'rock_climbing' => 'Rock Climbing', 153 | 'archery' => 'Archery' 154 | ]) 155 | ->displayUncheckedValuesOnIndex() 156 | ``` 157 | Note that this does NOT require you to save all unchecked values also using `saveUncheckedValues`. You can use any of the approaches to saving data along with this option. 158 | 159 | #### displayUncheckedValuesOnDetail 160 | 161 | By default, only the checked options will display on detail screens. If you wish to display all the options for this field along with their checked/unchecked status you can add this option: 162 | 163 | ```php 164 | Checkboxes::make('Hobbies') 165 | ->options([ 166 | 'sailing' => 'Sailing', 167 | 'rock_climbing' => 'Rock Climbing', 168 | 'archery' => 'Archery' 169 | ]) 170 | ->displayUncheckedValuesOnDetail() 171 | ``` 172 | Note that this does NOT require you to save all unchecked values also using `saveUncheckedValues`. You can use any of the approaches to saving data along with this option. 173 | 174 | #### Display checkbox in columns 175 | 176 | By default, only checked values are displayed in one column, but if you have enough space you can split them in many using the `columns` method on the field. 177 | 178 | ```php 179 | Checkboxes::make('Hobbies') 180 | ->options([ 181 | 'sailing' => 'Sailing', 182 | 'rock_climbing' => 'Rock Climbing', 183 | 'archery' => 'Archery' 184 | ]) 185 | ->columns(3) 186 | ``` 187 | This will render at most 3 columns with values. So if you have 8 values selected you will see 3 columns with 3, 3 and 2 values. 188 | 189 | ### Changelog 190 | 191 | Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently. 192 | 193 | 194 | ## Credits 195 | 196 | - [John Wyles](https://github.com/fourstacks) 197 | 198 | ## License 199 | 200 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 201 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fourstacks/nova-checkboxes", 3 | "description": "A Laravel Nova field.", 4 | "keywords": [ 5 | "laravel", 6 | "nova" 7 | ], 8 | "license": "MIT", 9 | "repositories": [ 10 | { 11 | "type": "composer", 12 | "url": "https://nova.laravel.com" 13 | } 14 | ], 15 | "require": { 16 | "php": ">=7.1.0" 17 | }, 18 | "require-dev": { 19 | "laravel/nova": "^1.0", 20 | "orchestra/testbench": "3.7.*", 21 | "phpunit/phpunit": "^7.0" 22 | }, 23 | "autoload": { 24 | "psr-4": { 25 | "Fourstacks\\NovaCheckboxes\\": "src/" 26 | } 27 | }, 28 | "autoload-dev": { 29 | "psr-4": { 30 | "Fourstacks\\NovaCheckboxes\\Tests\\": "tests/" 31 | } 32 | }, 33 | "extra": { 34 | "laravel": { 35 | "providers": [ 36 | "Fourstacks\\NovaCheckboxes\\FieldServiceProvider" 37 | ] 38 | } 39 | }, 40 | "config": { 41 | "sort-packages": true 42 | }, 43 | "minimum-stability": "dev", 44 | "prefer-stable": true 45 | } 46 | -------------------------------------------------------------------------------- /dist/css/field.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fourstacks/nova-checkboxes/73de263bfb500e5ab9159dba120818995f4605dc/dist/css/field.css -------------------------------------------------------------------------------- /dist/js/field.js: -------------------------------------------------------------------------------- 1 | !function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{configurable:!1,enumerable:!0,get:n})},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=2)}([function(e,t){e.exports=function(e,t,r,n,o,i){var u,s=e=e||{},a=typeof e.default;"object"!==a&&"function"!==a||(u=e,s=e.default);var c,f="function"==typeof s?s.options:s;if(t&&(f.render=t.render,f.staticRenderFns=t.staticRenderFns,f._compiled=!0),r&&(f.functional=!0),o&&(f._scopeId=o),i?(c=function(e){(e=e||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext)||"undefined"==typeof __VUE_SSR_CONTEXT__||(e=__VUE_SSR_CONTEXT__),n&&n.call(this,e),e&&e._registeredComponents&&e._registeredComponents.add(i)},f._ssrRegister=c):n&&(c=n),c){var l=f.functional,p=l?f.render:f.beforeCreate;l?(f._injectStyles=c,f.render=function(e,t){return c.call(t),p(e,t)}):f.beforeCreate=p?[].concat(p,c):[c]}return{esModule:u,exports:s,options:f}}},function(e,t,r){"use strict";var n=r(6),o=r.n(n),i=r(9),u=r.n(i);t.a={components:{CheckedItem:o.a,UncheckedItem:u.a},data:function(){return{value:[]}},methods:{getItemType:function(e){return e.status?"checked-item":"unchecked-item"},getAllOptions:function(){var e=this;return this.field.options.map(function(t){return{status:e.value[t.value],key:t.value,label:t.label}}).sort(function(e,t){return t.status-e.status})},getCheckedOptions:function(){var e=this;return this.field.options.filter(function(t){return e.value[t.value]}).map(function(e){return{status:!0,key:e.value,label:e.label}})}},mounted:function(){this.value=JSON.parse(this.field.value)||{}}}},function(e,t,r){r(3),e.exports=r(20)},function(e,t,r){Nova.booting(function(e,t){e.component("index-nova-checkboxes",r(4)),e.component("detail-nova-checkboxes",r(13)),e.component("form-nova-checkboxes",r(16))})},function(e,t,r){var n=r(0)(r(5),r(12),!1,null,null,null);e.exports=n.exports},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=r(1);t.default={mixins:[n.a],props:["resourceName","field"],computed:{optionList:function(){return this.field.display_unchecked_on_index?this.getAllOptions():this.getCheckedOptions()}}}},function(e,t,r){var n=r(0)(r(7),r(8),!1,null,null,null);e.exports=n.exports},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default={props:["option"]}},function(e,t){e.exports={render:function(){var e=this.$createElement,t=this._self._c||e;return t("li",{staticClass:"flex items-center mb-2"},[t("span",{staticClass:"text-success inline-block mr-4"},[t("svg",{staticClass:"block fill-current h-4 w-4",attrs:{version:"1.1",xmlns:"http://www.w3.org/2000/svg",width:"28",height:"28",viewBox:"0 0 28 28"}},[t("title",[this._v("check")]),this._v(" "),t("path",{attrs:{d:"M26.109 8.844c0 0.391-0.156 0.781-0.438 1.062l-13.438 13.438c-0.281 0.281-0.672 0.438-1.062 0.438s-0.781-0.156-1.062-0.438l-7.781-7.781c-0.281-0.281-0.438-0.672-0.438-1.062s0.156-0.781 0.438-1.062l2.125-2.125c0.281-0.281 0.672-0.438 1.062-0.438s0.781 0.156 1.062 0.438l4.594 4.609 10.25-10.266c0.281-0.281 0.672-0.438 1.062-0.438s0.781 0.156 1.062 0.438l2.125 2.125c0.281 0.281 0.438 0.672 0.438 1.062z"}})])]),this._v("\n "+this._s(this.option.label)+"\n")])},staticRenderFns:[]}},function(e,t,r){var n=r(0)(r(10),r(11),!1,null,null,null);e.exports=n.exports},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default={props:["option"]}},function(e,t){e.exports={render:function(){var e=this.$createElement,t=this._self._c||e;return t("li",{staticClass:"flex items-center mb-2"},[t("span",{staticClass:"text-danger inline-block mr-4"},[t("svg",{staticClass:"block fill-current h-4 w-4",attrs:{version:"1.1",xmlns:"http://www.w3.org/2000/svg",width:"22",height:"28",viewBox:"0 0 22 28"}},[t("title",[this._v("close")]),this._v(" "),t("path",{attrs:{d:"M20.281 20.656c0 0.391-0.156 0.781-0.438 1.062l-2.125 2.125c-0.281 0.281-0.672 0.438-1.062 0.438s-0.781-0.156-1.062-0.438l-4.594-4.594-4.594 4.594c-0.281 0.281-0.672 0.438-1.062 0.438s-0.781-0.156-1.062-0.438l-2.125-2.125c-0.281-0.281-0.438-0.672-0.438-1.062s0.156-0.781 0.438-1.062l4.594-4.594-4.594-4.594c-0.281-0.281-0.438-0.672-0.438-1.062s0.156-0.781 0.438-1.062l2.125-2.125c0.281-0.281 0.672-0.438 1.062-0.438s0.781 0.156 1.062 0.438l4.594 4.594 4.594-4.594c0.281-0.281 0.672-0.438 1.062-0.438s0.781 0.156 1.062 0.438l2.125 2.125c0.281 0.281 0.438 0.672 0.438 1.062s-0.156 0.781-0.438 1.062l-4.594 4.594 4.594 4.594c0.281 0.281 0.438 0.672 0.438 1.062z"}})])]),this._v("\n "+this._s(this.option.label)+"\n")])},staticRenderFns:[]}},function(e,t){e.exports={render:function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("ul",{staticClass:"list-reset pt-2"},e._l(e.optionList,function(t){return r(e.getItemType(t),{key:t.key,tag:"component",attrs:{option:t}})}),1)},staticRenderFns:[]}},function(e,t,r){var n=r(0)(r(14),r(15),!1,null,null,null);e.exports=n.exports},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=r(1);t.default={mixins:[n.a],props:["resource","resourceName","resourceId","field"],data:function(){return{columns:this.field.columns||1}},computed:{width:function(){return 1==this.columns?"w-full":"w-1/"+this.columns},chunkedOptions:function(){var e=this;return this.optionList.reduce(function(t,r,n){return t[n%=e.columns]||(t[n]=[]),t[n].push(r),t},[])},optionList:function(){return this.field.display_unchecked_on_detail?this.getAllOptions():this.getCheckedOptions()}}}},function(e,t){e.exports={render:function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("panel-item",{attrs:{field:e.field}},[r("div",{staticClass:"flex",attrs:{slot:"value"},slot:"value"},e._l(e.chunkedOptions,function(t){return r("ul",{class:["list-reset","items-top",e.width]},e._l(t,function(t){return r(e.getItemType(t),{key:t.key,tag:"component",attrs:{option:t}})}),1)}),0)])},staticRenderFns:[]}},function(e,t,r){var n=r(0)(r(17),r(19),!1,null,null,null);e.exports=n.exports},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=r(18),o=(r.n(n),Object.assign||function(e){for(var t=1;t=200&&e<300}};a.headers={common:{Accept:"application/json, text/plain, */*"}},n.forEach(["delete","get","head"],function(e){a.headers[e]={}}),n.forEach(["post","put","patch"],function(e){a.headers[e]=n.merge(i)}),e.exports=a}).call(t,r(75))},function(e,t,r){"use strict";t.__esModule=!0;var n,o=r(113),i=(n=o)&&n.__esModule?n:{default:n};t.default=function(e,t,r){return t in e?(0,i.default)(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}},function(e,t){e.exports=function(e){if(void 0==e)throw TypeError("Can't call method on "+e);return e}},function(e,t,r){var n=r(9),o=r(1).document,i=n(o)&&n(o.createElement);e.exports=function(e){return i?o.createElement(e):{}}},function(e,t){e.exports=function(e){try{return!!e()}catch(e){return!0}}},function(e,t){e.exports=!0},function(e,t,r){"use strict";var n=r(14);e.exports.f=function(e){return new function(e){var t,r;this.promise=new e(function(e,n){if(void 0!==t||void 0!==r)throw TypeError("Bad Promise constructor");t=e,r=n}),this.resolve=n(t),this.reject=n(r)}(e)}},function(e,t,r){var n=r(11).f,o=r(17),i=r(2)("toStringTag");e.exports=function(e,t,r){e&&!o(e=r?e:e.prototype,i)&&n(e,i,{configurable:!0,value:t})}},function(e,t,r){var n=r(60)("keys"),o=r(65);e.exports=function(e){return n[e]||(n[e]=o(e))}},function(e,t){var r=Math.ceil,n=Math.floor;e.exports=function(e){return isNaN(e=+e)?0:(e>0?n:r)(e)}},function(e,t,r){var n=r(54),o=r(27);e.exports=function(e){return n(o(e))}},function(e,t,r){var n=r(12).Symbol;e.exports=n},function(e,t,r){var n=r(170),o=r(189);e.exports=function(e,t){var r=o(e,t);return n(r)?r:void 0}},function(e,t){e.exports=function(e,t){return e===t||e!=e&&t!=t}},function(e,t){e.exports=function(e){return e}},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=["1/2","1/3","2/3","1/4","3/4","1/5","2/5","3/5","4/5","1/6","5/6"]},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=r(154);Object.defineProperty(t,"default",{enumerable:!0,get:function(){return i(n).default}}),Object.defineProperty(t,"Form",{enumerable:!0,get:function(){return i(n).default}});var o=r(66);function i(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"Errors",{enumerable:!0,get:function(){return i(o).default}})},function(e,t,r){"use strict";(function(t){var n=r(0),o=r(101),i=r(104),u=r(110),s=r(108),a=r(45),c="undefined"!=typeof window&&window.btoa&&window.btoa.bind(window)||r(103);e.exports=function(e){return new Promise(function(f,l){var p=e.data,h=e.headers;n.isFormData(p)&&delete h["Content-Type"];var d=new XMLHttpRequest,v="onreadystatechange",y=!1;if("test"===t.env.NODE_ENV||"undefined"==typeof window||!window.XDomainRequest||"withCredentials"in d||s(e.url)||(d=new window.XDomainRequest,v="onload",y=!0,d.onprogress=function(){},d.ontimeout=function(){}),e.auth){var g=e.auth.username||"",m=e.auth.password||"";h.Authorization="Basic "+c(g+":"+m)}if(d.open(e.method.toUpperCase(),i(e.url,e.params,e.paramsSerializer),!0),d.timeout=e.timeout,d[v]=function(){if(d&&(4===d.readyState||y)&&(0!==d.status||d.responseURL&&0===d.responseURL.indexOf("file:"))){var t="getAllResponseHeaders"in d?u(d.getAllResponseHeaders()):null,r={data:e.responseType&&"text"!==e.responseType?d.response:d.responseText,status:1223===d.status?204:d.status,statusText:1223===d.status?"No Content":d.statusText,headers:t,config:e,request:d};o(f,l,r),d=null}},d.onerror=function(){l(a("Network Error",e,null,d)),d=null},d.ontimeout=function(){l(a("timeout of "+e.timeout+"ms exceeded",e,"ECONNABORTED",d)),d=null},n.isStandardBrowserEnv()){var x=r(106),b=(e.withCredentials||s(e.url))&&e.xsrfCookieName?x.read(e.xsrfCookieName):void 0;b&&(h[e.xsrfHeaderName]=b)}if("setRequestHeader"in d&&n.forEach(h,function(e,t){void 0===p&&"content-type"===t.toLowerCase()?delete h[t]:d.setRequestHeader(t,e)}),e.withCredentials&&(d.withCredentials=!0),e.responseType)try{d.responseType=e.responseType}catch(t){if("json"!==e.responseType)throw t}"function"==typeof e.onDownloadProgress&&d.addEventListener("progress",e.onDownloadProgress),"function"==typeof e.onUploadProgress&&d.upload&&d.upload.addEventListener("progress",e.onUploadProgress),e.cancelToken&&e.cancelToken.promise.then(function(e){d&&(d.abort(),l(e),d=null)}),void 0===p&&(p=null),d.send(p)})}}).call(t,r(75))},function(e,t,r){"use strict";function n(e){this.message=e}n.prototype.toString=function(){return"Cancel"+(this.message?": "+this.message:"")},n.prototype.__CANCEL__=!0,e.exports=n},function(e,t,r){"use strict";e.exports=function(e){return!(!e||!e.__CANCEL__)}},function(e,t,r){"use strict";var n=r(100);e.exports=function(e,t,r,o,i){var u=new Error(e);return n(u,t,r,o,i)}},function(e,t,r){"use strict";e.exports=function(e,t){return function(){for(var r=new Array(arguments.length),n=0;nr;)t.push(arguments[r++]);return g[++y]=function(){s("function"==typeof e?e:Function(e),t)},n(y),y},h=function(e){delete g[e]},"process"==r(15)(l)?n=function(e){l.nextTick(u(m,e,1))}:v&&v.now?n=function(e){v.now(u(m,e,1))}:d?(i=(o=new d).port2,o.port1.onmessage=x,n=u(i.postMessage,i,1)):f.addEventListener&&"function"==typeof postMessage&&!f.importScripts?(n=function(e){f.postMessage(e+"","*")},f.addEventListener("message",x,!1)):n="onreadystatechange"in c("script")?function(e){a.appendChild(c("script")).onreadystatechange=function(){a.removeChild(this),m.call(e)}}:function(e){setTimeout(u(m,e,1),0)}),e.exports={set:p,clear:h}},function(e,t,r){var n=r(34),o=Math.min;e.exports=function(e){return e>0?o(n(e),9007199254740991):0}},function(e,t,r){var n=r(27);e.exports=function(e){return Object(n(e))}},function(e,t){var r=0,n=Math.random();e.exports=function(e){return"Symbol(".concat(void 0===e?"":e,")_",(++r+n).toString(36))}},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=function(){function e(e,t){for(var r=0;r0&&void 0!==arguments[0]?arguments[0]:{};!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),this.record(t)}return n(e,[{key:"all",value:function(){return this.errors}},{key:"has",value:function(e){var t=this.errors.hasOwnProperty(e);t||(t=Object.keys(this.errors).filter(function(t){return t.startsWith(e+".")||t.startsWith(e+"[")}).length>0);return t}},{key:"first",value:function(e){return this.get(e)[0]}},{key:"get",value:function(e){return this.errors[e]||[]}},{key:"any",value:function(){return Object.keys(this.errors).length>0}},{key:"record",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};this.errors=e}},{key:"clear",value:function(e){if(e){var t=Object.assign({},this.errors);Object.keys(t).filter(function(t){return t===e||t.startsWith(e+".")||t.startsWith(e+"[")}).forEach(function(e){return delete t[e]}),this.errors=t}else this.errors={}}}]),e}();t.default=o},function(e,t,r){var n=r(177),o=r(229),i=r(13),u=r(230),s=r(70),a=r(231),c=Object.prototype.hasOwnProperty;e.exports=function(e,t){var r=i(e),f=!r&&o(e),l=!r&&!f&&u(e),p=!r&&!f&&!l&&a(e),h=r||f||l||p,d=h?n(e.length,String):[],v=d.length;for(var y in e)!t&&!c.call(e,y)||h&&("length"==y||l&&("offset"==y||"parent"==y)||p&&("buffer"==y||"byteLength"==y||"byteOffset"==y)||s(y,v))||d.push(y);return d}},function(e,t,r){(function(t){var r="object"==typeof t&&t&&t.Object===Object&&t;e.exports=r}).call(t,r(241))},function(e,t){var r=RegExp("[\\u200d\\ud800-\\udfff\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff\\ufe0e\\ufe0f]");e.exports=function(e){return r.test(e)}},function(e,t){var r=9007199254740991,n=/^(?:0|[1-9]\d*)$/;e.exports=function(e,t){var o=typeof e;return!!(t=null==t?r:t)&&("number"==o||"symbol"!=o&&n.test(e))&&e>-1&&e%1==0&&e-1&&e%1==0&&e<=r}},function(e,t,r){var n=r(178);e.exports=function(e){return null==e?"":n(e)}},function(e,t){var r,n,o=e.exports={};function i(){throw new Error("setTimeout has not been defined")}function u(){throw new Error("clearTimeout has not been defined")}function s(e){if(r===setTimeout)return setTimeout(e,0);if((r===i||!r)&&setTimeout)return r=setTimeout,setTimeout(e,0);try{return r(e,0)}catch(t){try{return r.call(null,e,0)}catch(t){return r.call(this,e,0)}}}!function(){try{r="function"==typeof setTimeout?setTimeout:i}catch(e){r=i}try{n="function"==typeof clearTimeout?clearTimeout:u}catch(e){n=u}}();var a,c=[],f=!1,l=-1;function p(){f&&a&&(f=!1,a.length?c=a.concat(c):l=-1,c.length&&h())}function h(){if(!f){var e=s(p);f=!0;for(var t=c.length;t;){for(a=c,c=[];++l1)for(var r=1;r1&&void 0!==arguments[1]?arguments[1]:null;return this.viaManyToMany?this.detachResources(e):Nova.request({url:"/nova-api/"+this.resourceName,method:"delete",params:(0,i.default)({},this.queryString,{resources:u(e)})}).then(r||function(){t.deleteModalOpen=!1,t.getResources()})},deleteSelectedResources:function(){this.deleteResources(this.selectedResources)},deleteAllMatchingResources:function(){var e=this;return this.viaManyToMany?this.detachAllMatchingResources():Nova.request({url:this.deleteAllMatchingResourcesEndpoint,method:"delete",params:(0,i.default)({},this.queryString,{resources:"all"})}).then(function(){e.deleteModalOpen=!1,e.getResources()})},detachResources:function(e){var t=this;return Nova.request({url:"/nova-api/"+this.resourceName+"/detach",method:"delete",params:(0,i.default)({},this.queryString,{resources:u(e)})}).then(function(){t.deleteModalOpen=!1,t.getResources()})},detachAllMatchingResources:function(){var e=this;return Nova.request({url:"/nova-api/"+this.resourceName+"/detach",method:"delete",params:(0,i.default)({},this.queryString,{resources:"all"})}).then(function(){e.deleteModalOpen=!1,e.getResources()})},forceDeleteResources:function(e){var t=this,r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;return Nova.request({url:"/nova-api/"+this.resourceName+"/force",method:"delete",params:(0,i.default)({},this.queryString,{resources:u(e)})}).then(r||function(){t.deleteModalOpen=!1,t.getResources()})},forceDeleteSelectedResources:function(){this.forceDeleteResources(this.selectedResources)},forceDeleteAllMatchingResources:function(){var e=this;return Nova.request({url:this.forceDeleteSelectedResourcesEndpoint,method:"delete",params:(0,i.default)({},this.queryString,{resources:"all"})}).then(function(){e.deleteModalOpen=!1,e.getResources()})},restoreResources:function(e){var t=this,r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;return Nova.request({url:"/nova-api/"+this.resourceName+"/restore",method:"put",params:(0,i.default)({},this.queryString,{resources:u(e)})}).then(r||function(){t.restoreModalOpen=!1,t.getResources()})},restoreSelectedResources:function(){this.restoreResources(this.selectedResources)},restoreAllMatchingResources:function(){var e=this;return Nova.request({url:this.restoreAllMatchingResourcesEndpoint,method:"put",params:(0,i.default)({},this.queryString,{resources:"all"})}).then(function(){e.restoreModalOpen=!1,e.getResources()})}},computed:{deleteAllMatchingResourcesEndpoint:function(){return this.lens?"/nova-api/"+this.resourceName+"/lens/"+this.lens:"/nova-api/"+this.resourceName},forceDeleteSelectedResourcesEndpoint:function(){return this.lens?"/nova-api/"+this.resourceName+"/lens/"+this.lens+"/force":"/nova-api/"+this.resourceName+"/force"},restoreAllMatchingResourcesEndpoint:function(){return this.lens?"/nova-api/"+this.resourceName+"/lens/"+this.lens+"/restore":"/nova-api/"+this.resourceName+"/restore"},queryString:function(){return{search:this.currentSearch,filters:this.encodedFilters,trashed:this.currentTrashed,viaResource:this.viaResource,viaResourceId:this.viaResourceId,viaRelationship:this.viaRelationship}}}}},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=u(r(50)),o=u(r(26)),i=u(r(49));u(r(226)),u(r(228));function u(e){return e&&e.__esModule?e:{default:e}}t.default={methods:{clearSelectedFilters:function(){var e=(0,i.default)(n.default.mark(function e(t){var r;return n.default.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:if(!t){e.next=5;break}return e.next=3,this.$store.dispatch(this.resourceName+"/resetFilterState",{resourceName:this.resourceName,lens:t});case 3:e.next=7;break;case 5:return e.next=7,this.$store.dispatch(this.resourceName+"/resetFilterState",{resourceName:this.resourceName});case 7:this.updateQueryString((r={},(0,o.default)(r,this.pageParameter,1),(0,o.default)(r,this.filterParameter,""),r));case 8:case"end":return e.stop()}},e,this)}));return function(t){return e.apply(this,arguments)}}(),filterChanged:function(){var e;this.updateQueryString((e={},(0,o.default)(e,this.pageParameter,1),(0,o.default)(e,this.filterParameter,this.$store.getters[this.resourceName+"/currentEncodedFilters"]),e))},initializeFilters:function(){var e=(0,i.default)(n.default.mark(function e(t){return n.default.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:return this.$store.commit(this.resourceName+"/clearFilters"),e.next=3,this.$store.dispatch(this.resourceName+"/fetchFilters",{resourceName:this.resourceName,lens:t});case 3:return e.next=5,this.initializeState(t);case 5:case"end":return e.stop()}},e,this)}));return function(t){return e.apply(this,arguments)}}(),initializeState:function(){var e=(0,i.default)(n.default.mark(function e(t){return n.default.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:if(!this.initialEncodedFilters){e.next=5;break}return e.next=3,this.$store.dispatch(this.resourceName+"/initializeCurrentFilterValuesFromQueryString",this.initialEncodedFilters);case 3:e.next=7;break;case 5:return e.next=7,this.$store.dispatch(this.resourceName+"/resetFilterState",{resourceName:this.resourceName,lens:t});case 7:case"end":return e.stop()}},e,this)}));return function(t){return e.apply(this,arguments)}}()},computed:{filterParameter:function(){return this.resourceName+"_filter"}}}},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default={props:{resourceName:{},field:{}},data:function(){return{value:""}},mounted:function(){var e=this;this.setInitialValue(),this.field.fill=this.fill,Nova.$on(this.field.attribute+"-value",function(t){e.value=t})},destroyed:function(){Nova.$off(this.field.attribute+"-value")},methods:{setInitialValue:function(){this.value=void 0!==this.field.value&&null!==this.field.value?this.field.value:""},fill:function(e){e.append(this.field.attribute,String(this.value))},handleChange:function(e){this.value=e}},computed:{isReadonly:function(){return this.field.readonly||_.get(this.field,"extraAttributes.readonly")}}}},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=r(41);t.default={props:{errors:{default:function(){return new n.Errors}}},data:function(){return{errorClass:"border-danger"}},computed:{errorClasses:function(){return this.hasError?[this.errorClass]:[]},fieldAttribute:function(){return this.field.attribute},hasError:function(){return this.errors.has(this.fieldAttribute)},firstError:function(){if(this.hasError)return this.errors.first(this.fieldAttribute)}}}},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=u(r(50)),o=u(r(49)),i=u(r(40));function u(e){return e&&e.__esModule?e:{default:e}}t.default={props:{loadCards:{type:Boolean,default:!0}},data:function(){return{cards:[]}},created:function(){this.fetchCards()},watch:{cardsEndpoint:function(){this.fetchCards()}},methods:{fetchCards:function(){var e=(0,o.default)(n.default.mark(function e(){var t,r;return n.default.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:if(!this.loadCards){e.next=6;break}return e.next=3,Nova.request().get(this.cardsEndpoint,{params:this.extraCardParams});case 3:t=e.sent,r=t.data,this.cards=r;case 6:case"end":return e.stop()}},e,this)}));return function(){return e.apply(this,arguments)}}()},computed:{shouldShowCards:function(){return this.cards.length>0},smallCards:function(){return _.filter(this.cards,function(e){return-1!==i.default.indexOf(e.width)})},largeCards:function(){return _.filter(this.cards,function(e){return"full"==e.width})},extraCardParams:function(){return null}}}},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default={methods:{toAppTimezone:function(e){return e?moment.tz(e,this.userTimezone).clone().tz(Nova.config.timezone).format("YYYY-MM-DD HH:mm:ss"):e},fromAppTimezone:function(e){return e?moment.tz(e,Nova.config.timezone).clone().tz(this.userTimezone).format("YYYY-MM-DD HH:mm:ss"):e},localizeDateTimeField:function(e){if(!e.value)return e.value;var t=moment.tz(e.value,Nova.config.timezone).clone().tz(this.userTimezone);return e.format?t.format(e.format):this.usesTwelveHourTime?t.format("YYYY-MM-DD h:mm:ss A"):t.format("YYYY-MM-DD HH:mm:ss")},localizeDateField:function(e){if(!e.value)return e.value;var t=moment.tz(e.value,Nova.config.timezone).clone().tz(this.userTimezone);return e.format?t.format(e.format):t.format("YYYY-MM-DD")}},computed:{userTimezone:function(){return Nova.config.userTimezone?Nova.config.userTimezone:moment.tz.guess()},usesTwelveHourTime:function(){return _.endsWith((new Date).toLocaleString(),"AM")||_.endsWith((new Date).toLocaleString(),"PM")}}}},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n,o=r(225),i=(n=o)&&n.__esModule?n:{default:n};t.default={methods:{updateQueryString:function(e){this.$router.push({query:(0,i.default)(e,this.$route.query)})}}}},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default={computed:{resourceInformation:function(){var e=this;return _.find(Nova.config.resources,function(t){return t.uriKey==e.resourceName})},viaResourceInformation:function(){var e=this;if(this.viaResource)return _.find(Nova.config.resources,function(t){return t.uriKey==e.viaResource})},authorizedToCreate:function(){return this.resourceInformation.authorizedToCreate}}}},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n,o=r(26),i=(n=o)&&n.__esModule?n:{default:n};t.default={methods:{selectPreviousPage:function(){this.updateQueryString((0,i.default)({},this.pageParameter,this.currentPage-1))},selectNextPage:function(){this.updateQueryString((0,i.default)({},this.pageParameter,this.currentPage+1))}},computed:{currentPage:function(){return parseInt(this.$route.query[this.pageParameter]||1)}}}},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n,o=r(26),i=(n=o)&&n.__esModule?n:{default:n};t.default={data:function(){return{perPage:25}},methods:{initializePerPageFromQueryString:function(){this.perPage=this.currentPerPage},perPageChanged:function(){this.updateQueryString((0,i.default)({},this.perPageParameter,this.perPage))}},computed:{currentPerPage:function(){return this.$route.query[this.perPageParameter]||25}}}},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n,o=r(224),i=(n=o)&&n.__esModule?n:{default:n};t.default={data:function(){return{search:"",selectedResource:"",availableResources:[]}},methods:{selectResource:function(e){this.selectedResource=e},handleSearchCleared:function(){this.availableResources=[]},clearSelection:function(){this.selectedResource="",this.availableResources=[]},performSearch:function(e){var t=this;this.search=e;var r=e.trim();""!=r?this.debouncer(function(){t.selectedResource="",t.getAvailableResources(r)},500):this.clearSelection()},debouncer:(0,i.default)(function(e){return e()},500)}}},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default={data:function(){return{withTrashed:!1}},methods:{toggleWithTrashed:function(){this.withTrashed=!this.withTrashed},enableWithTrashed:function(){this.withTrashed=!0},disableWithTrashed:function(){this.withTrashed=!1}}}},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e){return(0,i.default)(e)};var n,o=r(238),i=(n=o)&&n.__esModule?n:{default:n}},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n,o=r(48),i=(n=o)&&n.__esModule?n:{default:n};t.default=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:100;return i.default.all([e,new i.default(function(e){setTimeout(function(){return e()},t)})]).then(function(e){return e[0]})}},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e,t){return e>1||0==e?n.Inflector.pluralize(t):n.Inflector.singularize(t)};var n=r(47)},function(e,t,r){"use strict";var n={uncountableWords:["equipment","information","rice","money","species","series","fish","sheep","moose","deer","news"],pluralRules:[[new RegExp("(m)an$","gi"),"$1en"],[new RegExp("(pe)rson$","gi"),"$1ople"],[new RegExp("(child)$","gi"),"$1ren"],[new RegExp("^(ox)$","gi"),"$1en"],[new RegExp("(ax|test)is$","gi"),"$1es"],[new RegExp("(octop|vir)us$","gi"),"$1i"],[new RegExp("(alias|status)$","gi"),"$1es"],[new RegExp("(bu)s$","gi"),"$1ses"],[new RegExp("(buffal|tomat|potat)o$","gi"),"$1oes"],[new RegExp("([ti])um$","gi"),"$1a"],[new RegExp("sis$","gi"),"ses"],[new RegExp("(?:([^f])fe|([lr])f)$","gi"),"$1$2ves"],[new RegExp("(hive)$","gi"),"$1s"],[new RegExp("([^aeiouy]|qu)y$","gi"),"$1ies"],[new RegExp("(x|ch|ss|sh)$","gi"),"$1es"],[new RegExp("(matr|vert|ind)ix|ex$","gi"),"$1ices"],[new RegExp("([m|l])ouse$","gi"),"$1ice"],[new RegExp("(quiz)$","gi"),"$1zes"],[new RegExp("s$","gi"),"s"],[new RegExp("$","gi"),"s"]],singularRules:[[new RegExp("(m)en$","gi"),"$1an"],[new RegExp("(pe)ople$","gi"),"$1rson"],[new RegExp("(child)ren$","gi"),"$1"],[new RegExp("([ti])a$","gi"),"$1um"],[new RegExp("((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$","gi"),"$1$2sis"],[new RegExp("(hive)s$","gi"),"$1"],[new RegExp("(tive)s$","gi"),"$1"],[new RegExp("(curve)s$","gi"),"$1"],[new RegExp("([lr])ves$","gi"),"$1f"],[new RegExp("([^fo])ves$","gi"),"$1fe"],[new RegExp("([^aeiouy]|qu)ies$","gi"),"$1y"],[new RegExp("(s)eries$","gi"),"$1eries"],[new RegExp("(m)ovies$","gi"),"$1ovie"],[new RegExp("(x|ch|ss|sh)es$","gi"),"$1"],[new RegExp("([m|l])ice$","gi"),"$1ouse"],[new RegExp("(bus)es$","gi"),"$1"],[new RegExp("(o)es$","gi"),"$1"],[new RegExp("(shoe)s$","gi"),"$1"],[new RegExp("(cris|ax|test)es$","gi"),"$1is"],[new RegExp("(octop|vir)i$","gi"),"$1us"],[new RegExp("(alias|status)es$","gi"),"$1"],[new RegExp("^(ox)en","gi"),"$1"],[new RegExp("(vert|ind)ices$","gi"),"$1ex"],[new RegExp("(matr)ices$","gi"),"$1ix"],[new RegExp("(quiz)zes$","gi"),"$1"],[new RegExp("s$","gi"),""]],nonTitlecasedWords:["and","or","nor","a","an","the","so","but","to","of","at","by","from","into","on","onto","off","out","in","over","with","for"],idSuffix:new RegExp("(_ids|_id)$","g"),underbar:new RegExp("_","g"),spaceOrUnderbar:new RegExp("[ _]","g"),uppercase:new RegExp("([A-Z])","g"),underbarPrefix:new RegExp("^_"),applyRules:function(e,t,r,n){if(n)e=n;else if(!(r.indexOf(e.toLowerCase())>-1))for(var o=0;o>8-s%1*8)){if((r=i.charCodeAt(s+=.75))>255)throw new o;t=t<<8|r}return u}},function(e,t,r){"use strict";var n=r(0);function o(e){return encodeURIComponent(e).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"+").replace(/%5B/gi,"[").replace(/%5D/gi,"]")}e.exports=function(e,t,r){if(!t)return e;var i;if(r)i=r(t);else if(n.isURLSearchParams(t))i=t.toString();else{var u=[];n.forEach(t,function(e,t){null!==e&&void 0!==e&&(n.isArray(e)?t+="[]":e=[e],n.forEach(e,function(e){n.isDate(e)?e=e.toISOString():n.isObject(e)&&(e=JSON.stringify(e)),u.push(o(t)+"="+o(e))}))}),i=u.join("&")}return i&&(e+=(-1===e.indexOf("?")?"?":"&")+i),e}},function(e,t,r){"use strict";e.exports=function(e,t){return t?e.replace(/\/+$/,"")+"/"+t.replace(/^\/+/,""):e}},function(e,t,r){"use strict";var n=r(0);e.exports=n.isStandardBrowserEnv()?{write:function(e,t,r,o,i,u){var s=[];s.push(e+"="+encodeURIComponent(t)),n.isNumber(r)&&s.push("expires="+new Date(r).toGMTString()),n.isString(o)&&s.push("path="+o),n.isString(i)&&s.push("domain="+i),!0===u&&s.push("secure"),document.cookie=s.join("; ")},read:function(e){var t=document.cookie.match(new RegExp("(^|;\\s*)("+e+")=([^;]*)"));return t?decodeURIComponent(t[3]):null},remove:function(e){this.write(e,"",Date.now()-864e5)}}:{write:function(){},read:function(){return null},remove:function(){}}},function(e,t,r){"use strict";e.exports=function(e){return/^([a-z][a-z\d\+\-\.]*:)?\/\//i.test(e)}},function(e,t,r){"use strict";var n=r(0);e.exports=n.isStandardBrowserEnv()?function(){var e,t=/(msie|trident)/i.test(navigator.userAgent),r=document.createElement("a");function o(e){var n=e;return t&&(r.setAttribute("href",n),n=r.href),r.setAttribute("href",n),{href:r.href,protocol:r.protocol?r.protocol.replace(/:$/,""):"",host:r.host,search:r.search?r.search.replace(/^\?/,""):"",hash:r.hash?r.hash.replace(/^#/,""):"",hostname:r.hostname,port:r.port,pathname:"/"===r.pathname.charAt(0)?r.pathname:"/"+r.pathname}}return e=o(window.location.href),function(t){var r=n.isString(t)?o(t):t;return r.protocol===e.protocol&&r.host===e.host}}():function(){return!0}},function(e,t,r){"use strict";var n=r(0);e.exports=function(e,t){n.forEach(e,function(r,n){n!==t&&n.toUpperCase()===t.toUpperCase()&&(e[t]=r,delete e[n])})}},function(e,t,r){"use strict";var n=r(0),o=["age","authorization","content-length","content-type","etag","expires","from","host","if-modified-since","if-unmodified-since","last-modified","location","max-forwards","proxy-authorization","referer","retry-after","user-agent"];e.exports=function(e){var t,r,i,u={};return e?(n.forEach(e.split("\n"),function(e){if(i=e.indexOf(":"),t=n.trim(e.substr(0,i)).toLowerCase(),r=n.trim(e.substr(i+1)),t){if(u[t]&&o.indexOf(t)>=0)return;u[t]="set-cookie"===t?(u[t]?u[t]:[]).concat([r]):u[t]?u[t]+", "+r:r}}),u):u}},function(e,t,r){"use strict";e.exports=function(e){return function(t){return e.apply(null,t)}}},function(e,t,r){e.exports={default:r(115),__esModule:!0}},function(e,t,r){e.exports={default:r(116),__esModule:!0}},function(e,t,r){"use strict";t.__esModule=!0;var n,o=r(112),i=(n=o)&&n.__esModule?n:{default:n};t.default=i.default||function(e){for(var t=1;tf;)if((s=a[f++])!=s)return!0}else for(;c>f;f++)if((e||f in a)&&a[f]===r)return e||f||0;return!e&&-1}}},function(e,t,r){var n=r(16),o=r(125),i=r(124),u=r(4),s=r(63),a=r(144),c={},f={};(t=e.exports=function(e,t,r,l,p){var h,d,v,y,g=p?function(){return e}:a(e),m=n(r,l,t?2:1),x=0;if("function"!=typeof g)throw TypeError(e+" is not iterable!");if(i(g)){for(h=s(e.length);h>x;x++)if((y=t?m(u(d=e[x])[0],d[1]):m(e[x]))===c||y===f)return y}else for(v=g.call(e);!(d=v.next()).done;)if((y=o(v,m,d.value,t))===c||y===f)return y}).BREAK=c,t.RETURN=f},function(e,t,r){e.exports=!r(5)&&!r(29)(function(){return 7!=Object.defineProperty(r(28)("div"),"a",{get:function(){return 7}}).a})},function(e,t){e.exports=function(e,t,r){var n=void 0===r;switch(t.length){case 0:return n?e():e.call(r);case 1:return n?e(t[0]):e.call(r,t[0]);case 2:return n?e(t[0],t[1]):e.call(r,t[0],t[1]);case 3:return n?e(t[0],t[1],t[2]):e.call(r,t[0],t[1],t[2]);case 4:return n?e(t[0],t[1],t[2],t[3]):e.call(r,t[0],t[1],t[2],t[3])}return e.apply(r,t)}},function(e,t,r){var n=r(10),o=r(2)("iterator"),i=Array.prototype;e.exports=function(e){return void 0!==e&&(n.Array===e||i[o]===e)}},function(e,t,r){var n=r(4);e.exports=function(e,t,r,o){try{return o?t(n(r)[0],r[1]):t(r)}catch(t){var i=e.return;throw void 0!==i&&n(i.call(e)),t}}},function(e,t,r){"use strict";var n=r(131),o=r(59),i=r(32),u={};r(7)(u,r(2)("iterator"),function(){return this}),e.exports=function(e,t,r){e.prototype=n(u,{next:o(1,r)}),i(e,t+" Iterator")}},function(e,t,r){var n=r(2)("iterator"),o=!1;try{var i=[7][n]();i.return=function(){o=!0},Array.from(i,function(){throw 2})}catch(e){}e.exports=function(e,t){if(!t&&!o)return!1;var r=!1;try{var i=[7],u=i[n]();u.next=function(){return{done:r=!0}},i[n]=function(){return u},e(i)}catch(e){}return r}},function(e,t){e.exports=function(e,t){return{value:t,done:!!e}}},function(e,t,r){var n=r(1),o=r(62).set,i=n.MutationObserver||n.WebKitMutationObserver,u=n.process,s=n.Promise,a="process"==r(15)(u);e.exports=function(){var e,t,r,c=function(){var n,o;for(a&&(n=u.domain)&&n.exit();e;){o=e.fn,e=e.next;try{o()}catch(n){throw e?r():t=void 0,n}}t=void 0,n&&n.enter()};if(a)r=function(){u.nextTick(c)};else if(!i||n.navigator&&n.navigator.standalone)if(s&&s.resolve){var f=s.resolve(void 0);r=function(){f.then(c)}}else r=function(){o.call(n,c)};else{var l=!0,p=document.createTextNode("");new i(c).observe(p,{characterData:!0}),r=function(){p.data=l=!l}}return function(n){var o={fn:n,next:void 0};t&&(t.next=o),e||(e=o,r()),t=o}}},function(e,t,r){"use strict";var n=r(56),o=r(133),i=r(136),u=r(64),s=r(54),a=Object.assign;e.exports=!a||r(29)(function(){var e={},t={},r=Symbol(),n="abcdefghijklmnopqrst";return e[r]=7,n.split("").forEach(function(e){t[e]=e}),7!=a({},e)[r]||Object.keys(a({},t)).join("")!=n})?function(e,t){for(var r=u(e),a=arguments.length,c=1,f=o.f,l=i.f;a>c;)for(var p,h=s(arguments[c++]),d=f?n(h).concat(f(h)):n(h),v=d.length,y=0;v>y;)l.call(h,p=d[y++])&&(r[p]=h[p]);return r}:a},function(e,t,r){var n=r(4),o=r(132),i=r(52),u=r(33)("IE_PROTO"),s=function(){},a=function(){var e,t=r(28)("iframe"),n=i.length;for(t.style.display="none",r(53).appendChild(t),t.src="javascript:",(e=t.contentWindow.document).open(),e.write(" 51 | -------------------------------------------------------------------------------- /resources/js/components/FormField.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 77 | -------------------------------------------------------------------------------- /resources/js/components/IndexField.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 31 | -------------------------------------------------------------------------------- /resources/js/components/list-items/CheckedItem.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | -------------------------------------------------------------------------------- /resources/js/components/list-items/UncheckedItem.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | -------------------------------------------------------------------------------- /resources/js/field.js: -------------------------------------------------------------------------------- 1 | Nova.booting((Vue, router) => { 2 | Vue.component('index-nova-checkboxes', require('./components/IndexField')); 3 | Vue.component('detail-nova-checkboxes', require('./components/DetailField')); 4 | Vue.component('form-nova-checkboxes', require('./components/FormField')); 5 | }) 6 | -------------------------------------------------------------------------------- /resources/js/mixins/CheckboxDisplay.js: -------------------------------------------------------------------------------- 1 | import CheckedItem from '../components/list-items/CheckedItem.vue'; 2 | import UncheckedItem from '../components/list-items/UncheckedItem.vue'; 3 | 4 | export default { 5 | 6 | components:{ 7 | CheckedItem, 8 | UncheckedItem 9 | }, 10 | 11 | data: () => ({ 12 | value: [], 13 | }), 14 | 15 | methods: { 16 | getItemType(option) { 17 | return (option.status) 18 | ? 'checked-item' 19 | : 'unchecked-item' 20 | }, 21 | getAllOptions(){ 22 | return this.field.options 23 | .map(option => { 24 | return { 25 | 'status': this.value[option.value], 26 | 'key': option.value, 27 | 'label': option.label 28 | } 29 | }) 30 | .sort((x, y) => y.status - x.status); 31 | }, 32 | getCheckedOptions(){ 33 | return this.field.options 34 | .filter(option => { 35 | return this.value[option.value]; 36 | }) 37 | .map(option => { 38 | return { 39 | 'status': true, 40 | 'key': option.value, 41 | 'label': option.label 42 | } 43 | }); 44 | } 45 | }, 46 | 47 | mounted() { 48 | this.value = JSON.parse(this.field.value) || {}; 49 | } 50 | 51 | } -------------------------------------------------------------------------------- /resources/sass/field.scss: -------------------------------------------------------------------------------- 1 | // Nova Tool CSS 2 | -------------------------------------------------------------------------------- /screenshot-detail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fourstacks/nova-checkboxes/73de263bfb500e5ab9159dba120818995f4605dc/screenshot-detail.png -------------------------------------------------------------------------------- /screenshot-form.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fourstacks/nova-checkboxes/73de263bfb500e5ab9159dba120818995f4605dc/screenshot-form.png -------------------------------------------------------------------------------- /screenshot-index.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fourstacks/nova-checkboxes/73de263bfb500e5ab9159dba120818995f4605dc/screenshot-index.png -------------------------------------------------------------------------------- /src/Checkboxes.php: -------------------------------------------------------------------------------- 1 | withMeta([ 18 | 'options' => collect($options ?? [])->map(function ($label, $value) { 19 | return ['label' => $label, 'value' => $value]; 20 | })->values()->all(), 21 | ]); 22 | } 23 | 24 | public function saveAsString() 25 | { 26 | return $this->withMeta([ 27 | 'save_as_string' => true 28 | ]); 29 | } 30 | 31 | public function saveUncheckedValues() 32 | { 33 | return $this->withMeta([ 34 | 'save_unchecked' => true 35 | ]); 36 | } 37 | 38 | public function displayUncheckedValuesOnIndex() 39 | { 40 | return $this->withMeta([ 41 | 'display_unchecked_on_index' => true 42 | ]); 43 | } 44 | 45 | public function displayUncheckedValuesOnDetail() 46 | { 47 | return $this->withMeta([ 48 | 'display_unchecked_on_detail' => true 49 | ]); 50 | } 51 | 52 | public function columns($columns = 1) 53 | { 54 | return $this->withMeta([ 55 | 'columns' => $columns 56 | ]); 57 | } 58 | 59 | public function resolveAttribute($resource, $attribute = null) 60 | { 61 | $value = data_get($resource, str_replace('->', '.', $attribute)); 62 | 63 | if ($value instanceof Collection) { 64 | $value = $value->toArray(); 65 | } elseif (is_object($value)) { 66 | $value = (array) $value; 67 | } elseif (is_array($value)) { 68 | $value = $value; 69 | } elseif (strlen($value)) { 70 | $value = explode(',', $value); 71 | } elseif (! $value) { 72 | $value = []; 73 | } 74 | 75 | if (Arr::isAssoc($value)) { 76 | $value = $this->onlyChecked($value); 77 | } 78 | 79 | return json_encode((object)$this->withUnchecked($value)); 80 | } 81 | 82 | protected function fillAttributeFromRequest( 83 | NovaRequest $request, 84 | $requestAttribute, 85 | $model, 86 | $attribute 87 | ) { 88 | if ($request->exists($requestAttribute)) { 89 | $data = json_decode($request[$requestAttribute]); 90 | 91 | if ($this->shouldSaveAsString()) { 92 | $value = implode(',', $this->onlyChecked($data)); 93 | } elseif ($this->shouldSaveUnchecked()) { 94 | $value = $data; 95 | } else { 96 | $value = $this->onlyChecked($data); 97 | } 98 | 99 | $model->{$attribute} = $value; 100 | } 101 | } 102 | 103 | protected function shouldSaveAsString() 104 | { 105 | return ( 106 | array_key_exists('save_as_string', $this->meta) 107 | && $this->meta['save_as_string'] 108 | ); 109 | } 110 | 111 | protected function shouldSaveUnchecked() 112 | { 113 | return ( 114 | array_key_exists('save_unchecked', $this->meta) 115 | && $this->meta['save_unchecked'] 116 | ); 117 | } 118 | 119 | protected function withUnchecked($data) 120 | { 121 | return collect($this->meta['options']) 122 | ->mapWithKeys(function ($option) use ($data) { 123 | $isChecked = in_array($option['value'], $data); 124 | 125 | return [ $option['value'] => $isChecked ]; 126 | }) 127 | ->all(); 128 | } 129 | 130 | protected function onlyChecked($data) 131 | { 132 | return collect($data) 133 | ->filter(function ($isChecked) { 134 | return $isChecked; 135 | }) 136 | ->keys() 137 | ->all(); 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/FieldServiceProvider.php: -------------------------------------------------------------------------------- 1 | registerTestingMacros(); 16 | } 17 | 18 | /** 19 | * Register extra testing macros. 20 | */ 21 | protected function registerTestingMacros() 22 | { 23 | Field::macro('assertValue', function($expected, $actual, $attribute = null) { 24 | $this->resolve((object) [$this->attribute => $actual], $attribute ?? $this->attribute); 25 | Assert::assertEquals($expected, $this->value); 26 | 27 | $this->resolveForDisplay((object) [$this->attribute => $actual], $attribute ?? $this->attribute); 28 | Assert::assertEquals($expected, $this->value); 29 | 30 | return $this; 31 | }); 32 | } 33 | 34 | /** 35 | * Get the service providers for the package. 36 | * 37 | * @param \Illuminate\Foundation\Application $app 38 | * @return array 39 | */ 40 | protected function getPackageProviders($app) 41 | { 42 | return [ 43 | 'Fourstacks\NovaCheckboxes\FieldServiceProvider', 44 | ]; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /tests/Unit/CheckboxesFieldTest.php: -------------------------------------------------------------------------------- 1 | assertEquals([ 16 | 'component' => 'nova-checkboxes', 17 | "prefixComponent" => true, 18 | 'name' => 'Options', 19 | 'attribute' => 'options', 20 | 'value' => null, 21 | 'panel' => null, 22 | 'sortable' => false, 23 | 'textAlign' => 'left', 24 | 'indexName' => 'Options' 25 | ], $field->jsonSerialize()); 26 | } 27 | 28 | function test_checkboxes_field_options_as_an_associative_array() 29 | { 30 | $field = Checkboxes::make('Hobbies')->options([ 31 | 'sailing' => 'Sailing', 32 | 'rock_climbing' => 'Rock Climbing', 33 | 'archery' => 'Archery' 34 | ]); 35 | 36 | $this->assertEquals([ 37 | 'options' => [ 38 | ['label' => 'Sailing', 'value' => 'sailing'], 39 | ['label' => 'Rock Climbing', 'value' => 'rock_climbing'], 40 | ['label' => 'Archery', 'value' => 'archery'], 41 | ], 42 | ], $field->meta()); 43 | } 44 | 45 | function test_checkboxes_field_options_as_a_value_only_array() 46 | { 47 | $field = Checkboxes::make('Hobbies')->options([ 48 | 'Sailing', 49 | 'Rock Climbing', 50 | 'Archery' 51 | ]); 52 | 53 | $this->assertEquals([ 54 | 'options' => [ 55 | ['label' => 'Sailing', 'value' => 0], 56 | ['label' => 'Rock Climbing', 'value' => 1], 57 | ['label' => 'Archery', 'value' => 2], 58 | ], 59 | ], $field->meta()); 60 | } 61 | 62 | function test_checkboxes_field_can_be_set_to_save_as_string() 63 | { 64 | $field = Checkboxes::make('options')->saveAsString(); 65 | 66 | $this->assertEquals(['save_as_string' => true], $field->meta()); 67 | } 68 | 69 | function test_checkboxes_field_can_be_set_to_save_unchecked_values() 70 | { 71 | $field = Checkboxes::make('options')->saveUncheckedValues(); 72 | 73 | $this->assertEquals(['save_unchecked' => true], $field->meta()); 74 | } 75 | 76 | function test_checkboxes_field_can_be_set_to_display_unchecked_values_on_index() 77 | { 78 | $field = Checkboxes::make('options')->displayUncheckedValuesOnIndex(); 79 | 80 | $this->assertEquals(['display_unchecked_on_index' => true], $field->meta()); 81 | } 82 | 83 | function test_checkboxes_field_can_be_set_to_display_unchecked_values_on_detail() 84 | { 85 | $field = Checkboxes::make('options')->displayUncheckedValuesOnDetail(); 86 | 87 | $this->assertEquals(['display_unchecked_on_detail' => true], $field->meta()); 88 | } 89 | 90 | function test_checkboxes_field_can_be_set_to_display_options_in_many_columns() 91 | { 92 | $field = Checkboxes::make('options')->columns(); 93 | 94 | $this->assertEquals(['columns' => 1], $field->meta()); 95 | $this->assertEquals(['columns' => 4], $field->columns(4)->meta()); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /tests/Unit/CheckedOptionsForVueFormFieldTest.php: -------------------------------------------------------------------------------- 1 | options([ 13 | 'archery' => 'Archery', 14 | 'painting' => 'Painting', 15 | 'running' => 'Running', 16 | ]); 17 | } 18 | 19 | protected function numericKeysField() 20 | { 21 | return Checkboxes::make('Hobbies')->options([ 22 | 1 => 'One', 23 | 2 => 'Two', 24 | 3 => 'Three', 25 | ]); 26 | } 27 | 28 | protected function zeroIndexedField() 29 | { 30 | return Checkboxes::make('Hobbies')->options([ 31 | 0 => 'Zero', 32 | 1 => 'One', 33 | 2 => 'Two', 34 | 3 => 'Three', 35 | ]); 36 | } 37 | 38 | function test_field_value_when_empty() 39 | { 40 | $empty = '{"archery":false,"painting":false,"running":false}'; 41 | $this->assocField()->assertValue($empty, null); 42 | $this->assocField()->assertValue($empty, ''); 43 | $this->assocField()->assertValue($empty, []); 44 | 45 | $empty = '{"0":false,"1":false,"2":false,"3":false}'; 46 | $this->zeroIndexedField()->assertValue($empty, null); 47 | $this->zeroIndexedField()->assertValue($empty, ''); 48 | $this->zeroIndexedField()->assertValue($empty, []); 49 | 50 | $empty = '{"1":false,"2":false,"3":false}'; 51 | $this->numericKeysField()->assertValue($empty, null); 52 | $this->numericKeysField()->assertValue($empty, ''); 53 | $this->numericKeysField()->assertValue($empty, []); 54 | } 55 | 56 | function test_resolves_field_value_from_array() 57 | { 58 | $this->assocField()->assertValue( 59 | '{"archery":false,"painting":false,"running":true}', ['running' => true, 'painting' => false] 60 | ); 61 | 62 | $this->zeroIndexedField()->assertValue( 63 | '{"0":false,"1":true,"2":true,"3":false}', [1, 2] 64 | ); 65 | 66 | $this->numericKeysField()->assertValue( 67 | '{"1":true,"2":true,"3":false}', [1, 2] 68 | ); 69 | } 70 | 71 | function test_resolves_field_value_from_collection() 72 | { 73 | $this->assocField()->assertValue( 74 | '{"archery":false,"painting":true,"running":false}', collect(['painting' => true]) 75 | ); 76 | 77 | $this->zeroIndexedField()->assertValue( 78 | '{"0":false,"1":true,"2":true,"3":false}', collect([1, 2]) 79 | ); 80 | 81 | $this->numericKeysField()->assertValue( 82 | '{"1":true,"2":true,"3":false}', collect([1, 2]) 83 | ); 84 | } 85 | 86 | function test_resolves_field_value_from_nested_json_attribute() 87 | { 88 | $this->assocField()->assertValue( 89 | '{"archery":true,"painting":false,"running":false}', 90 | (object)['selected' => (object)['archery' => true]], 'hobbies->selected' 91 | ); 92 | 93 | $this->zeroIndexedField()->assertValue( 94 | '{"0":false,"1":true,"2":true,"3":false}', 95 | (object)['selected' => (object)[1, 2]], 'hobbies->selected' 96 | ); 97 | 98 | $this->numericKeysField()->assertValue( 99 | '{"1":true,"2":true,"3":false}', 100 | (object)['selected' => (object)[1, 2]], 'hobbies->selected' 101 | ); 102 | } 103 | 104 | function test_resolves_field_value_from_object() 105 | { 106 | $this->assocField()->assertValue( 107 | '{"archery":false,"painting":false,"running":true}', (object)['running' => true] 108 | ); 109 | 110 | $this->zeroIndexedField()->assertValue( 111 | '{"0":false,"1":true,"2":true,"3":false}', (object)[1, 2] 112 | ); 113 | 114 | $this->numericKeysField()->assertValue( 115 | '{"1":true,"2":true,"3":false}', (object)[1, 2] 116 | ); 117 | } 118 | 119 | function test_resolves_field_value_from_string() 120 | { 121 | $this->assocField()->assertValue( 122 | '{"archery":true,"painting":false,"running":true}', 'running,archery' 123 | ); 124 | 125 | $this->zeroIndexedField()->assertValue('{"0":true,"1":false,"2":true,"3":false}', '0,2'); 126 | 127 | $this->numericKeysField()->assertValue('{"1":true,"2":true,"3":false}', '1,2'); 128 | } 129 | 130 | function test_resolves_field_value_from_string_when_option_zero_is_checked() 131 | { 132 | // There shouldn't be a case where 0 is passed as an integer, but handle it anyway. 133 | $this->zeroIndexedField()->assertValue('{"0":true,"1":false,"2":false,"3":false}', 0); 134 | $this->zeroIndexedField()->assertValue('{"0":true,"1":false,"2":false,"3":false}', '0'); 135 | } 136 | 137 | function test_when_previous_options_have_been_removed() 138 | { 139 | $this->assocField()->assertValue('{"archery":true,"painting":false,"running":false}', 'removed,archery'); 140 | $this->assocField()->assertValue('{"archery":true,"painting":false,"running":false}', ['removed' => true, 'archery' => true, 'running' => false]); 141 | $this->numericKeysField()->assertValue('{"1":true,"2":true,"3":false}', '1,2,6,5'); 142 | $this->zeroIndexedField()->assertValue('{"0":true,"1":false,"2":false,"3":true}', '0,3,7'); 143 | } 144 | 145 | } 146 | -------------------------------------------------------------------------------- /tests/Unit/SaveFormatsTest.php: -------------------------------------------------------------------------------- 1 | options([ 15 | 'archery' => 'Archery', 16 | 'painting' => 'Painting', 17 | 'running' => 'Running', 18 | ]); 19 | } 20 | 21 | protected function numericKeysField() 22 | { 23 | return Checkboxes::make('Hobbies')->options([ 24 | 1 => 'One', 25 | 2 => 'Two', 26 | 3 => 'Three', 27 | ]); 28 | } 29 | 30 | protected function zeroIndexedField() 31 | { 32 | return Checkboxes::make('Hobbies')->options([ 33 | 0 => 'Zero', 34 | 1 => 'One', 35 | 2 => 'Two', 36 | 3 => 'Three', 37 | ]); 38 | } 39 | 40 | function test_default_to_save_only_unchecked() 41 | { 42 | $this->zeroIndexedField()->fill((new NovaRequest)->merge([ 43 | 'hobbies' => '{"0":true,"1":false,"2":false,"3":false}' 44 | ]), $zero = new stdClass); 45 | 46 | $this->assocField()->fill((new NovaRequest)->merge([ 47 | 'hobbies' => '{"archery":true,"painting":false,"running":true}' 48 | ]), $assoc = new stdClass); 49 | 50 | $this->numericKeysField()->fill((new NovaRequest)->merge([ 51 | 'hobbies' => '{"1":true,"2":true,"3":false}' 52 | ]), $numeric = new stdClass); 53 | 54 | $this->assertSame(['0'], $zero->hobbies); 55 | $this->assertSame(['archery', 'running'], $assoc->hobbies); 56 | $this->assertSame(['1','2'], $numeric->hobbies); 57 | } 58 | 59 | function test_default_save_when_nothing_is_checked() 60 | { 61 | $this->zeroIndexedField()->fill((new NovaRequest)->merge([ 62 | 'hobbies' => '{"0":false,"1":false,"2":false,"3":false}' 63 | ]), $zero = new stdClass); 64 | 65 | $this->assocField()->fill((new NovaRequest)->merge([ 66 | 'hobbies' => '{"archery":false,"painting":false,"running":false}' 67 | ]), $assoc = new stdClass); 68 | 69 | $this->numericKeysField()->fill((new NovaRequest)->merge([ 70 | 'hobbies' => '{"1":false,"2":false,"3":false}' 71 | ]), $numeric = new stdClass); 72 | 73 | $this->assertSame([], $zero->hobbies); 74 | $this->assertSame([], $assoc->hobbies); 75 | $this->assertSame([], $numeric->hobbies); 76 | } 77 | 78 | function test_save_as_string() 79 | { 80 | $this->zeroIndexedField()->saveAsString()->fill((new NovaRequest)->merge([ 81 | 'hobbies' => '{"0":true,"1":false,"2":false,"3":false}' 82 | ]), $zero = new stdClass); 83 | 84 | $this->assocField()->saveAsString()->fill((new NovaRequest)->merge([ 85 | 'hobbies' => '{"archery":false,"painting":true,"running":true}' 86 | ]), $assoc = new stdClass); 87 | 88 | $this->numericKeysField()->saveAsString()->fill((new NovaRequest)->merge([ 89 | 'hobbies' => '{"1":true,"2":true,"3":false}' 90 | ]), $numeric = new stdClass); 91 | 92 | $this->assertSame('0', $zero->hobbies); 93 | $this->assertSame('painting,running', $assoc->hobbies); 94 | $this->assertSame('1,2', $numeric->hobbies); 95 | } 96 | 97 | function test_save_as_string_when_nothing_is_checked_even_if_save_unchecked_values_is_on() 98 | { 99 | $this->zeroIndexedField()->saveAsString()->saveUncheckedValues()->fill((new NovaRequest)->merge([ 100 | 'hobbies' => '{"0":false,"1":false,"2":false,"3":false}' 101 | ]), $zero = new stdClass); 102 | 103 | $this->assocField()->saveAsString()->saveUncheckedValues()->fill((new NovaRequest)->merge([ 104 | 'hobbies' => '{"archery":false,"painting":false,"running":false}' 105 | ]), $assoc = new stdClass); 106 | 107 | $this->numericKeysField()->saveAsString()->saveUncheckedValues()->fill((new NovaRequest)->merge([ 108 | 'hobbies' => '{"1":false,"2":false,"3":false}' 109 | ]), $numeric = new stdClass); 110 | 111 | $this->assertSame('', $zero->hobbies); 112 | $this->assertSame('', $assoc->hobbies); 113 | $this->assertSame('', $numeric->hobbies); 114 | } 115 | 116 | function test_save_unchecked_values() 117 | { 118 | $this->zeroIndexedField()->saveUncheckedValues()->fill((new NovaRequest)->merge([ 119 | 'hobbies' => '{"0":true,"1":false,"2":false,"3":false}' 120 | ]), $zero = new stdClass); 121 | 122 | $this->assocField()->saveUncheckedValues()->fill((new NovaRequest)->merge([ 123 | 'hobbies' => '{"archery":true,"painting":false,"running":true}' 124 | ]), $assoc = new stdClass); 125 | 126 | $this->numericKeysField()->saveUncheckedValues()->fill((new NovaRequest)->merge([ 127 | 'hobbies' => '{"1":false,"2":false,"3":false}' 128 | ]), $numeric = new stdClass); 129 | 130 | 131 | $this->assertEquals((object)[true, false, false, false], $zero->hobbies); 132 | $this->assertEquals((object)['archery' => true, 'painting' => false, 'running' => true], $assoc->hobbies); 133 | $this->assertEquals((object)['1' => false, '2' => false, '3' => false], $numeric->hobbies); 134 | } 135 | 136 | } 137 | -------------------------------------------------------------------------------- /webpack.mix.js: -------------------------------------------------------------------------------- 1 | let mix = require('laravel-mix') 2 | 3 | mix.js('resources/js/field.js', 'dist/js') 4 | .sass('resources/sass/field.scss', 'dist/css') 5 | .webpackConfig({ 6 | resolve: { 7 | symlinks: false 8 | } 9 | }) 10 | --------------------------------------------------------------------------------