| @@ -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,10 +25,14 @@ | ||
| 26 | 25 | PanelBody, |
| 27 | 26 | ToggleControl, |
| 28 | 27 | CheckboxControl, |
| 29 | 28 | RangeControl, |
| 29 | + TextControl, | |
| 30 | + Notice, | |
| 30 | 31 | } = wp.components; |
| 31 | 32 | |
| 33 | +const { withSelect } = wp.data; | |
| 34 | + | |
| 32 | 35 | const { |
| 33 | 36 | getDefaultBlockName, |
| 34 | 37 | createBlock, |
| 35 | 38 | } = wp.blocks; |
| @@ -39,20 +42,151 @@ | ||
| 39 | 42 | const CODOC_URL = OPTIONS.codoc_url; |
| 40 | 43 | const CODOC_USER_CODE = OPTIONS.codoc_usercode; |
| 41 | 44 | const CODOC_PLUGIN_VERSION = OPTIONS.codoc_plugin_version; |
| 42 | 45 | const CODOC_ENTRIES_CLASS = 'codoc-entries'; |
| 46 | +const CODOC_ACCOUNT_IS_PRO = OPTIONS.codoc_account_is_pro; | |
| 47 | +const CODOC_CURRENCY_CODE = OPTIONS.codoc_currency_code; | |
| 48 | +const CODOC_CURRENCY_DECIMAL_PLACES = OPTIONS.codoc_currency_decimal_places; | |
| 43 | 49 | |
| 44 | 50 | //import Cookies from 'universal-cookie'; |
| 45 | 51 | //const cookies = new Cookies(); |
| 46 | 52 | |
| 53 | +const CODOC_MAX_LENGTHS = OPTIONS.codoc_max_lengths || {}; | |
| 54 | + | |
| 55 | +// エディタで前回使った設定を localStorage に保存し、新規ブロックの初期値に使う | |
| 56 | +// (優先順位: 設定画面の Block Default Values -> 前回値 -> 固定値) | |
| 57 | +const CODOC_LAST_USED_KEY = 'codoc_block_last_used'; | |
| 58 | +const CODOC_LAST_USED_ATTRS = ['showPrice','price','limited','limitedCount','affiliateMode','affiliateRate','showSupport','showPaywalledSupport','showPayWithoutAccountButton','statusLimited','subscriptions']; | |
| 59 | +function loadLastUsedAttributes() { | |
| 60 | + try { | |
| 61 | + const parsed = JSON.parse(window.localStorage.getItem(CODOC_LAST_USED_KEY) || 'null'); | |
| 62 | + return (parsed && typeof parsed === 'object') ? parsed : {}; | |
| 63 | + } catch (e) { | |
| 64 | + return {}; | |
| 65 | + } | |
| 66 | +} | |
| 67 | +function saveLastUsedAttributes(attributes) { | |
| 68 | + try { | |
| 69 | + const saved = {}; | |
| 70 | + CODOC_LAST_USED_ATTRS.forEach((key) => { | |
| 71 | + if (attributes[key] !== undefined && attributes[key] !== null) { | |
| 72 | + saved[key] = attributes[key]; | |
| 73 | + } | |
| 74 | + }); | |
| 75 | + window.localStorage.setItem(CODOC_LAST_USED_KEY, JSON.stringify(saved)); | |
| 76 | + } catch (e) { | |
| 77 | + // localStorage が使えない環境では何もしない | |
| 78 | + } | |
| 79 | +} | |
| 80 | + | |
| 81 | +// codoc ブロックの直前/直後で本文を分割 | |
| 82 | +function splitCodocContent(content) { | |
| 83 | + const blockRegex = /<!--\s*wp:codoc\/codoc-block[\s\S]*?<!--\s*\/wp:codoc\/codoc-block\s*-->/; | |
| 84 | + const splited = (content || '').split(blockRegex); | |
| 85 | + return { | |
| 86 | + bodyFree: splited[0] || '', | |
| 87 | + bodyPaywalled: splited.slice(1).join('') || '', | |
| 88 | + }; | |
| 89 | +} | |
| 90 | + | |
| 91 | +function buildLengthErrors(title, bodyFree, bodyPaywalled) { | |
| 92 | + const errors = []; | |
| 93 | + const total = bodyFree.length + bodyPaywalled.length; | |
| 94 | + if (CODOC_MAX_LENGTHS.title && title.length > CODOC_MAX_LENGTHS.title) { | |
| 95 | + errors.push(__('Title exceeds the maximum length of', 'codoc') + ' ' + CODOC_MAX_LENGTHS.title + ' (' + title.length + ')'); | |
| 96 | + } | |
| 97 | + if (CODOC_MAX_LENGTHS.body_free && bodyFree.length > CODOC_MAX_LENGTHS.body_free) { | |
| 98 | + errors.push(__('Free area exceeds the maximum length of', 'codoc') + ' ' + CODOC_MAX_LENGTHS.body_free + ' (' + bodyFree.length + ')'); | |
| 99 | + } | |
| 100 | + if (CODOC_MAX_LENGTHS.body_paywalled && bodyPaywalled.length > CODOC_MAX_LENGTHS.body_paywalled) { | |
| 101 | + errors.push(__('Paid area exceeds the maximum length of', 'codoc') + ' ' + CODOC_MAX_LENGTHS.body_paywalled + ' (' + bodyPaywalled.length + ')'); | |
| 102 | + } | |
| 103 | + if (CODOC_MAX_LENGTHS.body && total > CODOC_MAX_LENGTHS.body) { | |
| 104 | + errors.push(__('Total body exceeds the maximum length of', 'codoc') + ' ' + CODOC_MAX_LENGTHS.body + ' (' + total + ')'); | |
| 105 | + } | |
| 106 | + return errors; | |
| 107 | +} | |
| 108 | + | |
| 109 | +// codoc ブロック選択時の Inspector サイドバーに警告を表示する | |
| 110 | +const CodocLengthNotices = withSelect((select) => { | |
| 111 | + const editor = select('core/editor'); | |
| 112 | + return { | |
| 113 | + postTitle: editor ? editor.getEditedPostAttribute('title') : '', | |
| 114 | + postContent: editor ? editor.getEditedPostAttribute('content') : '', | |
| 115 | + }; | |
| 116 | +})(({ postTitle, postContent }) => { | |
| 117 | + const { bodyFree, bodyPaywalled } = splitCodocContent(postContent); | |
| 118 | + const errors = buildLengthErrors(postTitle || '', bodyFree, bodyPaywalled); | |
| 119 | + if (errors.length === 0) { | |
| 120 | + return null; | |
| 121 | + } | |
| 122 | + return ( | |
| 123 | + <Notice status="error" isDismissible={ false }> | |
| 124 | + <strong>{ __('codoc length limit exceeded:', 'codoc') }</strong> | |
| 125 | + <ul style={{ marginTop: '0.5em', marginBottom: 0 }}> | |
| 126 | + { errors.map((e, i) => <li key={i}>{ e }</li>) } | |
| 127 | + </ul> | |
| 128 | + </Notice> | |
| 129 | + ); | |
| 130 | +}); | |
| 131 | + | |
| 132 | +// codoc ブロックを選択していなくても、本文中に存在すればエディタ上部に通知を表示する | |
| 133 | +(function() { | |
| 134 | + if (!wp.data || !wp.data.subscribe) { | |
| 135 | + return; | |
| 136 | + } | |
| 137 | + const NOTICE_ID = 'codoc-length-limit'; | |
| 138 | + let lastState = ''; | |
| 139 | + wp.data.subscribe(function() { | |
| 140 | + const editor = wp.data.select('core/editor'); | |
| 141 | + const blockEditor = wp.data.select('core/block-editor') || wp.data.select('core/editor'); | |
| 142 | + const noticesDispatch = wp.data.dispatch('core/notices'); | |
| 143 | + if (!editor || !blockEditor || !noticesDispatch) { | |
| 144 | + return; | |
| 145 | + } | |
| 146 | + const blocks = blockEditor.getBlocks ? blockEditor.getBlocks() : []; | |
| 147 | + const hasCodocBlock = blocks.some(function(b) { return b && b.name === 'codoc/codoc-block'; }); | |
| 148 | + if (!hasCodocBlock) { | |
| 149 | + if (lastState !== '') { | |
| 150 | + noticesDispatch.removeNotice(NOTICE_ID); | |
| 151 | + lastState = ''; | |
| 152 | + } | |
| 153 | + return; | |
| 154 | + } | |
| 155 | + const title = editor.getEditedPostAttribute('title') || ''; | |
| 156 | + const content = editor.getEditedPostAttribute('content') || ''; | |
| 157 | + const { bodyFree, bodyPaywalled } = splitCodocContent(content); | |
| 158 | + const errors = buildLengthErrors(title, bodyFree, bodyPaywalled); | |
| 159 | + const state = errors.join('||'); | |
| 160 | + if (state === lastState) { | |
| 161 | + return; | |
| 162 | + } | |
| 163 | + lastState = state; | |
| 164 | + noticesDispatch.removeNotice(NOTICE_ID); | |
| 165 | + if (errors.length > 0) { | |
| 166 | + noticesDispatch.createNotice( | |
| 167 | + 'error', | |
| 168 | + __('codoc length limit exceeded:', 'codoc') + ' ' + errors.join(' / '), | |
| 169 | + { id: NOTICE_ID, isDismissible: false } | |
| 170 | + ); | |
| 171 | + } | |
| 172 | + }); | |
| 173 | +})(); | |
| 174 | + | |
| 47 | 175 | class CodocControls extends Component { |
| 48 | 176 | constructor( props ) { |
| 49 | 177 | super( ...arguments ); |
| 50 | 178 | this.subscriptionsFetched = []; |
| 179 | + this.subscriptionSearchTerm = ''; | |
| 180 | + this.state = { | |
| 181 | + searchTerm: '', | |
| 182 | + filteredSubscriptions: [] | |
| 183 | + }; | |
| 51 | 184 | this.fetchSubscriptions(); |
| 185 | + this.handleSearchChange = this.handleSearchChange.bind(this); | |
| 52 | 186 | } |
| 53 | 187 | |
| 54 | - fetchSubscriptions() { | |
| 188 | + fetchSubscriptions(searchTitle = '') { | |
| 55 | 189 | const { |
| 56 | 190 | setAttributes, |
| 57 | 191 | attributes: { |
| 58 | 192 | fetching, |
| @@ -65,8 +199,13 @@ | ||
| 65 | 199 | |
| 66 | 200 | setAttributes( { fetching: true } ) |
| 67 | 201 | let url = CODOC_URL + '/api/v1/cms/' + CODOC_USER_CODE + '/subscriptions?without_token=1'; |
| 68 | 202 | |
| 203 | + // Add title parameter if search term exists | |
| 204 | + if (searchTitle) { | |
| 205 | + url += '&title=' + encodeURIComponent(searchTitle); | |
| 206 | + } | |
| 207 | + | |
| 69 | 208 | fetch(url) |
| 70 | 209 | .then( res => res.json() ) |
| 71 | 210 | .then( res => { |
| 72 | 211 | let list = []; |
| @@ -74,104 +213,173 @@ | ||
| 74 | 213 | for ( var i = 0; i < res.subscriptions.length; i++ ) { |
| 75 | 214 | let info = { |
| 76 | 215 | value: res.subscriptions[i].code, |
| 77 | 216 | label: res.subscriptions[i].title, |
| 217 | + term: res.subscriptions[i].term, | |
| 218 | + price: res.subscriptions[i].price, | |
| 219 | + currency: res.subscriptions[i].currency | |
| 78 | 220 | } |
| 79 | 221 | list[i] = info |
| 80 | 222 | } |
| 81 | 223 | } |
| 82 | - if (list.length) { | |
| 224 | + if (list.length || searchTitle) { | |
| 83 | 225 | this.subscriptionsFetched = list; |
| 226 | + this.setState({ filteredSubscriptions: list }); | |
| 84 | 227 | } |
| 85 | 228 | setAttributes( { fetching: false } ) |
| 86 | 229 | }) |
| 87 | 230 | } |
| 88 | - | |
| 231 | + | |
| 232 | + handleSearchChange(value) { | |
| 233 | + this.setState({ searchTerm: value }); | |
| 234 | + | |
| 235 | + // Debounce the API call | |
| 236 | + clearTimeout(this.searchTimeout); | |
| 237 | + this.searchTimeout = setTimeout(() => { | |
| 238 | + this.fetchSubscriptions(value); | |
| 239 | + }, 500); | |
| 240 | + } | |
| 241 | + | |
| 89 | 242 | getShowPriceHelp( checked ) { |
| 90 | 243 | return checked ? |
| 91 | - __( 'する' ) : | |
| 92 | - __( 'しない' ); | |
| 244 | + __( 'Enable','codoc' ) : | |
| 245 | + __( 'Disable','codoc' ); | |
| 93 | 246 | } |
| 94 | 247 | getShowSupportHelp( checked ) { |
| 95 | 248 | return checked ? |
| 96 | - __( '受け付ける' ) : | |
| 97 | - __( '受け付けない' ); | |
| 249 | + __( 'Accept' ,'codoc') : | |
| 250 | + __( 'Do not accept' ,'codoc'); | |
| 98 | 251 | } |
| 99 | - | |
| 252 | + getShowPaywalledSupportHelp( checked ) { | |
| 253 | + return checked ? | |
| 254 | + __( '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') : | |
| 255 | + __( ' ' ); | |
| 256 | + } | |
| 257 | + getStatusLimitedHelp( checked ) { | |
| 258 | + return checked ? | |
| 259 | + __( 'Unlisted' ,'codoc') : | |
| 260 | + __( 'Published' ,'codoc'); | |
| 261 | + } | |
| 262 | + getShowPayWithoutAccountButtonHelp( checked ) { | |
| 263 | + return checked ? | |
| 264 | + __( 'Viewers can purchase without a codoc account.' ,'codoc') : | |
| 265 | + __( 'Viewers must log in to codoc to purchase.' ,'codoc'); | |
| 266 | + } | |
| 267 | + | |
| 100 | 268 | render() { |
| 101 | 269 | const { |
| 102 | - setAttributes, | |
| 270 | + setAttributes: setBlockAttributes, | |
| 103 | 271 | attributes: { |
| 104 | 272 | showPrice, |
| 105 | 273 | price, |
| 106 | 274 | limited, |
| 107 | 275 | limitedCount, |
| 108 | - | |
| 276 | + | |
| 109 | 277 | affiliateMode, |
| 110 | 278 | affiliateRate, |
| 111 | 279 | |
| 112 | 280 | showSupport, |
| 113 | - | |
| 281 | + showPaywalledSupport, | |
| 282 | + showPayWithoutAccountButton, | |
| 283 | + statusLimited, | |
| 114 | 284 | subscriptions, |
| 115 | 285 | } |
| 116 | 286 | } = this.props; |
| 287 | + // 設定変更のたびに前回値として保存 | |
| 288 | + const setAttributes = (attrs) => { | |
| 289 | + setBlockAttributes(attrs); | |
| 290 | + saveLastUsedAttributes(Object.assign({}, this.props.attributes, attrs)); | |
| 291 | + }; | |
| 117 | 292 | |
| 118 | 293 | const toggleShowPrice = () => setAttributes( { showPrice: ! showPrice } ); |
| 119 | 294 | const toggleLimited = () => setAttributes( { limited: ! limited } ); |
| 295 | + const toggleShowPaywalledSupport = () => setAttributes( { showPaywalledSupport: ! showPaywalledSupport } ); | |
| 296 | + const toggleStatusLimited = () => setAttributes( { statusLimited: ! statusLimited } ); | |
| 120 | 297 | const toggleAffiliateMode = () => setAttributes( { affiliateMode: ! affiliateMode } ); |
| 121 | 298 | const toggleShowSupport = () => setAttributes( { showSupport: ! showSupport } ); |
| 122 | - | |
| 299 | + const toggleShowPayWithoutAccountButton = () => setAttributes( { showPayWithoutAccountButton: ! showPayWithoutAccountButton } ); | |
| 300 | + | |
| 123 | 301 | const SubscriptionCheckBoxes = withState({ |
| 124 | - checked_obj: Object.assign(new Object, subscriptions) | |
| 125 | - })( ( { checked_obj , setState } ) => ( | |
| 302 | + checked_obj: Object.assign({}, subscriptions) | |
| 303 | + })( ({ checked_obj, setState }) => ( | |
| 304 | + <div> | |
| 305 | + {this.state.filteredSubscriptions.length === 0 ? ( | |
| 306 | + <p style={{ fontStyle: 'italic', color: '#666' }}> | |
| 307 | + { this.state.searchTerm | |
| 308 | + ? __('No plans found matching your search.','codoc') | |
| 309 | + : __('No reader plans available.','codoc') | |
| 310 | + } | |
| 311 | + </p> | |
| 312 | + ) : ( | |
| 126 | 313 | <ul> |
| 127 | - { | |
| 128 | - this.subscriptionsFetched.map((v) => ( | |
| 129 | - <li><CheckboxControl | |
| 130 | - className="check_items" | |
| 131 | - label={v.label} | |
| 132 | - checked={checked_obj[v.value]} | |
| 314 | + { | |
| 315 | + this.state.filteredSubscriptions.map((v) => { | |
| 316 | + const isChecked = !!checked_obj[v.value]; | |
| 317 | + const checkedCount = Object.keys(checked_obj).length; | |
| 133 | 318 | |
| 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 | - ) ) | |
| 319 | + return ( | |
| 320 | + <li key={v.value}> | |
| 321 | + <CheckboxControl | |
| 322 | + className="check_items" | |
| 323 | + label={v.label} | |
| 324 | + checked={isChecked} | |
| 325 | + onChange={(check) => { | |
| 326 | + // 追加する場合、5個以上は無効 | |
| 327 | + if (check && checkedCount >= 5) { | |
| 328 | + return; // これ以上チェックできない | |
| 329 | + } | |
| 330 | + | |
| 331 | + const newChecked = { ...checked_obj }; | |
| 332 | + | |
| 333 | + if (check) { | |
| 334 | + newChecked[v.value] = true; | |
| 335 | + } else { | |
| 336 | + delete newChecked[v.value]; | |
| 337 | + } | |
| 338 | + | |
| 339 | + setAttributes({ subscriptions: newChecked }); | |
| 340 | + setState({ checked_obj: newChecked }); | |
| 341 | + }} | |
| 342 | + /> | |
| 343 | + </li> | |
| 344 | + ); | |
| 345 | + }) | |
| 141 | 346 | } |
| 142 | 347 | </ul> |
| 348 | + )} | |
| 349 | + </div> | |
| 143 | 350 | ) ) |
| 144 | 351 | 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%' }, | |
| 352 | + { value: '0.0500', label:'5%' }, | |
| 353 | + { value: '0.1000', label:'10%' }, | |
| 354 | + { value: '0.1500', label:'15%' }, | |
| 355 | + { value: '0.2000', label:'20%' }, | |
| 356 | + { value: '0.2500', label:'25%' }, | |
| 357 | + { value: '0.3000', label:'30%' }, | |
| 358 | + { value: '0.3500', label:'35%' }, | |
| 359 | + { value: '0.4000', label:'40%' }, | |
| 360 | + { value: '0.4500', label:'45%' }, | |
| 361 | + { value: '0.5000', label:'50%' }, | |
| 155 | 362 | ]; |
| 156 | 363 | |
| 157 | 364 | return( |
| 158 | 365 | <InspectorControls key="CodocControls"> |
| 159 | 366 | |
| 367 | + <CodocLengthNotices /> | |
| 368 | + | |
| 160 | 369 | <PanelBody> |
| 161 | 370 | |
| 162 | 371 | <ToggleControl |
| 163 | - label={ __( '単体販売' ) } | |
| 372 | + label={ __( 'individual sale','codoc' ) } | |
| 164 | 373 | checked={ !! showPrice } |
| 165 | 374 | help={ this.getShowPriceHelp } |
| 166 | 375 | ref="showPrice" |
| 167 | 376 | onChange={ toggleShowPrice } |
| 168 | 377 | /> |
| 169 | - | |
| 378 | + | |
| 170 | 379 | <div style={{ display: showPrice ? 'initial' : 'none' }}> |
| 171 | - | |
| 172 | 380 | <RangeControl |
| 173 | - label={ __( '価格(円)' ) } | |
| 381 | + 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 | 382 | value={ price } |
| 175 | 383 | initialPosition={ price } |
| 176 | 384 | onChange={ ( value ) => { |
| 177 | 385 | // do validate this |
| @@ -177,13 +385,21 @@ | ||
| 177 | 385 | // do validate this |
| 178 | 386 | setAttributes({ price: value }); |
| 179 | 387 | }} |
| 180 | 388 | min="100" |
| 181 | - max="50000" | |
| 389 | + max={ CODOC_ACCOUNT_IS_PRO == 1 ? 100000 : 50000 } | |
| 182 | 390 | /><br /> |
| 183 | - | |
| 391 | + | |
| 184 | 392 | <ToggleControl |
| 185 | - label={ __( '数量限定販売' ) } | |
| 393 | + label={ __( 'Pay-what-you-want','codoc' ) } | |
| 394 | + checked={ !! showPaywalledSupport } | |
| 395 | + help={ this.getShowPaywalledSupportHelp } | |
| 396 | + onChange={ toggleShowPaywalledSupport } | |
| 397 | + /> | |
| 398 | + | |
| 399 | + <div style={{ display: showPaywalledSupport ? 'none' : 'initial' }}> | |
| 400 | + <ToggleControl | |
| 401 | + label={ __( 'Limited quantity sale','codoc' ) } | |
| 186 | 402 | checked={ !! limited } |
| 187 | 403 | onChange={ toggleLimited } |
| 188 | 404 | /> |
| 189 | 405 | |
| @@ -188,9 +404,9 @@ | ||
| 188 | 404 | /> |
| 189 | 405 | |
| 190 | 406 | <div style={{ display: limited ? 'initial' : 'none' }}> |
| 191 | 407 | <RangeControl |
| 192 | - label={ __( '限定数' ) } | |
| 408 | + label={ __( 'Limited quantity','codoc' ) } | |
| 193 | 409 | value={ limitedCount } |
| 194 | 410 | onChange={ ( value ) => { |
| 195 | 411 | // do validate this |
| 196 | 412 | setAttributes({ limitedCount: value }); |
| @@ -195,15 +411,15 @@ | ||
| 195 | 411 | // do validate this |
| 196 | 412 | setAttributes({ limitedCount: value }); |
| 197 | 413 | }} |
| 198 | 414 | initialPosition={ limitedCount } |
| 199 | - min="1" | |
| 415 | + min="0" | |
| 200 | 416 | max="100" |
| 201 | 417 | /><br /> |
| 202 | 418 | </div> |
| 203 | - | |
| 419 | + | |
| 204 | 420 | <ToggleControl |
| 205 | - label={ __( 'アフィリエイト' ) } | |
| 421 | + label={ __( 'Affiliate','codoc' ) } | |
| 206 | 422 | checked={ !! affiliateMode } |
| 207 | 423 | onChange={ toggleAffiliateMode } |
| 208 | 424 | /> |
| 209 | 425 | |
| @@ -208,30 +424,72 @@ | ||
| 208 | 424 | /> |
| 209 | 425 | |
| 210 | 426 | <div style={{ display: affiliateMode ? 'initial' : 'none' }}> |
| 211 | 427 | <SelectControl |
| 212 | - label={ __( '料率' ) } | |
| 213 | - description={ __( '購入者を対象に指定した料率でアフィリエイトをオファーできます') } | |
| 428 | + label={ __( 'Rate' , 'codoc') } | |
| 429 | + description={ __( 'You can offer affiliate marketing at a specified rate for purchasers.', 'codoc') } | |
| 214 | 430 | options={ affiliateRateOptions } |
| 215 | 431 | value={ affiliateRate } |
| 216 | 432 | onChange={ ( value ) => { |
| 217 | 433 | setAttributes( { affiliateRate: value } ); |
| 218 | - }}/><br /> | |
| 434 | + }}/><br /> | |
| 219 | 435 | </div> |
| 220 | - | |
| 436 | + | |
| 221 | 437 | </div> |
| 222 | - | |
| 438 | + </div> | |
| 439 | + | |
| 440 | + <div style={{ display: showPaywalledSupport ? 'none' : 'initial' }}> | |
| 223 | 441 | <ToggleControl |
| 224 | - label={ __( 'サポート' ) } | |
| 442 | + label={ __( 'Tipping', 'codoc') } | |
| 225 | 443 | checked={ !! showSupport } |
| 226 | 444 | value="1" |
| 227 | 445 | onChange={ toggleShowSupport } |
| 228 | 446 | help={ this.getShowSupportHelp } |
| 229 | 447 | /> |
| 448 | + </div> | |
| 230 | 449 | |
| 231 | - <label>サブスクリプション</label> | |
| 450 | + <div style={{ display: 'initial' }}> | |
| 451 | + <ToggleControl | |
| 452 | + label={ __( 'Guest purchase', 'codoc') } | |
| 453 | + checked={ !! showPayWithoutAccountButton } | |
| 454 | + value="1" | |
| 455 | + onChange={ toggleShowPayWithoutAccountButton } | |
| 456 | + help={ this.getShowPayWithoutAccountButtonHelp } | |
| 457 | + /> | |
| 458 | + </div> | |
| 459 | + | |
| 460 | + <div style={{ display: 'initial' }}> | |
| 461 | + <ToggleControl | |
| 462 | + label={ __( 'Unlisted','codoc' ) } | |
| 463 | + checked={ !! statusLimited } | |
| 464 | + value="1" | |
| 465 | + onChange={ toggleStatusLimited } | |
| 466 | + help={ this.getStatusLimitedHelp } | |
| 467 | + /> | |
| 468 | + </div> | |
| 469 | + | |
| 470 | + <div class="codoc-subscription-title"> | |
| 471 | + <label> | |
| 472 | + { __('Reader Plans','codoc') } | |
| 473 | + </label> | |
| 474 | + <a | |
| 475 | + href={ CODOC_URL + '/me/subscriptions'} | |
| 476 | + target="_blank" class="codoc-subscription-add" | |
| 477 | + > | |
| 478 | + { __('Add','codoc') } | |
| 479 | + </a> | |
| 480 | + </div> | |
| 481 | + | |
| 482 | + <TextControl | |
| 483 | + label={ __('Search Plans','codoc') } | |
| 484 | + value={ this.state.searchTerm } | |
| 485 | + onChange={ this.handleSearchChange } | |
| 486 | + placeholder={ __('Enter title to search...','codoc') } | |
| 487 | + /> | |
| 488 | + | |
| 232 | 489 | <SubscriptionCheckBoxes /> |
| 233 | 490 | |
| 491 | + | |
| 234 | 492 | </PanelBody> |
| 235 | 493 | </InspectorControls> |
| 236 | 494 | ); |
| 237 | 495 | } |
| @@ -240,22 +498,28 @@ | ||
| 240 | 498 | class EditBlockContent extends Component { |
| 241 | 499 | constructor() { |
| 242 | 500 | super( ...arguments ); |
| 243 | 501 | // デフォルト値 |
| 502 | + const bd = OPTIONS.codoc_block_defaults || {}; | |
| 503 | + const lu = loadLastUsedAttributes(); | |
| 504 | + const d = (key, fallback) => bd.hasOwnProperty(key) ? bd[key] : (lu.hasOwnProperty(key) ? lu[key] : fallback); | |
| 244 | 505 | 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 }); | |
| 506 | + this.props.setAttributes({ showPrice: this.props.attributes.showPrice == null ? d('showPrice', true) : this.props.attributes.showPrice }); | |
| 507 | + this.props.setAttributes({ price: this.props.attributes.price == null ? d('price', 500) : this.props.attributes.price }); | |
| 508 | + this.props.setAttributes({ limited: this.props.attributes.limited == null ? d('limited', false) : this.props.attributes.limited }); | |
| 509 | + this.props.setAttributes({ limitedCount: this.props.attributes.limitedCount == null ? d('limitedCount', 10) : this.props.attributes.limitedCount }); | |
| 510 | + this.props.setAttributes({ affiliateMode: this.props.attributes.affiliateMode == null ? d('affiliateMode', false) : this.props.attributes.affiliateMode }); | |
| 511 | + this.props.setAttributes({ affiliateRate: this.props.attributes.affiliateRate == null ? d('affiliateRate', '0.0500') : this.props.attributes.affiliateRate }); | |
| 512 | + this.props.setAttributes({ showSupport: this.props.attributes.showSupport == null ? d('showSupport', false) : this.props.attributes.showSupport }); | |
| 513 | + this.props.setAttributes({ showPaywalledSupport: this.props.attributes.showPaywalledSupport == null ? d('showPaywalledSupport', false) : this.props.attributes.showPaywalledSupport }); | |
| 514 | + this.props.setAttributes({ statusLimited: this.props.attributes.statusLimited == null ? d('statusLimited', false) : this.props.attributes.statusLimited }); | |
| 515 | + this.props.setAttributes({ showPayWithoutAccountButton: this.props.attributes.showPayWithoutAccountButton == null ? d('showPayWithoutAccountButton', true) : this.props.attributes.showPayWithoutAccountButton }); | |
| 516 | + this.props.setAttributes({ subscriptions: this.props.attributes.subscriptions == null ? d('subscriptions', {}) : this.props.attributes.subscriptions }); | |
| 253 | 517 | |
| 254 | 518 | this.onChangeInput = this.onChangeInput.bind( this ); |
| 255 | 519 | this.onKeyDown = this.onKeyDown.bind( this ); |
| 256 | 520 | this.state = { |
| 257 | - defaultText: __( 'この続きをみるには' ), | |
| 521 | + defaultText: __( 'To continue reading, ...','codoc' ), | |
| 258 | 522 | }; |
| 259 | 523 | } |
| 260 | 524 | onChangeInput( event ) { |
| 261 | 525 | this.setState( { |
| @@ -271,9 +535,9 @@ | ||
| 271 | 535 | if ( keyCode === ENTER ) { |
| 272 | 536 | insertBlocksAfter( [ createBlock( getDefaultBlockName() ) ] ); |
| 273 | 537 | } |
| 274 | 538 | } |
| 275 | - | |
| 539 | + | |
| 276 | 540 | render() { |
| 277 | 541 | const { |
| 278 | 542 | attributes: { |
| 279 | 543 | customText, |
| @@ -305,10 +569,10 @@ | ||
| 305 | 569 | }; |
| 306 | 570 | |
| 307 | 571 | |
| 308 | 572 | registerBlockType( 'codoc/codoc-block', { |
| 309 | - title: __( 'codoc' ), | |
| 310 | - description: __( 'このブロックから下のブロックは認証されたcodocユーザーのみが閲覧できる有料エリアとなります。' ), | |
| 573 | + title: __( 'codoc' ,'codoc'), | |
| 574 | + description: __( 'The area from this block down is a paid area that only authenticated codoc users can view.','codoc' ), | |
| 311 | 575 | icon, |
| 312 | 576 | category: 'layout', |
| 313 | 577 | supports: { |
| 314 | 578 | customClassName: false, |
| @@ -316,11 +580,11 @@ | ||
| 316 | 580 | html: false, |
| 317 | 581 | multiple: false, |
| 318 | 582 | }, |
| 319 | 583 | keywords: [ |
| 320 | - __( 'codoc Block' ), | |
| 321 | - __( 'plugin for codoc' ), | |
| 322 | - __( 'codoc-block' ), | |
| 584 | + __( 'codoc Block' ,'codoc'), | |
| 585 | + __( 'plugin for codoc' ,'codoc'), | |
| 586 | + __( 'codoc-block' ,'codoc'), | |
| 323 | 587 | ], |
| 324 | 588 | attributes: { |
| 325 | 589 | showPrice: { |
| 326 | 590 | type: 'boolean', |
| @@ -349,8 +613,20 @@ | ||
| 349 | 613 | showSupport: { |
| 350 | 614 | type: 'boolean', |
| 351 | 615 | default: null, |
| 352 | 616 | }, |
| 617 | + showPaywalledSupport: { | |
| 618 | + type: 'boolean', | |
| 619 | + default: null, | |
| 620 | + }, | |
| 621 | + statusLimited: { | |
| 622 | + type: 'boolean', | |
| 623 | + default: null, | |
| 624 | + }, | |
| 625 | + showPayWithoutAccountButton: { | |
| 626 | + type: 'boolean', | |
| 627 | + default: null, | |
| 628 | + }, | |
| 353 | 629 | subscriptions: { |
| 354 | 630 | type: 'object', |
| 355 | 631 | default: null, |
| 356 | 632 | }, |
| @@ -362,11 +638,11 @@ | ||
| 362 | 638 | type: 'string', |
| 363 | 639 | default: null, |
| 364 | 640 | }, |
| 365 | 641 | }, |
| 366 | - | |
| 642 | + | |
| 367 | 643 | edit: EditBlockContent, |
| 368 | - | |
| 644 | + | |
| 369 | 645 | save: function( props ) { |
| 370 | 646 | const { |
| 371 | 647 | setAttributes, |
| 372 | 648 | attributes: { |