PluginProbe
codoc / 0.9.58
codoc v0.9.58
0.9.61 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 All 115 releases
← All changes | src/block/block.js +193 -72 0.8.3 → 0.9.58 View file →
@@ -10,9 +10,8 @@
10 10 import './editor.scss';
11 11 import icon from './icon';
12 12 //import { ENTER } from '@wordpress/keycodes';
13 13 const { ENTER } = wp.keycodes;
14 -
15 14 const { __ } = wp.i18n; // Import __() from wp.i18n
16 15 const { Component } = wp.element;
17 16
18 17 const { registerBlockType } = wp.blocks; // Import registerBlockType() from wp.blocks
@@ -26,8 +25,9 @@
26 25 PanelBody,
27 26 ToggleControl,
28 27 CheckboxControl,
29 28 RangeControl,
29 + TextControl,
30 30 } = wp.components;
31 31
32 32 const {
33 33 getDefaultBlockName,
@@ -39,8 +39,11 @@
39 39 const CODOC_URL = OPTIONS.codoc_url;
40 40 const CODOC_USER_CODE = OPTIONS.codoc_usercode;
41 41 const CODOC_PLUGIN_VERSION = OPTIONS.codoc_plugin_version;
42 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;
43 46
44 47 //import Cookies from 'universal-cookie';
45 48 //const cookies = new Cookies();
46 49
@@ -47,12 +50,18 @@
47 50 class CodocControls extends Component {
48 51 constructor( props ) {
49 52 super( ...arguments );
50 53 this.subscriptionsFetched = [];
54 + this.subscriptionSearchTerm = '';
55 + this.state = {
56 + searchTerm: '',
57 + filteredSubscriptions: []
58 + };
51 59 this.fetchSubscriptions();
60 + this.handleSearchChange = this.handleSearchChange.bind(this);
52 61 }
53 62
54 - fetchSubscriptions() {
63 + fetchSubscriptions(searchTitle = '') {
55 64 const {
56 65 setAttributes,
57 66 attributes: {
58 67 fetching,
@@ -65,8 +74,13 @@
65 74
66 75 setAttributes( { fetching: true } )
67 76 let url = CODOC_URL + '/api/v1/cms/' + CODOC_USER_CODE + '/subscriptions?without_token=1';
68 77
78 + // Add title parameter if search term exists
79 + if (searchTitle) {
80 + url += '&title=' + encodeURIComponent(searchTitle);
81 + }
82 +
69 83 fetch(url)
70 84 .then( res => res.json() )
71 85 .then( res => {
72 86 let list = [];
@@ -74,30 +88,54 @@
74 88 for ( var i = 0; i < res.subscriptions.length; i++ ) {
75 89 let info = {
76 90 value: res.subscriptions[i].code,
77 91 label: res.subscriptions[i].title,
92 + term: res.subscriptions[i].term,
93 + price: res.subscriptions[i].price,
94 + currency: res.subscriptions[i].currency
78 95 }
79 96 list[i] = info
80 97 }
81 98 }
82 - if (list.length) {
99 + if (list.length || searchTitle) {
83 100 this.subscriptionsFetched = list;
101 + this.setState({ filteredSubscriptions: list });
84 102 }
85 103 setAttributes( { fetching: false } )
86 104 })
87 105 }
88 -
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 +
89 117 getShowPriceHelp( checked ) {
90 118 return checked ?
91 - __( 'する' ) :
92 - __( 'しない' );
119 + __( 'Enable','codoc' ) :
120 + __( 'Disable','codoc' );
93 121 }
94 122 getShowSupportHelp( checked ) {
95 123 return checked ?
96 - __( '受け付ける' ) :
97 - __( '受け付けない' );
124 + __( 'Accept' ,'codoc') :
125 + __( 'Do not accept' ,'codoc');
98 126 }
99 -
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 +
100 138 render() {
101 139 const {
102 140 setAttributes,
103 141 attributes: {
@@ -104,14 +142,15 @@
104 142 showPrice,
105 143 price,
106 144 limited,
107 145 limitedCount,
108 -
146 +
109 147 affiliateMode,
110 148 affiliateRate,
111 149
112 150 showSupport,
113 -
151 + showPaywalledSupport,
152 + statusLimited,
114 153 subscriptions,
115 154 }
116 155 } = this.props;
117 156
@@ -116,43 +155,74 @@
116 155 } = this.props;
117 156
118 157 const toggleShowPrice = () => setAttributes( { showPrice: ! showPrice } );
119 158 const toggleLimited = () => setAttributes( { limited: ! limited } );
159 + const toggleShowPaywalledSupport = () => setAttributes( { showPaywalledSupport: ! showPaywalledSupport } );
160 + const toggleStatusLimited = () => setAttributes( { statusLimited: ! statusLimited } );
120 161 const toggleAffiliateMode = () => setAttributes( { affiliateMode: ! affiliateMode } );
121 162 const toggleShowSupport = () => setAttributes( { showSupport: ! showSupport } );
122 -
163 +
123 164 const SubscriptionCheckBoxes = withState({
124 - checked_obj: Object.assign(new Object, subscriptions)
125 - })( ( { checked_obj , setState } ) => (
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 + ) : (
126 176 <ul>
127 - {
128 - this.subscriptionsFetched.map((v) => (
129 - <li><CheckboxControl
130 - className="check_items"
131 - label={v.label}
132 - checked={checked_obj[v.value]}
177 + {
178 + this.state.filteredSubscriptions.map((v) => {
179 + const isChecked = !!checked_obj[v.value];
180 + const checkedCount = Object.keys(checked_obj).length;
133 181
134 - onChange={ ( check ) => {
135 - check ? checked_obj[v.value] = true : delete checked_obj[v.value]
136 - setAttributes({subscriptions : checked_obj})
137 - setState({checked_obj})
138 - } }
139 - /></li>
140 - ) )
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 + })
141 209 }
142 210 </ul>
211 + )}
212 + </div>
143 213 ) )
144 214 const affiliateRateOptions = [
145 - { value: '0.0500', label:'販売価格の5%' },
146 - { value: '0.1000', label:'販売価格の10%' },
147 - { value: '0.1500', label:'販売価格の15%' },
148 - { value: '0.2000', label:'販売価格の20%' },
149 - { value: '0.2500', label:'販売価格の25%' },
150 - { value: '0.3000', label:'販売価格の30%' },
151 - { value: '0.3500', label:'販売価格の35%' },
152 - { value: '0.4000', label:'販売価格の40%' },
153 - { value: '0.4500', label:'販売価格の45%' },
154 - { value: '0.5000', label:'販売価格の50%' },
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%' },
155 225 ];
156 226
157 227 return(
158 228 <InspectorControls key="CodocControls">
@@ -159,19 +229,18 @@
159 229
160 230 <PanelBody>
161 231
162 232 <ToggleControl
163 - label={ __( '単体販売' ) }
233 + label={ __( 'individual sale','codoc' ) }
164 234 checked={ !! showPrice }
165 235 help={ this.getShowPriceHelp }
166 236 ref="showPrice"
167 237 onChange={ toggleShowPrice }
168 238 />
169 -
239 +
170 240 <div style={{ display: showPrice ? 'initial' : 'none' }}>
171 -
172 241 <RangeControl
173 - label={ __( '価格(円)' ) }
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') + '】' : '' ) }
174 243 value={ price }
175 244 initialPosition={ price }
176 245 onChange={ ( value ) => {
177 246 // do validate this
@@ -177,13 +246,21 @@
177 246 // do validate this
178 247 setAttributes({ price: value });
179 248 }}
180 249 min="100"
181 - max="50000"
250 + max={ CODOC_ACCOUNT_IS_PRO == 1 ? 100000 : 50000 }
182 251 /><br />
183 -
252 +
184 253 <ToggleControl
185 - label={ __( '数量限定販売' ) }
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' ) }
186 263 checked={ !! limited }
187 264 onChange={ toggleLimited }
188 265 />
189 266
@@ -188,9 +265,9 @@
188 265 />
189 266
190 267 <div style={{ display: limited ? 'initial' : 'none' }}>
191 268 <RangeControl
192 - label={ __( '限定数' ) }
269 + label={ __( 'Limited quantity','codoc' ) }
193 270 value={ limitedCount }
194 271 onChange={ ( value ) => {
195 272 // do validate this
196 273 setAttributes({ limitedCount: value });
@@ -195,15 +272,15 @@
195 272 // do validate this
196 273 setAttributes({ limitedCount: value });
197 274 }}
198 275 initialPosition={ limitedCount }
199 - min="1"
276 + min="0"
200 277 max="100"
201 278 /><br />
202 279 </div>
203 -
280 +
204 281 <ToggleControl
205 - label={ __( 'アフィリエイト' ) }
282 + label={ __( 'Affiliate','codoc' ) }
206 283 checked={ !! affiliateMode }
207 284 onChange={ toggleAffiliateMode }
208 285 />
209 286
@@ -208,30 +285,62 @@
208 285 />
209 286
210 287 <div style={{ display: affiliateMode ? 'initial' : 'none' }}>
211 288 <SelectControl
212 - label={ __( '料率' ) }
213 - description={ __( '購入者を対象に指定した料率でアフィリエイトをオファーできます') }
289 + label={ __( 'Rate' , 'codoc') }
290 + description={ __( 'You can offer affiliate marketing at a specified rate for purchasers.', 'codoc') }
214 291 options={ affiliateRateOptions }
215 292 value={ affiliateRate }
216 293 onChange={ ( value ) => {
217 294 setAttributes( { affiliateRate: value } );
218 - }}/><br />
295 + }}/><br />
219 296 </div>
220 -
297 +
221 298 </div>
222 -
299 + </div>
300 +
301 + <div style={{ display: showPaywalledSupport ? 'none' : 'initial' }}>
223 302 <ToggleControl
224 - label={ __( 'サポート' ) }
303 + label={ __( 'Tipping', 'codoc') }
225 304 checked={ !! showSupport }
226 305 value="1"
227 306 onChange={ toggleShowSupport }
228 307 help={ this.getShowSupportHelp }
229 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>
230 332
231 - <label>サブスクリプション</label>
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 +
232 340 <SubscriptionCheckBoxes />
233 341
342 +
234 343 </PanelBody>
235 344 </InspectorControls>
236 345 );
237 346 }
@@ -240,22 +349,26 @@
240 349 class EditBlockContent extends Component {
241 350 constructor() {
242 351 super( ...arguments );
243 352 // デフォルト値
353 + const bd = OPTIONS.codoc_block_defaults || {};
354 + const d = (key, fallback) => bd.hasOwnProperty(key) ? bd[key] : fallback;
244 355 this.props.setAttributes({ version: CODOC_PLUGIN_VERSION });
245 - this.props.setAttributes({ showPrice: this.props.attributes.showPrice == null ? true : this.props.attributes.showPrice });
246 - this.props.setAttributes({ price: this.props.attributes.price == null ? 100 : this.props.attributes.price });
247 - this.props.setAttributes({ limited: this.props.attributes.limited == null ? false : this.props.attributes.limited });
248 - this.props.setAttributes({ limitedCount: this.props.attributes.limitedCount == null ? 10 : this.props.attributes.limitedCount });
249 - this.props.setAttributes({ affiliateMode: this.props.attributes.affiliateMode == null ? false : this.props.attributes.affiliateMode });
250 - this.props.setAttributes({ affiliateRate: this.props.attributes.affiliateRate == null ? '0.0500' : this.props.attributes.affiliateRate });
251 - this.props.setAttributes({ showSupport: this.props.attributes.showSupport == null ? false : this.props.attributes.showSupport });
252 - this.props.setAttributes({ subscriptions: this.props.attributes.subscriptions == null ? {} : this.props.attributes.subscriptions });
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 });
253 366
254 367 this.onChangeInput = this.onChangeInput.bind( this );
255 368 this.onKeyDown = this.onKeyDown.bind( this );
256 369 this.state = {
257 - defaultText: __( 'この続きをみるには' ),
370 + defaultText: __( 'To continue reading, ...','codoc' ),
258 371 };
259 372 }
260 373 onChangeInput( event ) {
261 374 this.setState( {
@@ -271,9 +384,9 @@
271 384 if ( keyCode === ENTER ) {
272 385 insertBlocksAfter( [ createBlock( getDefaultBlockName() ) ] );
273 386 }
274 387 }
275 -
388 +
276 389 render() {
277 390 const {
278 391 attributes: {
279 392 customText,
@@ -305,10 +418,10 @@
305 418 };
306 419
307 420
308 421 registerBlockType( 'codoc/codoc-block', {
309 - title: __( 'codoc' ),
310 - description: __( 'このブロックから下のブロックは認証されたcodocユーザーのみが閲覧できる有料エリアとなります。' ),
422 + title: __( 'codoc' ,'codoc'),
423 + description: __( 'The area from this block down is a paid area that only authenticated codoc users can view.','codoc' ),
311 424 icon,
312 425 category: 'layout',
313 426 supports: {
314 427 customClassName: false,
@@ -316,11 +429,11 @@
316 429 html: false,
317 430 multiple: false,
318 431 },
319 432 keywords: [
320 - __( 'codoc Block' ),
321 - __( 'plugin for codoc' ),
322 - __( 'codoc-block' ),
433 + __( 'codoc Block' ,'codoc'),
434 + __( 'plugin for codoc' ,'codoc'),
435 + __( 'codoc-block' ,'codoc'),
323 436 ],
324 437 attributes: {
325 438 showPrice: {
326 439 type: 'boolean',
@@ -349,8 +462,16 @@
349 462 showSupport: {
350 463 type: 'boolean',
351 464 default: null,
352 465 },
466 + showPaywalledSupport: {
467 + type: 'boolean',
468 + default: null,
469 + },
470 + statusLimited: {
471 + type: 'boolean',
472 + default: null,
473 + },
353 474 subscriptions: {
354 475 type: 'object',
355 476 default: null,
356 477 },
@@ -362,11 +483,11 @@
362 483 type: 'string',
363 484 default: null,
364 485 },
365 486 },
366 -
487 +
367 488 edit: EditBlockContent,
368 -
489 +
369 490 save: function( props ) {
370 491 const {
371 492 setAttributes,
372 493 attributes: {