blob: 72758665355c8db32109541868e1993ae6795065 [file] [log] [blame]
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
import PropTypes from 'prop-types';
import React from "react";
import { Button, Modal } from "react-bootstrap";
import FauxtonAPI from "../../core/api";
// formats a block of code and pretty-prints it in the page. Currently uses the prettyPrint plugin
class CodeFormat extends React.Component {
static defaultProps = {
lang: "js"
};
getClasses = () => {
// added for forward compatibility. This component defines an api via it's props so you can pass lang="N" and
// not the class that prettyprint requires for that lang. If (when, hopefully!) we drop prettyprint we won't
// have any change this component's props API and break things
var classMap = {
js: 'lang-js'
};
var classNames = 'prettyprint';
if (_.has(classMap, this.props.lang)) {
classNames += ' ' + classMap[this.props.lang];
}
return classNames;
};
componentDidMount() {
// this one function is all the lib offers. It parses the entire page and pretty-prints anything with
// a .prettyprint class; only executes on an element once
prettyPrint();
}
render() {
const code = JSON.stringify(this.props.code, null, " ");
return (
<div><pre className={this.getClasses()}>{code}</pre></div>
);
}
}
class Pagination extends React.Component {
static defaultProps = {
perPage: FauxtonAPI.constants.MISC.DEFAULT_PAGE_SIZE,
onClick: null,
page: 1,
total: 0,
urlPrefix: '',
urlSuffix: '',
maxNavPages: 10
};
getVisiblePages = (page, totalPages) => {
var from, to;
if (totalPages < this.props.maxNavPages) {
from = 1;
to = totalPages + 1;
} else {
var halfMaxNavPages = Math.floor(this.props.maxNavPages / 2);
from = page - halfMaxNavPages;
to = page + halfMaxNavPages;
if (from <= 1) {
from = 1;
to = this.props.maxNavPages + 1;
}
if (to > totalPages + 1) {
from = totalPages - (this.props.maxNavPages - 1);
to = totalPages + 1;
}
}
return {
from: from,
to: to
};
};
createItemsForPage = (visiblePages) => {
return _.range(visiblePages.from, visiblePages.to).map((i) => {
return (
<li key={i} className={'page-item ' + (this.props.page === i ? 'active' : '')}>
{this.getLink(i, i)}
</li>
);
});
};
getOnPageClick(pageNumber) {
return (e) => {
if (e) {
e.preventDefault();
}
this.props.onClick(pageNumber);
};
}
getLink = (i, label, fontIcon) => {
const linkClass = fontIcon ? `page-link ${fontIcon}` : 'page-link';
if (this.props.onClick) {
return (
<a className={linkClass} onClick={this.getOnPageClick(i)}>{label}</a>
);
}
return (
<a className={linkClass} href={this.props.urlPrefix + i + this.props.urlSuffix}>{label}</a>
);
};
getTotalPages = () => {
return this.props.total === 0 ? 1 : Math.ceil(this.props.total / this.props.perPage);
};
render() {
var totalPages = this.getTotalPages();
var visiblePages = this.getVisiblePages(this.props.page, totalPages);
var rangeItems = this.createItemsForPage(visiblePages);
var prevPage = Math.max(this.props.page - 1, 1);
var nextPage = Math.min(this.props.page + 1, totalPages);
return (
<ul className="pagination">
<li className={'page-item ' + (this.props.page === 1 ? "disabled" : '')}>
{this.getLink(prevPage, '', 'fonticon-left-open')}
</li>
{rangeItems}
<li className={'page-item ' + (this.props.page < totalPages ? '' : "disabled")}>
{this.getLink(nextPage, '', 'fonticon-right-open')}
</li>
</ul>
);
}
}
// a super-simple replacement for window.confirm()
class ConfirmationModal extends React.Component {
static propTypes = {
visible: PropTypes.bool.isRequired,
text: PropTypes.oneOfType([
PropTypes.string,
PropTypes.element
]).isRequired,
onClose: PropTypes.func.isRequired,
onSubmit: PropTypes.func.isRequired
};
static defaultProps = {
visible: false,
title: 'Confirmation',
text: '',
successButtonLabel: 'Ok',
buttonVariant: 'cf-primary'
};
close = (e) => {
if (e) {
e.preventDefault();
}
this.props.onClose();
};
render() {
let content = <p>{this.props.text}</p>;
if (!_.isString(this.props.text)) {
content = this.props.text;
}
const closeButton = this.props.onClose ? (
<Button href="#" data-bypass="true" variant="cf-cancel" className="cancel-link" onClick={this.close}>Cancel</Button>
) : null;
const submitButton = this.props.onSubmit ? (
<Button variant={this.props.buttonVariant} onClick={this.props.onSubmit}>
<i className="fonticon-ok-circled"></i> {this.props.successButtonLabel}
</Button>
) : null;
return (
<Modal dialogClassName="confirmation-modal" show={this.props.visible} onHide={this.close}>
<Modal.Header closeButton={true}>
<Modal.Title>{this.props.title}</Modal.Title>
</Modal.Header>
<Modal.Body>
{content}
</Modal.Body>
<Modal.Footer>
{ closeButton }
{ submitButton }
</Modal.Footer>
</Modal>
);
}
}
export default {
CodeFormat: CodeFormat,
Pagination: Pagination,
ConfirmationModal: ConfirmationModal
};