diff --git a/CHANGELOG.md b/CHANGELOG.md index dbd053afb..db1f95937 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,22 @@ +Changes in [0.16.4](https://github.com/vector-im/riot-web/releases/tag/v0.16.4) (2018-09-10) +============================================================================================ +[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.16.4-rc.1...v0.16.4) + + * No changes since rc.1 + +Changes in [0.16.4-rc.1](https://github.com/vector-im/riot-web/releases/tag/v0.16.4-rc.1) (2018-09-07) +====================================================================================================== +[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.16.3...v0.16.4-rc.1) + + * Update from Weblate. + [\#7296](https://github.com/vector-im/riot-web/pull/7296) + * Fix config not loading & mobileguide script being loaded in riot + [\#7288](https://github.com/vector-im/riot-web/pull/7288) + * Instructions for installing mobile apps + [\#7272](https://github.com/vector-im/riot-web/pull/7272) + * Tidy up index.js + [\#7265](https://github.com/vector-im/riot-web/pull/7265) + Changes in [0.16.3](https://github.com/vector-im/riot-web/releases/tag/v0.16.3) (2018-09-03) ============================================================================================ [Full Changelog](https://github.com/vector-im/riot-web/compare/v0.16.3-rc.2...v0.16.3) diff --git a/electron_app/package.json b/electron_app/package.json index 9e5cada14..7a508cd27 100644 --- a/electron_app/package.json +++ b/electron_app/package.json @@ -2,7 +2,7 @@ "name": "riot-web", "productName": "Riot", "main": "src/electron-main.js", - "version": "0.16.3", + "version": "0.16.4", "description": "A feature-rich client for Matrix.org", "author": "Vector Creations Ltd.", "dependencies": { diff --git a/package-lock.json b/package-lock.json index 551700517..2f775fd70 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "riot-web", - "version": "0.15.6", + "version": "0.16.4-rc.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 57688b59d..a546def42 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "riot-web", "productName": "Riot", "main": "electron_app/src/electron-main.js", - "version": "0.16.3", + "version": "0.16.4", "description": "A feature-rich client for Matrix.org", "author": "New Vector Ltd.", "repository": { @@ -64,8 +64,8 @@ "gemini-scrollbar": "matrix-org/gemini-scrollbar#b302279", "gfm.css": "^1.1.1", "highlight.js": "^9.0.0", - "matrix-js-sdk": "0.10.9", - "matrix-react-sdk": "0.13.3", + "matrix-js-sdk": "0.11.0", + "matrix-react-sdk": "0.13.4", "modernizr": "^3.1.0", "prop-types": "^15.5.10", "react": "^15.6.0", diff --git a/src/i18n/strings/en_US.json b/src/i18n/strings/en_US.json index 7803498a7..e5b060cf7 100644 --- a/src/i18n/strings/en_US.json +++ b/src/i18n/strings/en_US.json @@ -33,5 +33,7 @@ "Lots of rooms already exist in Matrix, linked to existing networks (Slack, IRC, Gitter etc) or independent. Check out the directory!": "Lots of rooms already exist in Matrix, linked to existing networks (Slack, IRC, Gitter etc) or independent. Check out the directory!", "Riot/Android & matrix-android-sdk chat": "Riot/Android & matrix-android-sdk chat", "Riot/Web & Desktop chat": "Riot/Web & Desktop chat", - "Riot/iOS & matrix-ios-sdk chat": "Riot/iOS & matrix-ios-sdk chat" + "Riot/iOS & matrix-ios-sdk chat": "Riot/iOS & matrix-ios-sdk chat", + "You can use the custom server options to sign into other Matrix servers by specifying a different Home server URL.
This allows you to use Riot with an existing Matrix account on a different home server.

You can also set a custom identity server but you won't be able to invite users by email address, or be invited by email address yourself.": "You can use the custom server options to sign into other Matrix servers by specifying a different Home server URL.
This allows you to use Riot with an existing Matrix account on a different home server.

You can also set a custom identity server but you won't be able to invite users by email address, or be invited by email address yourself.", + "Co-ordination for Riot translators": "Co-ordination for Riot translators" } diff --git a/src/i18n/strings/id.json b/src/i18n/strings/id.json index 40636f3af..7e202c7cb 100644 --- a/src/i18n/strings/id.json +++ b/src/i18n/strings/id.json @@ -34,5 +34,6 @@ "Dev chat for the Riot/Web dev team": "Obrolan Developer untuk tim developer Riot/Web", "Dev chat for the Dendrite dev team": "Obrolan Developer untuk tim developer Dendrite", "Lots of rooms already exist in Matrix, linked to existing networks (Slack, IRC, Gitter etc) or independent. Check out the directory!": "Banyak ruang sudah tersedia di Matrix, terhubung ke jaringan yang sudah ada (Slack, IRC, Gitter dls) atau independen. Cek direktori!", - "You can use the custom server options to sign into other Matrix servers by specifying a different Home server URL.
This allows you to use Riot with an existing Matrix account on a different home server.

You can also set a custom identity server but you won't be able to invite users by email address, or be invited by email address yourself.": "Anda dapat menggunakan opsi lain untuk mendaftar pada server Matrix yang berbeda dengan memasukkan URL server yang sesuai.
Hal ini memungkinkan anda untuk menggunakan Riot dengan akun matrix yang telah tersedia pada Home server yang berbeda.

Anda juga dapat melakukan pengubahan identitas server akan tetapi akan berakibat tidak dapat mengundang pengguna melalui email, atau diundang melalui email." + "You can use the custom server options to sign into other Matrix servers by specifying a different Home server URL.
This allows you to use Riot with an existing Matrix account on a different home server.

You can also set a custom identity server but you won't be able to invite users by email address, or be invited by email address yourself.": "Anda dapat menggunakan opsi lain untuk mendaftar pada server Matrix yang berbeda dengan memasukkan URL server yang sesuai.
Hal ini memungkinkan anda untuk menggunakan Riot dengan akun matrix yang telah tersedia pada Home server yang berbeda.

Anda juga dapat melakukan pengubahan identitas server akan tetapi akan berakibat tidak dapat mengundang pengguna melalui email, atau diundang melalui email.", + "Co-ordination for Riot translators": "Koordinasi dengan penerjemah Riot" } diff --git a/src/vector/getconfig.js b/src/vector/getconfig.js new file mode 100644 index 000000000..f3e7bea16 --- /dev/null +++ b/src/vector/getconfig.js @@ -0,0 +1,67 @@ +/* +Copyright 2018 New Vector Ltd + +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 Promise from 'bluebird'; +import request from 'browser-request'; + +export async function getVectorConfig(relativeLocation) { + if (relativeLocation === undefined) relativeLocation = ''; + if (relativeLocation !== '' && !relativeLocation.endsWith('/')) relativeLocation += '/'; + try { + const configJson = await getConfig(`${relativeLocation}config.${document.domain}.json`); + // 404s succeed with an empty json config, so check that there are keys + if (Object.keys(configJson).length === 0) { + throw new Error(); // throw to enter the catch + } + return configJson; + } catch (e) { + return await getConfig(relativeLocation + "config.json"); + } +} + +function getConfig(configJsonFilename) { + let deferred = Promise.defer(); + + request( + { method: "GET", url: configJsonFilename }, + (err, response, body) => { + if (err || response.status < 200 || response.status >= 300) { + // Lack of a config isn't an error, we should + // just use the defaults. + // Also treat a blank config as no config, assuming + // the status code is 0, because we don't get 404s + // from file: URIs so this is the only way we can + // not fail if the file doesn't exist when loading + // from a file:// URI. + if (response) { + if (response.status == 404 || (response.status == 0 && body == '')) { + deferred.resolve({}); + } + } + deferred.reject({err: err, response: response}); + return; + } + + // We parse the JSON ourselves rather than use the JSON + // parameter, since this throws a parse error on empty + // which breaks if there's no config.json and we're + // loading from the filesystem (see above). + deferred.resolve(JSON.parse(body)); + } + ); + + return deferred.promise; +} diff --git a/src/vector/index.js b/src/vector/index.js index 14e181d91..ff6b12856 100644 --- a/src/vector/index.js +++ b/src/vector/index.js @@ -1,6 +1,7 @@ /* Copyright 2015, 2016 OpenMarket Ltd Copyright 2017 Vector Creations Ltd +Copyright 2018 New Vector Ltd Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -15,8 +16,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -'use strict'; - // Require common CSS here; this will make webpack process it into bundle.css. // Our own CSS (which is themed) is imported via separate webpack entry points // in webpack.config.js @@ -25,36 +24,22 @@ require('gfm.css/gfm.css'); require('highlight.js/styles/github.css'); require('draft-js/dist/Draft.css'); -const rageshake = require("matrix-react-sdk/lib/rageshake/rageshake"); -rageshake.init().then(() => { - console.log("Initialised rageshake: See https://bugs.chromium.org/p/chromium/issues/detail?id=583193 to fix line numbers on Chrome."); - rageshake.cleanup(); -}, (err) => { - console.error("Failed to initialise rageshake: " + err); -}); - -window.addEventListener('beforeunload', (e) => { - console.log('riot-web closing'); - // try to flush the logs to indexeddb - rageshake.flush(); -}); - - - // add React and ReactPerf to the global namespace, to make them easier to - // access via the console -global.React = require("react"); +import React from 'react'; +// add React and ReactPerf to the global namespace, to make them easier to +// access via the console +global.React = React; if (process.env.NODE_ENV !== 'production') { - global.Perf = require("react-addons-perf"); + global.Perf = require('react-addons-perf'); } -var RunModernizrTests = require("./modernizr"); // this side-effects a global -var ReactDOM = require("react-dom"); -var sdk = require("matrix-react-sdk"); -const PlatformPeg = require("matrix-react-sdk/lib/PlatformPeg"); +import RunModernizrTests from './modernizr'; // this side-effects a global +import ReactDOM from 'react-dom'; +import sdk from 'matrix-react-sdk'; +import PlatformPeg from 'matrix-react-sdk/lib/PlatformPeg'; sdk.loadSkin(require('../component-index')); -var VectorConferenceHandler = require('matrix-react-sdk/lib/VectorConferenceHandler'); +import VectorConferenceHandler from 'matrix-react-sdk/lib/VectorConferenceHandler'; import Promise from 'bluebird'; -var request = require('browser-request'); +import request from 'browser-request'; import * as languageHandler from 'matrix-react-sdk/lib/languageHandler'; // Also import _t directly so we can call it just `_t` as this is what gen-i18n.js expects import { _t } from 'matrix-react-sdk/lib/languageHandler'; @@ -69,12 +54,29 @@ import SettingsStore, {SettingLevel} from "matrix-react-sdk/lib/settings/Setting import Tinter from 'matrix-react-sdk/lib/Tinter'; import SdkConfig from "matrix-react-sdk/lib/SdkConfig"; -var lastLocationHashSet = null; +import rageshake from "matrix-react-sdk/lib/rageshake/rageshake"; -var CallHandler = require("matrix-react-sdk/lib/CallHandler"); -CallHandler.setConferenceHandler(VectorConferenceHandler); +import CallHandler from 'matrix-react-sdk/lib/CallHandler'; -MatrixClientPeg.setIndexedDbWorkerScript(window.vector_indexeddb_worker_script); +import {getVectorConfig} from './getconfig'; + +let lastLocationHashSet = null; + +function initRageshake() { + rageshake.init().then(() => { + console.log("Initialised rageshake: See https://bugs.chromium.org/p/chromium/issues/detail?id=583193 to fix line numbers on Chrome."); + + window.addEventListener('beforeunload', (e) => { + console.log('riot-web closing'); + // try to flush the logs to indexeddb + rageshake.flush(); + }); + + rageshake.cleanup(); + }, (err) => { + console.error("Failed to initialise rageshake: " + err); + }); +} function checkBrowserFeatures(featureList) { if (!window.Modernizr) { @@ -100,11 +102,6 @@ function checkBrowserFeatures(featureList) { return featureComplete; } -var validBrowser = checkBrowserFeatures([ - "displaytable", "flexbox", "es5object", "es5function", "localstorage", - "objectfit", "indexeddb", "webworkers", -]); - // Parse the given window.location and return parameters that can be used when calling // MatrixChat.showScreen(screen, params) function getScreenFromLocation(location) { @@ -135,7 +132,7 @@ function onHashChange(ev) { // This will be called whenever the SDK changes screens, // so a web page can update the URL bar appropriately. -var onNewScreen = function(screen) { +function onNewScreen(screen) { console.log("newscreen "+screen); var hash = '#/' + screen; lastLocationHashSet = hash; @@ -151,7 +148,7 @@ var onNewScreen = function(screen) { // If we're in electron, we should never pass through a file:// URL otherwise // the identity server will try to 302 the browser to it, which breaks horribly. // so in that instance, hardcode to use riot.im/app for now instead. -var makeRegistrationUrl = function(params) { +function makeRegistrationUrl(params) { let url; if (window.location.protocol === "file:") { url = 'https://riot.im/app/#/register'; @@ -177,8 +174,6 @@ var makeRegistrationUrl = function(params) { return url; } -window.addEventListener('hashchange', onHashChange); - function getConfig(configJsonFilename) { let deferred = Promise.defer(); @@ -226,6 +221,12 @@ function onTokenLoginCompleted() { } async function loadApp() { + initRageshake(); + MatrixClientPeg.setIndexedDbWorkerScript(window.vector_indexeddb_worker_script); + CallHandler.setConferenceHandler(VectorConferenceHandler); + + window.addEventListener('hashchange', onHashChange); + await loadLanguage(); const fragparts = parseQsFromFragment(window.location); @@ -239,15 +240,7 @@ async function loadApp() { let configJson; let configError; try { - try { - configJson = await getConfig(`config.${document.domain}.json`); - // 404s succeed with an empty json config, so check that there are keys - if (Object.keys(configJson).length === 0) { - throw new Error(); // throw to enter the catch - } - } catch (e) { - configJson = await getConfig("config.json"); - } + configJson = await getVectorConfig(); } catch (e) { configError = e; } @@ -261,31 +254,13 @@ async function loadApp() { const preventRedirect = Boolean(fragparts.params.client_secret); if (!preventRedirect) { - if (/iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream) { - // FIXME: ugly status hardcoding - if (SettingsStore.getValue("theme") === 'status') { - window.location = "https://status.im/join-riot.html"; + const isIos = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream; + const isAndroid = /Android/.test(navigator.userAgent); + if (isIos || isAndroid) { + if (!document.cookie.split(';').some((c) => c.startsWith('mobile_redirect_to_guide'))) { + window.location = "mobile_guide/"; return; } - else { - if (confirm(_t("Riot is not supported on mobile web. Install the app?"))) { - window.location = "https://itunes.apple.com/us/app/vector.im/id1083446067"; - return; - } - } - } - else if (/Android/.test(navigator.userAgent)) { - // FIXME: ugly status hardcoding - if (SettingsStore.getValue("theme") === 'status') { - window.location = "https://status.im/join-riot.html"; - return; - } - else { - if (confirm(_t("Riot is not supported on mobile web. Install the app?"))) { - window.location = "https://play.google.com/store/apps/details?id=im.vector.alpha"; - return; - } - } } } @@ -325,17 +300,19 @@ async function loadApp() { } } - if (window.localStorage && window.localStorage.getItem('mx_accepts_unsupported_browser')) { - console.log('User has previously accepted risks in using an unsupported browser'); - validBrowser = true; - } + const validBrowser = checkBrowserFeatures([ + "displaytable", "flexbox", "es5object", "es5function", "localstorage", + "objectfit", "indexeddb", "webworkers", + ]); + + const acceptInvalidBrowser = window.localStorage && window.localStorage.getItem('mx_accepts_unsupported_browser'); console.log("Vector starting at "+window.location); if (configError) { window.matrixChat = ReactDOM.render(
Unable to load config file: please refresh the page to try again.
, document.getElementById('matrixchat')); - } else if (validBrowser) { + } else if (validBrowser || acceptInvalidBrowser) { const platform = PlatformPeg.get(); platform.startUpdater(); @@ -362,7 +339,6 @@ async function loadApp() { window.matrixChat = ReactDOM.render( , diff --git a/src/vector/mobile_guide/index.html b/src/vector/mobile_guide/index.html new file mode 100644 index 000000000..433d5b7e5 --- /dev/null +++ b/src/vector/mobile_guide/index.html @@ -0,0 +1,386 @@ + + + + + + + + + + +
+ + + +
+
+
+

Step 2: Register or Log in

+

Create a new account if you don't have one, or log in to your existing account.

+
+
+
+
+ +
+
+ + diff --git a/src/vector/mobile_guide/index.js b/src/vector/mobile_guide/index.js new file mode 100644 index 000000000..b2d007ac5 --- /dev/null +++ b/src/vector/mobile_guide/index.js @@ -0,0 +1,23 @@ +import {getVectorConfig} from '../getconfig'; + +function onBackToRiotClick() { + document.cookie = 'mobile_redirect_to_guide=false;path=/'; + window.location.href = '../'; +} + +async function initPage() { + document.getElementById('back_to_riot_button').onclick = onBackToRiotClick; + + const config = await getVectorConfig('..'); + let hsUrl; + if (config && config['default_hs_url']) { + hsUrl = config['default_hs_url']; + } + if (hsUrl && hsUrl !== 'https://matrix.org/') { + document.getElementById('step2_container').style.display = 'block'; + document.getElementById('hs_url').innerHTML = hsUrl; + document.getElementById('step_login_header').innerHTML= 'Step 3: Register or Log in'; + } +} + +initPage(); diff --git a/webpack.config.js b/webpack.config.js index 2a116f577..122facb24 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -13,6 +13,8 @@ module.exports = { "bundle": ["babel-polyfill", "./src/vector/index.js"], "indexeddb-worker": "./src/vector/indexeddb-worker.js", + "mobileguide": "./src/vector/mobile_guide/index.js", + // We ship olm.js as a separate lump of javascript. This makes it get // loaded via a separate