Skip to content

Commit

Permalink
EZP-28841: Content On the Fly v2
Browse files Browse the repository at this point in the history
  • Loading branch information
dew326 committed Mar 1, 2018
1 parent 9c7615d commit 34b0b46
Show file tree
Hide file tree
Showing 25 changed files with 757 additions and 26 deletions.
4 changes: 2 additions & 2 deletions Resources/public/js/MultiFileUpload.module.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Resources/public/js/MultiFileUpload.module.js.map

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions Resources/public/js/SubItems.module.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Resources/public/js/SubItems.module.js.map

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions Resources/public/js/UniversalDiscovery.module.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Resources/public/js/UniversalDiscovery.module.js.map

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';

import { loadLocation } from '../../services/universal.discovery.service';

import './css/content.creator.component.css';

export default class ContentCreatorComponent extends Component {
constructor(props) {
super(props);

this.state = {
iframeLoading: true
};
}

handlePublish() {
this._iframe.contentWindow.onbeforeunload = () => {};
this._iframe.contentWindow.document.body.querySelector('#ezrepoforms_content_edit_publish').click();
}

handleIframeLoad() {
const locationId = this._iframe.contentWindow.document.querySelector('meta[name="LocationID"]');

if (this._iframe.contentWindow.location.pathname !== this.generateIframeUrl() && !locationId) {
this._iframe.setAttribute('src', this.generateIframeUrl());

return;
}

if (locationId) {
this.loadLocationInfo(locationId.content);
} else {
this.setState(state => Object.assign({}, state, { iframeLoading: false }));

this._iframe.contentWindow.onbeforeunload = () => {
return '';
};
this._iframe.contentWindow.onunload = () => {
this.setState(state => Object.assign({}, state, { iframeLoading: true }));
};
}
}

loadLocationInfo(locationId) {
const promise = new Promise(resolve => this.props.loadLocation(
Object.assign({}, this.props.restInfo, { locationId }),
resolve
));

promise
.then((response) => {
this.props.handlePublish(response.View.Result.searchHits.searchHit[0].value.Location);
});
}

generateIframeUrl() {
return window.Routing.generate('ezplatform.content.create.on_the_fly', {
locationId: this.props.selectedLocationId,
languageCode: this.props.selectedLanguage.languageCode,
contentTypeIdentifier: this.props.selectedContentType.identifier
});
}

/**
* Renders a loading state icon
*
* @method renderLoadingIcon
* @returns {Element}
* @memberof FinderTreeLeafComponent
*/
renderLoadingIcon() {
if (!this.state.iframeLoading) {
return null;
}

return (
<svg className="ez-icon ez-spin ez-icon-x2 ez-icon-spinner">
<use xlinkHref="/bundles/ezplatformadminui/img/ez-icons.svg#spinner"></use>
</svg>
);
}

render() {
const title = this.props.labels.contentOnTheFly.creatingContent
.replace('{contentType}', this.props.selectedContentType.name)
.replace('{language}', this.props.selectedLanguage.name);
const iframeUrl = this.generateIframeUrl();
const contentClass = this.state.iframeLoading ? "m-ud__content is-loading" : "m-ud__content";

return (
<div className="m-ud__wrapper">
<div className="m-ud c-content-creator">
<h1 className="m-ud__title">{title}</h1>
<div className="m-ud__content-wrapper">
<div className={contentClass} ref={ref => this._refContentContainer = ref}>
{this.renderLoadingIcon()}
<iframe
src={iframeUrl}
ref={ref => this._iframe = ref}
className="c-content-creator__iframe"
onLoad={this.handleIframeLoad.bind(this)}
style={{height:`${this.props.maxHeight + 32}px`}} />
</div>
<div className="m-ud__actions">
<div className="m-ud__btns">
<button className="m-ud__action--cancel" onClick={this.props.onCancel}>{this.props.labels.udw.cancel}</button>
<button className="m-ud__action--publish" onClick={this.handlePublish.bind(this)}>{this.props.labels.contentOnTheFly.publish}</button>
</div>
</div>
</div>
</div>
</div>
);
}
}

ContentCreatorComponent.propTypes = {
maxHeight: PropTypes.number.isRequired,
labels: PropTypes.object.isRequired,
selectedLanguage: PropTypes.object.isRequired,
selectedContentType: PropTypes.object.isRequired,
selectedLocationId: PropTypes.number.isRequired,
onCancel: PropTypes.func.isRequired,
handlePublish: PropTypes.func.isRequired,
loadLocation: PropTypes.func,
restInfo: PropTypes.object.isRequired
};

ContentCreatorComponent.defaultProps = {
loadLocation
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
.c-content-creator .m-ud__content-wrapper {
padding: 0 0 16px 0;
grid-template-rows: 1fr 64px;
grid-template-areas: "main" "footer";
}

.c-content-creator .m-ud__content {
padding: 0
}

.c-content-creator .m-ud__actions {
padding-right: 16px;
}

.c-content-creator .ez-icon-spinner {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}

.c-content-creator__iframe {
width: 100%;
border: none;
}

.m-ud__action--publish {
font-weight: 700;
background: #f15a10;
}

.m-ud__action--publish:hover,
.m-ud__action--publish:focus {
background: #cb3400;
}

.m-ud__content {
position: relative;
}

.is-loading:before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #e3e3e3;
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import PropTypes from 'prop-types';

import './css/content.meta.preview.component.css';

const TAB_CREATE = 'create';

export default class ContentMetaPreviewComponent extends Component {
constructor() {
super();
Expand Down Expand Up @@ -93,6 +95,10 @@ export default class ContentMetaPreviewComponent extends Component {
onClick: onSelectContent
};

if (this.props.activeTab === TAB_CREATE) {
return null;
}

canSelectContent(data, this.toggleEnabledState.bind(this));

if (!this.state.selectContentEnabled) {
Expand Down Expand Up @@ -181,5 +187,6 @@ ContentMetaPreviewComponent.propTypes = {
lastModified: PropTypes.string.isRequired,
translations: PropTypes.string.isRequired
}).isRequired,
maxHeight: PropTypes.number.isRequired
maxHeight: PropTypes.number.isRequired,
activeTab: PropTypes.string.isRequired
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';

import './css/create.choose.content.type.component.css';

export default class ChooseContentTypeComponent extends Component {
constructor(props) {
super(props);

this._filterTimeout = null;

this.updateFilterQuery = this.updateFilterQuery.bind(this);
this.renderGroup = this.renderGroup.bind(this);
this.renderItem = this.renderItem.bind(this);

this.state = {
selected: {},
filterQuery: ''
};
}

updateSelectedItem(item) {
this.props.onContentTypeSelected(item);

this.setState(state => Object.assign({}, state, {selected: item}));
}

updateFilterQuery(event) {
const value = event.target.value.toLowerCase();

window.clearTimeout(this._filterTimeout);

this._filterTimeout = window.setTimeout(() => {
this.setState(state => Object.assign({}, state, {filterQuery: value}));
}, 200);
}

renderItem(item, index) {
const attrs = {
className: 'c-choose-content-type__group-item'
};

if (this.state.selected.identifier === item.identifier) {
attrs.className = `${attrs.className} is-selected`;
}

if (this.state.filterQuery && !item.name.toLowerCase().includes(this.state.filterQuery)) {
attrs.hidden = true;
}

return (
<div {...attrs} key={index} onClick={this.updateSelectedItem.bind(this, item)}>
{item.name}
</div>
);
}

renderGroup(groupName, index) {
const items = this.props.contentTypes[groupName];
const groupAttrs = {};

if (this.state.filterQuery && items.every(item => !item.name.toLowerCase().includes(this.state.filterQuery))) {
groupAttrs.hidden = true;
}

return (
<div className="c-choose-content-type__group" key={index}>
<div className="c-choose-content-type__group-name" {...groupAttrs}>
{groupName}
</div>
{items.map(this.renderItem)}
</div>
);
}

render() {
return (
<div className="c-choose-content-type">
<p className="c-choose-content-type__title">{this.props.labels.contentOnTheFly.selectContentType}</p>
<div className="c-choose-content-type__list-wrapper">
<input className="form-control" type="text" placeholder="Type to refine" onChange={this.updateFilterQuery} />
<div className="c-choose-content-type__list" style={{maxHeight:`${this.props.maxHeight - 232}px`}}>
{Object.keys(this.props.contentTypes).map(this.renderGroup)}
</div>
</div>
</div>
);
}
}

ChooseContentTypeComponent.propTypes = {
maxHeight: PropTypes.number.isRequired,
labels: PropTypes.object.isRequired,
contentTypes: PropTypes.object.isRequired,
onContentTypeSelected: PropTypes.func.isRequired
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';

import './css/create.choose.language.component.css';

export default class ChooseLanguageComponent extends Component {
constructor(props) {
super(props);

this.updateSelection = this.updateSelection.bind(this);

this.state = {
selected: this.props.languages[0]
}
}

updateSelection(event) {
const value = event.target.value;
const selectedLanguage = this.props.languages.find(language => language.languageCode === value);

this.props.onLanguageSelected(selectedLanguage);

this.setState(state => Object.assign({}, state, {selected: selectedLanguage}));
}

renderOption(item, index) {
const attrs = {
key: index,
value: item.languageCode
}

if (item.languageCode === this.props.forcedLanguage) {
attrs.selected = true;
}

return (
<option {...attrs}>{item.name}</option>
);
}

render() {
const selectAttrs = {
className: "form-control",
onChange: this.updateSelection.bind(this)
};

if (this.props.forcedLanguage) {
selectAttrs.disabled = true;
}

return (
<div className="c-choose-language">
<p className="c-choose-language__title">{this.props.labels.contentOnTheFly.selectLanguage}</p>
<div className="c-choose-lagauge__select-wrapper">
<select {...selectAttrs}>
{this.props.languages.map(this.renderOption.bind(this))}
</select>
</div>
</div>
);
}
}

ChooseLanguageComponent.propTypes = {
maxHeight: PropTypes.number.isRequired,
labels: PropTypes.object.isRequired,
languages: PropTypes.array.isRequired,
onLanguageSelected: PropTypes.func.isRequired,
forcedLanguage: PropTypes.string.isRequired
};
Loading

0 comments on commit 34b0b46

Please sign in to comment.