PluginProbe ʕ •ᴥ•ʔ
JetFormBuilder — Dynamic Blocks Form Builder / 3.1.1
JetFormBuilder — Dynamic Blocks Form Builder v3.1.1
3.6.3.1 3.6.3 3.6.2.2 3.6.2.1 3.6.2 3.6.1.1 3.6.1 3.6.0.1 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.3.0 1.3.1 1.3.2 1.3.3 1.4.0 1.4.1 1.4.2 1.4.3 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.1.0 2.1.1 2.1.10 2.1.11 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 3.0.0 3.0.0.1 3.0.0.2 3.0.0.3 3.0.1 3.0.1.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.0.1 3.1.1 3.1.2 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.1.8 3.1.9 3.2.0 3.2.1 3.2.2 3.2.3 3.3.0 3.3.1 3.3.2 3.3.3 3.3.3.1 3.3.4 3.3.4.1 3.3.4.2 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.4.5 3.4.5.1 3.4.5.2 3.4.6 3.4.7 3.4.7.1 3.5.0 3.5.1 3.5.1.1 3.5.1.2 3.5.2 3.5.2.1 3.5.3 3.5.4 3.5.5 3.5.6 3.5.6.1 3.5.6.2 3.5.6.3 3.6.0
jetformbuilder / assets / src / frontend / main / Observable.js
jetformbuilder / assets / src / frontend / main Last commit date
attrs 2 years ago calc.module 2 years ago html.macro 2 years ago init 2 years ago inputs 2 years ago reactive 2 years ago reporting 2 years ago signals 2 years ago submit 2 years ago Observable.js 2 years ago functions.js 2 years ago main.js 2 years ago supports.js 2 years ago
Observable.js
269 lines
1 import { createInput, populateInputs } from './inputs/functions';
2 import FormSubmit from './submit/FormSubmit';
3 import {
4 iterateJfbComments,
5 observeComment,
6 observeMacroAttr,
7 queryByAttrValue,
8 } from './html.macro/functions';
9 import { validateInputsAll } from './reporting/functions';
10 import ReportingContext from './reporting/ReportingContext';
11
12 const {
13 doAction,
14 } = JetPlugins.hooks;
15
16 function Observable( parent = null ) {
17 this.parent = parent;
18 this.dataInputs = {};
19 this.form = null;
20 this.multistep = null;
21 this.rootNode = null;
22 this.isObserved = false;
23
24 /**
25 * @since 3.0.1
26 *
27 * @type {ReportingContext}
28 */
29 this.context = this.parent ? null : new ReportingContext( this );
30 }
31
32 Observable.prototype = {
33 /**
34 * @type {RepeaterData|null}
35 */
36 parent: null,
37 /**
38 * {
39 * [field_name]: {InputData}
40 * }
41 */
42 dataInputs: {},
43
44 /**
45 * @type {FormSubmit}
46 */
47 form: null,
48
49 /**
50 * @type {MultiStepState}
51 */
52 multistep: null,
53
54 /**
55 * @type {HTMLElement|HTMLFormElement}
56 */
57 rootNode: null,
58 isObserved: false,
59 observe: function ( root = null ) {
60 if ( this.isObserved ) {
61 return;
62 }
63 if ( null !== root ) {
64 this.rootNode = root;
65 }
66 this.isObserved = true;
67
68 doAction( 'jet.fb.observe.before', this );
69
70 this.initSubmitHandler();
71
72 /**
73 * Initialize dataInputs with fields.
74 * Without values
75 */
76 this.initFields();
77
78 /**
79 * Setup fields values and make them reactive
80 */
81 this.makeReactiveProxy();
82
83 this.initMacros();
84
85 this.initActionButtons();
86
87 doAction( 'jet.fb.observe.after', this );
88 },
89
90 initFields: function () {
91 for ( const formElement of this.rootNode.querySelectorAll(
92 '[data-jfb-sync]',
93 ) ) {
94 this.pushInput( formElement );
95 }
96 },
97
98 initMacros: function () {
99 for (
100 const comment of iterateJfbComments( this.rootNode )
101 ) {
102 observeComment( comment, this );
103 }
104
105 const nodes = queryByAttrValue( this.rootNode, 'JFB_FIELD::' );
106
107 const { replaceAttrs = [] } = window.JetFormBuilderSettings;
108
109 for ( const node of nodes ) {
110 for ( const replaceAttr of replaceAttrs ) {
111 observeMacroAttr( node, replaceAttr, this );
112 }
113 }
114 },
115
116 initSubmitHandler: function () {
117 // check is current object related for global form element
118 if ( this.parent ) {
119 return;
120 }
121
122 this.form = new FormSubmit( this );
123 },
124
125 initActionButtons: function () {
126 if ( this.parent ) {
127 return;
128 }
129 for ( const button of this.rootNode.querySelectorAll(
130 '.jet-form-builder__button-switch-state',
131 ) ) {
132 let states;
133 try {
134 states = JSON.parse( button.dataset.switchOn );
135 }
136 catch ( error ) {
137 continue;
138 }
139
140 button.addEventListener( 'click', () => {
141 this.getState().value.current = states;
142 } );
143 }
144 },
145
146 /**
147 * @return {Promise<Promise<never>|Promise<void>>}
148 */
149 inputsAreValid: async function () {
150 const invalid = await validateInputsAll(
151 populateInputs( this.getInputs() ),
152 );
153
154 return Boolean( invalid.length )
155 ? Promise.reject( invalid )
156 : Promise.resolve();
157 },
158
159 watch: function ( fieldName, callable ) {
160 const input = this.getInput( fieldName );
161
162 if ( input ) {
163 return input.watch( callable );
164 }
165
166 throw new Error(
167 `dataInputs in Observable don\'t have ${ fieldName } field`,
168 );
169 },
170
171 /**
172 * @param node {Element}
173 * @param replace {Boolean}
174 */
175 observeInput: function ( node, replace = false ) {
176 const input = this.pushInput( node, replace );
177
178 input.makeReactive();
179
180 doAction( 'jet.fb.observe.input.manual', input );
181 },
182
183 makeReactiveProxy: function () {
184 for ( const current of this.getInputs() ) {
185 current.makeReactive();
186 }
187 },
188
189 /**
190 * @param node {Element}
191 * @param replace {Boolean}
192 */
193 pushInput: function ( node, replace = false ) {
194 // prevent saving inputs from preset repeater items in root object
195 // those inputs would saved in ObservableRow object
196
197 if ( !this.parent &&
198 node.parentElement.closest( '.jet-form-builder-repeater' )
199 ) {
200 return;
201 }
202
203 const inputData = createInput( node, this );
204 const findInput = this.dataInputs[ inputData.getName() ] ?? false;
205
206 if ( false === findInput || replace ) {
207 this.dataInputs[ inputData.getName() ] = inputData;
208
209 return inputData;
210 }
211
212 findInput.merge( inputData );
213
214 return findInput;
215 },
216
217 /**
218 * @returns {array<InputData>}
219 */
220 getInputs: function () {
221 return Object.values( this.dataInputs );
222 },
223
224 /**
225 * @returns {null|RenderStateData|InputData}
226 */
227 getState: function () {
228 return this.getInput( '_jfb_current_render_states' );
229 },
230
231 /**
232 * @param fieldName
233 * @returns {null|InputData}
234 */
235 getInput: function ( fieldName ) {
236 if ( this.dataInputs.hasOwnProperty( fieldName ) ) {
237 return this.dataInputs[ fieldName ];
238 }
239 const root = this.parent?.root ?? null;
240
241 if ( !root ) {
242 return null;
243 }
244
245 if ( root.dataInputs.hasOwnProperty( fieldName ) ) {
246 return root.dataInputs[ fieldName ];
247 }
248
249 return null;
250 },
251 getSubmit: function () {
252 return this.form ? this.form : this.parent.root.form;
253 },
254 getContext: function () {
255 return this.context ?? this.parent.root.context;
256 },
257 /**
258 * @see https://github.com/Crocoblock/issues-tracker/issues/2711
259 *
260 * @since 3.0.8
261 */
262 remove: function () {
263 for ( const input of this.getInputs() ) {
264 input.onRemove();
265 }
266 },
267 };
268
269 export default Observable;