PluginProbe
codoc / 0.9.57
codoc v0.9.57
0.9.8.8 0.9.8.9 0.9.9 0.9.9.1 trunk 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.8.1 0.8.2 0.8.3 0.8.4 0.8.6 0.8.7 0.8.8 0.8.9 0.9 0.9.1 0.9.10 0.9.11 All 114 releases
codoc / src / block / block.js

block.js in codoc 0.9.57, at src/block/block.js

509 lines 16.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * BLOCK: codoc-block
3 *
4 * Registering a basic block with Gutenberg.
5 * Simple block, renders and saves the same content without any interactivity.
6 */
7
8 // Import CSS.
9 import './style.scss';
10 import './editor.scss';
11 import icon from './icon';
12 //import { ENTER } from '@wordpress/keycodes';
13 const { ENTER } = wp.keycodes;
14 const { __ } = wp.i18n; // Import __() from wp.i18n
15 const { Component } = wp.element;
16
17 const { registerBlockType } = wp.blocks; // Import registerBlockType() from wp.blocks
18 const {
19 InspectorControls,
20 RichText
21 } = wp.editor;
22
23 const {
24 SelectControl,
25 PanelBody,
26 ToggleControl,
27 CheckboxControl,
28 RangeControl,
29 TextControl,
30 } = wp.components;
31
32 const {
33 getDefaultBlockName,
34 createBlock,
35 } = wp.blocks;
36
37 const { withState } = wp.compose;
38
39 const CODOC_URL = OPTIONS.codoc_url;
40 const CODOC_USER_CODE = OPTIONS.codoc_usercode;
41 const CODOC_PLUGIN_VERSION = OPTIONS.codoc_plugin_version;
42 const CODOC_ENTRIES_CLASS = 'codoc-entries';
43 const CODOC_ACCOUNT_IS_PRO = OPTIONS.codoc_account_is_pro;
44 const CODOC_CURRENCY_CODE = OPTIONS.codoc_currency_code;
45 const CODOC_CURRENCY_DECIMAL_PLACES = OPTIONS.codoc_currency_decimal_places;
46
47 //import Cookies from 'universal-cookie';
48 //const cookies = new Cookies();
49
50 class CodocControls extends Component {
51 constructor( props ) {
52 super( ...arguments );
53 this.subscriptionsFetched = [];
54 this.subscriptionSearchTerm = '';
55 this.state = {
56 searchTerm: '',
57 filteredSubscriptions: []
58 };
59 this.fetchSubscriptions();
60 this.handleSearchChange = this.handleSearchChange.bind(this);
61 }
62
63 fetchSubscriptions(searchTitle = '') {
64 const {
65 setAttributes,
66 attributes: {
67 fetching,
68 }
69 } = this.props;
70
71 if (fetching) {
72 return
73 }
74
75 setAttributes( { fetching: true } )
76 let url = CODOC_URL + '/api/v1/cms/' + CODOC_USER_CODE + '/subscriptions?without_token=1';
77
78 // Add title parameter if search term exists
79 if (searchTitle) {
80 url += '&title=' + encodeURIComponent(searchTitle);
81 }
82
83 fetch(url)
84 .then( res => res.json() )
85 .then( res => {
86 let list = [];
87 if (res.status && res.subscriptions) {
88 for ( var i = 0; i < res.subscriptions.length; i++ ) {
89 let info = {
90 value: res.subscriptions[i].code,
91 label: res.subscriptions[i].title,
92 term: res.subscriptions[i].term,
93 price: res.subscriptions[i].price,
94 currency: res.subscriptions[i].currency
95 }
96 list[i] = info
97 }
98 }
99 if (list.length || searchTitle) {
100 this.subscriptionsFetched = list;
101 this.setState({ filteredSubscriptions: list });
102 }
103 setAttributes( { fetching: false } )
104 })
105 }
106
107 handleSearchChange(value) {
108 this.setState({ searchTerm: value });
109
110 // Debounce the API call
111 clearTimeout(this.searchTimeout);
112 this.searchTimeout = setTimeout(() => {
113 this.fetchSubscriptions(value);
114 }, 500);
115 }
116
117 getShowPriceHelp( checked ) {
118 return checked ?
119 __( 'Enable','codoc' ) :
120 __( 'Disable','codoc' );
121 }
122 getShowSupportHelp( checked ) {
123 return checked ?
124 __( 'Accept' ,'codoc') :
125 __( 'Do not accept' ,'codoc');
126 }
127 getShowPaywalledSupportHelp( checked ) {
128 return checked ?
129 __( 'The paid part will be hidden upon access, but will be displayed after tapping "Pay to Read". Viewers can freely specify the amount to purchase based on the content. Please note that there may be cases where it is not purchased.' ,'codoc') :
130 __( ' ' );
131 }
132 getStatusLimitedHelp( checked ) {
133 return checked ?
134 __( 'Unlisted' ,'codoc') :
135 __( 'Published' ,'codoc');
136 }
137
138 render() {
139 const {
140 setAttributes,
141 attributes: {
142 showPrice,
143 price,
144 limited,
145 limitedCount,
146
147 affiliateMode,
148 affiliateRate,
149
150 showSupport,
151 showPaywalledSupport,
152 statusLimited,
153 subscriptions,
154 }
155 } = this.props;
156
157 const toggleShowPrice = () => setAttributes( { showPrice: ! showPrice } );
158 const toggleLimited = () => setAttributes( { limited: ! limited } );
159 const toggleShowPaywalledSupport = () => setAttributes( { showPaywalledSupport: ! showPaywalledSupport } );
160 const toggleStatusLimited = () => setAttributes( { statusLimited: ! statusLimited } );
161 const toggleAffiliateMode = () => setAttributes( { affiliateMode: ! affiliateMode } );
162 const toggleShowSupport = () => setAttributes( { showSupport: ! showSupport } );
163
164 const SubscriptionCheckBoxes = withState({
165 checked_obj: Object.assign({}, subscriptions)
166 })( ({ checked_obj, setState }) => (
167 <div>
168 {this.state.filteredSubscriptions.length === 0 ? (
169 <p style={{ fontStyle: 'italic', color: '#666' }}>
170 { this.state.searchTerm
171 ? __('No plans found matching your search.','codoc')
172 : __('No reader plans available.','codoc')
173 }
174 </p>
175 ) : (
176 <ul>
177 {
178 this.state.filteredSubscriptions.map((v) => {
179 const isChecked = !!checked_obj[v.value];
180 const checkedCount = Object.keys(checked_obj).length;
181
182 return (
183 <li key={v.value}>
184 <CheckboxControl
185 className="check_items"
186 label={v.label}
187 checked={isChecked}
188 onChange={(check) => {
189 // 追加する場合、5個以上は無効
190 if (check && checkedCount >= 5) {
191 return; // これ以上チェックできない
192 }
193
194 const newChecked = { ...checked_obj };
195
196 if (check) {
197 newChecked[v.value] = true;
198 } else {
199 delete newChecked[v.value];
200 }
201
202 setAttributes({ subscriptions: newChecked });
203 setState({ checked_obj: newChecked });
204 }}
205 />
206 </li>
207 );
208 })
209 }
210 </ul>
211 )}
212 </div>
213 ) )
214 const affiliateRateOptions = [
215 { value: '0.0500', label:'5%' },
216 { value: '0.1000', label:'10%' },
217 { value: '0.1500', label:'15%' },
218 { value: '0.2000', label:'20%' },
219 { value: '0.2500', label:'25%' },
220 { value: '0.3000', label:'30%' },
221 { value: '0.3500', label:'35%' },
222 { value: '0.4000', label:'40%' },
223 { value: '0.4500', label:'45%' },
224 { value: '0.5000', label:'50%' },
225 ];
226
227 return(
228 <InspectorControls key="CodocControls">
229
230 <PanelBody>
231
232 <ToggleControl
233 label={ __( 'individual sale','codoc' ) }
234 checked={ !! showPrice }
235 help={ this.getShowPriceHelp }
236 ref="showPrice"
237 onChange={ toggleShowPrice }
238 />
239
240 <div style={{ display: showPrice ? 'initial' : 'none' }}>
241 <RangeControl
242 label={ __('price','codoc') + ' ' + (CODOC_CURRENCY_DECIMAL_PLACES > 0 ? (price / 100).toFixed(CODOC_CURRENCY_DECIMAL_PLACES) : price) + ' ' + __(CODOC_CURRENCY_CODE) + __(showPaywalledSupport ? '' + __('Displayed as the your suggested price','codoc') + '' : '' ) }
243 value={ price }
244 initialPosition={ price }
245 onChange={ ( value ) => {
246 // do validate this
247 setAttributes({ price: value });
248 }}
249 min="100"
250 max={ CODOC_ACCOUNT_IS_PRO == 1 ? 100000 : 50000 }
251 /><br />
252
253 <ToggleControl
254 label={ __( 'Pay-what-you-want','codoc' ) }
255 checked={ !! showPaywalledSupport }
256 help={ this.getShowPaywalledSupportHelp }
257 onChange={ toggleShowPaywalledSupport }
258 />
259
260 <div style={{ display: showPaywalledSupport ? 'none' : 'initial' }}>
261 <ToggleControl
262 label={ __( 'Limited quantity sale','codoc' ) }
263 checked={ !! limited }
264 onChange={ toggleLimited }
265 />
266
267 <div style={{ display: limited ? 'initial' : 'none' }}>
268 <RangeControl
269 label={ __( 'Limited quantity','codoc' ) }
270 value={ limitedCount }
271 onChange={ ( value ) => {
272 // do validate this
273 setAttributes({ limitedCount: value });
274 }}
275 initialPosition={ limitedCount }
276 min="0"
277 max="100"
278 /><br />
279 </div>
280
281 <ToggleControl
282 label={ __( 'Affiliate','codoc' ) }
283 checked={ !! affiliateMode }
284 onChange={ toggleAffiliateMode }
285 />
286
287 <div style={{ display: affiliateMode ? 'initial' : 'none' }}>
288 <SelectControl
289 label={ __( 'Rate' , 'codoc') }
290 description={ __( 'You can offer affiliate marketing at a specified rate for purchasers.', 'codoc') }
291 options={ affiliateRateOptions }
292 value={ affiliateRate }
293 onChange={ ( value ) => {
294 setAttributes( { affiliateRate: value } );
295 }}/><br />
296 </div>
297
298 </div>
299 </div>
300
301 <div style={{ display: showPaywalledSupport ? 'none' : 'initial' }}>
302 <ToggleControl
303 label={ __( 'Tipping', 'codoc') }
304 checked={ !! showSupport }
305 value="1"
306 onChange={ toggleShowSupport }
307 help={ this.getShowSupportHelp }
308 />
309 </div>
310
311 <div style={{ display: 'initial' }}>
312 <ToggleControl
313 label={ __( 'Unlisted','codoc' ) }
314 checked={ !! statusLimited }
315 value="1"
316 onChange={ toggleStatusLimited }
317 help={ this.getStatusLimitedHelp }
318 />
319 </div>
320
321 <div class="codoc-subscription-title">
322 <label>
323 { __('Reader Plans','codoc') }
324 </label>
325 <a
326 href={ CODOC_URL + '/me/subscriptions'}
327 target="_blank" class="codoc-subscription-add"
328 >
329 { __('Add','codoc') }
330 </a>
331 </div>
332
333 <TextControl
334 label={ __('Search Plans','codoc') }
335 value={ this.state.searchTerm }
336 onChange={ this.handleSearchChange }
337 placeholder={ __('Enter title to search...','codoc') }
338 />
339
340 <SubscriptionCheckBoxes />
341
342
343 </PanelBody>
344 </InspectorControls>
345 );
346 }
347 };
348
349 class EditBlockContent extends Component {
350 constructor() {
351 super( ...arguments );
352 // デフォルト値
353 this.props.setAttributes({ version: CODOC_PLUGIN_VERSION });
354 this.props.setAttributes({ showPrice: this.props.attributes.showPrice == null ? true : this.props.attributes.showPrice });
355 this.props.setAttributes({ price: this.props.attributes.price == null ? 500 : this.props.attributes.price });
356 this.props.setAttributes({ limited: this.props.attributes.limited == null ? false : this.props.attributes.limited });
357 this.props.setAttributes({ limitedCount: this.props.attributes.limitedCount == null ? 10 : this.props.attributes.limitedCount });
358 this.props.setAttributes({ affiliateMode: this.props.attributes.affiliateMode == null ? false : this.props.attributes.affiliateMode });
359 this.props.setAttributes({ affiliateRate: this.props.attributes.affiliateRate == null ? '0.0500' : this.props.attributes.affiliateRate });
360 this.props.setAttributes({ showSupport: this.props.attributes.showSupport == null ? false : this.props.attributes.showSupport });
361 this.props.setAttributes({ showPaywalledSupport: this.props.attributes.showPaywalledSupport == null ? false : this.props.attributes.showPaywalledSupport });
362 this.props.setAttributes({ statusLimited: this.props.attributes.statusLimited == null ? false : this.props.attributes.statusLimited });
363 this.props.setAttributes({ subscriptions: this.props.attributes.subscriptions == null ? {} : this.props.attributes.subscriptions });
364
365 this.onChangeInput = this.onChangeInput.bind( this );
366 this.onKeyDown = this.onKeyDown.bind( this );
367 this.state = {
368 defaultText: __( 'To continue reading, ...','codoc' ),
369 };
370 }
371 onChangeInput( event ) {
372 this.setState( {
373 defaultText: '',
374 } );
375
376 const value = event.target.value.length === 0 ? undefined : event.target.value;
377 this.props.setAttributes( { customText: value } );
378 }
379 onKeyDown( event ) {
380 const { keyCode } = event;
381 const { insertBlocksAfter } = this.props;
382 if ( keyCode === ENTER ) {
383 insertBlocksAfter( [ createBlock( getDefaultBlockName() ) ] );
384 }
385 }
386
387 render() {
388 const {
389 attributes: {
390 customText,
391 },
392 setAttributes
393 } = this.props;
394
395 const { defaultText } = this.state;
396 //const value = customText !== undefined ? customText : defaultText;
397 const value = customText ? customText : defaultText;
398 //const value = defaultText;
399 const inputLength = value.length + 10;
400
401 return[
402 <CodocControls { ...{setAttributes, ...this.props } } />,
403
404 <div className="wp-block-more">
405 <input
406 type="text"
407 value={ value }
408 size={ inputLength }
409 onChange={ this.onChangeInput }
410 onKeyDown={ this.onKeyDown }
411 />
412 </div>
413
414 ];
415 }
416 };
417
418
419 registerBlockType( 'codoc/codoc-block', {
420 title: __( 'codoc' ,'codoc'),
421 description: __( 'The area from this block down is a paid area that only authenticated codoc users can view.','codoc' ),
422 icon,
423 category: 'layout',
424 supports: {
425 customClassName: false,
426 className: false,
427 html: false,
428 multiple: false,
429 },
430 keywords: [
431 __( 'codoc Block' ,'codoc'),
432 __( 'plugin for codoc' ,'codoc'),
433 __( 'codoc-block' ,'codoc'),
434 ],
435 attributes: {
436 showPrice: {
437 type: 'boolean',
438 default: null,
439 },
440 price: {
441 type: 'number',
442 default: null,
443 },
444 limited: {
445 type: 'boolean',
446 default: null,
447 },
448 limitedCount: {
449 type: 'number',
450 default: null,
451 },
452 affiliateMode: {
453 type: 'boolean',
454 default: null,
455 },
456 affiliateRate: {
457 type: 'string',
458 default: null,
459 },
460 showSupport: {
461 type: 'boolean',
462 default: null,
463 },
464 showPaywalledSupport: {
465 type: 'boolean',
466 default: null,
467 },
468 statusLimited: {
469 type: 'boolean',
470 default: null,
471 },
472 subscriptions: {
473 type: 'object',
474 default: null,
475 },
476 customText: {
477 type: 'string',
478 default: '',
479 },
480 version: {
481 type: 'string',
482 default: null,
483 },
484 },
485
486 edit: EditBlockContent,
487
488 save: function( props ) {
489 const {
490 setAttributes,
491 attributes: {
492 customText,
493 }
494 } = props;
495 return ( // return if link behavior normal
496 <div
497 data-id='codoc-tag'
498 className={ CODOC_ENTRIES_CLASS }
499 >
500 { customText && !! customText.length && (
501 <RichText.Content
502 value={ customText }
503 />
504 )}
505 </div>
506 )
507 },
508 } );
509