PluginProbe
WP Ultimate Post Grid / 4.0.1
WP Ultimate Post Grid v4.0.1
4.1.1 trunk 1.5 1.6 1.7 1.7.1 1.7.2 1.8 1.9 2.0 2.1 2.2 2.3 2.4.0 2.5.0 2.6.0 2.7.0 2.8.0 2.8.2 3.0.0 3.3.0 3.4.0 3.5.0 3.6.0 3.7.0 All 32 releases
wp-ultimate-post-grid / assets / js / admin-template / main / preview-template / index.js

index.js in WP Ultimate Post Grid 4.0.1, at assets/js/admin-template/main/preview-template/index.js

460 lines 17.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import React, { Component, Fragment } from 'react';
2 import Parser from 'html-react-parser';
3
4 import '../../../../../../wp-ultimate-post-grid/assets/css/template/template_reset.scss';
5 import '../../../../../../wp-ultimate-post-grid/assets/css/template/shortcodes.scss';
6
7 import Helpers from '../../general/Helpers';
8 import Loader from 'Shared/Loader';
9 import Block from './Block';
10 import AddBlocks from '../../menu/AddBlocks';
11 import RemoveBlocks from '../../menu/RemoveBlocks';
12 import BlockProperties from '../../menu/BlockProperties';
13 import PreviewItem from './PreviewItem';
14
15 // Sort shortcodes for "Add Blocks" section.
16 const generalShortcodeKeys = [
17 'wpupg-spacer',
18 'wpupg-text',
19 'wpupg-link',
20 'wpupg-image',
21 'wpupg-icon',
22 ];
23 let gridShortcodeKeys = [];
24 let recipeShortcodeKeys = [];
25 const shortcodeKeysAlphebetically = Object.keys(wpupg_admin_template.shortcodes).sort();
26
27 for ( let shortcode of shortcodeKeysAlphebetically ) {
28 if ( ! generalShortcodeKeys.includes( shortcode ) ) {
29 if ( 'wpupg' === shortcode.substr(0,5) ) {
30 gridShortcodeKeys.push( shortcode );
31 } else {
32 recipeShortcodeKeys.push( shortcode );
33 }
34 }
35 }
36
37 export default class PreviewTemplate extends Component {
38 constructor(props) {
39 super(props);
40
41 let item = wpupg_admin_template.preview_item;
42
43 this.state = {
44 item,
45 width: 300,
46 html: '',
47 htmlMap: '',
48 parsedHtml: '',
49 shortcodes: [],
50 editingBlock: false,
51 addingBlock: false,
52 hoveringBlock: false,
53 hasError: false,
54 }
55
56 this.previewItem = React.createRef();
57 }
58
59 componentDidCatch() {
60 this.setState({
61 hasError: true,
62 });
63 }
64
65 componentDidMount() {
66 this.checkHtmlChange();
67 }
68
69 componentDidUpdate(prevProps) {
70 // If changing to edit blocks mode, reset the editing blocks.
71 if ( 'blocks' === this.props.mode && this.props.mode !== prevProps.mode ) {
72 this.onChangeEditingBlock(false);
73 } else {
74 this.checkHtmlChange(); // onChangeEditingBlock forces HTML update, so no need to check.
75 }
76 }
77
78 checkHtmlChange() {
79 if ( this.props.template.html !== this.state.html ) {
80 this.changeHtml();
81 }
82 }
83
84 changeHtml() {
85 const parsed = this.parseHtml(this.props.template.html);
86
87 this.setState({
88 html: this.props.template.html,
89 htmlMap: parsed.htmlMap,
90 parsedHtml: parsed.html,
91 shortcodes: parsed.shortcodes,
92 hasError: false,
93 });
94 }
95
96 parseHtml(html) {
97 let htmlToParse = html;
98
99 // Remove closing wpupg-condition shortcode from preview.
100 htmlToParse = htmlToParse.replace( /\[\/wpupg\-condition\]/g, '' );
101
102 // Find shortcodes in HTML.
103 let shortcodes = [];
104 const regex = /\[([^\s\]]*)\s*([^\]]*?)\]/gmi;
105
106 let match;
107 while ((match = regex.exec(html)) !== null) {
108 // Check for attributes in shortcode.
109 let shortcode_atts = {};
110 let attributes = match[2].match(/(\w+=\"[^\"]*?\"|\w+=\'[^\']*?\'|\w+=\w*)/gmi);
111
112 if (attributes) {
113 for (let i = 0; i < attributes.length; i++) {
114 let attribute = attributes[i];
115 let property = attribute.substring(0, attribute.indexOf('='));
116 let value = attribute.substring(attribute.indexOf('=') + 1);
117
118 // Trim value if necessary.
119 if ('"' === value[0] || "'" === value[0] ) {
120 value = value.substr(1, value.length-2);
121 }
122
123 shortcode_atts[property] = value;
124 }
125 }
126
127 // Get shortcode name.
128 let id = match[1];
129 const name = Helpers.getShortcodeName(id);
130
131 // Generate UID.
132 let uid = shortcodes.length;
133
134 // Replace with HTML tag to parse in next step, save attributes for access.
135 htmlToParse = htmlToParse.replace(match[0], '<wpupg-replace-shortcode-with-block uid="' + uid + '"></wpupg-replace-shortcode-with-block>');
136 shortcodes.push({
137 uid,
138 id,
139 name,
140 attributes: shortcode_atts,
141 });
142 }
143
144 // Get HTML with shortcodes replaced by blocks.
145 let parsedHtml = <Loader/>;
146 try {
147 parsedHtml = Parser(htmlToParse, {
148 replace: function(domNode) {
149 if (domNode.name == 'wpupg-replace-shortcode-with-block') {
150 return <Block
151 item={ this.state.item ? this.state.item.value : false }
152 shortcode={ shortcodes[ domNode.attribs.uid ] }
153 shortcodes={ shortcodes }
154 onBlockPropertyChange={ this.onBlockPropertyChange.bind(this) }
155 onBlockPropertiesChange={ this.onBlockPropertiesChange.bind(this) }
156 editingBlock={this.state.editingBlock}
157 onChangeEditingBlock={this.onChangeEditingBlock.bind(this)}
158 hoveringBlock={this.state.hoveringBlock}
159 onChangeHoveringBlock={this.onChangeHoveringBlock.bind(this)}
160 />;
161 }
162 }.bind(this)
163 });
164 } catch ( error ) {}
165
166 return {
167 htmlMap: htmlToParse,
168 html: parsedHtml,
169 shortcodes,
170 }
171 }
172
173 unparseHtml() {
174 let html = this.state.htmlMap;
175
176 for ( let shortcode of this.state.shortcodes ) {
177 let fullShortcode = Helpers.getFullShortcode(shortcode);
178 html = html.replace('<wpupg-replace-shortcode-with-block uid="' + shortcode.uid + '"></wpupg-replace-shortcode-with-block>', fullShortcode);
179 }
180
181 return html;
182 }
183
184 onBlockPropertyChange(uid, property, value) {
185 let properties = {};
186 properties[property] = value;
187 this.onBlockPropertiesChange(uid, properties);
188 }
189
190 onBlockPropertiesChange(uid, properties) {
191 let newState = this.state;
192 newState.shortcodes[uid].attributes = {
193 ...newState.shortcodes[uid].attributes,
194 ...properties,
195 }
196
197 this.setState(newState,
198 () => {
199 let newHtml = this.unparseHtml();
200 this.props.onChangeHTML(newHtml);
201 });
202 }
203
204 onChangeEditingBlock(uid) {
205 if (uid !== this.state.editingBlock) {
206 this.setState({
207 editingBlock: uid,
208 hoveringBlock: false,
209 }, this.changeHtml);
210 // Force HTML update to trickle down editingBlock prop.
211 }
212 }
213
214 onChangeHoveringBlock(uid) {
215 if (uid !== this.state.hoveringBlock) {
216 this.setState({
217 hoveringBlock: uid,
218 }, this.changeHtml);
219 // Force HTML update to trickle down hoveringBlock prop.
220 }
221 }
222
223 onChangeAddingBlock(id) {
224 if (id !== this.state.addingBlock) {
225 this.setState({
226 addingBlock: id,
227 });
228 }
229 }
230
231 onAddBlockAfter(uid) {
232 let htmlMap = this.state.htmlMap;
233 const shortcode = '[' + this.state.addingBlock + ']';
234 const afterShortcode = '<wpupg-replace-shortcode-with-block uid="' + uid + '"></wpupg-replace-shortcode-with-block>';
235 htmlMap = htmlMap.replace(afterShortcode, afterShortcode + '\n' + shortcode);
236
237 if ( htmlMap !== this.state.htmlMap) {
238 this.setState({
239 addingBlock: false,
240 hoveringBlock: false,
241 htmlMap,
242 },
243 () => {
244 let newHtml = this.unparseHtml();
245 this.props.onChangeHTML(newHtml);
246 this.props.onChangeMode( 'blocks' );
247
248 this.setState({
249 addingBlock: false,
250 hoveringBlock: false,
251 }, () => {
252 this.onChangeEditingBlock(uid + 1);
253 });
254 });
255 }
256 }
257
258 onRemoveBlock(uid) {
259 let htmlMap = this.state.htmlMap;
260 htmlMap = htmlMap.replace('<wpupg-replace-shortcode-with-block uid="' + uid + '"></wpupg-replace-shortcode-with-block>', '');
261
262 if ( htmlMap !== this.state.htmlMap) {
263 this.setState({
264 htmlMap,
265 },
266 () => {
267 let newHtml = this.unparseHtml();
268 this.props.onChangeHTML(newHtml);
269 });
270 }
271 }
272
273 toggleHover( hovering ) {
274 const containers = this.previewItem.current.querySelectorAll('.wpupg-hover');
275
276 for ( let container of containers ) {
277 if ( hovering ) {
278 container.classList.add('wpupg-hovering');
279 } else {
280 container.classList.remove('wpupg-hovering');
281 }
282 }
283 }
284
285 render() {
286 const parsedHtml = this.state.hasError ? <Loader /> : this.state.parsedHtml;
287
288 let itemClasses = [
289 'wpupg-item',
290 `wpupg-template-${this.props.template.slug}`,
291 ];
292 if ( this.state.item && Array.isArray( this.state.item.classes ) ) {
293 itemClasses = [
294 ...itemClasses,
295 ...this.state.item.classes,
296 ];
297 }
298
299 return (
300 <Fragment>
301 <div className="wpupg-main-container">
302 <h2 className="wpupg-main-container-name">Preview at <input type="number" min="1" value={ this.state.width } onChange={ (e) => { this.setState({ width: e.target.value } ); } } />px</h2>
303 <div className="wpupg-main-container-preview">
304 <PreviewItem
305 item={ this.state.item }
306 onChange={ (item) => {
307 if ( item !== this.state.item ) {
308 this.setState( {
309 item,
310 html: '', // Force HTML to update.
311 });
312 }
313 }}
314 />
315 {
316 this.state.item && this.state.item.value
317 ?
318 <Fragment>
319 <style>{ Helpers.parseCSS( this.props.template ) }</style>
320 <div
321 ref={this.previewItem}
322 className={ itemClasses.join( ' ' ) }
323 style={{
324 width: `${this.state.width}px`,
325 }}
326 onMouseEnter={ () => this.toggleHover( true ) }
327 onMouseLeave={ () => this.toggleHover( false ) }
328 >{ parsedHtml }</div>
329 </Fragment>
330 :
331 <p style={{color: 'darkred', textAlign: 'center'}}>You have to select an item to use for the preview in the dropdown above.<br/>This will be used as an example of one grid item. For a grid of posts, select a post.</p>
332 }
333 </div>
334 </div>
335 {
336 false === this.state.editingBlock || this.state.shortcodes.length <= this.state.editingBlock
337 ?
338 <BlockProperties>
339 {
340 this.state.shortcodes.map((shortcode, i) => {
341 return (
342 <div
343 key={i}
344 className={ shortcode.uid === this.state.hoveringBlock ? 'wpupg-template-menu-block wpupg-template-menu-block-hover' : 'wpupg-template-menu-block' }
345 onClick={ () => this.onChangeEditingBlock(shortcode.uid) }
346 onMouseEnter={ () => this.onChangeHoveringBlock(shortcode.uid) }
347 onMouseLeave={ () => this.onChangeHoveringBlock(false) }
348 >{ shortcode.name }</div>
349 );
350 })
351 }
352 {
353 ! this.state.shortcodes.length && <p>There are no adjustable blocks.</p>
354 }
355 </BlockProperties>
356 :
357 null
358 }
359 <AddBlocks>
360 {
361 ! this.state.addingBlock
362 ?
363 <Fragment>
364 <p>Select block to add:</p>
365 <div className="wpupg-template-menu-add-block-group">General Blocks</div>
366 {
367 generalShortcodeKeys.map((id, i) => {
368 return (
369 <div
370 key={i}
371 className="wpupg-template-menu-block"
372 onClick={ () => this.onChangeAddingBlock(id) }
373 >{ Helpers.getShortcodeName(id) }</div>
374 );
375 })
376 }
377 <div className="wpupg-template-menu-add-block-group">Grid Item Blocks</div>
378 {
379 gridShortcodeKeys.map((id, i) => {
380 return (
381 <div
382 key={i}
383 className="wpupg-template-menu-block"
384 onClick={ () => this.onChangeAddingBlock(id) }
385 >{ Helpers.getShortcodeName(id) }</div>
386 );
387 })
388 }
389 {
390 0 < recipeShortcodeKeys.length
391 &&
392 <Fragment>
393 <div className="wpupg-template-menu-add-block-group">Recipe Blocks</div>
394 {
395 recipeShortcodeKeys.map((id, i) => {
396 return (
397 <div
398 key={i}
399 className="wpupg-template-menu-block"
400 onClick={ () => this.onChangeAddingBlock(id) }
401 >{ Helpers.getShortcodeName(id) }</div>
402 );
403 })
404 }
405 </Fragment>
406 }
407 </Fragment>
408 :
409 <Fragment>
410 <a href="#" onClick={(e) => {
411 e.preventDefault();
412 this.onChangeAddingBlock(false);
413 }}>Cancel</a>
414 <p>Add "{ Helpers.getShortcodeName(this.state.addingBlock) }" after:</p>
415 {
416 this.state.shortcodes.map((shortcode, i) => {
417 return (
418 <div
419 key={i}
420 className={ shortcode.uid === this.state.hoveringBlock ? 'wpupg-template-menu-block wpupg-template-menu-block-hover' : 'wpupg-template-menu-block' }
421 onClick={ () => this.onAddBlockAfter(shortcode.uid) }
422 onMouseEnter={ () => this.onChangeHoveringBlock(shortcode.uid) }
423 onMouseLeave={ () => this.onChangeHoveringBlock(false) }
424 >{ shortcode.name }</div>
425 );
426 })
427 }
428 {
429 ! this.state.shortcodes.length && <p>There are no blocks in the Template.</p>
430 }
431 </Fragment>
432 }
433 </AddBlocks>
434 <RemoveBlocks>
435 {
436 this.state.shortcodes.map((shortcode, i) => {
437 return (
438 <div
439 key={i}
440 className={ shortcode.uid === this.state.hoveringBlock ? 'wpupg-template-menu-block wpupg-template-menu-block-hover' : 'wpupg-template-menu-block' }
441 onClick={ () => {
442 if (confirm( 'Are you sure you want to delete the "' + shortcode.name + '" block?' )) {
443 this.onRemoveBlock(shortcode.uid);
444 }
445 }}
446 onMouseEnter={ () => this.onChangeHoveringBlock(shortcode.uid) }
447 onMouseLeave={ () => this.onChangeHoveringBlock(false) }
448 >{ shortcode.name }</div>
449 );
450 })
451 }
452 {
453 ! this.state.shortcodes.length && <p>There are no blocks to remove.</p>
454 }
455 </RemoveBlocks>
456 </Fragment>
457 );
458 }
459 }
460