PluginProbe
FV Player 8 / 8.1
FV Player 8 v8.1
trunk 8.0.18 8.0.19 8.0.20 8.0.21 8.0.25 8.0.27 8.1 8.1.3
fv-player / blocks / index.js

index.js in FV Player 8 8.1, at blocks/index.js

399 lines 14.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { __ } from '@wordpress/i18n';
2 import ServerSideRender from '@wordpress/server-side-render';
3 import { createElement, RawHTML, useEffect, useState } from '@wordpress/element';
4 import { registerBlockType } from '@wordpress/blocks';
5 import { InspectorControls, MediaUpload, MediaUploadCheck, URLPopover } from '@wordpress/block-editor';
6 import { SVG, Path, Panel, PanelBody, TextControl, Button, PanelRow } from '@wordpress/components';
7
8 registerBlockType( 'fv-player-gutenberg/basic', {
9 icon: {
10 foreground: '#C20B33',
11 src: createElement(
12 SVG, {
13 viewBox: "0 0 24 24"
14 }, createElement(Path, {
15 d: "M21.8 8s-.195-1.377-.795-1.984c-.76-.797-1.613-.8-2.004-.847-2.798-.203-6.996-.203-6.996-.203h-.01s-4.197 0-6.996.202c-.39.046-1.242.05-2.003.846C2.395 6.623 2.2 8 2.2 8S2 9.62 2 11.24v1.517c0 1.618.2 3.237.2 3.237s.195 1.378.795 1.985c.76.797 1.76.77 2.205.855 1.6.153 6.8.2 6.8.2s4.203-.005 7-.208c.392-.047 1.244-.05 2.005-.847.6-.607.795-1.985.795-1.985s.2-1.618.2-3.237v-1.517C22 9.62 21.8 8 21.8 8zM9.935 14.595v-5.62l5.403 2.82-5.403 2.8z"
16 })
17 )
18 },
19 title: __( 'FV Player', 'fv-player-gutenberg' ),
20 description: __( 'Embed a video from your Media Library or one of your video hosting services.', 'fv-player-gutenberg' ),
21 category: 'media',
22 keywords: ['fv player', 'player', 'fv', 'flowplayer', 'freedomplayer', 'video', 'embed', 'media', 'stream'],
23 supports: {
24 align: true,
25 },
26 attributes: {
27 src: {
28 type: 'string',
29 default: ''
30 },
31 splash: {
32 type: 'string',
33 default: ''
34 },
35 timeline_previews: {
36 type: 'string',
37 default: ''
38 },
39 hls_hlskey: {
40 type: 'string',
41 default: ''
42 },
43 title: {
44 type: 'string',
45 default: ''
46 },
47 shortcodeContent: {
48 type: 'string',
49 default: '',
50 source: 'text'
51 },
52 player_id: {
53 type: 'string',
54 default: '0',
55 },
56 splash_attachment_id: {
57 type: 'string',
58 default: '0',
59 },
60 forceUpdate: {
61 type: 'string',
62 default: '0',
63 }
64 },
65 edit: ({ isSelected ,attributes, setAttributes, context, clientId}) => {
66 const { src, splash, title, shortcodeContent, player_id, splash_attachment_id, timeline_previews, hls_hlskey } = attributes;
67
68 // interval
69 const [count, setCount] = useState(0);
70
71 // debounce
72 const [debouncedSrc, setDebouncedSrc] = useState(src);
73 const [debouncedTitle, setDebouncedTitle] = useState(title);
74 const [debouncedSplash, setDebouncedSplash] = useState(splash);
75 const [debouncedHlskey, setDebouncedHlskey] = useState(hls_hlskey);
76 const [debounceTimelinePreviews, setDebounceTimelinePreviews] = useState(timeline_previews);
77
78 // popover
79 const [URLPopoverIsOpen, setURLPopoverIsOpen] = useState(false);
80
81 // we need to handle first load
82 let firstLoad = true;
83 let firstInsert = false;
84
85 // debounce block ajax
86 useEffect(() => {
87 const timeoutId = setTimeout(() => {
88 if (debouncedSrc !== src || debouncedTitle !== title || debouncedSplash !== splash || debounceTimelinePreviews !== timeline_previews || debouncedHlskey !== hls_hlskey ) {
89 setDebouncedSrc(src);
90 setDebouncedTitle(title);
91 setDebouncedSplash(splash);
92 setDebouncedHlskey(hls_hlskey);
93 setDebounceTimelinePreviews(timeline_previews);
94 ajaxUpdateAttributes({ ...attributes });
95 }
96 }, 500);
97
98 return () => {
99 clearTimeout(timeoutId);
100 };
101 }, [src, title, splash, timeline_previews, hls_hlskey]);
102
103 // block interval to load player and resize
104 useEffect(() => {
105 const intervalId = setInterval(() => {
106 fv_player_load();
107 fv_flowplayer_safety_resize();
108 setCount(count + 1);
109 }, 1000);
110
111 return () => {
112 clearInterval(intervalId);
113 };
114 }, [count]);
115
116 // block is being loaded
117 useEffect(() => {
118 if (firstLoad && player_id > 0) {
119 firstLoad = false;
120 ajaxUpdateFromDB();
121 }
122 }, []);
123
124 // used shorctcode editor or media library
125 useEffect(() => {
126 if( isSelected && player_id > 0 && player_id != 'undefined' ) { // run only when block is selected
127 ajaxUpdateAttributes({ ...attributes });
128 }
129 }, [shortcodeContent, player_id, splash_attachment_id]);
130
131 const ajaxUpdateFromDB = (id = null) => {
132 console.log( 'FV Player Block: attributes_load', id ? id : player_id );
133
134 const data = new FormData();
135 data.append('action', 'fv_player_guttenberg_attributes_load');
136 data.append('player_id', id ? id : player_id);
137
138 // nonce is required for security
139 data.append('security', fv_player_gutenberg.nonce);
140
141 fetch(ajaxurl, {
142 method: 'POST',
143 body: data,
144 credentials: 'same-origin',
145 })
146 .then((response) => response.json())
147 .then((data) => {
148 if( data.src != 'undefined' && data.splash != 'undefined' && data.title != 'undefined' ) {
149 setAttributes({ splash: String(data.splash) });
150 setAttributes({ title: String(data.title) });
151 setAttributes({ src: String(data.src) });
152 setAttributes({ splash_attachment_id: String(data.splash_attachment_id) });
153 setAttributes({ hls_hlskey: String(data.hls_hlskey) });
154 setAttributes({ timeline_previews: String(data.timeline_previews) });
155 setAttributes({ forceUpdate: String(Math.random()) });
156 }
157 })
158 .catch((error) => {
159 console.error('Error:', error);
160 });
161 };
162
163 // handle ajax update of attributes
164 const ajaxUpdateAttributes = (newAttributes) => {
165 console.log( 'FV Player Block: attributes_save', player_id );
166
167 if( player_id == 'undefined' || player_id == 0 ) {
168 firstInsert = true;
169 }
170
171 const data = new FormData();
172 data.append('action', 'fv_player_guttenberg_attributes_save');
173 data.append('player_id', newAttributes.player_id);
174 data.append('src', newAttributes.src);
175 data.append('splash', newAttributes.splash);
176 data.append('title', newAttributes.title);
177 data.append('splash_attachment_id', newAttributes.splash_attachment_id);
178 data.append('hls_hlskey', newAttributes.hls_hlskey);
179 data.append('timeline_previews', newAttributes.timeline_previews);
180
181 // nonce is required for security
182 data.append('security', fv_player_gutenberg.nonce);
183
184 fetch(ajaxurl, {
185 method: 'POST',
186 body: data,
187 credentials: 'same-origin',
188 })
189 .then((response) => response.json())
190 .then((data) => {
191 if( data.shortcodeContent != 'undefined' && data.player_id != 'undefined' ) {
192 // update the shortcode content and player id
193 setAttributes({ shortcodeContent: String(data.shortcodeContent) });
194 setAttributes({ player_id: String(data.player_id) });
195 setAttributes({ forceUpdate: String(Math.random()) });
196
197 if( firstInsert ) {
198 ajaxUpdateFromDB(data.player_id);
199 firstInsert = false;
200 }
201
202 }
203 })
204 .catch((error) => {
205 console.error('Error:', error);
206 });
207 }
208
209 // show initial state when no player
210 if( player_id == 'undefined' || player_id == 0 ) {
211 return(
212 <div className="components-placeholder block-editor-media-placeholder is-large fv-player-editor-wrapper fv-player-gutenberg">
213 <div className="components-placeholder__label">
214 <svg viewBox="0 0 24 24" width="24" height="24" aria-hidden="true" focusable="false">
215 <path d="M21.8 8s-.195-1.377-.795-1.984c-.76-.797-1.613-.8-2.004-.847-2.798-.203-6.996-.203-6.996-.203h-.01s-4.197 0-6.996.202c-.39.046-1.242.05-2.003.846C2.395 6.623 2.2 8 2.2 8S2 9.62 2 11.24v1.517c0 1.618.2 3.237.2 3.237s.195 1.378.795 1.985c.76.797 1.76.77 2.205.855 1.6.153 6.8.2 6.8.2s4.203-.005 7-.208c.392-.047 1.244-.05 2.005-.847.6-.607.795-1.985.795-1.985s.2-1.618.2-3.237v-1.517C22 9.62 21.8 8 21.8 8zM9.935 14.595v-5.62l5.403 2.82-5.403 2.8z"></path>
216 </svg>
217 FV Player
218 </div>
219 <div className='components-placeholder__instructions'>{__('Select Media or Use FV Player Editor to see all the features.', 'fv-player-gutenberg')}</div>
220 <input className='fv-player-gutenberg-client-id' type="hidden" value={clientId} />
221 <input
222 className="attachement-shortcode fv-player-editor-field"
223 type="hidden"
224 value=""
225 />
226 <div className="components-placeholder__fieldset">
227 <Button
228 className='is-primary fv-player-gutenberg-media'
229 name="fv-player-gutenberg-media"
230 onClick={() => {
231 setURLPopoverIsOpen(false);
232 }}
233 >Select Media
234 </Button>
235 <Button
236 className="fv-wordpress-flowplayer-button is-secondary"
237 onClick={() => {
238 setURLPopoverIsOpen(false);
239 }}
240 >FV Player Editor
241 </Button>
242 <Button
243 className="is-secondary"
244 onClick={() => setURLPopoverIsOpen(!URLPopoverIsOpen)}
245 >Insert from URL
246 </Button>
247 </div>
248 {URLPopoverIsOpen && (
249 <URLPopover>
250 <form
251 className="block-editor-media-placeholder__url-input-form"
252 onSubmit={(event) => {
253 event.preventDefault();
254 // get input value
255 const input = event.target.querySelector(
256 ".block-editor-media-placeholder__url-input-field, .fv-player-gutenberg-url-input-field"
257 );
258 setAttributes({ src: input.value });
259 setURLPopoverIsOpen(false);
260 }}
261 >
262 <input
263 data-cy="url-input"
264 className="block-editor-media-placeholder__url-input-field fv-player-gutenberg-url-input"
265 type="url"
266 aria-label={__("URL", "fv-player-gutenberg/basic")}
267 placeholder={__(
268 "Add video URL",
269 "fv-player-gutenberg/basic"
270 )}
271 />
272 <Button
273 data-cy="url-submit"
274 className="block-editor-media-placeholder__url-input-submit-button"
275 icon={"editor-break"}
276 label={__("Submit", "fv-player-gutenberg/basic")}
277 type="submit"
278 />
279 </form>
280 </URLPopover>
281 )}
282 </div>
283 )
284 }
285
286 return (
287 <>
288 <InspectorControls>
289 <Panel>
290 <PanelBody title="Video Settings" initialOpen={true}>
291 <TextControl
292 label="Source URL"
293 className='fv-player-gutenberg-src'
294 name="fv-player-gutenberg-media"
295 value={src}
296 onChange={(newSrc) => {
297 setAttributes({ src: newSrc });
298 }}
299 />
300 <Button
301 className={ ( src ? 'is-secondary' : 'is-primary' ) + ' fv-player-gutenberg-media' }
302 style={{ marginBottom: '10px' }}
303 >{ src ? 'Change Media' : 'Select Media' }
304 </Button>
305 <TextControl
306 label="Splash URL"
307 className='fv-player-gutenberg-splash'
308 value={splash}
309 onChange={(newSplash) => {
310 setAttributes({ splash: newSplash });
311 }}
312 />
313 <MediaUploadCheck>
314 <MediaUpload
315 onSelect={(attachment) => {
316 setAttributes({ splash: attachment.url });
317 setAttributes({ splash_attachment_id: String(attachment.id) });
318
319 let newAttributes = { ...attributes, splash: attachment.url };
320 newAttributes.splash_attachment_id = attachment.id;
321
322 ajaxUpdateAttributes(newAttributes);
323 }
324 }
325 allowedTypes={['image']}
326 render={({ open }) => (
327 <Button
328 onClick={open}
329 className={ splash ? 'is-secondary' : 'is-primary' }
330 style={{ marginBottom: '10px' }}
331 >{ splash ? 'Change Image' : 'Select Image' }
332 </Button>
333 )}
334 />
335 </MediaUploadCheck>
336 {timeline_previews && (
337 <TextControl
338 label="Timeline Previews"
339 className='fv-player-gutenberg-timeline-previews'
340 value={timeline_previews}
341 onChange={(newTimelinePreviews) => {
342 setAttributes({ timeline_previews: newTimelinePreviews });
343 }}
344 />
345 )}
346 {hls_hlskey && (
347 <TextControl
348 label="HLS Key"
349 className='fv-player-gutenberg-hls-hlskey'
350 value={hls_hlskey}
351 onChange={(newHlsHlskey) => {
352 setAttributes({ hls_hlskey: newHlsHlskey });
353 }}
354 />
355 )}
356 <TextControl
357 label="Video Title"
358 className='fv-player-gutenberg-title'
359 value={title}
360 onChange={(newTitle) => {
361 setAttributes({ title: newTitle });
362 }}
363 />
364 <div className="fv-player-gutenberg">
365 <p>{__('Looking for subtitles or player settings?', 'fv-player-gutenberg')}</p>
366 <Button className="fv-wordpress-flowplayer-button is-primary">Open in Editor</Button>
367 <input className='fv-player-gutenberg-splash-attachement-id' type="hidden" value={splash_attachment_id} />
368 <input className='fv-player-gutenberg-client-id' type="hidden" value={clientId} />
369 <input className='fv-player-gutenberg-player-id' type="hidden" value={player_id} />
370 <input
371 className="attachement-shortcode fv-player-editor-field"
372 type="hidden"
373 value={shortcodeContent}
374 onChange={() =>{
375 setAttributes({ shortcodeContent: shortcodeContent });
376 }}
377 />
378 </div>
379 </PanelBody>
380 </Panel>
381 </InspectorControls>
382
383 <ServerSideRender
384 block="fv-player-gutenberg/basic"
385 attributes={ attributes }
386 />
387
388 </>
389 );
390 },
391 save: (props) => {
392 return (
393 <>
394 <RawHTML>{props.attributes.shortcodeContent}</RawHTML>
395 </>
396 );
397 }
398 });
399