Skip to content

Commit 34ea5f4

Browse files
committed
Add basic functionality
1 parent 56239ce commit 34ea5f4

File tree

12 files changed

+295
-0
lines changed

12 files changed

+295
-0
lines changed

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/vendor
2+
/node_modules
3+
package-lock.json
4+
composer.lock
5+
phpunit.xml
6+
.phpunit.result.cache

composer.json

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"name": "idf/nova-unlayer-field",
3+
"description": "A Laravel Nova field for Unlayer to compose emails and landing pages",
4+
"keywords": [
5+
"laravel",
6+
"nova"
7+
],
8+
"license": "MIT",
9+
"require": {
10+
"php": ">=7.1.0"
11+
},
12+
"autoload": {
13+
"psr-4": {
14+
"IDF\\NovaUnlayerField\\": "src/"
15+
}
16+
},
17+
"extra": {
18+
"laravel": {
19+
"providers": [
20+
"IDF\\NovaUnlayerField\\ServiceProvider"
21+
]
22+
}
23+
},
24+
"config": {
25+
"sort-packages": true
26+
},
27+
"minimum-stability": "dev",
28+
"prefer-stable": true
29+
}

dist/js/field.js

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/mix-manifest.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"/js/field.js": "/js/field.js"
3+
}

package.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"private": false,
3+
"scripts": {
4+
"dev": "npm run development",
5+
"development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
6+
"watch": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
7+
"watch-poll": "npm run watch -- --watch-poll",
8+
"hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
9+
"prod": "npm run production",
10+
"production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
11+
},
12+
"devDependencies": {
13+
"cross-env": "^5.0.0",
14+
"laravel-mix": "^1.0",
15+
"laravel-nova": "^1.0"
16+
},
17+
"dependencies": {
18+
"vue": "^2.5.0"
19+
}
20+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<template>
2+
<panel-item :field="field">
3+
<template slot="value">
4+
<div class="overflow-hidden">
5+
<code>{{ field.value }}</code>
6+
</div>
7+
</template>
8+
</panel-item>
9+
</template>
10+
11+
<script>
12+
export default {
13+
props: ['resource', 'resourceName', 'resourceId', 'field'],
14+
}
15+
</script>
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
<template>
2+
<default-field :field="field" :errors="errors">
3+
<template slot="field">
4+
<div :id=containerId :style="{height: field.height || '800px'}"></div>
5+
<p v-if="hasError" class="my-2 text-danger">
6+
{{ firstError }}
7+
</p>
8+
</template>
9+
</default-field>
10+
</template>
11+
12+
<script>
13+
import { FormField, HandlesValidationErrors } from 'laravel-nova'
14+
15+
export default {
16+
mixins: [FormField, HandlesValidationErrors],
17+
18+
props: ['resourceName', 'resourceId', 'field'],
19+
20+
created() {
21+
this.injectUnlayerScript(this.initEditor);
22+
},
23+
24+
computed: {
25+
containerId: function () {
26+
return `${this.field.attribute}--editorContainer`;
27+
}
28+
},
29+
30+
methods: {
31+
/*
32+
* Set the initial, internal value for the field.
33+
*/
34+
setInitialValue() {
35+
this.value = JSON.parse(this.field.value) || {};
36+
},
37+
38+
/**
39+
* Fill the given FormData object with the field's internal value.
40+
* @property {FormData} formData
41+
*/
42+
fill(formData) {
43+
formData.append(this.field.attribute, JSON.stringify(this.value));
44+
formData.append(`${this.field.attribute}_html`, this.finalHtml);
45+
},
46+
47+
/**
48+
* Update the field's internal value.
49+
*/
50+
handleChange(value) {
51+
this.value = value
52+
},
53+
54+
/**
55+
* @param {Function} onLoadCallback
56+
*/
57+
injectUnlayerScript(onLoadCallback) {
58+
const unlayerScript = document.createElement('script');
59+
unlayerScript.setAttribute('src', '//editor.unlayer.com/embed.js');
60+
unlayerScript.onload = onLoadCallback;
61+
document.head.appendChild(unlayerScript);
62+
},
63+
initEditor() {
64+
const unlayerConfig = this.field.config;
65+
unlayerConfig.id = this.containerId;
66+
const editExistDesign = this.value && Object.keys(this.value).length;
67+
if (editExistDesign && unlayerConfig.templateId) {
68+
this.templateId = unlayerConfig.templateId;
69+
delete unlayerConfig.templateId;
70+
}
71+
72+
window.unlayer.init(unlayerConfig);
73+
74+
if (editExistDesign) {
75+
window.unlayer.loadDesign(this.value);
76+
}
77+
78+
window.unlayer.addEventListener('design:loaded', this.designLoaded);
79+
window.unlayer.addEventListener('design:updated', this.designUpdated);
80+
},
81+
82+
/**
83+
* @param {{design: Object}} loadedDesign
84+
*/
85+
designLoaded(loadedDesign) {
86+
window.unlayer.exportHtml((editorData) => {
87+
this.finalHtml = editorData.html;
88+
this.value = editorData.design;
89+
});
90+
},
91+
92+
/**
93+
* @param {{item: Object, type: string}} changeLog
94+
*/
95+
designUpdated(changeLog) {
96+
window.unlayer.exportHtml((editorData) => {
97+
this.finalHtml = editorData.html;
98+
this.value = editorData.design;
99+
});
100+
},
101+
},
102+
}
103+
</script>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<template>
2+
<code>{{ field.value }}</code>
3+
</template>
4+
5+
<script>
6+
export default {
7+
props: ['resourceName', 'field'],
8+
}
9+
</script>

resources/js/field.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Nova.booting((Vue, router, store) => {
2+
Vue.component('index-nova-unlayer-field', require('./components/IndexField'))
3+
Vue.component('detail-nova-unlayer-field', require('./components/DetailField'))
4+
Vue.component('form-nova-unlayer-field', require('./components/FormField'))
5+
})

src/ServiceProvider.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace Idf\NovaUnlayerField;
4+
5+
use Illuminate\Support\ServiceProvider as BasicServiceProvider;
6+
use Laravel\Nova\Nova;
7+
8+
final class ServiceProvider extends BasicServiceProvider
9+
{
10+
/** @inheritDoc */
11+
public function boot(): void
12+
{
13+
Nova::serving(function () {
14+
Nova::script('nova-unlayer-field', __DIR__.'/../dist/js/field.js');
15+
});
16+
}
17+
}

0 commit comments

Comments
 (0)