Gutenberg: Allow additional formatting in RichText
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}
I have created a fairly simple accordion block, and it works great for basic text. The problem is that the control I am using for the accordion content is the RichText, which only allows for basic formatting such as bold.
What if I wanted to create an Unordered List as well as basic text? I am currently using multiline: "p", but how can I add additional elements so that I can also have UL elements in there as well?
The only two ideas I can think of, I cannot figure out how to implement. The first is to extend the block toolbar with BlockControls to include additional formatters for UL, and the second is to use another element instead of RichText - such as Freeform (which might have been renamed to Classic Editor?) - but I cannot find any documentation on these.
Here is an example of my current code:
ATTRIBUTES
attributes: {
title: {
type: 'string',
selector: '.hd-accordion-title',
},
content: {
type: 'array',
source: 'children',
selector: '.hd-accordion-content',
}
},
EDIT
edit: function( props ) {
var title = props.attributes.title;
var content = props.attributes.content;
function onChangeTitle(newTitle) {
props.setAttributes({
title: newTitle
});
}
function onChangeContent(newContent) {
props.setAttributes({
content: newContent
});
}
return [
(
<div className={"hd-accordion"}>
<RichText
tagName="h3"
className= "hd-accordion-title"
value= { title }
onChange= { onChangeTitle }
placeholder = "Title"
keepPlaceholderOnFocus = { true }
multiline= { false }
/>
<RichText
tagName="div"
className="hd-accordion-content"
value={ content }
onChange= { onChangeContent }
placeholder = "content"
multiline="p"
/>
</div>
)
];
},
wordpress wordpress-gutenberg gutenberg-blocks
add a comment |
I have created a fairly simple accordion block, and it works great for basic text. The problem is that the control I am using for the accordion content is the RichText, which only allows for basic formatting such as bold.
What if I wanted to create an Unordered List as well as basic text? I am currently using multiline: "p", but how can I add additional elements so that I can also have UL elements in there as well?
The only two ideas I can think of, I cannot figure out how to implement. The first is to extend the block toolbar with BlockControls to include additional formatters for UL, and the second is to use another element instead of RichText - such as Freeform (which might have been renamed to Classic Editor?) - but I cannot find any documentation on these.
Here is an example of my current code:
ATTRIBUTES
attributes: {
title: {
type: 'string',
selector: '.hd-accordion-title',
},
content: {
type: 'array',
source: 'children',
selector: '.hd-accordion-content',
}
},
EDIT
edit: function( props ) {
var title = props.attributes.title;
var content = props.attributes.content;
function onChangeTitle(newTitle) {
props.setAttributes({
title: newTitle
});
}
function onChangeContent(newContent) {
props.setAttributes({
content: newContent
});
}
return [
(
<div className={"hd-accordion"}>
<RichText
tagName="h3"
className= "hd-accordion-title"
value= { title }
onChange= { onChangeTitle }
placeholder = "Title"
keepPlaceholderOnFocus = { true }
multiline= { false }
/>
<RichText
tagName="div"
className="hd-accordion-content"
value={ content }
onChange= { onChangeContent }
placeholder = "content"
multiline="p"
/>
</div>
)
];
},
wordpress wordpress-gutenberg gutenberg-blocks
add a comment |
I have created a fairly simple accordion block, and it works great for basic text. The problem is that the control I am using for the accordion content is the RichText, which only allows for basic formatting such as bold.
What if I wanted to create an Unordered List as well as basic text? I am currently using multiline: "p", but how can I add additional elements so that I can also have UL elements in there as well?
The only two ideas I can think of, I cannot figure out how to implement. The first is to extend the block toolbar with BlockControls to include additional formatters for UL, and the second is to use another element instead of RichText - such as Freeform (which might have been renamed to Classic Editor?) - but I cannot find any documentation on these.
Here is an example of my current code:
ATTRIBUTES
attributes: {
title: {
type: 'string',
selector: '.hd-accordion-title',
},
content: {
type: 'array',
source: 'children',
selector: '.hd-accordion-content',
}
},
EDIT
edit: function( props ) {
var title = props.attributes.title;
var content = props.attributes.content;
function onChangeTitle(newTitle) {
props.setAttributes({
title: newTitle
});
}
function onChangeContent(newContent) {
props.setAttributes({
content: newContent
});
}
return [
(
<div className={"hd-accordion"}>
<RichText
tagName="h3"
className= "hd-accordion-title"
value= { title }
onChange= { onChangeTitle }
placeholder = "Title"
keepPlaceholderOnFocus = { true }
multiline= { false }
/>
<RichText
tagName="div"
className="hd-accordion-content"
value={ content }
onChange= { onChangeContent }
placeholder = "content"
multiline="p"
/>
</div>
)
];
},
wordpress wordpress-gutenberg gutenberg-blocks
I have created a fairly simple accordion block, and it works great for basic text. The problem is that the control I am using for the accordion content is the RichText, which only allows for basic formatting such as bold.
What if I wanted to create an Unordered List as well as basic text? I am currently using multiline: "p", but how can I add additional elements so that I can also have UL elements in there as well?
The only two ideas I can think of, I cannot figure out how to implement. The first is to extend the block toolbar with BlockControls to include additional formatters for UL, and the second is to use another element instead of RichText - such as Freeform (which might have been renamed to Classic Editor?) - but I cannot find any documentation on these.
Here is an example of my current code:
ATTRIBUTES
attributes: {
title: {
type: 'string',
selector: '.hd-accordion-title',
},
content: {
type: 'array',
source: 'children',
selector: '.hd-accordion-content',
}
},
EDIT
edit: function( props ) {
var title = props.attributes.title;
var content = props.attributes.content;
function onChangeTitle(newTitle) {
props.setAttributes({
title: newTitle
});
}
function onChangeContent(newContent) {
props.setAttributes({
content: newContent
});
}
return [
(
<div className={"hd-accordion"}>
<RichText
tagName="h3"
className= "hd-accordion-title"
value= { title }
onChange= { onChangeTitle }
placeholder = "Title"
keepPlaceholderOnFocus = { true }
multiline= { false }
/>
<RichText
tagName="div"
className="hd-accordion-content"
value={ content }
onChange= { onChangeContent }
placeholder = "content"
multiline="p"
/>
</div>
)
];
},
wordpress wordpress-gutenberg gutenberg-blocks
wordpress wordpress-gutenberg gutenberg-blocks
asked Nov 16 '18 at 21:32
HarmonicHarmonic
215214
215214
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
You can register new formatting options like this-
Adding simple formatting button
registerFormat( 'bold', {
selector: 'strong',
edit( { isActive, toggleFormat } ) {
return (
<Fragment>
<Shortcut
type="primary"
key="b"
onUse={ () => toggleFormat() }
/>
<ToolbarControls>
<ToolbarButton
icon="editor-bold",
title={ __( 'Bold' ) }
isActive ={ isActive }
onClick={ () => toggleFormat() }
/>
</ToolbarControls>
</Fragment>
);
},
} );
Adding A Link Button
registerFormat( 'link', {
selector: 'a',
attributes: {
url: {
source: 'attribute',
attribute: 'href',
},
},
edit( { isActive, removeFormat } ) {
return (
<Fragment>
<Shortcut
type="access"
key="s"
onUse={ () => removeFormat() }
/>
<Shortcut
type="access"
key="a"
onUse={ /* Set state and pass to LinkContainer */ }
/>
<Shortcut
type="primary"
key="k"
onUse={ /* Set state and pass to LinkContainer */ }
/>
<ToolbarControls>
{ isActive && <ToolbarButton
icon="editor-unlink",
title={ __( 'Unlink' ) }
onClick={ () => removeFormat() }
/> }
{ ! isActive && <ToolbarButton
icon="admin-links",
title={ __( 'Link' ) }
onClick={ () => /* Set state and pass to LinkContainer */ }
/> }
</ToolbarControls>
<LinkContainer { ...props } />
</Fragment>
);
},
} );
Adding an Image button
registerFormat( 'image', {
selector: 'img',
attributes: {
url: {
source: 'attribute',
attribute: 'src',
},
},
edit: class ImageFormatEdit extends Component {
constructor() {
super( ...arguments );
this.state = {
modal: false;
};
}
openModal() {
this.setState( { modal: true } )
}
closeModal() {
this.setState( { modal: false } )
}
render() {
const { insertObject } = this.props;
return (
<Fragment>
<InserterItems>
<InserterItem
icon="inline-image",
title={ __( 'Inline Image' ) }
onClick={ openModal }
/>
</InserterItems>
{ this.state.modal && <MediaUpload
type="image"
onSelect={ ( { id, url, alt, width } ) => {
this.closeModal()
insertObject( {
src: url,
alt,
class: `wp-image-${ id }`,
style: `width: ${ Math.min( width, 150 ) }px;`,
} );
} }
onClose={ this.closeModal }
render={ ( { open } ) => {
open();
return null;
} }
/> }
</Fragment>
);
}
},
} );
You might encounter few bugs here and there. Relevant ticket
Thanks! I already discovered this (it's apparently very new), but failed miserably at getting it to work with UL, but maybe using your examples I'll have better luck. For now, I just wrote a shortcode called[list]to wrap around any eleents that automatically turns a list of paragraphs into UL
– Harmonic
Nov 19 '18 at 2:08
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53345703%2fgutenberg-allow-additional-formatting-in-richtext%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
You can register new formatting options like this-
Adding simple formatting button
registerFormat( 'bold', {
selector: 'strong',
edit( { isActive, toggleFormat } ) {
return (
<Fragment>
<Shortcut
type="primary"
key="b"
onUse={ () => toggleFormat() }
/>
<ToolbarControls>
<ToolbarButton
icon="editor-bold",
title={ __( 'Bold' ) }
isActive ={ isActive }
onClick={ () => toggleFormat() }
/>
</ToolbarControls>
</Fragment>
);
},
} );
Adding A Link Button
registerFormat( 'link', {
selector: 'a',
attributes: {
url: {
source: 'attribute',
attribute: 'href',
},
},
edit( { isActive, removeFormat } ) {
return (
<Fragment>
<Shortcut
type="access"
key="s"
onUse={ () => removeFormat() }
/>
<Shortcut
type="access"
key="a"
onUse={ /* Set state and pass to LinkContainer */ }
/>
<Shortcut
type="primary"
key="k"
onUse={ /* Set state and pass to LinkContainer */ }
/>
<ToolbarControls>
{ isActive && <ToolbarButton
icon="editor-unlink",
title={ __( 'Unlink' ) }
onClick={ () => removeFormat() }
/> }
{ ! isActive && <ToolbarButton
icon="admin-links",
title={ __( 'Link' ) }
onClick={ () => /* Set state and pass to LinkContainer */ }
/> }
</ToolbarControls>
<LinkContainer { ...props } />
</Fragment>
);
},
} );
Adding an Image button
registerFormat( 'image', {
selector: 'img',
attributes: {
url: {
source: 'attribute',
attribute: 'src',
},
},
edit: class ImageFormatEdit extends Component {
constructor() {
super( ...arguments );
this.state = {
modal: false;
};
}
openModal() {
this.setState( { modal: true } )
}
closeModal() {
this.setState( { modal: false } )
}
render() {
const { insertObject } = this.props;
return (
<Fragment>
<InserterItems>
<InserterItem
icon="inline-image",
title={ __( 'Inline Image' ) }
onClick={ openModal }
/>
</InserterItems>
{ this.state.modal && <MediaUpload
type="image"
onSelect={ ( { id, url, alt, width } ) => {
this.closeModal()
insertObject( {
src: url,
alt,
class: `wp-image-${ id }`,
style: `width: ${ Math.min( width, 150 ) }px;`,
} );
} }
onClose={ this.closeModal }
render={ ( { open } ) => {
open();
return null;
} }
/> }
</Fragment>
);
}
},
} );
You might encounter few bugs here and there. Relevant ticket
Thanks! I already discovered this (it's apparently very new), but failed miserably at getting it to work with UL, but maybe using your examples I'll have better luck. For now, I just wrote a shortcode called[list]to wrap around any eleents that automatically turns a list of paragraphs into UL
– Harmonic
Nov 19 '18 at 2:08
add a comment |
You can register new formatting options like this-
Adding simple formatting button
registerFormat( 'bold', {
selector: 'strong',
edit( { isActive, toggleFormat } ) {
return (
<Fragment>
<Shortcut
type="primary"
key="b"
onUse={ () => toggleFormat() }
/>
<ToolbarControls>
<ToolbarButton
icon="editor-bold",
title={ __( 'Bold' ) }
isActive ={ isActive }
onClick={ () => toggleFormat() }
/>
</ToolbarControls>
</Fragment>
);
},
} );
Adding A Link Button
registerFormat( 'link', {
selector: 'a',
attributes: {
url: {
source: 'attribute',
attribute: 'href',
},
},
edit( { isActive, removeFormat } ) {
return (
<Fragment>
<Shortcut
type="access"
key="s"
onUse={ () => removeFormat() }
/>
<Shortcut
type="access"
key="a"
onUse={ /* Set state and pass to LinkContainer */ }
/>
<Shortcut
type="primary"
key="k"
onUse={ /* Set state and pass to LinkContainer */ }
/>
<ToolbarControls>
{ isActive && <ToolbarButton
icon="editor-unlink",
title={ __( 'Unlink' ) }
onClick={ () => removeFormat() }
/> }
{ ! isActive && <ToolbarButton
icon="admin-links",
title={ __( 'Link' ) }
onClick={ () => /* Set state and pass to LinkContainer */ }
/> }
</ToolbarControls>
<LinkContainer { ...props } />
</Fragment>
);
},
} );
Adding an Image button
registerFormat( 'image', {
selector: 'img',
attributes: {
url: {
source: 'attribute',
attribute: 'src',
},
},
edit: class ImageFormatEdit extends Component {
constructor() {
super( ...arguments );
this.state = {
modal: false;
};
}
openModal() {
this.setState( { modal: true } )
}
closeModal() {
this.setState( { modal: false } )
}
render() {
const { insertObject } = this.props;
return (
<Fragment>
<InserterItems>
<InserterItem
icon="inline-image",
title={ __( 'Inline Image' ) }
onClick={ openModal }
/>
</InserterItems>
{ this.state.modal && <MediaUpload
type="image"
onSelect={ ( { id, url, alt, width } ) => {
this.closeModal()
insertObject( {
src: url,
alt,
class: `wp-image-${ id }`,
style: `width: ${ Math.min( width, 150 ) }px;`,
} );
} }
onClose={ this.closeModal }
render={ ( { open } ) => {
open();
return null;
} }
/> }
</Fragment>
);
}
},
} );
You might encounter few bugs here and there. Relevant ticket
Thanks! I already discovered this (it's apparently very new), but failed miserably at getting it to work with UL, but maybe using your examples I'll have better luck. For now, I just wrote a shortcode called[list]to wrap around any eleents that automatically turns a list of paragraphs into UL
– Harmonic
Nov 19 '18 at 2:08
add a comment |
You can register new formatting options like this-
Adding simple formatting button
registerFormat( 'bold', {
selector: 'strong',
edit( { isActive, toggleFormat } ) {
return (
<Fragment>
<Shortcut
type="primary"
key="b"
onUse={ () => toggleFormat() }
/>
<ToolbarControls>
<ToolbarButton
icon="editor-bold",
title={ __( 'Bold' ) }
isActive ={ isActive }
onClick={ () => toggleFormat() }
/>
</ToolbarControls>
</Fragment>
);
},
} );
Adding A Link Button
registerFormat( 'link', {
selector: 'a',
attributes: {
url: {
source: 'attribute',
attribute: 'href',
},
},
edit( { isActive, removeFormat } ) {
return (
<Fragment>
<Shortcut
type="access"
key="s"
onUse={ () => removeFormat() }
/>
<Shortcut
type="access"
key="a"
onUse={ /* Set state and pass to LinkContainer */ }
/>
<Shortcut
type="primary"
key="k"
onUse={ /* Set state and pass to LinkContainer */ }
/>
<ToolbarControls>
{ isActive && <ToolbarButton
icon="editor-unlink",
title={ __( 'Unlink' ) }
onClick={ () => removeFormat() }
/> }
{ ! isActive && <ToolbarButton
icon="admin-links",
title={ __( 'Link' ) }
onClick={ () => /* Set state and pass to LinkContainer */ }
/> }
</ToolbarControls>
<LinkContainer { ...props } />
</Fragment>
);
},
} );
Adding an Image button
registerFormat( 'image', {
selector: 'img',
attributes: {
url: {
source: 'attribute',
attribute: 'src',
},
},
edit: class ImageFormatEdit extends Component {
constructor() {
super( ...arguments );
this.state = {
modal: false;
};
}
openModal() {
this.setState( { modal: true } )
}
closeModal() {
this.setState( { modal: false } )
}
render() {
const { insertObject } = this.props;
return (
<Fragment>
<InserterItems>
<InserterItem
icon="inline-image",
title={ __( 'Inline Image' ) }
onClick={ openModal }
/>
</InserterItems>
{ this.state.modal && <MediaUpload
type="image"
onSelect={ ( { id, url, alt, width } ) => {
this.closeModal()
insertObject( {
src: url,
alt,
class: `wp-image-${ id }`,
style: `width: ${ Math.min( width, 150 ) }px;`,
} );
} }
onClose={ this.closeModal }
render={ ( { open } ) => {
open();
return null;
} }
/> }
</Fragment>
);
}
},
} );
You might encounter few bugs here and there. Relevant ticket
You can register new formatting options like this-
Adding simple formatting button
registerFormat( 'bold', {
selector: 'strong',
edit( { isActive, toggleFormat } ) {
return (
<Fragment>
<Shortcut
type="primary"
key="b"
onUse={ () => toggleFormat() }
/>
<ToolbarControls>
<ToolbarButton
icon="editor-bold",
title={ __( 'Bold' ) }
isActive ={ isActive }
onClick={ () => toggleFormat() }
/>
</ToolbarControls>
</Fragment>
);
},
} );
Adding A Link Button
registerFormat( 'link', {
selector: 'a',
attributes: {
url: {
source: 'attribute',
attribute: 'href',
},
},
edit( { isActive, removeFormat } ) {
return (
<Fragment>
<Shortcut
type="access"
key="s"
onUse={ () => removeFormat() }
/>
<Shortcut
type="access"
key="a"
onUse={ /* Set state and pass to LinkContainer */ }
/>
<Shortcut
type="primary"
key="k"
onUse={ /* Set state and pass to LinkContainer */ }
/>
<ToolbarControls>
{ isActive && <ToolbarButton
icon="editor-unlink",
title={ __( 'Unlink' ) }
onClick={ () => removeFormat() }
/> }
{ ! isActive && <ToolbarButton
icon="admin-links",
title={ __( 'Link' ) }
onClick={ () => /* Set state and pass to LinkContainer */ }
/> }
</ToolbarControls>
<LinkContainer { ...props } />
</Fragment>
);
},
} );
Adding an Image button
registerFormat( 'image', {
selector: 'img',
attributes: {
url: {
source: 'attribute',
attribute: 'src',
},
},
edit: class ImageFormatEdit extends Component {
constructor() {
super( ...arguments );
this.state = {
modal: false;
};
}
openModal() {
this.setState( { modal: true } )
}
closeModal() {
this.setState( { modal: false } )
}
render() {
const { insertObject } = this.props;
return (
<Fragment>
<InserterItems>
<InserterItem
icon="inline-image",
title={ __( 'Inline Image' ) }
onClick={ openModal }
/>
</InserterItems>
{ this.state.modal && <MediaUpload
type="image"
onSelect={ ( { id, url, alt, width } ) => {
this.closeModal()
insertObject( {
src: url,
alt,
class: `wp-image-${ id }`,
style: `width: ${ Math.min( width, 150 ) }px;`,
} );
} }
onClose={ this.closeModal }
render={ ( { open } ) => {
open();
return null;
} }
/> }
</Fragment>
);
}
},
} );
You might encounter few bugs here and there. Relevant ticket
answered Nov 18 '18 at 6:12
Ashiquzzaman KironAshiquzzaman Kiron
345212
345212
Thanks! I already discovered this (it's apparently very new), but failed miserably at getting it to work with UL, but maybe using your examples I'll have better luck. For now, I just wrote a shortcode called[list]to wrap around any eleents that automatically turns a list of paragraphs into UL
– Harmonic
Nov 19 '18 at 2:08
add a comment |
Thanks! I already discovered this (it's apparently very new), but failed miserably at getting it to work with UL, but maybe using your examples I'll have better luck. For now, I just wrote a shortcode called[list]to wrap around any eleents that automatically turns a list of paragraphs into UL
– Harmonic
Nov 19 '18 at 2:08
Thanks! I already discovered this (it's apparently very new), but failed miserably at getting it to work with UL, but maybe using your examples I'll have better luck. For now, I just wrote a shortcode called
[list] to wrap around any eleents that automatically turns a list of paragraphs into UL– Harmonic
Nov 19 '18 at 2:08
Thanks! I already discovered this (it's apparently very new), but failed miserably at getting it to work with UL, but maybe using your examples I'll have better luck. For now, I just wrote a shortcode called
[list] to wrap around any eleents that automatically turns a list of paragraphs into UL– Harmonic
Nov 19 '18 at 2:08
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53345703%2fgutenberg-allow-additional-formatting-in-richtext%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown