PluginProbe
codoc / 0.9.59
codoc v0.9.59
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.59, at src/block/block.js

511 lines 16.3 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 const bd = OPTIONS.codoc_block_defaults || {};
354 const d = (key, fallback) => bd.hasOwnProperty(key) ? bd[key] : fallback;
355 this.props.setAttributes({ version: CODOC_PLUGIN_VERSION });
356 this.props.setAttributes({ showPrice: this.props.attributes.showPrice == null ? d('showPrice', true) : this.props.attributes.showPrice });
357 this.props.setAttributes({ price: this.props.attributes.price == null ? d('price', 500) : this.props.attributes.price });
358 this.props.setAttributes({ limited: this.props.attributes.limited == null ? d('limited', false) : this.props.attributes.limited });
359 this.props.setAttributes({ limitedCount: this.props.attributes.limitedCount == null ? d('limitedCount', 10) : this.props.attributes.limitedCount });
360 this.props.setAttributes({ affiliateMode: this.props.attributes.affiliateMode == null ? d('affiliateMode', false) : this.props.attributes.affiliateMode });
361 this.props.setAttributes({ affiliateRate: this.props.attributes.affiliateRate == null ? d('affiliateRate', '0.0500') : this.props.attributes.affiliateRate });
362 this.props.setAttributes({ showSupport: this.props.attributes.showSupport == null ? d('showSupport', false) : this.props.attributes.showSupport });
363 this.props.setAttributes({ showPaywalledSupport: this.props.attributes.showPaywalledSupport == null ? d('showPaywalledSupport', false) : this.props.attributes.showPaywalledSupport });
364 this.props.setAttributes({ statusLimited: this.props.attributes.statusLimited == null ? d('statusLimited', false) : this.props.attributes.statusLimited });
365 this.props.setAttributes({ subscriptions: this.props.attributes.subscriptions == null ? d('subscriptions', {}) : this.props.attributes.subscriptions });
366
367 this.onChangeInput = this.onChangeInput.bind( this );
368 this.onKeyDown = this.onKeyDown.bind( this );
369 this.state = {
370 defaultText: __( 'To continue reading, ...','codoc' ),
371 };
372 }
373 onChangeInput( event ) {
374 this.setState( {
375 defaultText: '',
376 } );
377
378 const value = event.target.value.length === 0 ? undefined : event.target.value;
379 this.props.setAttributes( { customText: value } );
380 }
381 onKeyDown( event ) {
382 const { keyCode } = event;
383 const { insertBlocksAfter } = this.props;
384 if ( keyCode === ENTER ) {
385 insertBlocksAfter( [ createBlock( getDefaultBlockName() ) ] );
386 }
387 }
388
389 render() {
390 const {
391 attributes: {
392 customText,
393 },
394 setAttributes
395 } = this.props;
396
397 const { defaultText } = this.state;
398 //const value = customText !== undefined ? customText : defaultText;
399 const value = customText ? customText : defaultText;
400 //const value = defaultText;
401 const inputLength = value.length + 10;
402
403 return[
404 <CodocControls { ...{setAttributes, ...this.props } } />,
405
406 <div className="wp-block-more">
407 <input
408 type="text"
409 value={ value }
410 size={ inputLength }
411 onChange={ this.onChangeInput }
412 onKeyDown={ this.onKeyDown }
413 />
414 </div>
415
416 ];
417 }
418 };
419
420
421 registerBlockType( 'codoc/codoc-block', {
422 title: __( 'codoc' ,'codoc'),
423 description: __( 'The area from this block down is a paid area that only authenticated codoc users can view.','codoc' ),
424 icon,
425 category: 'layout',
426 supports: {
427 customClassName: false,
428 className: false,
429 html: false,
430 multiple: false,
431 },
432 keywords: [
433 __( 'codoc Block' ,'codoc'),
434 __( 'plugin for codoc' ,'codoc'),
435 __( 'codoc-block' ,'codoc'),
436 ],
437 attributes: {
438 showPrice: {
439 type: 'boolean',
440 default: null,
441 },
442 price: {
443 type: 'number',
444 default: null,
445 },
446 limited: {
447 type: 'boolean',
448 default: null,
449 },
450 limitedCount: {
451 type: 'number',
452 default: null,
453 },
454 affiliateMode: {
455 type: 'boolean',
456 default: null,
457 },
458 affiliateRate: {
459 type: 'string',
460 default: null,
461 },
462 showSupport: {
463 type: 'boolean',
464 default: null,
465 },
466 showPaywalledSupport: {
467 type: 'boolean',
468 default: null,
469 },
470 statusLimited: {
471 type: 'boolean',
472 default: null,
473 },
474 subscriptions: {
475 type: 'object',
476 default: null,
477 },
478 customText: {
479 type: 'string',
480 default: '',
481 },
482 version: {
483 type: 'string',
484 default: null,
485 },
486 },
487
488 edit: EditBlockContent,
489
490 save: function( props ) {
491 const {
492 setAttributes,
493 attributes: {
494 customText,
495 }
496 } = props;
497 return ( // return if link behavior normal
498 <div
499 data-id='codoc-tag'
500 className={ CODOC_ENTRIES_CLASS }
501 >
502 { customText && !! customText.length && (
503 <RichText.Content
504 value={ customText }
505 />
506 )}
507 </div>
508 )
509 },
510 } );
511