wip
This commit is contained in:
10
nova-components/DynamicFields/.gitignore
vendored
Normal file
10
nova-components/DynamicFields/.gitignore
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
/.idea
|
||||
/vendor
|
||||
/node_modules
|
||||
package-lock.json
|
||||
composer.phar
|
||||
composer.lock
|
||||
phpunit.xml
|
||||
.phpunit.result.cache
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
29
nova-components/DynamicFields/composer.json
Normal file
29
nova-components/DynamicFields/composer.json
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "nurmuhammet/dynamic-fields",
|
||||
"description": "A Laravel Nova field.",
|
||||
"keywords": [
|
||||
"laravel",
|
||||
"nova"
|
||||
],
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"php": "^7.3|^8.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Nurmuhammet\\DynamicFields\\": "src/"
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Nurmuhammet\\DynamicFields\\FieldServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"sort-packages": true
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true
|
||||
}
|
||||
1
nova-components/DynamicFields/dist/css/field.css
vendored
Normal file
1
nova-components/DynamicFields/dist/css/field.css
vendored
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
2
nova-components/DynamicFields/dist/js/field.js
vendored
Normal file
2
nova-components/DynamicFields/dist/js/field.js
vendored
Normal file
File diff suppressed because one or more lines are too long
23
nova-components/DynamicFields/dist/js/field.js.LICENSE.txt
vendored
Normal file
23
nova-components/DynamicFields/dist/js/field.js.LICENSE.txt
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
/*!
|
||||
* The buffer module from node.js, for the browser.
|
||||
*
|
||||
* @author Feross Aboukhadijeh <http://feross.org>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
/*!
|
||||
* vuex v4.1.0
|
||||
* (c) 2022 Evan You
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */
|
||||
|
||||
/**
|
||||
* @license
|
||||
* Lodash <https://lodash.com/>
|
||||
* Copyright OpenJS Foundation and other contributors <https://openjsf.org/>
|
||||
* Released under MIT license <https://lodash.com/license>
|
||||
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
|
||||
* Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
|
||||
*/
|
||||
4
nova-components/DynamicFields/dist/mix-manifest.json
vendored
Normal file
4
nova-components/DynamicFields/dist/mix-manifest.json
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"/js/field.js": "/js/field.js",
|
||||
"/css/field.css": "/css/field.css"
|
||||
}
|
||||
40
nova-components/DynamicFields/nova.mix.js
Normal file
40
nova-components/DynamicFields/nova.mix.js
Normal file
@@ -0,0 +1,40 @@
|
||||
const mix = require('laravel-mix')
|
||||
const webpack = require('webpack')
|
||||
const path = require('path')
|
||||
|
||||
class NovaExtension {
|
||||
name() {
|
||||
return 'nova-extension'
|
||||
}
|
||||
|
||||
register(name) {
|
||||
this.name = name
|
||||
}
|
||||
|
||||
webpackPlugins() {
|
||||
return new webpack.ProvidePlugin({
|
||||
_: 'lodash',
|
||||
Errors: 'form-backend-validation',
|
||||
})
|
||||
}
|
||||
|
||||
webpackConfig(webpackConfig) {
|
||||
webpackConfig.externals = {
|
||||
vue: 'Vue',
|
||||
}
|
||||
|
||||
webpackConfig.resolve.alias = {
|
||||
...(webpackConfig.resolve.alias || {}),
|
||||
'laravel-nova': path.join(
|
||||
__dirname,
|
||||
'../../vendor/laravel/nova/resources/js/mixins/packages.js'
|
||||
),
|
||||
}
|
||||
|
||||
webpackConfig.output = {
|
||||
uniqueName: this.name,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mix.extend('nova', new NovaExtension())
|
||||
22
nova-components/DynamicFields/package.json
Normal file
22
nova-components/DynamicFields/package.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "npm run development",
|
||||
"development": "mix",
|
||||
"watch": "mix watch",
|
||||
"watch-poll": "mix watch -- --watch-options-poll=1000",
|
||||
"hot": "mix watch --hot",
|
||||
"prod": "npm run production",
|
||||
"production": "mix --production",
|
||||
"nova:install": "npm --prefix='../../vendor/laravel/nova' ci"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/compiler-sfc": "^3.2.22",
|
||||
"form-backend-validation": "^2.3.3",
|
||||
"laravel-mix": "^6.0.41",
|
||||
"lodash": "^4.17.21",
|
||||
"postcss": "^8.3.11",
|
||||
"vue-loader": "^16.8.3"
|
||||
},
|
||||
"dependencies": {}
|
||||
}
|
||||
1
nova-components/DynamicFields/postcss.config.js
Normal file
1
nova-components/DynamicFields/postcss.config.js
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = {}
|
||||
1
nova-components/DynamicFields/resources/css/field.css
Normal file
1
nova-components/DynamicFields/resources/css/field.css
Normal file
@@ -0,0 +1 @@
|
||||
/* Nova Field CSS */
|
||||
@@ -0,0 +1,107 @@
|
||||
<template>
|
||||
<div>
|
||||
<div v-for="userField in userFields">
|
||||
<DefaultField :field="currentFieldFor(userField.name)" :fieldName="userField.label" :errors="errors">
|
||||
<template #field>
|
||||
<template v-if="userField.type == 'select'">
|
||||
<select
|
||||
:id="userField.name"
|
||||
v-model="values[userField.name]"
|
||||
class="w-full block form-control form-input form-control-bordered"
|
||||
disabled
|
||||
>
|
||||
<option value="">Saýla</option>
|
||||
<option v-for="option in userField.options" :value="option.value">
|
||||
{{ option.label }}
|
||||
</option>
|
||||
</select>
|
||||
</template>
|
||||
<template v-else>
|
||||
<input
|
||||
:id="userField.name"
|
||||
:type="userField.type"
|
||||
class="w-full form-control form-input form-control-bordered"
|
||||
:class="errorClasses"
|
||||
v-model="values[userField.name]"
|
||||
:placeholder="userField.placeholder"
|
||||
disabled
|
||||
/>
|
||||
</template>
|
||||
|
||||
<p v-if="hasError" class="my-2 text-danger">
|
||||
{{ firstError }}
|
||||
</p>
|
||||
</template>
|
||||
</DefaultField>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { DependentFormField, HandlesValidationErrors } from 'laravel-nova'
|
||||
import { capitalize } from 'lodash'
|
||||
|
||||
export default {
|
||||
mixins: [DependentFormField, HandlesValidationErrors],
|
||||
|
||||
props: ['resourceName', 'resourceId', 'field'],
|
||||
|
||||
data() {
|
||||
return {
|
||||
userFields: [],
|
||||
values: [],
|
||||
fillWithArrayName: '',
|
||||
value: '',
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
/*
|
||||
* Set the initial, internal value for the field.
|
||||
*/
|
||||
setInitialValue() {
|
||||
this.value = this.field.value || ''
|
||||
},
|
||||
|
||||
setValueFor(name, value) {
|
||||
this.values[name] = value
|
||||
},
|
||||
|
||||
currentFieldFor(name) {
|
||||
const new_field = JSON.parse(JSON.stringify(this.currentField))
|
||||
new_field.name = capitalize(name)
|
||||
|
||||
let userField = this.userFields.filter(field => field.name == name)[0]
|
||||
|
||||
if (userField['placeholder']) {
|
||||
new_field.placeholder = userField['placeholder']
|
||||
}
|
||||
|
||||
return new_field
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
placeholder() {
|
||||
return this.__('Choose an option')
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.fillWithArrayName = this.field.fillWithArrayName;
|
||||
|
||||
this.userFields = this.field.fields.map(field => {
|
||||
this.values[field.name.toLowerCase()] = field.default ? field.default : ''
|
||||
|
||||
return {
|
||||
type: field.type,
|
||||
name: field.name.toLowerCase(),
|
||||
label: field.label ? capitalize(field.label) : capitalize(field.name),
|
||||
default: field.default,
|
||||
placeholder: field.placeholder,
|
||||
options: field.options
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,139 @@
|
||||
<template>
|
||||
<div>
|
||||
<div v-for="userField in userFields">
|
||||
<DefaultField :field="currentFieldFor(userField.name)" :fieldName="userField.label" :errors="errors">
|
||||
<template #field>
|
||||
<template v-if="userField.type == 'select'">
|
||||
<select
|
||||
:id="userField.name"
|
||||
v-model="values[userField.name]"
|
||||
:required="userField.required"
|
||||
class="w-full block form-control form-input form-control-bordered"
|
||||
>
|
||||
<option value="">Saýla</option>
|
||||
<option v-for="option in userField.options" :value="option.value">
|
||||
{{ option.label }}
|
||||
</option>
|
||||
</select>
|
||||
</template>
|
||||
<template v-else>
|
||||
<input
|
||||
:id="userField.name"
|
||||
:type="userField.type"
|
||||
class="w-full form-control form-input form-control-bordered"
|
||||
:class="errorClasses"
|
||||
v-model="values[userField.name]"
|
||||
:required="userField.required"
|
||||
:placeholder="userField.placeholder"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<p v-if="hasError" class="my-2 text-danger">
|
||||
{{ firstError }}
|
||||
</p>
|
||||
</template>
|
||||
</DefaultField>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<script>
|
||||
import { DependentFormField, HandlesValidationErrors } from 'laravel-nova'
|
||||
import { capitalize } from 'lodash'
|
||||
|
||||
export default {
|
||||
mixins: [DependentFormField, HandlesValidationErrors],
|
||||
|
||||
props: ['resourceName', 'resourceId', 'field'],
|
||||
|
||||
data() {
|
||||
return {
|
||||
userFields: [],
|
||||
values: [],
|
||||
fillWithArrayName: '',
|
||||
value: '',
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
/*
|
||||
* Set the initial, internal value for the field.
|
||||
*/
|
||||
setInitialValue() {
|
||||
this.value = this.field.value || ''
|
||||
},
|
||||
|
||||
/**
|
||||
* Fill the given FormData object with the field's internal value.
|
||||
*/
|
||||
fill(formData) {
|
||||
if (this.fillWithArrayName) {
|
||||
this.userFields.forEach(field => {
|
||||
formData.append(this.fillWithArrayName + '[' + field['name'] + ']', this.values[field['name']])
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
this.userFields.forEach(field => {
|
||||
formData.append(field['name'], this.values[field['name']])
|
||||
})
|
||||
},
|
||||
|
||||
setValueFor(name, value) {
|
||||
this.values[name] = value
|
||||
},
|
||||
|
||||
currentFieldFor(name) {
|
||||
const new_field = JSON.parse(JSON.stringify(this.currentField))
|
||||
new_field.name = capitalize(name)
|
||||
|
||||
let userField = this.userFields.filter(field => field.name == name)[0]
|
||||
|
||||
if (userField['placeholder']) {
|
||||
new_field.placeholder = userField['placeholder']
|
||||
}
|
||||
|
||||
if (userField['required']) {
|
||||
new_field.required = userField['required']
|
||||
}
|
||||
|
||||
return new_field
|
||||
},
|
||||
|
||||
onSyncedField() {
|
||||
this.userFields = this.formatFields()
|
||||
},
|
||||
|
||||
formatFields() {
|
||||
return this.currentField.fields.map(field => {
|
||||
this.values[field.name.toLowerCase()] = this.values[field.name.toLowerCase()] || (field.default || '')
|
||||
|
||||
return {
|
||||
type: field.type,
|
||||
name: field.name.toLowerCase(),
|
||||
label: field.label ? capitalize(field.label) : capitalize(field.name),
|
||||
default: field.default,
|
||||
required: field.required,
|
||||
placeholder: field.placeholder,
|
||||
options: field.options
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
placeholder() {
|
||||
return this.__('Choose an option')
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.fillWithArrayName = this.field.fillWithArrayName
|
||||
this.currentField.fields = this.currentField.fields || [];
|
||||
|
||||
this.userFields = this.formatFields()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
7
nova-components/DynamicFields/resources/js/field.js
Normal file
7
nova-components/DynamicFields/resources/js/field.js
Normal file
@@ -0,0 +1,7 @@
|
||||
import DetailField from './components/DetailField'
|
||||
import FormField from './components/FormField'
|
||||
|
||||
Nova.booting((app, store) => {
|
||||
app.component('detail-dynamic-fields', DetailField)
|
||||
app.component('form-dynamic-fields', FormField)
|
||||
})
|
||||
58
nova-components/DynamicFields/src/DynamicFields.php
Normal file
58
nova-components/DynamicFields/src/DynamicFields.php
Normal file
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace Nurmuhammet\DynamicFields;
|
||||
|
||||
use Laravel\Nova\Exceptions\NovaException;
|
||||
use Laravel\Nova\Fields\Field;
|
||||
use Laravel\Nova\Fields\SupportsDependentFields;
|
||||
|
||||
class DynamicFields extends Field
|
||||
{
|
||||
use SupportsDependentFields;
|
||||
|
||||
/**
|
||||
* The field's component.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $component = 'dynamic-fields';
|
||||
|
||||
/**
|
||||
* Specify that the element should be visible on the index view.
|
||||
*
|
||||
* @param (callable():bool)|bool $callback
|
||||
* @return $this
|
||||
*
|
||||
* @throws \Laravel\Nova\Exceptions\NovaException
|
||||
*/
|
||||
public function showOnIndex($callback = true)
|
||||
{
|
||||
throw NovaException::helperNotSupported(__FUNCTION__, static::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fields to be rendered
|
||||
*
|
||||
* @param array $hues
|
||||
* @return $this
|
||||
*/
|
||||
public function fields(array|callable $fields)
|
||||
{
|
||||
$fieldsForFrontEnd = $fields;
|
||||
if (is_callable($fields)) {
|
||||
$fieldsForFrontEnd = call_user_func($fields);
|
||||
}
|
||||
|
||||
return $this->withMeta(['fields' => $fieldsForFrontEnd]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill with array name
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function fillWithArrayName(string $requestArrayName = '')
|
||||
{
|
||||
return $this->withMeta(['fillWithArrayName' => $requestArrayName]);
|
||||
}
|
||||
}
|
||||
33
nova-components/DynamicFields/src/FieldServiceProvider.php
Normal file
33
nova-components/DynamicFields/src/FieldServiceProvider.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Nurmuhammet\DynamicFields;
|
||||
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Laravel\Nova\Events\ServingNova;
|
||||
use Laravel\Nova\Nova;
|
||||
|
||||
class FieldServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Bootstrap any application services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
Nova::serving(function (ServingNova $event) {
|
||||
Nova::script('dynamic-fields', __DIR__.'/../dist/js/field.js');
|
||||
Nova::style('dynamic-fields', __DIR__.'/../dist/css/field.css');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Register any application services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
10
nova-components/DynamicFields/webpack.mix.js
Normal file
10
nova-components/DynamicFields/webpack.mix.js
Normal file
@@ -0,0 +1,10 @@
|
||||
let mix = require('laravel-mix')
|
||||
|
||||
require('./nova.mix')
|
||||
|
||||
mix
|
||||
.setPublicPath('dist')
|
||||
.js('resources/js/field.js', 'js')
|
||||
.vue({ version: 3 })
|
||||
.css('resources/css/field.css', 'css')
|
||||
.nova('nurmuhammet/dynamic-fields')
|
||||
Reference in New Issue
Block a user