Commit 5cc5cf9f authored by Jason Salyers's avatar Jason Salyers
Browse files

Merge branch '114-post-image-preview-selection' into 'develop'

Resolve "Allow selecting post preview image"

Closes #114

See merge request !190
parents 65612ae0 85087a0d
...@@ -14,6 +14,7 @@ import SlateEditor, { ...@@ -14,6 +14,7 @@ import SlateEditor, {
deserializeHtml, deserializeHtml,
getDemoState, getDemoState,
} from 'app/components/elements/SlateEditor'; } from 'app/components/elements/SlateEditor';
import { extractRtags } from 'app/utils/ExtractContent';
import LoadingIndicator from 'app/components/elements/LoadingIndicator'; import LoadingIndicator from 'app/components/elements/LoadingIndicator';
import PostCategoryBanner from 'app/components/elements/PostCategoryBanner'; import PostCategoryBanner from 'app/components/elements/PostCategoryBanner';
import shouldComponentUpdate from 'app/utils/shouldComponentUpdate'; import shouldComponentUpdate from 'app/utils/shouldComponentUpdate';
...@@ -657,6 +658,14 @@ class ReplyEditor extends React.Component { ...@@ -657,6 +658,14 @@ class ReplyEditor extends React.Component {
const disabled = submitting || !valid; const disabled = submitting || !valid;
const loading = submitting || this.state.loading; const loading = submitting || this.state.loading;
// Generate an array of images used in the post body.
// This will be used to display the cover image selector.
let selectedCoverImage = '';
let rtags;
if (isStory) {
rtags = extractRtags(body.value);
}
const errorCallback = estr => { const errorCallback = estr => {
this.setState({ postError: estr, loading: false }); this.setState({ postError: estr, loading: false });
}; };
...@@ -724,6 +733,23 @@ class ReplyEditor extends React.Component { ...@@ -724,6 +733,23 @@ class ReplyEditor extends React.Component {
}); });
}; };
const onSelectCoverImage = event => {
const { target } = event;
const postImages = document.getElementsByClassName(
'ReplyEditor__options__image_selector__image_container'
);
for (let pi = 0; pi < postImages.length; pi += 1) {
const postImage = postImages[pi];
postImage.classList.remove('selected');
}
target.classList.add('selected');
selectedCoverImage = target.style.backgroundImage
.slice(4, -1)
.replace(/"/g, '');
};
return ( return (
<div <div
className={classnames({ className={classnames({
...@@ -771,6 +797,7 @@ class ReplyEditor extends React.Component { ...@@ -771,6 +797,7 @@ class ReplyEditor extends React.Component {
...data, ...data,
...replyParams, ...replyParams,
startLoadingIndicator, startLoadingIndicator,
selectedCoverImage,
}; };
reply(replyPayload); reply(replyPayload);
})} })}
...@@ -1016,6 +1043,36 @@ class ReplyEditor extends React.Component { ...@@ -1016,6 +1043,36 @@ class ReplyEditor extends React.Component {
</span> </span>
)} )}
</div> </div>
{Array.from(rtags.images).length >
0 && (
<div className="ReplyEditor__options__cover_image_selector">
<h6>
{tt(
'reply_editor.select_cover_image'
)}
:
</h6>
<div className="ReplyEditor__options__image_selector">
{Array.from(
rtags.images
).map(image => {
return (
<div
className="ReplyEditor__options__image_selector__image_container"
style={{
backgroundImage: `url(${
image
})`,
}}
onClick={
onSelectCoverImage
}
/>
);
})}
</div>
</div>
)}
<a <a
href="#" href="#"
onClick={ onClick={
...@@ -1369,6 +1426,7 @@ export default formId => ...@@ -1369,6 +1426,7 @@ export default formId =>
successCallback, successCallback,
errorCallback, errorCallback,
startLoadingIndicator, startLoadingIndicator,
selectedCoverImage,
}) => { }) => {
const isEdit = type === 'edit'; const isEdit = type === 'edit';
const isNew = /^submit_/.test(type); const isNew = /^submit_/.test(type);
...@@ -1426,16 +1484,40 @@ export default formId => ...@@ -1426,16 +1484,40 @@ export default formId =>
// merge // merge
const meta = isEdit ? jsonMetadata : {}; const meta = isEdit ? jsonMetadata : {};
if (metaTags.size) meta.tags = metaTags.toJS();
else delete meta.tags; if (metaTags.size) {
if (rtags.usertags.size) meta.users = Array.from(rtags.usertags); meta.tags = metaTags.toJS();
else delete meta.users; } else {
if (rtags.images.size) delete meta.tags;
meta.image = Array.from(rtags.images).slice(0, 1); }
else delete meta.image;
if (rtags.links.size) if (rtags.usertags.size) {
meta.users = Array.from(rtags.usertags);
} else {
delete meta.users;
}
if (rtags.images.size) {
const moveToFirst = (array, first) => {
array.sort((x, y) => {
return x === first ? -1 : y === first ? 1 : 0;
});
};
meta.image = Array.from(rtags.images);
// If a cover image has been manually selected,
// move it to the first element of the image array.
if (selectedCoverImage) {
moveToFirst(meta.image, selectedCoverImage);
}
} else {
delete meta.image;
}
if (rtags.links.size) {
meta.links = Array.from(rtags.links).slice(0, 1); meta.links = Array.from(rtags.links).slice(0, 1);
else delete meta.links; } else {
delete meta.links;
}
meta.app = 'hiveblog/0.1'; meta.app = 'hiveblog/0.1';
if (isStory) { if (isStory) {
......
...@@ -156,3 +156,35 @@ ...@@ -156,3 +156,35 @@
.Dropdown__root___1B9ta { .Dropdown__root___1B9ta {
color: black!important; color: black!important;
} }
.ReplyEditor__options__cover_image_selector {
margin-top: 10px;
}
.ReplyEditor__options__image_selector {
.ReplyEditor__options__image_selector__image_container {
width: 60px;
height: 60px;
margin-right: 5px;
margin-bottom: 5px;
border: 1px solid grey;
background-size: cover;
display: inline-block;
transition: width 0.5s, height 0.5s;
vertical-align: top;
opacity: 0.5;
&.selected {
opacity: 1;
@include themify($themes) {
border: 3px solid $color-hive-red;
}
}
&:hover {
opacity: 1;
width: 120px;
height: 120px;
}
}
}
...@@ -361,7 +361,8 @@ ...@@ -361,7 +361,8 @@
"tags_input": "Enter your tags separated by a space", "tags_input": "Enter your tags separated by a space",
"enable_sidebyside": "Enable side-by-side editor", "enable_sidebyside": "Enable side-by-side editor",
"disable_sidebyside": "Disable side-by-side editor", "disable_sidebyside": "Disable side-by-side editor",
"post_options": "Post options" "post_options": "Post options",
"select_cover_image": "Select your cover image"
}, },
"beneficiary_selector_jsx": { "beneficiary_selector_jsx": {
"header": "Who should receive any rewards?", "header": "Who should receive any rewards?",
......
...@@ -15,8 +15,26 @@ const getValidImage = array => { ...@@ -15,8 +15,26 @@ const getValidImage = array => {
: null; : null;
}; };
export function extractRtags(body = null) {
let rtags;
{
const isHtml = /^<html>([\S\s]*)<\/html>$/.test(body);
const htmlText = isHtml
? body
: remarkable.render(
body.replace(
/<!--([\s\S]+?)(-->|$)/g,
'(html comment removed: $1)'
)
);
rtags = HtmlReady(htmlText, { mutate: false });
}
return rtags;
}
export function extractImageLink(json_metadata, body = null) { export function extractImageLink(json_metadata, body = null) {
let json = json_metadata || {}; const json = json_metadata || {};
let image_link; let image_link;
try { try {
...@@ -25,19 +43,7 @@ export function extractImageLink(json_metadata, body = null) { ...@@ -25,19 +43,7 @@ export function extractImageLink(json_metadata, body = null) {
// If nothing found in json metadata, parse body and check images/links // If nothing found in json metadata, parse body and check images/links
if (!image_link) { if (!image_link) {
let rtags; const rtags = extractRtags(body);
{
const isHtml = /^<html>([\S\s]*)<\/html>$/.test(body);
const htmlText = isHtml
? body
: remarkable.render(
body.replace(
/<!--([\s\S]+?)(-->|$)/g,
'(html comment removed: $1)'
)
);
rtags = HtmlReady(htmlText, { mutate: false });
}
if (rtags.images) { if (rtags.images) {
[image_link] = Array.from(rtags.images); [image_link] = Array.from(rtags.images);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment