Merge pull request #109 from lbryio/development
Merge development into master
This commit is contained in:
commit
cadb901209
33 changed files with 970 additions and 267 deletions
6
.babelrc
Normal file
6
.babelrc
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"presets": [
|
||||
"es2015",
|
||||
"react"
|
||||
],
|
||||
}
|
239
.eslintrc.js
Normal file
239
.eslintrc.js
Normal file
|
@ -0,0 +1,239 @@
|
|||
module.exports = {
|
||||
"extends": "airbnb",
|
||||
"plugins": [
|
||||
"react",
|
||||
"jsx-a11y",
|
||||
"import"
|
||||
],
|
||||
"env": {
|
||||
"browser": true,
|
||||
},
|
||||
// Grabbed from https://gist.github.com/cletusw/e01a85e399ab563b1236
|
||||
"rules": {
|
||||
////////// Possible Errors //////////
|
||||
|
||||
"no-comma-dangle": 0, // disallow trailing commas in object literals
|
||||
"no-cond-assign": 0, // disallow assignment in conditional expressions
|
||||
"no-console": 0, // disallow use of console (off by default in the node environment)
|
||||
"no-constant-condition": 0, // disallow use of constant expressions in conditions
|
||||
"no-control-regex": 0, // disallow control characters in regular expressions
|
||||
"no-debugger": 0, // disallow use of debugger
|
||||
"no-dupe-keys": 0, // disallow duplicate keys when creating object literals
|
||||
"no-empty": 0, // disallow empty statements
|
||||
"no-empty-class": 0, // disallow the use of empty character classes in regular expressions
|
||||
"no-ex-assign": 0, // disallow assigning to the exception in a catch block
|
||||
"no-extra-boolean-cast": 0, // disallow double-negation boolean casts in a boolean context
|
||||
"no-extra-parens": 0, // disallow unnecessary parentheses (off by default)
|
||||
"no-extra-semi": 0, // disallow unnecessary semicolons
|
||||
"no-func-assign": 0, // disallow overwriting functions written as function declarations
|
||||
"no-inner-declarations": 0, // disallow function or variable declarations in nested blocks
|
||||
"no-invalid-regexp": 0, // disallow invalid regular expression strings in the RegExp constructor
|
||||
"no-irregular-whitespace": 0, // disallow irregular whitespace outside of strings and comments
|
||||
"no-negated-in-lhs": 0, // disallow negation of the left operand of an in expression
|
||||
"no-obj-calls": 0, // disallow the use of object properties of the global object (Math and JSON) as functions
|
||||
"no-regex-spaces": 0, // disallow multiple spaces in a regular expression literal
|
||||
"no-reserved-keys": 0, // disallow reserved words being used as object literal keys (off by default)
|
||||
"no-sparse-arrays": 0, // disallow sparse arrays
|
||||
"no-unreachable": 0, // disallow unreachable statements after a return, throw, continue, or break statement
|
||||
"use-isnan": 0, // disallow comparisons with the value NaN
|
||||
"valid-jsdoc": 0, // Ensure JSDoc comments are valid (off by default)
|
||||
"valid-typeof": 0, // Ensure that the results of typeof are compared against a valid string
|
||||
|
||||
|
||||
////////// Best Practices //////////
|
||||
|
||||
"block-scoped-var": 0, // treat var statements as if they were block scoped (off by default)
|
||||
"complexity": 0, // specify the maximum cyclomatic complexity allowed in a program (off by default)
|
||||
"consistent-return": 0, // require return statements to either always or never specify values
|
||||
"curly": 0, // specify curly brace conventions for all control statements
|
||||
"default-case": 0, // require default case in switch statements (off by default)
|
||||
"dot-notation": 0, // encourages use of dot notation whenever possible
|
||||
"eqeqeq": 0, // require the use of === and !==
|
||||
"guard-for-in": 0, // make sure for-in loops have an if statement (off by default)
|
||||
"no-alert": 0, // disallow the use of alert, confirm, and prompt
|
||||
"no-caller": 0, // disallow use of arguments.caller or arguments.callee
|
||||
"no-div-regex": 0, // disallow division operators explicitly at beginning of regular expression (off by default)
|
||||
"no-else-return": 0, // disallow else after a return in an if (off by default)
|
||||
"no-empty-label": 0, // disallow use of labels for anything other then loops and switches
|
||||
"no-eq-null": 0, // disallow comparisons to null without a type-checking operator (off by default)
|
||||
"no-eval": 0, // disallow use of eval()
|
||||
"no-extend-native": 0, // disallow adding to native types
|
||||
"no-extra-bind": 0, // disallow unnecessary function binding
|
||||
"no-fallthrough": 0, // disallow fallthrough of case statements
|
||||
"no-floating-decimal": 0, // disallow the use of leading or trailing decimal points in numeric literals (off by default)
|
||||
"no-implied-eval": 0, // disallow use of eval()-like methods
|
||||
"no-iterator": 0, // disallow usage of __iterator__ property
|
||||
"no-labels": 0, // disallow use of labeled statements
|
||||
"no-lone-blocks": 0, // disallow unnecessary nested blocks
|
||||
"no-loop-func": 0, // disallow creation of functions within loops
|
||||
"no-multi-spaces": 0, // disallow use of multiple spaces
|
||||
"no-multi-str": 0, // disallow use of multiline strings
|
||||
"no-native-reassign": 0, // disallow reassignments of native objects
|
||||
"no-new": 0, // disallow use of new operator when not part of the assignment or comparison
|
||||
"no-new-func": 0, // disallow use of new operator for Function object
|
||||
"no-new-wrappers": 0, // disallows creating new instances of String, Number, and Boolean
|
||||
"no-octal": 0, // disallow use of octal literals
|
||||
"no-octal-escape": 0, // disallow use of octal escape sequences in string literals, such as var foo = "Copyright \251";
|
||||
"no-process-env": 0, // disallow use of process.env (off by default)
|
||||
"no-proto": 0, // disallow usage of __proto__ property
|
||||
"no-redeclare": 0, // disallow declaring the same variable more then once
|
||||
"no-return-assign": 0, // disallow use of assignment in return statement
|
||||
"no-script-url": 0, // disallow use of javascript: urls.
|
||||
"no-self-compare": 0, // disallow comparisons where both sides are exactly the same (off by default)
|
||||
"no-sequences": 0, // disallow use of comma operator
|
||||
"no-unused-expressions": 0, // disallow usage of expressions in statement position
|
||||
"no-void": 0, // disallow use of void operator (off by default)
|
||||
"no-warning-comments": 0, // disallow usage of configurable warning terms in comments, e.g. TODO or FIXME (off by default)
|
||||
"no-with": 0, // disallow use of the with statement
|
||||
"radix": 0, // require use of the second argument for parseInt() (off by default)
|
||||
"vars-on-top": 0, // requires to declare all vars on top of their containing scope (off by default)
|
||||
"wrap-iife": 0, // require immediate function invocation to be wrapped in parentheses (off by default)
|
||||
"yoda": 0, // require or disallow Yoda conditions
|
||||
|
||||
|
||||
////////// Strict Mode //////////
|
||||
|
||||
"global-strict": 0, // (deprecated) require or disallow the "use strict" pragma in the global scope (off by default in the node environment)
|
||||
"no-extra-strict": 0, // (deprecated) disallow unnecessary use of "use strict"; when already in strict mode
|
||||
"strict": 0, // controls location of Use Strict Directives
|
||||
|
||||
|
||||
////////// Variables //////////
|
||||
|
||||
"no-catch-shadow": 0, // disallow the catch clause parameter name being the same as a variable in the outer scope (off by default in the node environment)
|
||||
"no-delete-var": 0, // disallow deletion of variables
|
||||
"no-label-var": 0, // disallow labels that share a name with a variable
|
||||
"no-shadow": 0, // disallow declaration of variables already declared in the outer scope
|
||||
"no-shadow-restricted-names": 0, // disallow shadowing of names such as arguments
|
||||
"no-undef": 1, // disallow use of undeclared variables unless mentioned in a /*global */ block
|
||||
"no-undef-init": 0, // disallow use of undefined when initializing variables
|
||||
"no-undefined": 0, // disallow use of undefined variable (off by default)
|
||||
"no-unused-vars": 0, // disallow declaration of variables that are not used in the code
|
||||
"no-use-before-define": 0, // disallow use of variables before they are defined
|
||||
|
||||
|
||||
////////// Node.js //////////
|
||||
|
||||
"handle-callback-err": 0, // enforces error handling in callbacks (off by default) (on by default in the node environment)
|
||||
"no-mixed-requires": 0, // disallow mixing regular variable and require declarations (off by default) (on by default in the node environment)
|
||||
"no-new-require": 0, // disallow use of new operator with the require function (off by default) (on by default in the node environment)
|
||||
"no-path-concat": 0, // disallow string concatenation with __dirname and __filename (off by default) (on by default in the node environment)
|
||||
"no-process-exit": 0, // disallow process.exit() (on by default in the node environment)
|
||||
"no-restricted-modules": 0, // restrict usage of specified node modules (off by default)
|
||||
"no-sync": 0, // disallow use of synchronous methods (off by default)
|
||||
|
||||
|
||||
////////// Stylistic Issues //////////
|
||||
|
||||
"brace-style": 0, // enforce one true brace style (off by default)
|
||||
"camelcase": 0, // require camel case names
|
||||
"comma-spacing": 0, // enforce spacing before and after comma
|
||||
"comma-style": 0, // enforce one true comma style (off by default)
|
||||
"consistent-this": 0, // enforces consistent naming when capturing the current execution context (off by default)
|
||||
"eol-last": 0, // enforce newline at the end of file, with no multiple empty lines
|
||||
"func-names": 0, // require function expressions to have a name (off by default)
|
||||
"func-style": 0, // enforces use of function declarations or expressions (off by default)
|
||||
"key-spacing": 0, // enforces spacing between keys and values in object literal properties
|
||||
"max-nested-callbacks": 0, // specify the maximum depth callbacks can be nested (off by default)
|
||||
"new-cap": 0, // require a capital letter for constructors
|
||||
"new-parens": 0, // disallow the omission of parentheses when invoking a constructor with no arguments
|
||||
"no-array-constructor": 0, // disallow use of the Array constructor
|
||||
"no-inline-comments": 0, // disallow comments inline after code (off by default)
|
||||
"no-lonely-if": 0, // disallow if as the only statement in an else block (off by default)
|
||||
"no-mixed-spaces-and-tabs": 0, // disallow mixed spaces and tabs for indentation
|
||||
"no-multiple-empty-lines": 0, // disallow multiple empty lines (off by default)
|
||||
"no-nested-ternary": 0, // disallow nested ternary expressions (off by default)
|
||||
"no-new-object": 0, // disallow use of the Object constructor
|
||||
"no-space-before-semi": 0, // disallow space before semicolon
|
||||
"no-spaced-func": 0, // disallow space between function identifier and application
|
||||
"no-ternary": 0, // disallow the use of ternary operators (off by default)
|
||||
"no-trailing-spaces": 0, // disallow trailing whitespace at the end of lines
|
||||
"no-underscore-dangle": 0, // disallow dangling underscores in identifiers
|
||||
"no-wrap-func": 0, // disallow wrapping of non-IIFE statements in parens
|
||||
"one-var": 0, // allow just one var statement per function (off by default)
|
||||
"operator-assignment": 0, // require assignment operator shorthand where possible or prohibit it entirely (off by default)
|
||||
"padded-blocks": 0, // enforce padding within blocks (off by default)
|
||||
"quote-props": 0, // require quotes around object literal property names (off by default)
|
||||
"quotes": 0, // specify whether double or single quotes should be used
|
||||
"semi": 0, // require or disallow use of semicolons instead of ASI
|
||||
"sort-vars": 0, // sort variables within the same declaration block (off by default)
|
||||
"space-after-function-name": 0, // require a space after function names (off by default)
|
||||
"space-after-keywords": 0, // require a space after certain keywords (off by default)
|
||||
"space-before-blocks": 0, // require or disallow space before blocks (off by default)
|
||||
"space-in-brackets": 0, // require or disallow spaces inside brackets (off by default)
|
||||
"space-in-parens": 0, // require or disallow spaces inside parentheses (off by default)
|
||||
"space-infix-ops": 0, // require spaces around operators
|
||||
"space-return-throw-case": 0, // require a space after return, throw, and case
|
||||
"space-unary-ops": 0, // Require or disallow spaces before/after unary operators (words on by default, nonwords off by default)
|
||||
"spaced-line-comment": 0, // require or disallow a space immediately following the // in a line comment (off by default)
|
||||
"wrap-regex": 0, // require regex literals to be wrapped in parentheses (off by default)
|
||||
|
||||
|
||||
////////// ECMAScript 6 //////////
|
||||
|
||||
"no-var": 0, // require let or const instead of var (off by default)
|
||||
"generator-star": 0, // enforce the position of the * in generator functions (off by default)
|
||||
|
||||
|
||||
////////// Legacy //////////
|
||||
|
||||
"max-depth": 0, // specify the maximum depth that blocks can be nested (off by default)
|
||||
"max-len": 0, // specify the maximum length of a line in your program (off by default)
|
||||
"max-params": 0, // limits the number of parameters that can be used in the function declaration. (off by default)
|
||||
"max-statements": 0, // specify the maximum number of statement allowed in a function (off by default)
|
||||
"no-bitwise": 0, // disallow use of bitwise operators (off by default)
|
||||
"no-plusplus": 0, // disallow use of unary operators, ++ and -- (off by default)
|
||||
|
||||
// There were other errors that were being thrown
|
||||
"import/newline-after-import": 0,
|
||||
"object-curly-spacing": 0,
|
||||
"space-before-function-paren": 0,
|
||||
"no-restricted-syntax": 0,
|
||||
"no-unneeded-ternary": 0,
|
||||
"react/prefer-es6-class": 0,
|
||||
"arrow-parens": 0,
|
||||
"jsx-quotes": 0,
|
||||
"react/sort-comp": 0,
|
||||
"react/no-unescaped-entities": 0,
|
||||
"object-shorthand": 0,
|
||||
"jsx-a11y/label-has-for": 0,
|
||||
"no-mixed-operators": 0,
|
||||
"react/jsx-no-bind": 0,
|
||||
"no-duplicate-case": 0,
|
||||
"react/jsx-filename-extension": 0,
|
||||
"jsx-a11y/img-has-alt": 0,
|
||||
"react/self-closing-comp": 0,
|
||||
"prefer-const": 0,
|
||||
"one-var-declaration-per-line": 0,
|
||||
"react/jsx-indent": 0,
|
||||
"react/jsx-curly-spacing": 0,
|
||||
"react/prefer-stateless-function": 0,
|
||||
"react/jsx-indent-props": 0,
|
||||
"react/no-find-dom-node": 0,
|
||||
"react/no-unused-prop-types": 0,
|
||||
"react/jsx-no-undef": 0,
|
||||
"react/no-string-refs": 0,
|
||||
"react/jsx-first-prop-new-line": 0,
|
||||
"comma-dangle": 0,
|
||||
"react/no-multi-comp": 0,
|
||||
"spaced-comment": 0,
|
||||
"jsx-a11y/anchor-has-content": 0,
|
||||
"semi-spacing": 0,
|
||||
"no-param-reassign": 0,
|
||||
"react/jsx-no-target-blank": 0,
|
||||
"prefer-arrow-callback": 0,
|
||||
"react/jsx-space-before-closing": 0,
|
||||
"react/forbid-prop-types": 0,
|
||||
"indent": 0,
|
||||
"import/no-unresolved": 0,
|
||||
"react/jsx-boolean-value": 0,
|
||||
"prefer-template": 0,
|
||||
"react/jsx-wrap-multilines": 0,
|
||||
"keyword-spacing": 0,
|
||||
"react/jsx-closing-bracket-location": 0,
|
||||
"react/react-in-jsx-scope": 0,
|
||||
"no-useless-escape": 0,
|
||||
"no-continue": 0,
|
||||
"react/prop-types": 0
|
||||
}
|
||||
};
|
|
@ -7,8 +7,7 @@ install:
|
|||
script:
|
||||
- mkdir -p dist/css dist/js
|
||||
- node_modules/.bin/node-sass scss/all.scss dist/css/all.css
|
||||
- node_modules/.bin/babel -V
|
||||
- node_modules/.bin/babel --presets es2015,react --out-dir dist/js js
|
||||
- node_modules/.bin/webpack
|
||||
- mkdir upload
|
||||
- cd dist; zip -r ../upload/dist.zip *; cd -
|
||||
- .travis/echo_sha.sh > upload/data.json
|
||||
|
|
BIN
dist.zip
BIN
dist.zip
Binary file not shown.
34
dist/index.html
vendored
34
dist/index.html
vendored
|
@ -20,38 +20,6 @@
|
|||
</head>
|
||||
<body>
|
||||
<div id="canvas"></div>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.2/react.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.2/react-dom.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-modal/1.5.2/react-modal.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/6.7.4/polyfill.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/Clamp.js/0.5.1/clamp.min.js"></script>
|
||||
<script src="./js/mediaelement/jquery.js"></script>
|
||||
<script src="./js/mediaelement/mediaelement-and-player.min.js"></script>
|
||||
<script src="./js/lbry.js?i=0"></script>
|
||||
<script src="./js/lighthouse.js?i=0"></script>
|
||||
<script src="./js/component/common.js?i=0"></script>
|
||||
<script src="./js/component/form.js?i=0"></script>
|
||||
<script src="./js/component/link.js?i=0"></script>
|
||||
<script src="./js/component/menu.js?i=0"></script>
|
||||
<script src="./js/component/modal.js?i=0"></script>
|
||||
<script src="./js/component/header.js?i=0"></script>
|
||||
<script src="./js/component/drawer.js?i=0"></script>
|
||||
<script src="./js/component/splash.js?i=0"></script>
|
||||
<script src="./js/component/load_screen.js?i=0"></script>
|
||||
<script src="./js/page/discover.js?i=0"></script>
|
||||
<script src="./js/page/settings.js?i=0"></script>
|
||||
<script src="./js/page/help.js?i=0"></script>
|
||||
<script src="./js/page/watch.js?i=0"></script>
|
||||
<script src="./js/page/report.js?i=0"></script>
|
||||
<script src="./js/page/my_files.js?i=0"></script>
|
||||
<script src="./js/page/publish.js?i=0"></script>
|
||||
<script src="./js/page/start.js?i=0"></script>
|
||||
<script src="./js/page/claim_code.js?i=0"></script>
|
||||
<script src="./js/page/referral.js?i=0"></script>
|
||||
<script src="./js/page/wallet.js?i=0"></script>
|
||||
<script src="./js/page/show.js?i=0"></script>
|
||||
<script src="./js/page/wallet.js?i=0"></script>
|
||||
<script src="./js/app.js?i=0"></script>
|
||||
<script src="./js/main.js?i=0"></script>
|
||||
<script src="./js/bundle.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
27
js/app.js
27
js/app.js
|
@ -1,3 +1,23 @@
|
|||
import React from 'react';
|
||||
import lbry from './lbry.js';
|
||||
import SettingsPage from './page/settings.js';
|
||||
import HelpPage from './page/help.js';
|
||||
import WatchPage from './page/watch.js';
|
||||
import ReportPage from './page/report.js';
|
||||
import MyFilesPage from './page/my_files.js';
|
||||
import StartPage from './page/start.js';
|
||||
import ClaimCodePage from './page/claim_code.js';
|
||||
import ReferralPage from './page/referral.js';
|
||||
import WalletPage from './page/wallet.js';
|
||||
import DetailPage from './page/show.js';
|
||||
import PublishPage from './page/publish.js';
|
||||
import DiscoverPage from './page/discover.js';
|
||||
import SplashScreen from './component/splash.js';
|
||||
import Drawer from './component/drawer.js';
|
||||
import Header from './component/header.js';
|
||||
import Modal from './component/modal.js';
|
||||
import {Link} from './component/link.js';
|
||||
|
||||
var App = React.createClass({
|
||||
_error_key_labels: {
|
||||
connectionString: 'API connection string',
|
||||
|
@ -167,10 +187,6 @@ var App = React.createClass({
|
|||
case 'send':
|
||||
case 'receive':
|
||||
return <WalletPage viewingPage={this.state.viewingPage} />;
|
||||
case 'send':
|
||||
return <SendPage />;
|
||||
case 'receive':
|
||||
return <ReceivePage />;
|
||||
case 'show':
|
||||
return <DetailPage name={this.state.pageArgs} />;
|
||||
case 'publish':
|
||||
|
@ -220,3 +236,6 @@ var App = React.createClass({
|
|||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
export default App;
|
||||
|
|
|
@ -1,17 +1,22 @@
|
|||
//component/icon.js
|
||||
import React from 'react';
|
||||
import lbry from '../lbry.js';
|
||||
import $clamp from 'clamp';
|
||||
|
||||
var Icon = React.createClass({
|
||||
//component/icon.js
|
||||
export let Icon = React.createClass({
|
||||
propTypes: {
|
||||
style: React.PropTypes.object,
|
||||
fixed: React.PropTypes.bool,
|
||||
className: React.PropTypes.string,
|
||||
},
|
||||
render: function() {
|
||||
var className = 'icon ' + ('fixed' in this.props ? 'icon-fixed-width ' : '') + this.props.icon;
|
||||
var className = ('icon ' + ('fixed' in this.props ? 'icon-fixed-width ' : '') + this.props.icon + ' ' +
|
||||
(this.props.className || ''));
|
||||
return <span className={className} style={this.props.style}></span>
|
||||
}
|
||||
});
|
||||
|
||||
var TruncatedText = React.createClass({
|
||||
export let TruncatedText = React.createClass({
|
||||
propTypes: {
|
||||
lines: React.PropTypes.number,
|
||||
height: React.PropTypes.string,
|
||||
|
@ -35,7 +40,7 @@ var TruncatedText = React.createClass({
|
|||
}
|
||||
});
|
||||
|
||||
var BusyMessage = React.createClass({
|
||||
export let BusyMessage = React.createClass({
|
||||
propTypes: {
|
||||
message: React.PropTypes.string
|
||||
},
|
||||
|
@ -55,7 +60,7 @@ var toolTipStyle = {
|
|||
backgroundColor: '#fff',
|
||||
fontSize: '14px',
|
||||
};
|
||||
var ToolTip = React.createClass({
|
||||
export let ToolTip = React.createClass({
|
||||
propTypes: {
|
||||
open: React.PropTypes.bool.isRequired,
|
||||
onMouseOut: React.PropTypes.func
|
||||
|
@ -78,11 +83,11 @@ var creditAmountStyle = {
|
|||
color: '#aaa',
|
||||
};
|
||||
|
||||
var CurrencySymbol = React.createClass({
|
||||
export let CurrencySymbol = React.createClass({
|
||||
render: function() { return <span>LBC</span>; }
|
||||
});
|
||||
|
||||
var CreditAmount = React.createClass({
|
||||
export let CreditAmount = React.createClass({
|
||||
propTypes: {
|
||||
amount: React.PropTypes.number,
|
||||
precision: React.PropTypes.number
|
||||
|
@ -101,7 +106,7 @@ var CreditAmount = React.createClass({
|
|||
var addressStyle = {
|
||||
fontFamily: '"Consolas", "Lucida Console", "Adobe Source Code Pro", monospace',
|
||||
};
|
||||
var Address = React.createClass({
|
||||
export let Address = React.createClass({
|
||||
propTypes: {
|
||||
address: React.PropTypes.string,
|
||||
},
|
||||
|
@ -112,7 +117,7 @@ var Address = React.createClass({
|
|||
}
|
||||
});
|
||||
|
||||
var Thumbnail = React.createClass({
|
||||
export let Thumbnail = React.createClass({
|
||||
_defaultImageUri: '/img/default-thumb.svg',
|
||||
_maxLoadTime: 10000,
|
||||
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
import lbry from '../lbry.js';
|
||||
import React from 'react';
|
||||
import {Link} from './link.js';
|
||||
|
||||
var DrawerItem = React.createClass({
|
||||
getDefaultProps: function() {
|
||||
return {
|
||||
|
@ -46,4 +50,7 @@ var Drawer = React.createClass({
|
|||
</nav>
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
export default Drawer;
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
import React from 'react';
|
||||
|
||||
var requiredFieldWarningStyle = {
|
||||
color: '#cc0000',
|
||||
transition: 'opacity 400ms ease-in',
|
||||
};
|
||||
|
||||
var FormField = React.createClass({
|
||||
_fieldRequiredText: 'This field is required',
|
||||
_type: null,
|
||||
_element: null,
|
||||
|
||||
|
@ -13,7 +16,8 @@ var FormField = React.createClass({
|
|||
},
|
||||
getInitialState: function() {
|
||||
return {
|
||||
warningState: 'hidden',
|
||||
adviceState: 'hidden',
|
||||
adviceText: null,
|
||||
}
|
||||
},
|
||||
componentWillMount: function() {
|
||||
|
@ -25,22 +29,26 @@ var FormField = React.createClass({
|
|||
this._element = this.props.type;
|
||||
}
|
||||
},
|
||||
warnRequired: function() {
|
||||
showAdvice: function(text) {
|
||||
this.setState({
|
||||
warningState: 'shown',
|
||||
adviceState: 'shown',
|
||||
adviceText: text,
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
this.setState({
|
||||
warningState: 'fading',
|
||||
adviceState: 'fading',
|
||||
});
|
||||
setTimeout(() => {
|
||||
this.setState({
|
||||
warningState: 'hidden',
|
||||
adviceState: 'hidden',
|
||||
});
|
||||
}, 450);
|
||||
}, 5000);
|
||||
},
|
||||
warnRequired: function() {
|
||||
this.showAdvice(this._fieldRequiredText);
|
||||
},
|
||||
focus: function() {
|
||||
this.refs.field.focus();
|
||||
},
|
||||
|
@ -55,24 +63,45 @@ var FormField = React.createClass({
|
|||
return this.refs.field.options[this.refs.field.selectedIndex];
|
||||
},
|
||||
render: function() {
|
||||
var warningStyle = Object.assign({}, requiredFieldWarningStyle);
|
||||
if (this.state.warningState == 'fading') {
|
||||
warningStyle.opacity = '0';
|
||||
}
|
||||
|
||||
// Pass all unhandled props to the field element
|
||||
var otherProps = Object.assign({}, this.props);
|
||||
delete otherProps.type;
|
||||
delete otherProps.hidden;
|
||||
|
||||
return (
|
||||
<span className={this.props.hidden ? 'hidden' : ''}>
|
||||
<this._element type={this._type} name={this.props.name} ref="field" placeholder={this.props.placeholder}
|
||||
{...otherProps}>
|
||||
{this.props.children}
|
||||
</this._element>
|
||||
<span className={this.state.warningState == 'hidden' ? 'hidden' : ''} style={warningStyle}> This field is required</span>
|
||||
</span>
|
||||
!this.props.hidden
|
||||
? <div className="form-field-container">
|
||||
<this._element type={this._type} className="form-field" name={this.props.name} ref="field" placeholder={this.props.placeholder}
|
||||
{...otherProps}>
|
||||
{this.props.children}
|
||||
</this._element>
|
||||
<FormFieldAdvice field={this.refs.field} state={this.state.adviceState}>{this.state.adviceText}</FormFieldAdvice>
|
||||
</div>
|
||||
: null
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var FormFieldAdvice = React.createClass({
|
||||
propTypes: {
|
||||
state: React.PropTypes.string.isRequired,
|
||||
},
|
||||
render: function() {
|
||||
return (
|
||||
this.props.state != 'hidden'
|
||||
? <div className="form-field-advice-container">
|
||||
<div className={'form-field-advice' + (this.props.state == 'fading' ? ' form-field-advice--fading' : '')}>
|
||||
<Icon icon="icon-caret-up" className="form-field-advice__arrow" />
|
||||
<div className="form-field-advice__content-container">
|
||||
<span className="form-field-advice__content">
|
||||
{this.props.children}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
: null
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default FormField;
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
import React from 'react';
|
||||
import {Link} from './link.js';
|
||||
|
||||
var Header = React.createClass({
|
||||
getInitialState: function() {
|
||||
return {
|
||||
|
@ -81,4 +84,6 @@ var SubHeader = React.createClass({
|
|||
</nav>
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
export default Header;
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
var Link = React.createClass({
|
||||
import React from 'react';
|
||||
import lbry from '../lbry.js';
|
||||
import Modal from './modal.js';
|
||||
import {Icon, ToolTip} from './common.js';
|
||||
|
||||
|
||||
export let Link = React.createClass({
|
||||
handleClick: function() {
|
||||
if (this.props.onClick) {
|
||||
this.props.onClick();
|
||||
|
@ -27,7 +33,7 @@ var linkContainerStyle = {
|
|||
position: 'relative',
|
||||
};
|
||||
|
||||
var ToolTipLink = React.createClass({
|
||||
export let ToolTipLink = React.createClass({
|
||||
getInitialState: function() {
|
||||
return {
|
||||
showTooltip: false,
|
||||
|
@ -73,7 +79,7 @@ var ToolTipLink = React.createClass({
|
|||
}
|
||||
});
|
||||
|
||||
var DownloadLink = React.createClass({
|
||||
export let DownloadLink = React.createClass({
|
||||
propTypes: {
|
||||
type: React.PropTypes.string,
|
||||
streamName: React.PropTypes.string,
|
||||
|
@ -107,16 +113,16 @@ var DownloadLink = React.createClass({
|
|||
downloading: true
|
||||
});
|
||||
|
||||
lbry.getCostEstimate(this.props.streamName, (amount) => {
|
||||
lbry.getCostInfoForName(this.props.streamName, ({cost}) => {
|
||||
lbry.getBalance((balance) => {
|
||||
if (amount > balance) {
|
||||
if (cost > balance) {
|
||||
this.setState({
|
||||
modal: 'notEnoughCredits',
|
||||
downloading: false
|
||||
});
|
||||
} else {
|
||||
lbry.getStream(this.props.streamName, (streamInfo) => {
|
||||
if (typeof streamInfo !== 'object') {
|
||||
if (streamInfo === null || typeof streamInfo !== 'object') {
|
||||
this.setState({
|
||||
modal: 'timedOut',
|
||||
downloading: false,
|
||||
|
@ -138,8 +144,9 @@ var DownloadLink = React.createClass({
|
|||
<span className="button-container">
|
||||
<Link button={this.props.button} hidden={this.props.hidden} style={this.props.style}
|
||||
disabled={this.state.downloading} label={label} icon={this.props.icon} onClick={this.handleClick} />
|
||||
<Modal isOpen={this.state.modal == 'downloadStarted'} onConfirmed={this.closeModal}>
|
||||
Downloading to {this.state.filePath}
|
||||
<Modal className="download-started-modal" isOpen={this.state.modal == 'downloadStarted'} onConfirmed={this.closeModal}>
|
||||
<p>Downloading to:</p>
|
||||
<div className="download-started-modal__file-path">{this.state.filePath}</div>
|
||||
</Modal>
|
||||
<Modal isOpen={this.state.modal == 'notEnoughCredits'} onConfirmed={this.closeModal}>
|
||||
You don't have enough LBRY credits to pay for this stream.
|
||||
|
@ -152,7 +159,7 @@ var DownloadLink = React.createClass({
|
|||
}
|
||||
});
|
||||
|
||||
var WatchLink = React.createClass({
|
||||
export let WatchLink = React.createClass({
|
||||
propTypes: {
|
||||
type: React.PropTypes.string,
|
||||
streamName: React.PropTypes.string,
|
||||
|
@ -165,9 +172,9 @@ var WatchLink = React.createClass({
|
|||
this.setState({
|
||||
loading: true,
|
||||
})
|
||||
lbry.getCostEstimate(this.props.streamName, (amount) => {
|
||||
lbry.getCostInfoForName(this.props.streamName, ({cost}) => {
|
||||
lbry.getBalance((balance) => {
|
||||
if (amount > balance) {
|
||||
if (cost > balance) {
|
||||
this.setState({
|
||||
modal: 'notEnoughCredits',
|
||||
loading: false,
|
||||
|
@ -207,4 +214,4 @@ var WatchLink = React.createClass({
|
|||
</span>
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
import React from 'react';
|
||||
import lbry from '../lbry.js';
|
||||
import {BusyMessage, Icon} from './common.js';
|
||||
|
||||
var loadScreenStyle = {
|
||||
color: 'white',
|
||||
backgroundImage: 'url(' + lbry.imagePath('lbry-bg.png') + ')',
|
||||
|
@ -46,4 +50,7 @@ var LoadScreen = React.createClass({
|
|||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
export default LoadScreen;
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import {Icon} from './common.js';
|
||||
|
||||
// Generic menu styles
|
||||
var menuStyle = {
|
||||
export let menuStyle = {
|
||||
whiteSpace: 'nowrap'
|
||||
};
|
||||
|
||||
var Menu = React.createClass({
|
||||
export let Menu = React.createClass({
|
||||
handleWindowClick: function(e) {
|
||||
if (this.props.toggleButton && ReactDOM.findDOMNode(this.props.toggleButton).contains(e.target)) {
|
||||
// Toggle button was clicked
|
||||
|
@ -40,10 +44,10 @@ var Menu = React.createClass({
|
|||
}
|
||||
});
|
||||
|
||||
var menuItemStyle = {
|
||||
export let menuItemStyle = {
|
||||
display: 'block',
|
||||
};
|
||||
var MenuItem = React.createClass({
|
||||
export let MenuItem = React.createClass({
|
||||
propTypes: {
|
||||
href: React.PropTypes.string,
|
||||
label: React.PropTypes.string,
|
||||
|
@ -67,4 +71,4 @@ var MenuItem = React.createClass({
|
|||
</a>
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
import React from 'react';
|
||||
import ReactModal from 'react-modal';
|
||||
import {Link} from './link.js';
|
||||
|
||||
|
||||
var Modal = React.createClass({
|
||||
propTypes: {
|
||||
type: React.PropTypes.oneOf(['alert', 'confirm', 'custom']),
|
||||
|
@ -57,3 +62,5 @@ var Modal = React.createClass({
|
|||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default Modal;
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
import React from 'react';
|
||||
import lbry from '../lbry.js';
|
||||
import LoadScreen from './load_screen.js';
|
||||
|
||||
var SplashScreen = React.createClass({
|
||||
propTypes: {
|
||||
message: React.PropTypes.string,
|
||||
|
@ -32,4 +36,6 @@ var SplashScreen = React.createClass({
|
|||
render: function() {
|
||||
return <LoadScreen message={this.props.message} details={this.state.details} isWarning={this.state.isLagging} />;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
export default SplashScreen;
|
||||
|
|
87
js/lbry.js
87
js/lbry.js
|
@ -1,7 +1,10 @@
|
|||
import lighthouse from './lighthouse.js';
|
||||
|
||||
var lbry = {
|
||||
isConnected: false,
|
||||
rootPath: '.',
|
||||
daemonConnectionString: 'http://localhost:5279/lbryapi',
|
||||
webUiUri: 'http://localhost:5279',
|
||||
colors: {
|
||||
primary: '#155B4A'
|
||||
},
|
||||
|
@ -178,10 +181,59 @@ lbry.getMyClaim = function(name, callback) {
|
|||
lbry.call('get_my_claim', { name: name }, callback);
|
||||
}
|
||||
|
||||
lbry.getCostEstimate = function(name, callback) {
|
||||
lbry.getKeyFee = function(name, callback) {
|
||||
lbry.call('get_est_cost', { name: name }, callback);
|
||||
}
|
||||
|
||||
lbry.getTotalCost = function(name, size, callback) {
|
||||
lbry.call('get_est_cost', {
|
||||
name: name,
|
||||
size: size,
|
||||
}, callback);
|
||||
}
|
||||
|
||||
lbry.getPeersForBlobHash = function(blobHash, callback) {
|
||||
lbry.call('get_peers_for_hash', { blob_hash: blobHash }, callback)
|
||||
}
|
||||
|
||||
lbry.getCostInfoForName = function(name, callback) {
|
||||
/**
|
||||
* Takes a LBRY name; will first try and calculate a total cost using
|
||||
* Lighthouse. If Lighthouse can't be reached, it just retrives the
|
||||
* key fee.
|
||||
*
|
||||
* Returns an object with members:
|
||||
* - cost: Number; the calculated cost of the name
|
||||
* - includes_data: Boolean; indicates whether or not the data fee info
|
||||
* from Lighthouse is included.
|
||||
*/
|
||||
function getCostWithData(name, size, callback) {
|
||||
lbry.getTotalCost(name, size, (cost) => {
|
||||
callback({
|
||||
cost: cost,
|
||||
includesData: true,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getCostNoData(name, callback) {
|
||||
lbry.getKeyFee(name, (cost) => {
|
||||
callback({
|
||||
cost: cost,
|
||||
includesData: false,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
lighthouse.getSizeForName(name, (size) => {
|
||||
getCostWithData(name, size, callback);
|
||||
}, () => {
|
||||
getCostNoData(name, callback);
|
||||
}, () => {
|
||||
getCostNoData(name, callback);
|
||||
});
|
||||
}
|
||||
|
||||
lbry.getFileStatus = function(name, callback) {
|
||||
lbry.call('get_lbry_file', { 'name': name }, callback);
|
||||
}
|
||||
|
@ -190,6 +242,22 @@ lbry.getFilesInfo = function(callback) {
|
|||
lbry.call('get_lbry_files', {}, callback);
|
||||
}
|
||||
|
||||
lbry.getFileInfoByName = function(name, callback) {
|
||||
lbry.call('get_lbry_file', {name: name}, callback);
|
||||
}
|
||||
|
||||
lbry.getFileInfoBySdHash = function(sdHash, callback) {
|
||||
lbry.call('get_lbry_file', {sd_hash: sdHash}, callback);
|
||||
}
|
||||
|
||||
lbry.getFileInfoByFilename = function(filename, callback) {
|
||||
lbry.call('get_lbry_file', {file_name: filename}, callback);
|
||||
}
|
||||
|
||||
lbry.getMyClaims = function(callback) {
|
||||
lbry.call('get_name_claims', {}, callback);
|
||||
}
|
||||
|
||||
lbry.startFile = function(name, callback) {
|
||||
lbry.call('start_lbry_file', { name: name }, callback);
|
||||
}
|
||||
|
@ -310,6 +378,9 @@ lbry.setClientSetting = function(setting, value) {
|
|||
return localStorage.setItem('setting_' + setting, JSON.stringify(value));
|
||||
}
|
||||
|
||||
lbry.getSessionInfo = function(callback) {
|
||||
lbry.call('get_lbry_session_info', {}, callback);
|
||||
}
|
||||
|
||||
lbry.reportBug = function(message, callback) {
|
||||
lbry.call('upload_log', {
|
||||
|
@ -327,8 +398,15 @@ lbry.formatCredits = function(amount, precision)
|
|||
}
|
||||
|
||||
lbry.formatName = function(name) {
|
||||
// Converts LBRY name to standard format (all lower case, no special characters)
|
||||
return name.toLowerCase().replace(/[^a-z0-9\-]/g, '');
|
||||
// Converts LBRY name to standard format (all lower case, no special characters, spaces replaced by dashes)
|
||||
name = name.replace('/\s+/g', '-');
|
||||
name = name.toLowerCase().replace(/[^a-z0-9\-]/g, '');
|
||||
return name;
|
||||
}
|
||||
|
||||
lbry.nameIsValid = function(name, checkCase=true) {
|
||||
const regexp = new RegExp('^[a-z0-9-]+$', checkCase ? '' : 'i');
|
||||
return regexp.test(name);
|
||||
}
|
||||
|
||||
lbry.loadJs = function(src, type, onload)
|
||||
|
@ -341,7 +419,7 @@ lbry.loadJs = function(src, type, onload)
|
|||
newScriptTag.type = type;
|
||||
if (onload)
|
||||
{
|
||||
newScript.onload = onload;
|
||||
newScriptTag.onload = onload;
|
||||
}
|
||||
lbryScriptTag.parentNode.insertBefore(newScriptTag, lbryScriptTag);
|
||||
}
|
||||
|
@ -380,3 +458,4 @@ lbry.stop = function(callback) {
|
|||
};
|
||||
|
||||
|
||||
export default lbry;
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
lbry.lighthouse = {
|
||||
import lbry from './lbry.js';
|
||||
|
||||
var lighthouse = {
|
||||
_search_timeout: 5000,
|
||||
_max_search_tries: 5,
|
||||
|
||||
servers: [
|
||||
'http://lighthouse1.lbry.io:50005',
|
||||
'http://lighthouse2.lbry.io:50005',
|
||||
'http://lighthouse3.lbry.io:50005',
|
||||
'http://lighthouse4.lbry.io:50005',
|
||||
'http://lighthouse5.lbry.io:50005',
|
||||
'http://lighthouse6.lbry.io:50005',
|
||||
],
|
||||
path: '/',
|
||||
|
||||
|
@ -13,24 +15,34 @@ lbry.lighthouse = {
|
|||
lbry.jsonrpc_call(this.server + this.path, method, params, callback, errorCallback, connectFailedCallback, timeout);
|
||||
},
|
||||
|
||||
search: function(query, callback) {
|
||||
search: function(query, callback, errorCallback, connectFailedCallback, timeout) {
|
||||
let handleSearchFailed = function(tryNum=0) {
|
||||
if (tryNum > lbry.lighthouse._max_search_tries) {
|
||||
throw new Error(`Could not connect to Lighthouse server. Last server attempted: ${lbry.lighthouse.server}`);
|
||||
if (tryNum > lighthouse._max_search_tries) {
|
||||
if (connectFailedCallback) {
|
||||
connectFailedCallback();
|
||||
} else {
|
||||
throw new Error(`Could not connect to Lighthouse server. Last server attempted: ${lighthouse.server}`);
|
||||
}
|
||||
} else {
|
||||
// Randomly choose one of the other search servers to switch to
|
||||
let otherServers = lbry.lighthouse.servers.slice();
|
||||
otherServers.splice(otherServers.indexOf(lbry.lighthouse.server), 1);
|
||||
lbry.lighthouse.server = otherServers[Math.round(Math.random() * (otherServers.length - 1))];
|
||||
let otherServers = lighthouse.servers.slice();
|
||||
otherServers.splice(otherServers.indexOf(lighthouse.server), 1);
|
||||
lighthouse.server = otherServers[Math.round(Math.random() * (otherServers.length - 1))];
|
||||
|
||||
lbry.lighthouse.call('search', [query], callback, undefined, function() {
|
||||
lighthouse.call('search', [query], callback, errorCallback, function() {
|
||||
handleSearchFailed(tryNum + 1);
|
||||
}, lbry.lighthouse._search_timeout);
|
||||
}, lighthouse._search_timeout);
|
||||
}
|
||||
}
|
||||
|
||||
lbry.lighthouse.call('search', [query], callback, undefined, function() { handleSearchFailed() }, lbry.lighthouse._search_timeout);
|
||||
lighthouse.call('search', [query], callback, errorCallback, function() { handleSearchFailed() }, lighthouse._search_timeout);
|
||||
},
|
||||
|
||||
getSizeForName: function(name, callback, errorCallback, connectFailedCallback, timeout) {
|
||||
return lighthouse.call('get_size_for_name', [name], callback, errorCallback, connectFailedCallback, timeout);
|
||||
}
|
||||
};
|
||||
|
||||
lbry.lighthouse.server = lbry.lighthouse.servers[Math.round(Math.random() * (lbry.lighthouse.servers.length - 1))];
|
||||
lighthouse.server = lighthouse.servers[Math.round(Math.random() * (lighthouse.servers.length - 1))];
|
||||
|
||||
export default lighthouse;
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
//main.js
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import lbry from './lbry.js';
|
||||
import App from './app.js';
|
||||
import SplashScreen from './component/splash.js';
|
||||
|
||||
|
||||
var init = function() {
|
||||
var canvas = document.getElementById('canvas');
|
||||
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
import React from 'react';
|
||||
import lbry from '../lbry.js';
|
||||
import Modal from '../component/modal.js';
|
||||
import {Link} from '../component/link.js';
|
||||
|
||||
var claimCodeContentStyle = {
|
||||
display: 'inline-block',
|
||||
textAlign: 'left',
|
||||
|
@ -126,10 +131,10 @@ var ClaimCodePage = React.createClass({
|
|||
<Modal isOpen={this.state.modal == 'codeRedeemed'} onConfirmed={this.handleFinished}>
|
||||
Your invite code has been redeemed.
|
||||
{this.state.referralCredits > 0
|
||||
? `You have also earned {referralCredits} credits from referrals. A total of {activationCredits + referralCredits}
|
||||
? `You have also earned ${referralCredits} credits from referrals. A total of ${activationCredits + referralCredits}
|
||||
will be added to your balance shortly.`
|
||||
: (this.state.activationCredits > 0
|
||||
? `{this.state.activationCredits} credits will be added to your balance shortly.`
|
||||
? `${this.state.activationCredits} credits will be added to your balance shortly.`
|
||||
: 'The credits will be added to your balance shortly.')}
|
||||
</Modal>
|
||||
<Modal isOpen={this.state.modal == 'skipped'} onConfirmed={this.handleFinished}>
|
||||
|
@ -143,3 +148,5 @@ var ClaimCodePage = React.createClass({
|
|||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default ClaimCodePage;
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
import React from 'react';
|
||||
import lbry from '../lbry.js';
|
||||
import lighthouse from '../lighthouse.js';
|
||||
import {Link, ToolTipLink, DownloadLink, WatchLink} from '../component/link.js';
|
||||
import {Thumbnail, CreditAmount, TruncatedText} from '../component/common.js';
|
||||
|
||||
var fetchResultsStyle = {
|
||||
color: '#888',
|
||||
textAlign: 'center',
|
||||
|
@ -40,8 +46,7 @@ var SearchResults = React.createClass({
|
|||
var mediaType = lbry.getMediaType(result.value.content_type);
|
||||
rows.push(
|
||||
<SearchResultRow key={result.name} name={result.name} title={result.value.title} imgUrl={result.value.thumbnail}
|
||||
description={result.value.description} cost={result.cost} nsfw={result.value.nsfw}
|
||||
mediaType={mediaType} />
|
||||
description={result.value.description} nsfw={result.value.nsfw} mediaType={mediaType} />
|
||||
);
|
||||
});
|
||||
return (
|
||||
|
@ -87,6 +92,8 @@ var SearchResultRow = React.createClass({
|
|||
return {
|
||||
downloading: false,
|
||||
isHovered: false,
|
||||
cost: null,
|
||||
costIncludesData: null,
|
||||
}
|
||||
},
|
||||
handleMouseOver: function() {
|
||||
|
@ -99,6 +106,21 @@ var SearchResultRow = React.createClass({
|
|||
isHovered: false,
|
||||
});
|
||||
},
|
||||
componentWillMount: function() {
|
||||
if ('cost' in this.props) {
|
||||
this.setState({
|
||||
cost: this.props.cost,
|
||||
costIncludesData: this.props.costIncludesData,
|
||||
});
|
||||
} else {
|
||||
lbry.getCostInfoForName(this.props.name, ({cost, includesData}) => {
|
||||
this.setState({
|
||||
cost: cost,
|
||||
costIncludesData: includesData,
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
render: function() {
|
||||
var obscureNsfw = !lbry.getClientSetting('showNsfw') && this.props.nsfw;
|
||||
if (!this.props.compact) {
|
||||
|
@ -116,9 +138,11 @@ var SearchResultRow = React.createClass({
|
|||
<a href={'/?show=' + this.props.name}><Thumbnail src={this.props.imgUrl} alt={'Photo for ' + (this.props.title || this.props.name)} style={searchRowImgStyle} /></a>
|
||||
</div>
|
||||
<div className="span9">
|
||||
<span style={searchRowCostStyle}>
|
||||
<CreditAmount amount={this.props.cost} isEstimate={!this.props.available}/>
|
||||
</span>
|
||||
{this.state.cost !== null
|
||||
? <span style={searchRowCostStyle}>
|
||||
<CreditAmount amount={this.state.cost} isEstimate={!this.state.costIncludesData}/>
|
||||
</span>
|
||||
: null}
|
||||
<div className="meta"><a href={'/?show=' + this.props.name}>lbry://{this.props.name}</a></div>
|
||||
<h3 style={titleStyle}>
|
||||
<a href={'/?show=' + this.props.name}>
|
||||
|
@ -167,7 +191,7 @@ var FeaturedContentItem = React.createClass({
|
|||
return {
|
||||
metadata: null,
|
||||
title: null,
|
||||
amount: 0.0,
|
||||
cost: null,
|
||||
overlayShowing: false,
|
||||
};
|
||||
},
|
||||
|
@ -177,21 +201,18 @@ var FeaturedContentItem = React.createClass({
|
|||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
this.resolveSearch = true;
|
||||
this._isMounted = true;
|
||||
|
||||
lbry.lighthouse.search(this.props.name, function(results) {
|
||||
var result = results[0];
|
||||
var metadata = result.value;
|
||||
if (this.resolveSearch)
|
||||
{
|
||||
this.setState({
|
||||
metadata: metadata,
|
||||
amount: result.cost,
|
||||
available: result.available,
|
||||
title: metadata && metadata.title ? metadata.title : ('lbry://' + this.props.name),
|
||||
});
|
||||
lbry.resolveName(this.props.name, (metadata) => {
|
||||
if (!this._isMounted) {
|
||||
return;
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
this.setState({
|
||||
metadata: metadata,
|
||||
title: metadata && metadata.title ? metadata.title : ('lbry://' + this.props.name),
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
render: function() {
|
||||
|
@ -203,7 +224,7 @@ var FeaturedContentItem = React.createClass({
|
|||
return (<div style={featuredContentItemContainerStyle}>
|
||||
<SearchResultRow name={this.props.name} title={this.state.title} imgUrl={this.state.metadata.thumbnail}
|
||||
description={this.state.metadata.description} mediaType={lbry.getMediaType(this.state.metadata.content_type)}
|
||||
cost={this.state.amount} nsfw={this.state.metadata.nsfw} available={this.state.available} compact />
|
||||
nsfw={this.state.metadata.nsfw} compact />
|
||||
</div>);
|
||||
}
|
||||
});
|
||||
|
@ -257,7 +278,7 @@ var DiscoverPage = React.createClass({
|
|||
query: this.props.query,
|
||||
});
|
||||
|
||||
lbry.lighthouse.search(this.props.query, this.searchCallback);
|
||||
lighthouse.search(this.props.query, this.searchCallback);
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
|
@ -297,3 +318,5 @@ var DiscoverPage = React.createClass({
|
|||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default DiscoverPage;
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
//@TODO: Customize advice based on OS
|
||||
//@TODO: Customize advice based on OS
|
||||
import React from 'react';
|
||||
import lbry from '../lbry.js';
|
||||
import {Link} from '../component/link.js';
|
||||
|
||||
var HelpPage = React.createClass({
|
||||
getInitialState: function() {
|
||||
return {
|
||||
versionInfo: null,
|
||||
lbryId: null,
|
||||
};
|
||||
},
|
||||
componentWillMount: function() {
|
||||
|
@ -12,26 +17,34 @@ var HelpPage = React.createClass({
|
|||
versionInfo: info,
|
||||
});
|
||||
});
|
||||
lbry.getSessionInfo((info) => {
|
||||
this.setState({
|
||||
lbryId: info.lbry_id,
|
||||
});
|
||||
});
|
||||
},
|
||||
componentDidMount: function() {
|
||||
document.title = "Help";
|
||||
},
|
||||
render: function() {
|
||||
var ver = this.state.versionInfo;
|
||||
let ver, osName, platform, newVerLink;
|
||||
if (this.state.versionInfo) {
|
||||
ver = this.state.versionInfo;
|
||||
|
||||
if (ver) {
|
||||
if (ver.os_system == 'Darwin') {
|
||||
var osName = (parseInt(ver.os_release.match(/^\d+/)) < 16 ? 'Mac OS X' : 'Mac OS');
|
||||
osName = (parseInt(ver.os_release.match(/^\d+/)) < 16 ? 'Mac OS X' : 'Mac OS');
|
||||
|
||||
var platform = osName + ' ' + ver.os_release;
|
||||
var newVerLink = 'https://lbry.io/get/lbry.dmg';
|
||||
platform = `${osName} ${ver.os_release}`
|
||||
newVerLink = 'https://lbry.io/get/lbry.dmg';
|
||||
} else if (ver.os_system == 'Linux') {
|
||||
var platform = 'Linux (' + ver.platform + ')';
|
||||
var newVerLink = 'https://lbry.io/get/lbry.deb';
|
||||
platform = `Linux (${ver.platform})`;
|
||||
newVerLink = 'https://lbry.io/get/lbry.deb';
|
||||
} else {
|
||||
var platform = 'Windows (' + ver.platform + ')';
|
||||
var newVerLink = 'https://lbry.io/get/lbry.msi';
|
||||
platform = `Windows (${ver.platform})`;
|
||||
newVerLink = 'https://lbry.io/get/lbry.msi';
|
||||
}
|
||||
} else {
|
||||
ver = null;
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -60,7 +73,7 @@ var HelpPage = React.createClass({
|
|||
<section className="card">
|
||||
<h3>About</h3>
|
||||
{ver.lbrynet_update_available || ver.lbryum_update_available ?
|
||||
<p>A newer version of LBRY is available. <Link href={newVerLink} label={"Download LBRY " + ver.remote_lbrynet + " now!"} /></p>
|
||||
<p>A newer version of LBRY is available. <Link href={newVerLink} label={`Download LBRY ${ver.remote_lbrynet} now!`} /></p>
|
||||
: <p>Your copy of LBRY is up to date.</p>
|
||||
}
|
||||
<table className="table-standard">
|
||||
|
@ -77,6 +90,10 @@ var HelpPage = React.createClass({
|
|||
<th>Platform</th>
|
||||
<td>{platform}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Installation ID</th>
|
||||
<td>{this.state.lbryId}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
|
@ -85,3 +102,5 @@ var HelpPage = React.createClass({
|
|||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default HelpPage;
|
|
@ -1,3 +1,11 @@
|
|||
import React from 'react';
|
||||
import lbry from '../lbry.js';
|
||||
import {Link, WatchLink} from '../component/link.js';
|
||||
import {Menu, MenuItem} from '../component/menu.js';
|
||||
import FormField from '../component/form.js';
|
||||
import Modal from '../component/modal.js';
|
||||
import {BusyMessage, Thumbnail} from '../component/common.js';
|
||||
|
||||
var moreMenuStyle = {
|
||||
position: 'absolute',
|
||||
display: 'block',
|
||||
|
@ -24,7 +32,12 @@ var MyFilesRowMoreMenu = React.createClass({
|
|||
},
|
||||
handleDeleteConfirmed: function() {
|
||||
lbry.deleteFile(this.props.lbryUri);
|
||||
lbry.setState({
|
||||
this.setState({
|
||||
modal: null,
|
||||
});
|
||||
},
|
||||
closeModal: function() {
|
||||
this.setState({
|
||||
modal: null,
|
||||
});
|
||||
},
|
||||
|
@ -43,7 +56,8 @@ var MyFilesRowMoreMenu = React.createClass({
|
|||
<MenuItem onClick={this.handleDeleteClicked} label="Remove and delete file" />
|
||||
</section>
|
||||
</Menu>
|
||||
<Modal isOpen={this.state.modal == 'confirmDelete'} type="confirm" confirmButtonLabel="Delete File" onConfirmed={this.handleDeleteConfirmed}>
|
||||
<Modal isOpen={this.state.modal == 'confirmDelete'} type="confirm" confirmButtonLabel="Delete File"
|
||||
onConfirmed={this.handleDeleteConfirmed} onAborted={this.closeModal}>
|
||||
Are you sure you'd like to delete <cite>{this.props.title}</cite>? This will {this.props.completed ? ' stop the download and ' : ''}
|
||||
permanently remove the file from your system.
|
||||
</Modal>
|
||||
|
@ -153,14 +167,33 @@ var MyFilesRow = React.createClass({
|
|||
|
||||
var MyFilesPage = React.createClass({
|
||||
_fileTimeout: null,
|
||||
_fileInfoCheckRate: 300,
|
||||
_fileInfoCheckNum: 0,
|
||||
_filesOwnership: {},
|
||||
_sortFunctions: {
|
||||
date: function(filesInfo) {
|
||||
return filesInfo.reverse();
|
||||
},
|
||||
title: function(filesInfo) {
|
||||
return filesInfo.sort(function(a, b) {
|
||||
console.log('in title sort. a is', a, '; b is', b)
|
||||
return ((a.metadata ? a.metadata.title.toLowerCase() : a.name) >
|
||||
(b.metadata ? b.metadata.title.toLowerCase() : b.name));
|
||||
});
|
||||
},
|
||||
filename: function(filesInfo) {
|
||||
return filesInfo.sort(function(a, b) {
|
||||
return (a.file_name.toLowerCase() >
|
||||
b.file_name.toLowerCase());
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
filesInfo: null,
|
||||
filesOwnershipLoaded: false,
|
||||
publishedFilesSdHashes: null,
|
||||
filesAvailable: {},
|
||||
sortBy: 'date',
|
||||
};
|
||||
},
|
||||
getDefaultProps: function() {
|
||||
|
@ -172,8 +205,30 @@ var MyFilesPage = React.createClass({
|
|||
document.title = "My Files";
|
||||
},
|
||||
componentWillMount: function() {
|
||||
this.getFilesOwnership();
|
||||
this.updateFilesInfo();
|
||||
if (this.props.show == 'downloaded') {
|
||||
this.getPublishedFilesSdHashes(() => {
|
||||
this.updateFilesInfo();
|
||||
});
|
||||
} else {
|
||||
this.updateFilesInfo();
|
||||
}
|
||||
},
|
||||
getPublishedFilesSdHashes: function(callback) {
|
||||
// Determines which files were published by the user and saves their SD hashes in
|
||||
// this.state.publishedFilesSdHashes. Used on the Downloads page to filter out claims published
|
||||
// by the user.
|
||||
var publishedFilesSdHashes = [];
|
||||
lbry.getMyClaims((claimsInfo) => {
|
||||
for (let claimInfo of claimsInfo) {
|
||||
let metadata = JSON.parse(claimInfo.value);
|
||||
publishedFilesSdHashes.push(metadata.sources.lbry_sd_hash);
|
||||
}
|
||||
|
||||
this.setState({
|
||||
publishedFilesSdHashes: publishedFilesSdHashes,
|
||||
});
|
||||
callback();
|
||||
});
|
||||
},
|
||||
componentWillUnmount: function() {
|
||||
if (this._fileTimeout)
|
||||
|
@ -181,102 +236,95 @@ var MyFilesPage = React.createClass({
|
|||
clearTimeout(this._fileTimeout);
|
||||
}
|
||||
},
|
||||
getFilesOwnership: function() {
|
||||
lbry.getFilesInfo((filesInfo) => {
|
||||
if (!filesInfo) {
|
||||
this.setState({
|
||||
filesOwnershipLoaded: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
var ownershipLoadedCount = 0;
|
||||
for (let i = 0; i < filesInfo.length; i++) {
|
||||
let fileInfo = filesInfo[i];
|
||||
lbry.call('get_my_claim', {name: fileInfo.lbry_uri}, (claim) => {
|
||||
this._filesOwnership[fileInfo.lbry_uri] = !!claim;
|
||||
ownershipLoadedCount++;
|
||||
if (ownershipLoadedCount >= filesInfo.length) {
|
||||
this.setState({
|
||||
filesOwnershipLoaded: true,
|
||||
});
|
||||
}
|
||||
}, (claim) => {
|
||||
this._filesOwnership[fileInfo.lbry_uri] = true;
|
||||
ownershipLoadedCount++;
|
||||
if (ownershipLoadedCount >= filesInfo.length) {
|
||||
this.setState({
|
||||
filesOwnershipLoaded: true,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
setFilesInfo: function(filesInfo) {
|
||||
this.setState({
|
||||
filesInfo: this._sortFunctions[this.state.sortBy](filesInfo),
|
||||
});
|
||||
},
|
||||
handleSortChanged: function(event) {
|
||||
this.setState({
|
||||
sortBy: event.target.value,
|
||||
filesInfo: this._sortFunctions[event.target.value](this.state.filesInfo),
|
||||
});
|
||||
},
|
||||
updateFilesInfo: function() {
|
||||
lbry.getFilesInfo((filesInfo) => {
|
||||
if (!filesInfo) {
|
||||
filesInfo = [];
|
||||
}
|
||||
this._fileInfoCheckNum += 1;
|
||||
|
||||
if (!(this._fileInfoCheckNum % 5)) {
|
||||
// Time to update file availability status
|
||||
if (this.props.show == 'published') {
|
||||
// We're in the Published tab, so populate this.state.filesInfo with data from the user's claims
|
||||
lbry.getMyClaims((claimsInfo) => {
|
||||
let newFilesInfo = [];
|
||||
let claimInfoProcessedCount = 0;
|
||||
for (let claimInfo of claimsInfo) {
|
||||
let metadata = JSON.parse(claimInfo.value);
|
||||
lbry.getFileInfoBySdHash(metadata.sources.lbry_sd_hash, (fileInfo) => {
|
||||
claimInfoProcessedCount++;
|
||||
if (fileInfo !== false) {
|
||||
newFilesInfo.push(fileInfo);
|
||||
}
|
||||
if (claimInfoProcessedCount >= claimsInfo.length) {
|
||||
this.setFilesInfo(newFilesInfo);
|
||||
|
||||
for (let fileInfo of filesInfo) {
|
||||
let name = fileInfo.lbry_uri;
|
||||
|
||||
if (name === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
lbry.lighthouse.search(name, (results) => {
|
||||
var result = results[0];
|
||||
|
||||
var available = result.name == name && result.available;
|
||||
|
||||
if (typeof this.state.filesAvailable[name] === 'undefined' || available != this.state.filesAvailable[name]) {
|
||||
var newFilesAvailable = Object.assign({}, this.state.filesAvailable);
|
||||
newFilesAvailable[name] = available;
|
||||
this.setState({
|
||||
filesAvailable: newFilesAvailable,
|
||||
});
|
||||
this._fileTimeout = setTimeout(() => { this.updateFilesInfo() }, 1000);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this._fileInfoCheckNum += 1;
|
||||
|
||||
this.setState({
|
||||
filesInfo: filesInfo,
|
||||
});
|
||||
} else {
|
||||
// We're in the Downloaded tab, so populate this.state.filesInfo with files the user has in
|
||||
// lbrynet, with published files filtered out.
|
||||
lbry.getFilesInfo((filesInfo) => {
|
||||
this.setFilesInfo(filesInfo.filter(({sd_hash}) => {
|
||||
return this.state.publishedFilesSdHashes.indexOf(sd_hash) == -1;
|
||||
}));
|
||||
|
||||
this._fileTimeout = setTimeout(() => { this.updateFilesInfo() }, 1000);
|
||||
});
|
||||
let newFilesAvailable;
|
||||
if (!(this._fileInfoCheckNum % this._fileInfoCheckRate)) {
|
||||
// Time to update file availability status
|
||||
|
||||
newFilesAvailable = {};
|
||||
let filePeersCheckCount = 0;
|
||||
for (let {sd_hash} of filesInfo) {
|
||||
lbry.getPeersForBlobHash(sd_hash, (peers) => {
|
||||
filePeersCheckCount++;
|
||||
newFilesAvailable[sd_hash] = peers.length >= 0;
|
||||
if (filePeersCheckCount >= filesInfo.length) {
|
||||
this.setState({
|
||||
filesAvailable: newFilesAvailable,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this._fileTimeout = setTimeout(() => { this.updateFilesInfo() }, 1000);
|
||||
})
|
||||
}
|
||||
},
|
||||
render: function() {
|
||||
if (this.state.filesInfo === null || !this.state.filesOwnershipLoaded) {
|
||||
if (this.state.filesInfo === null || (this.props.show == 'downloaded' && this.state.publishedFileSdHashes === null)) {
|
||||
return (
|
||||
<main className="page">
|
||||
<BusyMessage message="Loading" />
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
if (!this.state.filesInfo.length) {
|
||||
var content = <span>You haven't downloaded anything from LBRY yet. Go <Link href="/" label="search for your first download" />!</span>;
|
||||
} else if (!this.state.filesInfo.length) {
|
||||
return (
|
||||
<main className="page">
|
||||
{this.props.show == 'downloaded'
|
||||
? <span>You haven't downloaded anything from LBRY yet. Go <Link href="/" label="search for your first download" />!</span>
|
||||
: <span>You haven't published anything to LBRY yet.</span>}
|
||||
</main>
|
||||
);
|
||||
} else {
|
||||
var content = [],
|
||||
seenUris = {};
|
||||
|
||||
for (let fileInfo of this.state.filesInfo) {
|
||||
let {completed, written_bytes, total_bytes, lbry_uri, file_name, download_path,
|
||||
stopped, metadata} = fileInfo;
|
||||
stopped, metadata, sd_hash} = fileInfo;
|
||||
|
||||
var isMine = this._filesOwnership[lbry_uri];
|
||||
|
||||
if (!metadata || seenUris[lbry_uri] || (this.props.show == 'downloaded' && isMine) ||
|
||||
(this.props.show == 'published' && !isMine)) {
|
||||
if (!metadata || seenUris[lbry_uri]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -301,13 +349,24 @@ var MyFilesPage = React.createClass({
|
|||
content.push(<MyFilesRow key={lbry_uri} lbryUri={lbry_uri} title={title || ('lbry://' + lbry_uri)} completed={completed} stopped={stopped}
|
||||
ratioLoaded={ratioLoaded} imgUrl={thumbnail} path={download_path}
|
||||
showWatchButton={showWatchButton} pending={pending}
|
||||
available={this.state.filesAvailable[lbry_uri]} isMine={isMine} />);
|
||||
available={this.state.filesAvailable[sd_hash]} isMine={this.props.show == 'published'} />);
|
||||
}
|
||||
}
|
||||
return (
|
||||
<main className="page">
|
||||
<span className='sort-section'>
|
||||
Sort by { ' ' }
|
||||
<FormField type="select" onChange={this.handleSortChanged}>
|
||||
<option value="date">Date</option>
|
||||
<option value="title">Title</option>
|
||||
<option value="filename">File name</option>
|
||||
</FormField>
|
||||
</span>
|
||||
{content}
|
||||
</main>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
export default MyFilesPage;
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
import React from 'react';
|
||||
import lbry from '../lbry.js';
|
||||
import FormField from '../component/form.js';
|
||||
import {Link} from '../component/link.js';
|
||||
import Modal from '../component/modal.js';
|
||||
|
||||
|
||||
var publishNumberStyle = {
|
||||
width: '50px',
|
||||
}, publishFieldLabelStyle = {
|
||||
|
@ -38,7 +45,14 @@ var PublishPage = React.createClass({
|
|||
}
|
||||
}
|
||||
|
||||
if (missingFieldFound) {
|
||||
let fileProcessing = false;
|
||||
if (this.state.fileInfo && !this.state.tempFileReady) {
|
||||
this.refs.file.showAdvice('Your file is still processing.');
|
||||
this.refs.file.focus();
|
||||
fileProcessing = true;
|
||||
}
|
||||
|
||||
if (missingFieldFound || fileProcessing) {
|
||||
this.setState({
|
||||
submitting: false,
|
||||
});
|
||||
|
@ -104,6 +118,7 @@ var PublishPage = React.createClass({
|
|||
this._tempFilePath = null;
|
||||
|
||||
return {
|
||||
rawName: '',
|
||||
name: '',
|
||||
bid: '',
|
||||
feeAmount: '',
|
||||
|
@ -145,6 +160,7 @@ var PublishPage = React.createClass({
|
|||
|
||||
if (!rawName) {
|
||||
this.setState({
|
||||
rawName: '',
|
||||
name: '',
|
||||
nameResolved: false,
|
||||
});
|
||||
|
@ -152,10 +168,19 @@ var PublishPage = React.createClass({
|
|||
return;
|
||||
}
|
||||
|
||||
var name = lbry.formatName(rawName);
|
||||
if (!lbry.nameIsValid(rawName, false)) {
|
||||
this.refs.name.showAdvice('LBRY names must contain only letters, numbers and dashes.');
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
rawName: rawName,
|
||||
});
|
||||
|
||||
var name = rawName.toLowerCase();
|
||||
|
||||
lbry.resolveName(name, (info) => {
|
||||
if (name != lbry.formatName(this.refs.name.getValue())) {
|
||||
if (name != this.refs.name.getValue().toLowerCase()) {
|
||||
// A new name has been typed already, so bail
|
||||
return;
|
||||
}
|
||||
|
@ -164,6 +189,7 @@ var PublishPage = React.createClass({
|
|||
this.setState({
|
||||
name: name,
|
||||
nameResolved: false,
|
||||
myClaimExists: false,
|
||||
});
|
||||
} else {
|
||||
lbry.getMyClaim(name, (myClaimInfo) => {
|
||||
|
@ -258,7 +284,7 @@ var PublishPage = React.createClass({
|
|||
|
||||
var formData = new FormData(fileInput.form);
|
||||
formData.append('file', fileInput.files[0]);
|
||||
xhr.open('POST', '/upload', true);
|
||||
xhr.open('POST', lbry.webUiUri + '/upload', true);
|
||||
xhr.send(formData);
|
||||
}
|
||||
},
|
||||
|
@ -325,6 +351,7 @@ var PublishPage = React.createClass({
|
|||
}
|
||||
}
|
||||
},
|
||||
// Also getting a type warning here too
|
||||
render: function() {
|
||||
return (
|
||||
<main ref="page">
|
||||
|
@ -332,7 +359,7 @@ var PublishPage = React.createClass({
|
|||
<section className="card">
|
||||
<h4>LBRY Name</h4>
|
||||
<div className="form-row">
|
||||
lbry://<FormField type="text" ref="name" onChange={this.handleNameChange} />
|
||||
lbry://<FormField type="text" ref="name" value={this.state.rawName} onChange={this.handleNameChange} />
|
||||
{
|
||||
(!this.state.name ? '' :
|
||||
(! this.state.nameResolved ? <em> The name <strong>{this.state.name}</strong> is available.</em>
|
||||
|
@ -477,3 +504,5 @@ var PublishPage = React.createClass({
|
|||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default PublishPage;
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
import React from 'react';
|
||||
import lbry from '../lbry.js';
|
||||
import {Link} from '../component/link.js';
|
||||
import Modal from '../component/modal.js';
|
||||
|
||||
var referralCodeContentStyle = {
|
||||
display: 'inline-block',
|
||||
textAlign: 'left',
|
||||
|
@ -105,7 +110,7 @@ var ReferralPage = React.createClass({
|
|||
</form>
|
||||
<Modal isOpen={this.state.modal == 'referralInfo'} onConfirmed={this.handleFinished}>
|
||||
{this.state.referralCredits > 0
|
||||
? `You have earned {response.referralCredits} credits from referrals. We will credit your account shortly. Thanks!`
|
||||
? `You have earned ${response.referralCredits} credits from referrals. We will credit your account shortly. Thanks!`
|
||||
: 'You have not earned any new referral credits since the last time you checked. Please check back in a week or two.'}
|
||||
</Modal>
|
||||
<Modal isOpen={this.state.modal == 'lookupFailed'} onConfirmed={this.closeModal}>
|
||||
|
@ -118,3 +123,5 @@ var ReferralPage = React.createClass({
|
|||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default ReferralPage;
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
import React from 'react';
|
||||
import lbry from '../lbry.js';
|
||||
|
||||
var ReportPage = React.createClass({
|
||||
submitMessage: function() {
|
||||
if (this._messageArea.value) {
|
||||
|
@ -50,4 +53,6 @@ var ReportPage = React.createClass({
|
|||
</main>
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
export default ReportPage;
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
import React from 'react';
|
||||
import lbry from '../lbry.js';
|
||||
|
||||
var settingsRadioOptionStyles = {
|
||||
display: 'block',
|
||||
marginLeft: '13px'
|
||||
|
@ -129,3 +132,6 @@ var SettingsPage = React.createClass({
|
|||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
export default SettingsPage;
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
import React from 'react';
|
||||
import lbry from '../lbry.js';
|
||||
import lighthouse from '../lighthouse.js';
|
||||
import {CreditAmount, Thumbnail} from '../component/common.js';
|
||||
import {Link, DownloadLink, WatchLink} from '../component/link.js';
|
||||
|
||||
var formatItemImgStyle = {
|
||||
maxWidth: '100%',
|
||||
maxHeight: '100%',
|
||||
|
@ -10,9 +16,9 @@ var formatItemImgStyle = {
|
|||
var FormatItem = React.createClass({
|
||||
propTypes: {
|
||||
claimInfo: React.PropTypes.object,
|
||||
amount: React.PropTypes.number,
|
||||
cost: React.PropTypes.number,
|
||||
name: React.PropTypes.string,
|
||||
available: React.PropTypes.bool,
|
||||
costIncludesData: React.PropTypes.bool,
|
||||
},
|
||||
render: function() {
|
||||
|
||||
|
@ -25,8 +31,8 @@ var FormatItem = React.createClass({
|
|||
var license = claimInfo.license;
|
||||
var fileContentType = (claimInfo.content_type || claimInfo['content-type']);
|
||||
var mediaType = lbry.getMediaType(fileContentType);
|
||||
var available = this.props.available;
|
||||
var amount = this.props.amount || 0.0;
|
||||
var costIncludesData = this.props.costIncludesData;
|
||||
var cost = this.props.cost || 0.0;
|
||||
|
||||
return (
|
||||
<div className="row-fluid">
|
||||
|
@ -42,7 +48,7 @@ var FormatItem = React.createClass({
|
|||
<td>Content-Type</td><td>{fileContentType}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Cost</td><td><CreditAmount amount={amount} isEstimate={!available}/></td>
|
||||
<td>Cost</td><td><CreditAmount amount={cost} isEstimate={!costIncludesData}/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Author</td><td>{author}</td>
|
||||
|
@ -72,9 +78,9 @@ var FormatItem = React.createClass({
|
|||
var FormatsSection = React.createClass({
|
||||
propTypes: {
|
||||
claimInfo: React.PropTypes.object,
|
||||
amount: React.PropTypes.number,
|
||||
cost: React.PropTypes.number,
|
||||
name: React.PropTypes.string,
|
||||
available: React.PropTypes.bool,
|
||||
costIncludesData: React.PropTypes.bool,
|
||||
},
|
||||
render: function() {
|
||||
var name = this.props.name;
|
||||
|
@ -96,7 +102,7 @@ var FormatsSection = React.createClass({
|
|||
{/* In future, anticipate multiple formats, just a guess at what it could look like
|
||||
// var formats = this.props.claimInfo.formats
|
||||
// return (<tbody>{formats.map(function(format,i){ */}
|
||||
<FormatItem claimInfo={format} amount={this.props.amount} name={this.props.name} available={this.props.available} />
|
||||
<FormatItem claimInfo={format} cost={this.props.cost} name={this.props.name} costIncludesData={this.props.costIncludesData} />
|
||||
{/* })}</tbody>); */}
|
||||
</div>);
|
||||
}
|
||||
|
@ -108,50 +114,44 @@ var DetailPage = React.createClass({
|
|||
},
|
||||
getInitialState: function() {
|
||||
return {
|
||||
claimInfo: null,
|
||||
amount: null,
|
||||
searching: true,
|
||||
matchFound: null,
|
||||
metadata: null,
|
||||
cost: null,
|
||||
costIncludesData: null,
|
||||
nameLookupComplete: null,
|
||||
};
|
||||
},
|
||||
componentWillMount: function() {
|
||||
document.title = 'lbry://' + this.props.name;
|
||||
|
||||
lbry.lighthouse.search(this.props.name, (results) => {
|
||||
var result = results[0];
|
||||
lbry.resolveName(this.props.name, (metadata) => {
|
||||
this.setState({
|
||||
metadata: metadata,
|
||||
nameLookupComplete: true,
|
||||
});
|
||||
});
|
||||
|
||||
if (result.name != this.props.name) {
|
||||
this.setState({
|
||||
searching: false,
|
||||
matchFound: false,
|
||||
});
|
||||
} else {
|
||||
this.setState({
|
||||
amount: result.cost,
|
||||
available: result.available,
|
||||
claimInfo: result.value,
|
||||
searching: false,
|
||||
matchFound: true,
|
||||
});
|
||||
}
|
||||
lbry.getCostInfoForName(this.props.name, ({cost, includesData}) => {
|
||||
this.setState({
|
||||
cost: cost,
|
||||
costIncludesData: includesData,
|
||||
});
|
||||
});
|
||||
},
|
||||
render: function() {
|
||||
if (this.state.claimInfo == null && this.state.searching) {
|
||||
// Still waiting for metadata
|
||||
if (this.state.metadata == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var name = this.props.name;
|
||||
var available = this.state.available;
|
||||
var claimInfo = this.state.claimInfo;
|
||||
var amount = this.state.amount;
|
||||
const name = this.props.name;
|
||||
const costIncludesData = this.state.costIncludesData;
|
||||
const metadata = this.state.metadata;
|
||||
const cost = this.state.cost;
|
||||
|
||||
return (
|
||||
<main>
|
||||
<section className="card">
|
||||
{this.state.matchFound ? (
|
||||
<FormatsSection name={name} claimInfo={claimInfo} amount={amount} available={available} />
|
||||
{this.state.nameLookupComplete ? (
|
||||
<FormatsSection name={name} claimInfo={metadata} cost={cost} costIncludesData={costIncludesData} />
|
||||
) : (
|
||||
<div>
|
||||
<h2>No content</h2>
|
||||
|
@ -161,4 +161,6 @@ var DetailPage = React.createClass({
|
|||
</section>
|
||||
</main>);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
export default DetailPage;
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
import React from 'react';
|
||||
import lbry from '../lbry.js';
|
||||
|
||||
var StartPage = React.createClass({
|
||||
componentWillMount: function() {
|
||||
lbry.stop();
|
||||
|
@ -13,4 +16,6 @@ var StartPage = React.createClass({
|
|||
</main>
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
export default StartPage;
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
import React from 'react';
|
||||
import lbry from '../lbry.js';
|
||||
import {Link} from '../component/link.js';
|
||||
import Modal from '../component/modal.js';
|
||||
import {Address, BusyMessage, CreditAmount} from '../component/common.js';
|
||||
|
||||
|
||||
var addressRefreshButtonStyle = {
|
||||
fontSize: '11pt',
|
||||
};
|
||||
|
@ -8,7 +15,7 @@ var AddressSection = React.createClass({
|
|||
}
|
||||
|
||||
lbry.getNewAddress((address) => {
|
||||
localStorage.setItem('wallet_address', address);
|
||||
window.localStorage.setItem('wallet_address', address);
|
||||
this.setState({
|
||||
address: address,
|
||||
});
|
||||
|
@ -21,7 +28,7 @@ var AddressSection = React.createClass({
|
|||
}
|
||||
},
|
||||
componentWillMount: function() {
|
||||
var address = localStorage.getItem('wallet_address');
|
||||
var address = window.localStorage.getItem('wallet_address');
|
||||
if (address === null) {
|
||||
this._refreshAddress();
|
||||
} else {
|
||||
|
@ -272,3 +279,5 @@ var WalletPage = React.createClass({
|
|||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default WalletPage;
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
import React from 'react';
|
||||
import lbry from '../lbry.js';
|
||||
import MediaElementPlayer from 'mediaelement';
|
||||
|
||||
var WatchPage = React.createClass({
|
||||
propTypes: {
|
||||
name: React.PropTypes.string,
|
||||
|
@ -43,9 +47,11 @@ var WatchPage = React.createClass({
|
|||
? <LoadScreen message={'Loading video...'} details={this.state.loadStatusMessage} />
|
||||
: <main className="full-screen">
|
||||
<video ref="player" width="100%" height="100%">
|
||||
<source type={(this.state.mimeType == 'audio/m4a' || this.state.mimeType == 'audio/mp4a-latm') ? 'video/mp4' : this.state.mimeType} src={'/view?name=' + this.props.name} />
|
||||
<source type={(this.state.mimeType == 'audio/m4a' || this.state.mimeType == 'audio/mp4a-latm') ? 'video/mp4' : this.state.mimeType} src={lbry.webUiUri + '/view?name=' + this.props.name} />
|
||||
</video>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default WatchPage;
|
||||
|
|
23
package.json
23
package.json
|
@ -22,6 +22,27 @@
|
|||
"babel-cli": "^6.11.4",
|
||||
"babel-preset-es2015": "^6.13.2",
|
||||
"babel-preset-react": "^6.11.1",
|
||||
"node-sass": "^3.8.0"
|
||||
"clamp": "^1.0.1",
|
||||
"mediaelement": "^2.23.4",
|
||||
"node-sass": "^3.8.0",
|
||||
"react": "^15.4.0",
|
||||
"react-dom": "^15.4.0",
|
||||
"react-modal": "^1.5.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel": "^6.5.2",
|
||||
"babel-core": "^6.18.2",
|
||||
"babel-loader": "^6.2.8",
|
||||
"babel-plugin-react-require": "^3.0.0",
|
||||
"babel-preset-es2015": "^6.18.0",
|
||||
"babel-preset-react": "^6.16.0",
|
||||
"eslint": "^3.10.2",
|
||||
"eslint-config-airbnb": "^13.0.0",
|
||||
"eslint-loader": "^1.6.1",
|
||||
"eslint-plugin-import": "^2.2.0",
|
||||
"eslint-plugin-jsx-a11y": "^2.2.3",
|
||||
"eslint-plugin-react": "^6.7.1",
|
||||
"node-sass": "^3.13.0",
|
||||
"webpack": "^1.13.3"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -234,6 +234,65 @@ input[type="text"], input[type="search"]
|
|||
}
|
||||
}
|
||||
|
||||
.form-field-container {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.form-field-advice-container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.form-field-advice {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
white-space: nowrap;
|
||||
|
||||
transition: opacity 400ms ease-in;
|
||||
}
|
||||
|
||||
.form-field-advice--fading {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.form-field-advice__arrow {
|
||||
text-align: left;
|
||||
padding-left: 18px;
|
||||
|
||||
font-size: 22px;
|
||||
line-height: 0.3;
|
||||
color: darken($color-primary, 5%);
|
||||
}
|
||||
|
||||
|
||||
.form-field-advice__content-container {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.form-field-advice__content {
|
||||
display: inline-block;
|
||||
|
||||
padding: 5px;
|
||||
border-radius: 2px;
|
||||
|
||||
background-color: darken($color-primary, 5%);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
|
||||
.sort-section {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
|
||||
|
||||
text-align: right;
|
||||
font-size: 0.85em;
|
||||
color: $color-help;
|
||||
}
|
||||
|
||||
.modal-overlay {
|
||||
position: fixed;
|
||||
|
@ -302,4 +361,8 @@ input[type="text"], input[type="search"]
|
|||
.error-modal__warning-symbol {
|
||||
margin-top: 6px;
|
||||
margin-right: 7px;
|
||||
}
|
||||
|
||||
.download-started-modal__file-path {
|
||||
word-break: break-all;
|
||||
}
|
37
webpack.config.js
Normal file
37
webpack.config.js
Normal file
|
@ -0,0 +1,37 @@
|
|||
const path = require('path');
|
||||
|
||||
const PATHS = {
|
||||
app: path.join(__dirname, 'app'),
|
||||
dist: path.join(__dirname, 'dist')
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
entry: "./js/main.js",
|
||||
output: {
|
||||
path: path.join(PATHS.dist, 'js'),
|
||||
publicPath: '/js/',
|
||||
filename: "bundle.js"
|
||||
},
|
||||
devtool: 'source-map',
|
||||
module: {
|
||||
preLoaders: [
|
||||
{
|
||||
test: /\.jsx?$/,
|
||||
loaders: ['eslint'],
|
||||
// define an include so we check just the files we need
|
||||
include: PATHS.app
|
||||
}
|
||||
],
|
||||
loaders: [
|
||||
{ test: /\.css$/, loader: "style!css" },
|
||||
{
|
||||
test: /\.jsx?$/,
|
||||
// Enable caching for improved performance during development
|
||||
// It uses default OS directory by default. If you need
|
||||
// something more custom, pass a path to it.
|
||||
// I.e., babel?cacheDirectory=<path>
|
||||
loader: 'babel?cacheDirectory'
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
Loading…
Add table
Reference in a new issue