diff --git a/package-lock.json b/package-lock.json index 5b8489b8..1bcfa131 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9809,6 +9809,11 @@ "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==", "dev": true }, + "whatwg-fetch": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz", + "integrity": "sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q==" + }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", diff --git a/package.json b/package.json index 4d490e39..63f72328 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,8 @@ "react-visibility-sensor": "^5.0.2", "string-hash": "^1.1.3", "underscore": "^1.9.1", - "universal-cookie": "^3.0.7" + "universal-cookie": "^3.0.7", + "whatwg-fetch": "^3.0.0" }, "devDependencies": { "@babel/core": "^7.0.0", diff --git a/src/cleanCache.js b/src/cleanCache.js index f41d78d7..eb29db68 100644 --- a/src/cleanCache.js +++ b/src/cleanCache.js @@ -35,7 +35,7 @@ folders1.forEach(p1 => { //nothing }else if(stat.isDirectory()){ const subfiles = fs.readdirSync(p1); - subfiles.sort((a, b) => a.firstname.localeCompare(b.firstname)) + subfiles.sort((a, b) => a.localeCompare(b)); if(subfiles.length > 3){ for(let ii = 2; ii < subfiles.length; ii++){ del(path.resolve(p1, subfiles[ii])); diff --git a/src/client/ExplorerPage.js b/src/client/ExplorerPage.js index be196a06..8f0a7f82 100644 --- a/src/client/ExplorerPage.js +++ b/src/client/ExplorerPage.js @@ -12,13 +12,14 @@ import ErrorPage from './ErrorPage'; import Pagination from 'rc-pagination'; import FileChangeToolbar from './subcomponent/FileChangeToolbar'; import Spinner from './subcomponent/Spinner'; -const PER_PAGE = 4 * 5; +const util = require("../util"); export default class ExplorerPage extends Component { constructor(prop) { super(prop); this.state = { pageIndex: 1 }; this.failedTimes = 0; + this.perPage = util.getPerPageItemNumber(); } getHash() { @@ -133,7 +134,7 @@ export default class ExplorerPage extends Component { //! !todo if the file is already an image file files = files.filter(_.isCompress); - files = files.slice((this.state.pageIndex-1) * PER_PAGE, (this.state.pageIndex) * PER_PAGE); + files = files.slice((this.state.pageIndex-1) * this.perPage, (this.state.pageIndex) * this.perPage); const zipfileItems = files.map((item) => { const text = _.getFn(item); @@ -194,7 +195,7 @@ export default class ExplorerPage extends Component { } return (); } diff --git a/src/client/LoadingImage.js b/src/client/LoadingImage.js index 1e873f47..23779f49 100644 --- a/src/client/LoadingImage.js +++ b/src/client/LoadingImage.js @@ -4,9 +4,6 @@ import PropTypes from 'prop-types'; import loading from './images/loading.png'; import notAvailable from './images/not-available.png'; import Sender from './Sender'; -import ImageLoader from 'react-image-file'; -// const VisibilitySensor = require('react-visibility-sensor').default; - const VisibilitySensor = require('react-visibility-sensor').default; export default class LoadingImage extends Component { @@ -28,40 +25,50 @@ export default class LoadingImage extends Component { } onChange(isVisible){ - if(isVisible && !this.state.loaded & !this.loading){ - const {mode} = this.props; - const api = (mode === "author" || mode === "tag") ? "/api/tagFirstImagePath" : '/api/firstImage'; - const body = {}; + const {onChange, url, mode, fileName} = this.props; - if(mode === "author" || mode === "tag"){ - body[mode] = this.props.fileName; - }else{ - body["fileName"] = this.props.fileName; - } + if(isVisible){ + onChange && onChange(); + } - this.loading = true; + if(isVisible && !this.state.loaded & !this.loading){ + if(url){ + this.url = url; + this.setState({ loaded: true }); + } else { + const api = (mode === "author" || mode === "tag") ? "/api/tagFirstImagePath" : '/api/firstImage'; + const body = {}; - fetch(api, { - method: 'POST', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - }, - body: JSON.stringify(body) - }) - .then((res) => res.blob()) - .then((res) => { - if(!this.isUnmounted){ - this.url = URL.createObjectURL(res); - this.setState({ loaded: true }); + if(mode === "author" || mode === "tag"){ + body[mode] = fileName; + }else{ + body["fileName"] = fileName; } - }); + + this.loading = true; + + fetch(api, { + method: 'POST', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + }, + body: JSON.stringify(body) + }) + .then((res) => res.blob()) + .then((res) => { + if(!this.isUnmounted){ + this.url = URL.createObjectURL(res); + this.setState({ loaded: true }); + } + }); + } } } render() { let content; - const {className, fileName} = this.props; + const {className, fileName, url, bottomOffet, topOffet} = this.props; const cn = "loading-image " + className; let active = true; if (this.state.failed) { @@ -76,8 +83,8 @@ export default class LoadingImage extends Component { return ( {content} @@ -89,4 +96,8 @@ LoadingImage.propTypes = { fileName: PropTypes.string, className: PropTypes.string, mode: PropTypes.string, + url: PropTypes.string, //predefined url, not request from this component, + bottomOffet: PropTypes.number, + topOffet: PropTypes.number, + onChange: PropTypes.func }; diff --git a/src/client/OneBook.js b/src/client/OneBook.js index 3e20b6a4..39894bf5 100644 --- a/src/client/OneBook.js +++ b/src/client/OneBook.js @@ -12,6 +12,7 @@ const spop = require("./subcomponent/spop"); import FileChangeToolbar from './subcomponent/FileChangeToolbar'; var classNames = require('classnames'); var dateFormat = require('dateformat'); +import LoadingImage from './LoadingImage'; export default class OneBook extends Component { constructor(props) { @@ -61,7 +62,9 @@ export default class OneBook extends Component { if (!res.failed) { this.loadedHash = this.getHash(); - this.setState({ files: res.files || [], index: 0, path:res.path, fileStat: res.stat }); + let files = res.files || []; + files.sort((a, b) => a.localeCompare(b)); + this.setState({ files: files, index: 0, path:res.path, fileStat: res.stat }); document.addEventListener('keydown', this.handleKeyDown.bind(this)); }else{ this.failTimes++; @@ -109,29 +112,24 @@ export default class OneBook extends Component { this.changePage(index); } - renderFileList() { - const { files, index } = this.state; - const listItems = files.map((item) => (
  • book-image
  • )); - return (); - } - + isFailedLoading(){ return this.res && this.res.failed; } renderPagination() { + if(_.isPad()){ return; } const { files, index } = this.state; const isLast = index+1 === files.length; const text = (index+1) + "/" + files.length; const cn = classNames("one-book-foot-index-number", { "is-last": isLast }) - return
    {text}
    ; } renderFileSizeAndTime(){ - if(this.state.fileStat){ + if (this.state.fileStat) { const size = Math.ceil(this.state.fileStat.size/ 1000000.0) + "MB"; const mTime = dateFormat(this.state.fileStat.mtime, "isoDate");; const text = mTime + " :: " + size; @@ -139,6 +137,46 @@ export default class OneBook extends Component { } } + renderImage(){ + const { files, index } = this.state; + if(!_.isPad()){ + return book-image + } else { + const images = files.map(file => { + return + }); + + return (
    + {images} +
    ); + } + } + + renderPath() { + if (!this.state.path) { + return; + } + + const parentPath = _.getDir(this.state.path); + const parentHash = stringHash(parentPath); + const toUrl = ('/explorer/'+ parentHash); + const toolbar = !_.isPad() && ; + + return ( +
    + {parentPath} + {toolbar} +
    ); + } + render() { if (this.isFailedLoading()) { return ; @@ -172,10 +210,6 @@ export default class OneBook extends Component { ); }) - const parentPath = _.getDir(this.state.path); - const parentHash = stringHash(parentPath); - const toUrl =('/explorer/'+ parentHash); - if(this.state.path){ document.title = _.getFn(this.state.path); } @@ -184,26 +218,14 @@ export default class OneBook extends Component {
    {_.getFn(this.state.path)}
    - book-image + {this.renderImage()}
    {this.renderPagination()}
    {tagDivs}
    - {this.state.path && -
    - {parentPath} - -
    - } + {this.renderPath()} {this.renderFileSizeAndTime()} - {/* { - this.state.path && - } */}
    ); } diff --git a/src/client/Sender.js b/src/client/Sender.js index 3cea6d33..5cfa223e 100644 --- a/src/client/Sender.js +++ b/src/client/Sender.js @@ -1,4 +1,5 @@ import _ from "underscore"; +import 'whatwg-fetch'; const Sender = {}; diff --git a/src/client/TagPage.js b/src/client/TagPage.js index a362d400..952b91ff 100644 --- a/src/client/TagPage.js +++ b/src/client/TagPage.js @@ -11,12 +11,14 @@ import ErrorPage from './ErrorPage'; import Spinner from './subcomponent/Spinner' import Pagination from 'rc-pagination'; import { Redirect } from 'react-router-dom'; -const PER_PAGE = 4 * 5; + +const util = require("../util"); export default class TagPage extends Component { constructor(prop) { super(prop); this.state = { tags: [], sortByNumber: true }; + this.perPage = util.getPerPageItemNumber(); } get pageIndex(){ @@ -67,7 +69,7 @@ export default class TagPage extends Component { keys.sort((a, b) => items[b] - items[a]); } - keys = keys.slice((this.pageIndex-1) * PER_PAGE, this.pageIndex * PER_PAGE); + keys = keys.slice((this.pageIndex-1) * this.perPage, this.pageIndex * this.perPage); const tagItems = keys.map((tag) => { const itemText = `${tag} (${items[tag]})`; @@ -114,7 +116,7 @@ export default class TagPage extends Component { } return (); } diff --git a/src/client/style/OneBook.scss b/src/client/style/OneBook.scss index 9037c4f2..2d91fdac 100644 --- a/src/client/style/OneBook.scss +++ b/src/client/style/OneBook.scss @@ -2,7 +2,7 @@ text-align: center; font-size: 3rem; position: fixed; - left: 45%; + left: 40%; top: 50%; } @@ -52,6 +52,17 @@ z-index: 10; } + .mobile-one-book-image{ + // width: 95%; + width: calc(100% - 10px); + margin:1px 5px; + + } + + .mobile-one-book-container{ + width: 100%; + } + .one-book-footer { display: flex; justify-content: flex-start; diff --git a/src/util.js b/src/util.js index e77afc70..8067b8ce 100644 --- a/src/util.js +++ b/src/util.js @@ -24,9 +24,25 @@ module.exports.getFn = function (fn) { return tokens[tokens.length - 1]; }; +const isPad = module.exports.isPad = function(){ + // https://stackoverflow.com/questions/9038625/detect-if-device-is-ios + return /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream; +} + +module.exports.getPerPageItemNumber = function() { + if(isPad()){ + return 3 * 6; + }else{ + return 4 * 5; + } +} + module.exports.attach = function (obj) { obj.isImage = module.exports.isImage; obj.isCompress = module.exports.isCompress; obj.getDir = module.exports.getDir; obj.getFn = module.exports.getFn; + obj.isPad = module.exports.isPad; + obj.getPerPageItemNumber = module.exports.getPerPageItemNumber; } + diff --git a/webpack.config.js b/webpack.config.js index baeb5fb5..304c0c4a 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -40,6 +40,7 @@ module.exports = { port: 3000, open: false, host: '0.0.0.0', + disableHostCheck: true, historyApiFallback: true, publicPath: "/", proxy: {