PluginProbe ʕ •ᴥ•ʔ
FrontBlocks for Gutenberg/GeneratePress / trunk
FrontBlocks for Gutenberg/GeneratePress vtrunk
trunk 0.2.0 0.2.1 0.2.2 0.2.3 0.2.4 0.2.5 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.1.0 1.2.0 1.2.1 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 ci-artifacts
frontblocks / assets / insert-post / frontblocks-insert-post-option.js
frontblocks / assets / insert-post Last commit date
frontblocks-insert-post-option.js 1 month ago frontblocks-insert-post-option.jsx 1 month ago frontblocks-insert-post.css 8 months ago jquery-ui.css 8 months ago
frontblocks-insert-post-option.js
335 lines
1 "use strict";
2
3 function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); }
4 function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
5 function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); }
6 function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); }
7 function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
8 function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
9 function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
10 function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
11 function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
12 function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
13 // Insert Post Block Component
14 var addFilter = wp.hooks.addFilter;
15 var _wp$element = wp.element,
16 Fragment = _wp$element.Fragment,
17 useState = _wp$element.useState,
18 useEffect = _wp$element.useEffect,
19 useRef = _wp$element.useRef;
20 var _wp$blockEditor = wp.blockEditor,
21 InspectorControls = _wp$blockEditor.InspectorControls,
22 useBlockProps = _wp$blockEditor.useBlockProps,
23 RichText = _wp$blockEditor.RichText;
24 var _wp$components = wp.components,
25 SelectControl = _wp$components.SelectControl,
26 TextControl = _wp$components.TextControl,
27 PanelBody = _wp$components.PanelBody,
28 Button = _wp$components.Button,
29 Spinner = _wp$components.Spinner,
30 Notice = _wp$components.Notice,
31 Card = _wp$components.Card,
32 CardBody = _wp$components.CardBody,
33 CardHeader = _wp$components.CardHeader,
34 ToggleControl = _wp$components.ToggleControl;
35 var __ = wp.i18n.__;
36 var _wp = wp,
37 apiFetch = _wp.apiFetch;
38
39 // Custom Insert Post Block
40 function InsertPostBlock(props) {
41 var attributes = props.attributes,
42 setAttributes = props.setAttributes;
43 var _attributes$selectedP = attributes.selectedPostId,
44 selectedPostId = _attributes$selectedP === void 0 ? 0 : _attributes$selectedP,
45 _attributes$selectedP2 = attributes.selectedPostType,
46 selectedPostType = _attributes$selectedP2 === void 0 ? 'post' : _attributes$selectedP2,
47 _attributes$selectedP3 = attributes.selectedPostTitle,
48 selectedPostTitle = _attributes$selectedP3 === void 0 ? '' : _attributes$selectedP3,
49 _attributes$selectedP4 = attributes.selectedPostContent,
50 selectedPostContent = _attributes$selectedP4 === void 0 ? '' : _attributes$selectedP4,
51 _attributes$className = attributes.className,
52 className = _attributes$className === void 0 ? '' : _attributes$className;
53 var _useState = useState(''),
54 _useState2 = _slicedToArray(_useState, 2),
55 searchTerm = _useState2[0],
56 setSearchTerm = _useState2[1];
57 var _useState3 = useState(false),
58 _useState4 = _slicedToArray(_useState3, 2),
59 isSearching = _useState4[0],
60 setIsSearching = _useState4[1];
61 var _useState5 = useState(''),
62 _useState6 = _slicedToArray(_useState5, 2),
63 searchError = _useState6[0],
64 setSearchError = _useState6[1];
65 var _useState7 = useState(false),
66 _useState8 = _slicedToArray(_useState7, 2),
67 showSearch = _useState8[0],
68 setShowSearch = _useState8[1];
69 var searchInputRef = useRef(null);
70
71 // Get available post types
72 var _useState9 = useState([{
73 label: __('Posts', 'frontblocks'),
74 value: 'post'
75 }, {
76 label: __('Pages', 'frontblocks'),
77 value: 'page'
78 }]),
79 _useState0 = _slicedToArray(_useState9, 2),
80 postTypes = _useState0[0],
81 setPostTypes = _useState0[1];
82 useEffect(function () {
83 // Get custom post types
84 apiFetch({
85 path: '/wp/v2/types'
86 }).then(function (types) {
87 var customTypes = Object.keys(types).filter(function (type) {
88 return type !== 'post' && type !== 'page';
89 }).map(function (type) {
90 return {
91 label: types[type].name,
92 value: type
93 };
94 });
95 setPostTypes(function (prev) {
96 return [].concat(_toConsumableArray(prev), _toConsumableArray(customTypes));
97 });
98 }).catch(function () {
99 // If API fails, continue with default post types
100 });
101 }, []);
102
103 // Initialize jQuery autocomplete when component mounts or search is shown
104 useEffect(function () {
105 if (showSearch && searchInputRef.current && typeof jQuery !== 'undefined') {
106 var $input = jQuery(searchInputRef.current);
107
108 // Check if autocomplete is already initialized before destroying
109 if ($input.hasClass('ui-autocomplete-input')) {
110 try {
111 $input.autocomplete('destroy');
112 } catch (e) {
113 // If destroy fails, remove the autocomplete class manually
114 $input.removeClass('ui-autocomplete-input');
115 }
116 }
117
118 // Initialize autocomplete
119 $input.autocomplete({
120 source: function source(request, response) {
121 if (request.term.length < 2) {
122 response([]);
123 return;
124 }
125 setIsSearching(true);
126 setSearchError('');
127 var formData = new FormData();
128 formData.append('action', 'frbl_search_posts');
129 formData.append('nonce', frblInsertPost.nonce);
130 formData.append('search', request.term);
131 formData.append('post_type', selectedPostType);
132 fetch(frblInsertPost.ajaxUrl, {
133 method: 'POST',
134 body: formData
135 }).then(function (response) {
136 return response.json();
137 }).then(function (data) {
138 setIsSearching(false);
139 if (data.success) {
140 var results = data.data.map(function (post) {
141 return {
142 label: "".concat(post.title, " (").concat(post.type, ")"),
143 value: post.title,
144 post: post
145 };
146 });
147 response(results);
148 } else {
149 setSearchError(data.data || __('Search failed', 'frontblocks'));
150 response([]);
151 }
152 }).catch(function (error) {
153 setIsSearching(false);
154 setSearchError(__('Search failed. Please try again.', 'frontblocks'));
155 response([]);
156 });
157 },
158 minLength: 2,
159 delay: 300,
160 select: function select(event, ui) {
161 selectPost(ui.item.post);
162 return false;
163 },
164 open: function open() {
165 jQuery(this).autocomplete('widget').css('z-index', 999999);
166 }
167 });
168
169 // Cleanup function
170 return function () {
171 try {
172 if ($input.hasClass('ui-autocomplete-input')) {
173 $input.autocomplete('destroy');
174 }
175 } catch (e) {
176 // If destroy fails, just remove the class
177 $input.removeClass('ui-autocomplete-input');
178 }
179 };
180 }
181 }, [showSearch, selectedPostType]);
182 var selectPost = function selectPost(post) {
183 setAttributes({
184 selectedPostId: post.id,
185 selectedPostTitle: post.title,
186 selectedPostType: post.type
187 });
188 setShowSearch(false);
189 setSearchTerm('');
190 setSearchError('');
191 };
192 var clearSelection = function clearSelection() {
193 setAttributes({
194 selectedPostId: 0,
195 selectedPostTitle: '',
196 selectedPostContent: ''
197 });
198 setShowSearch(false);
199 setSearchTerm('');
200 setSearchError('');
201 };
202 var blockProps = useBlockProps({
203 className: "frbl-insert-post-block ".concat(className)
204 });
205 return /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement("div", blockProps, selectedPostId ? /*#__PURE__*/React.createElement("div", {
206 className: "frbl-insert-post-preview"
207 }, /*#__PURE__*/React.createElement("h2", {
208 className: "frbl-insert-post-title"
209 }, selectedPostTitle), /*#__PURE__*/React.createElement("div", {
210 className: "frbl-insert-post-content"
211 }, selectedPostContent || __('Content will be loaded on the frontend', 'frontblocks')), /*#__PURE__*/React.createElement("div", {
212 className: "frbl-insert-post-actions"
213 }, /*#__PURE__*/React.createElement(Button, {
214 isSecondary: true,
215 onClick: function onClick() {
216 return setShowSearch(true);
217 }
218 }, __('Change Post', 'frontblocks')), /*#__PURE__*/React.createElement(Button, {
219 isDestructive: true,
220 onClick: clearSelection
221 }, __('Clear Selection', 'frontblocks')))) : /*#__PURE__*/React.createElement("div", {
222 className: "frbl-insert-post-empty"
223 }, /*#__PURE__*/React.createElement("p", null, __('No post selected. Use the sidebar to search and select a post.', 'frontblocks')), /*#__PURE__*/React.createElement(Button, {
224 isPrimary: true,
225 onClick: function onClick() {
226 return setShowSearch(true);
227 }
228 }, __('Select Post', 'frontblocks')))), /*#__PURE__*/React.createElement(InspectorControls, null, /*#__PURE__*/React.createElement(PanelBody, {
229 title: __('Insert Post Settings', 'frontblocks'),
230 initialOpen: true
231 }, (!selectedPostId || showSearch) && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(SelectControl, {
232 label: __('Post Type', 'frontblocks'),
233 value: selectedPostType,
234 options: postTypes,
235 onChange: function onChange(value) {
236 return setAttributes({
237 selectedPostType: value
238 });
239 }
240 }), /*#__PURE__*/React.createElement(TextControl, {
241 ref: searchInputRef,
242 label: __('Search Posts', 'frontblocks'),
243 value: searchTerm,
244 onChange: setSearchTerm,
245 placeholder: __('Start typing to search posts...', 'frontblocks'),
246 help: __('Type at least 2 characters to search', 'frontblocks')
247 }), isSearching && /*#__PURE__*/React.createElement("div", {
248 style: {
249 marginTop: '10px'
250 }
251 }, /*#__PURE__*/React.createElement(Spinner, null), /*#__PURE__*/React.createElement("span", {
252 style: {
253 marginLeft: '8px'
254 }
255 }, __('Searching...', 'frontblocks'))), searchError && /*#__PURE__*/React.createElement(Notice, {
256 status: "error",
257 isDismissible: false
258 }, searchError)), selectedPostId && !showSearch && /*#__PURE__*/React.createElement("div", {
259 className: "frbl-selected-post-info"
260 }, /*#__PURE__*/React.createElement("h4", null, __('Selected Post', 'frontblocks')), /*#__PURE__*/React.createElement(Card, null, /*#__PURE__*/React.createElement(CardBody, null, /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement("strong", null, __('Title:', 'frontblocks')), " ", selectedPostTitle), /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement("strong", null, __('Type:', 'frontblocks')), " ", selectedPostType), /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement("strong", null, __('ID:', 'frontblocks')), " ", selectedPostId))), /*#__PURE__*/React.createElement(Button, {
261 isSecondary: true,
262 onClick: function onClick() {
263 return setShowSearch(true);
264 },
265 style: {
266 marginTop: '10px'
267 }
268 }, __('Change Post', 'frontblocks'))))));
269 }
270
271 // Register the custom block
272 var registerBlockType = wp.blocks.registerBlockType;
273 registerBlockType('frontblocks/insert-post', {
274 title: __('FrontBlocks - Insert Post', 'frontblocks'),
275 description: __('Display content from another post or page', 'frontblocks'),
276 category: 'generateblocks',
277 icon: 'admin-post',
278 keywords: [__('post', 'frontblocks'), __('content', 'frontblocks'), __('insert', 'frontblocks'), __('display', 'frontblocks')],
279 supports: {
280 html: false,
281 align: ['wide', 'full']
282 },
283 attributes: {
284 selectedPostId: {
285 type: 'number',
286 default: 0
287 },
288 selectedPostType: {
289 type: 'string',
290 default: 'post'
291 },
292 selectedPostTitle: {
293 type: 'string',
294 default: ''
295 },
296 selectedPostContent: {
297 type: 'string',
298 default: ''
299 },
300 className: {
301 type: 'string',
302 default: ''
303 }
304 },
305 edit: InsertPostBlock,
306 save: function save() {
307 return null;
308 } // Using PHP render callback
309 });
310
311 // Add custom panel to existing GenerateBlocks Grid block
312 function addInsertPostPanel(BlockEdit) {
313 return function (props) {
314 if (props.name !== 'generateblocks/grid') {
315 return /*#__PURE__*/React.createElement(BlockEdit, props);
316 }
317 var _props$attributes$frb = props.attributes.frblInsertPostEnabled,
318 frblInsertPostEnabled = _props$attributes$frb === void 0 ? false : _props$attributes$frb;
319 return /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement(BlockEdit, props), /*#__PURE__*/React.createElement(InspectorControls, null, /*#__PURE__*/React.createElement(PanelBody, {
320 title: __('FrontBlocks - Insert Post', 'frontblocks'),
321 initialOpen: false
322 }, /*#__PURE__*/React.createElement(ToggleControl, {
323 label: __('Enable Insert Post Grid', 'frontblocks'),
324 checked: frblInsertPostEnabled,
325 onChange: function onChange(value) {
326 return props.setAttributes({
327 frblInsertPostEnabled: value
328 });
329 },
330 help: __('Enable insert post functionality for this grid', 'frontblocks')
331 }))));
332 };
333 }
334 addFilter('editor.BlockEdit', 'frontblocks/insert-post-grid-panel', addInsertPostPanel);
335