2019-08-12 14:15:55 +02:00
const ELECTRON _APP _VERSION = "4.0.0" ;
2019-05-20 14:01:13 +02:00
const ELECTRON _APP _URL _LINUX = "https://github.com/zulip/zulip-desktop/releases/download/v" + ELECTRON _APP _VERSION + "/Zulip-" + ELECTRON _APP _VERSION + "-x86_64.AppImage" ;
const ELECTRON _APP _URL _MAC = "https://github.com/zulip/zulip-desktop/releases/download/v" + ELECTRON _APP _VERSION + "/Zulip-" + ELECTRON _APP _VERSION + ".dmg" ;
const ELECTRON _APP _URL _WINDOWS = "https://github.com/zulip/zulip-desktop/releases/download/v" + ELECTRON _APP _VERSION + "/Zulip-Web-Setup-" + ELECTRON _APP _VERSION + ".exe" ;
2017-07-08 02:28:18 +02:00
2019-10-30 20:13:53 +01:00
import { detect _user _os } from './tabbed-instructions.js' ;
2017-11-17 19:50:55 +01:00
import render _tabs from './team.js' ;
2017-08-01 07:21:44 +02:00
export function path _parts ( ) {
2017-07-18 04:40:31 +02:00
return window . location . pathname . split ( '/' ) . filter ( function ( chunk ) {
return chunk !== '' ;
} ) ;
}
2017-07-01 01:29:15 +02:00
2019-11-02 00:06:25 +01:00
const hello _events = function ( ) {
let counter = 0 ;
2017-04-20 20:44:49 +02:00
$ ( window ) . scroll ( function ( ) {
if ( counter % 2 === 0 ) {
$ ( ".screen.hero-screen .message-feed" ) . css ( "transform" , "translateY(-" + $ ( this ) . scrollTop ( ) / 5 + "px)" ) ;
}
counter += 1 ;
} ) ;
$ ( ".footer" ) . addClass ( "hello" ) ;
} ;
2019-11-02 00:06:25 +01:00
const apps _events = function ( ) {
const info = {
2017-07-08 02:28:18 +02:00
windows : {
image : "/static/images/landing-page/microsoft.png" ,
alt : "Windows" ,
description : "Zulip for Windows is even better than Zulip on the web, with a cleaner look, tray integration, native notifications, and support for multiple Zulip accounts." ,
link : ELECTRON _APP _URL _WINDOWS ,
2017-09-28 03:37:05 +02:00
show _instructions : true ,
2018-09-15 21:35:25 +02:00
install _guide : "/help/desktop-app-install-guide" ,
2017-07-08 02:28:18 +02:00
} ,
mac : {
image : "/static/images/landing-page/macbook.png" ,
2017-08-26 09:33:47 +02:00
alt : "macOS" ,
description : "Zulip on macOS is even better than Zulip on the web, with a cleaner look, tray integration, native notifications, and support for multiple Zulip accounts." ,
2017-07-08 02:28:18 +02:00
link : ELECTRON _APP _URL _MAC ,
2017-09-28 03:37:05 +02:00
show _instructions : true ,
2018-09-15 21:35:25 +02:00
install _guide : "/help/desktop-app-install-guide" ,
2017-07-08 02:28:18 +02:00
} ,
android : {
image : "/static/images/app-screenshots/zulip-android.png" ,
alt : "Android" ,
description : "Zulip's native Android app makes it easy to keep up while on the go." ,
2019-07-11 20:46:43 +02:00
show _instructions : false ,
2017-09-28 20:26:52 +02:00
link : "https://play.google.com/store/apps/details?id=com.zulipmobile" ,
2017-07-08 02:28:18 +02:00
} ,
ios : {
image : "/static/images/app-screenshots/zulip-iphone-rough.png" ,
alt : "iOS" ,
description : "Zulip's native iOS app makes it easy to keep up while on the go." ,
2019-07-11 20:46:43 +02:00
show _instructions : false ,
2017-07-08 02:28:18 +02:00
link : "https://itunes.apple.com/us/app/zulip/id1203036395" ,
} ,
linux : {
image : "/static/images/landing-page/ubuntu.png" ,
alt : "Linux" ,
description : "Zulip on the Linux desktop is even better than Zulip on the web, with a cleaner look, tray integration, native notifications, and support for multiple Zulip accounts." ,
link : ELECTRON _APP _URL _LINUX ,
2017-09-28 03:37:05 +02:00
show _instructions : true ,
2018-09-15 21:35:25 +02:00
install _guide : "/help/desktop-app-install-guide" ,
2017-07-08 02:28:18 +02:00
} ,
} ;
2019-11-02 00:06:25 +01:00
let version ;
2017-07-08 02:28:18 +02:00
2017-07-28 04:29:37 +02:00
function get _version _from _path ( ) {
2019-11-02 00:06:25 +01:00
let result ;
const parts = path _parts ( ) ;
2017-07-08 02:28:18 +02:00
2017-07-28 04:29:37 +02:00
Object . keys ( info ) . forEach ( function ( version ) {
js: Convert a.indexOf(…) !== -1 to a.includes(…).
Babel polyfills this for us for Internet Explorer.
import * as babelParser from "recast/parsers/babel";
import * as recast from "recast";
import * as tsParser from "recast/parsers/typescript";
import { builders as b, namedTypes as n } from "ast-types";
import K from "ast-types/gen/kinds";
import fs from "fs";
import path from "path";
import process from "process";
const checkExpression = (node: n.Node): node is K.ExpressionKind =>
n.Expression.check(node);
for (const file of process.argv.slice(2)) {
console.log("Parsing", file);
const ast = recast.parse(fs.readFileSync(file, { encoding: "utf8" }), {
parser: path.extname(file) === ".ts" ? tsParser : babelParser,
});
let changed = false;
recast.visit(ast, {
visitBinaryExpression(path) {
const { operator, left, right } = path.node;
if (
n.CallExpression.check(left) &&
n.MemberExpression.check(left.callee) &&
!left.callee.computed &&
n.Identifier.check(left.callee.property) &&
left.callee.property.name === "indexOf" &&
left.arguments.length === 1 &&
checkExpression(left.arguments[0]) &&
((["===", "!==", "==", "!=", ">", "<="].includes(operator) &&
n.UnaryExpression.check(right) &&
right.operator == "-" &&
n.Literal.check(right.argument) &&
right.argument.value === 1) ||
([">=", "<"].includes(operator) &&
n.Literal.check(right) &&
right.value === 0))
) {
const test = b.callExpression(
b.memberExpression(left.callee.object, b.identifier("includes")),
[left.arguments[0]]
);
path.replace(
["!==", "!=", ">", ">="].includes(operator)
? test
: b.unaryExpression("!", test)
);
changed = true;
}
this.traverse(path);
},
});
if (changed) {
console.log("Writing", file);
fs.writeFileSync(file, recast.print(ast).code, { encoding: "utf8" });
}
}
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-08 04:55:06 +01:00
if ( parts . includes ( version ) ) {
2017-07-28 04:29:37 +02:00
result = version ;
2017-07-08 02:28:18 +02:00
}
2017-07-28 04:29:37 +02:00
} ) ;
2017-07-08 02:28:18 +02:00
2019-01-14 20:13:47 +01:00
result = result || detect _user _os ( ) ;
2017-07-28 04:29:37 +02:00
return result ;
}
function get _path _from _version ( ) {
return '/apps/' + version ;
}
2017-07-08 02:28:18 +02:00
2017-07-28 04:29:37 +02:00
function update _path ( ) {
2019-11-02 00:06:25 +01:00
const next _path = get _path _from _version ( ) ;
2017-07-28 04:29:37 +02:00
history . pushState ( version , '' , next _path ) ;
2017-07-08 02:28:18 +02:00
}
2019-11-02 00:06:25 +01:00
const update _page = function ( ) {
const $download _instructions = $ ( ".download-instructions" ) ;
const $third _party _apps = $ ( "#third-party-apps" ) ;
const $download _android _apk = $ ( "#download-android-apk" ) ;
const version _info = info [ version ] ;
2017-09-28 03:37:05 +02:00
2017-07-08 02:28:18 +02:00
$ ( ".info .platform" ) . text ( version _info . alt ) ;
$ ( ".info .description" ) . text ( version _info . description ) ;
$ ( ".info .link" ) . attr ( "href" , version _info . link ) ;
$ ( ".image img" ) . attr ( "src" , version _info . image ) ;
2017-09-29 20:27:56 +02:00
$download _instructions . find ( "a" ) . attr ( "href" , version _info . install _guide ) ;
2017-09-28 03:37:05 +02:00
2019-03-15 17:59:52 +01:00
$download _instructions . toggle ( version _info . show _instructions ) ;
$third _party _apps . toggle ( version === "mac" ||
version === "windows" ||
version === "linux" ) ;
2019-03-03 16:59:03 +01:00
$download _android _apk . toggle ( version === "android" ) ;
2017-07-08 02:28:18 +02:00
} ;
2017-07-28 04:29:37 +02:00
$ ( window ) . on ( 'popstate' , function ( ) {
version = get _version _from _path ( ) ;
update _page ( ) ;
$ ( "body" ) . animate ( { scrollTop : 0 } , 200 ) ;
} ) ;
2017-07-08 02:28:18 +02:00
2017-07-28 04:29:37 +02:00
$ ( ".apps a .icon" ) . click ( function ( e ) {
2019-11-02 00:06:25 +01:00
const next _version = $ ( e . target ) . closest ( 'a' )
2017-07-28 04:29:37 +02:00
. attr ( 'href' )
. replace ( '/apps/' , '' ) ;
version = next _version ;
2017-07-08 02:28:18 +02:00
2017-07-28 04:29:37 +02:00
update _path ( ) ;
update _page ( ) ;
2017-07-08 02:28:18 +02:00
$ ( "body" ) . animate ( { scrollTop : 0 } , 200 ) ;
2017-07-28 04:29:37 +02:00
return false ;
2017-07-08 02:28:18 +02:00
} ) ;
2017-07-28 04:29:37 +02:00
// init
version = get _version _from _path ( ) ;
history . replaceState ( version , '' , get _path _from _version ( ) ) ;
update _page ( ) ;
2017-07-08 02:28:18 +02:00
} ;
2019-11-02 00:06:25 +01:00
const events = function ( ) {
2017-02-28 01:45:25 +01:00
// get the location url like `zulipchat.com/features/`, cut off the trailing
// `/` and then split by `/` to get ["zulipchat.com", "features"], then
// pop the last element to get the current section (eg. `features`).
2019-11-02 00:06:25 +01:00
const location = window . location . pathname . replace ( /\/#*$/ , "" ) . split ( /\// ) . pop ( ) ;
2017-02-28 01:45:25 +01:00
2018-07-06 23:19:15 +02:00
$ ( "[data-on-page='" + location + "']" ) . addClass ( "active" ) ;
2017-02-28 01:45:25 +01:00
$ ( "body" ) . click ( function ( e ) {
2019-11-02 00:06:25 +01:00
const $e = $ ( e . target ) ;
2017-02-28 01:45:25 +01:00
2017-06-12 22:05:29 +02:00
if ( $e . is ( "nav ul .exit" ) ) {
2017-02-28 01:45:25 +01:00
$ ( "nav ul" ) . removeClass ( "show" ) ;
}
2018-01-31 01:40:31 +01:00
if ( $ ( "nav ul.show" ) && ! $e . closest ( "nav ul.show" ) . length && ! $e . is ( "nav ul.show" ) ) {
$ ( "nav ul" ) . removeClass ( "show" ) ;
}
2017-02-28 01:45:25 +01:00
} ) ;
2018-01-31 01:40:31 +01:00
$ ( ".hamburger" ) . click ( function ( e ) {
2017-02-28 01:45:25 +01:00
$ ( "nav ul" ) . addClass ( "show" ) ;
2018-01-31 01:40:31 +01:00
e . stopPropagation ( ) ;
2017-02-28 01:45:25 +01:00
} ) ;
2017-05-10 19:55:40 +02:00
js: Convert a.indexOf(…) !== -1 to a.includes(…).
Babel polyfills this for us for Internet Explorer.
import * as babelParser from "recast/parsers/babel";
import * as recast from "recast";
import * as tsParser from "recast/parsers/typescript";
import { builders as b, namedTypes as n } from "ast-types";
import K from "ast-types/gen/kinds";
import fs from "fs";
import path from "path";
import process from "process";
const checkExpression = (node: n.Node): node is K.ExpressionKind =>
n.Expression.check(node);
for (const file of process.argv.slice(2)) {
console.log("Parsing", file);
const ast = recast.parse(fs.readFileSync(file, { encoding: "utf8" }), {
parser: path.extname(file) === ".ts" ? tsParser : babelParser,
});
let changed = false;
recast.visit(ast, {
visitBinaryExpression(path) {
const { operator, left, right } = path.node;
if (
n.CallExpression.check(left) &&
n.MemberExpression.check(left.callee) &&
!left.callee.computed &&
n.Identifier.check(left.callee.property) &&
left.callee.property.name === "indexOf" &&
left.arguments.length === 1 &&
checkExpression(left.arguments[0]) &&
((["===", "!==", "==", "!=", ">", "<="].includes(operator) &&
n.UnaryExpression.check(right) &&
right.operator == "-" &&
n.Literal.check(right.argument) &&
right.argument.value === 1) ||
([">=", "<"].includes(operator) &&
n.Literal.check(right) &&
right.value === 0))
) {
const test = b.callExpression(
b.memberExpression(left.callee.object, b.identifier("includes")),
[left.arguments[0]]
);
path.replace(
["!==", "!=", ">", ">="].includes(operator)
? test
: b.unaryExpression("!", test)
);
changed = true;
}
this.traverse(path);
},
});
if (changed) {
console.log("Writing", file);
fs.writeFileSync(file, recast.print(ast).code, { encoding: "utf8" });
}
}
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-08 04:55:06 +01:00
if ( path _parts ( ) . includes ( "apps" ) ) {
2017-07-08 02:28:18 +02:00
apps _events ( ) ;
}
2017-02-28 01:45:25 +01:00
js: Convert a.indexOf(…) !== -1 to a.includes(…).
Babel polyfills this for us for Internet Explorer.
import * as babelParser from "recast/parsers/babel";
import * as recast from "recast";
import * as tsParser from "recast/parsers/typescript";
import { builders as b, namedTypes as n } from "ast-types";
import K from "ast-types/gen/kinds";
import fs from "fs";
import path from "path";
import process from "process";
const checkExpression = (node: n.Node): node is K.ExpressionKind =>
n.Expression.check(node);
for (const file of process.argv.slice(2)) {
console.log("Parsing", file);
const ast = recast.parse(fs.readFileSync(file, { encoding: "utf8" }), {
parser: path.extname(file) === ".ts" ? tsParser : babelParser,
});
let changed = false;
recast.visit(ast, {
visitBinaryExpression(path) {
const { operator, left, right } = path.node;
if (
n.CallExpression.check(left) &&
n.MemberExpression.check(left.callee) &&
!left.callee.computed &&
n.Identifier.check(left.callee.property) &&
left.callee.property.name === "indexOf" &&
left.arguments.length === 1 &&
checkExpression(left.arguments[0]) &&
((["===", "!==", "==", "!=", ">", "<="].includes(operator) &&
n.UnaryExpression.check(right) &&
right.operator == "-" &&
n.Literal.check(right.argument) &&
right.argument.value === 1) ||
([">=", "<"].includes(operator) &&
n.Literal.check(right) &&
right.value === 0))
) {
const test = b.callExpression(
b.memberExpression(left.callee.object, b.identifier("includes")),
[left.arguments[0]]
);
path.replace(
["!==", "!=", ">", ">="].includes(operator)
? test
: b.unaryExpression("!", test)
);
changed = true;
}
this.traverse(path);
},
});
if (changed) {
console.log("Writing", file);
fs.writeFileSync(file, recast.print(ast).code, { encoding: "utf8" });
}
}
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-08 04:55:06 +01:00
if ( path _parts ( ) . includes ( 'hello' ) ) {
2017-04-20 20:44:49 +02:00
hello _events ( ) ;
}
2017-02-28 01:45:25 +01:00
} ;
2017-06-21 03:14:26 +02:00
2017-02-28 01:45:25 +01:00
// run this callback when the page is determined to have loaded.
2019-11-02 00:06:25 +01:00
const load = function ( ) {
2017-02-28 01:45:25 +01:00
2018-05-01 22:54:30 +02:00
// Initiate the bootstrap carousel logic
$ ( '.carousel' ) . carousel ( {
interval : false ,
} ) ;
2018-05-25 15:16:10 +02:00
// Move to the next slide on clicking inside the carousel container
$ ( ".carousel-inner .item-container" ) . click ( function ( e ) {
2019-11-02 00:06:25 +01:00
const get _tag _name = e . target . tagName . toLowerCase ( ) ;
const is _button = get _tag _name === "button" ;
const is _link = get _tag _name === "a" ;
const is _last _slide = $ ( "#tour-carousel .carousel-inner .item:last-child" ) . hasClass ( "active" ) ;
2018-06-04 21:07:09 +02:00
// Do not trigger this event if user clicks on a button, link
// or if it's the last slide
2019-11-02 00:06:25 +01:00
const move _slide _forward = ! is _button && ! is _link && ! is _last _slide ;
2018-06-04 21:07:09 +02:00
if ( move _slide _forward ) {
2018-06-04 10:39:08 +02:00
$ ( this ) . closest ( '.carousel' ) . carousel ( 'next' ) ;
2018-05-25 15:16:10 +02:00
}
} ) ;
2018-06-04 10:18:18 +02:00
$ ( '.carousel' ) . on ( 'slid' , function ( ) {
2019-11-02 00:06:25 +01:00
const $this = $ ( this ) ;
2018-06-04 10:18:18 +02:00
$this . find ( '.visibility-control' ) . show ( ) ;
2019-06-06 06:04:16 +02:00
if ( $this . find ( '.carousel-inner .item' ) . first ( ) . hasClass ( 'active' ) ) {
2018-06-04 10:18:18 +02:00
$this . find ( '.left.visibility-control' ) . hide ( ) ;
2019-06-06 06:04:16 +02:00
} else if ( $this . find ( '.carousel-inner .item' ) . last ( ) . hasClass ( 'active' ) ) {
2018-06-04 10:18:18 +02:00
$this . find ( '.right.visibility-control' ) . hide ( ) ;
}
} ) ;
2017-06-21 03:14:26 +02:00
// Set up events / categories / search
2017-02-28 01:45:25 +01:00
events ( ) ;
} ;
if ( document . readyState === "complete" ) {
load ( ) ;
} else {
2017-10-05 16:01:50 +02:00
$ ( load ) ;
2017-02-28 01:45:25 +01:00
}
2017-11-17 19:50:55 +01:00
$ ( function ( ) {
if ( window . location . pathname === '/team/' ) {
render _tabs ( ) ;
}
} ) ;
2018-03-12 04:45:01 +01:00
// Prevent Firefox from bfcaching the page.
// According to https://developer.mozilla.org/en-US/docs/DOM/window.onunload
// Using this event handler in your page prevents Firefox from caching the
// page in the in-memory bfcache (backward/forward cache).
$ ( window ) . on ( 'unload' , function ( ) {
$ ( window ) . unbind ( 'unload' ) ;
} ) ;