Commit 5263c95a authored by Mark Harding's avatar Mark Harding

(wip): Server Side Rendering - work in progress

1 merge request!343Epic/ssr
Pipeline #65460743 (#484) failed with stage
in 5 minutes and 18 seconds
......@@ -16,6 +16,7 @@
"main": "src/main.ts",
"tsConfig": "src/tsconfig.app.json",
"polyfills": "src/polyfills.ts",
"extractCss": true,
"assets": [
"src/assets",
"src/favicon.ico"
......@@ -98,6 +99,22 @@
"**/node_modules/**"
]
}
},
"server": {
"builder": "@angular-devkit/build-angular:server",
"options": {
"outputPath": "dist/server",
"main": "src/main.server.ts",
"tsConfig": "src/tsconfig.server.json"
},
"configurations": {
"production": {
"fileReplacements": [{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}]
}
}
}
}
},
......
......@@ -25,7 +25,11 @@
"@angular/http": "~7.2.0",
"@angular/platform-browser": "~7.2.0",
"@angular/platform-browser-dynamic": "~7.2.0",
"@angular/platform-server": "^8.0.0",
"@angular/router": "~7.2.0",
"@nguniversal/common": "^7.1.1",
"@nguniversal/module-map-ngfactory-loader": "^7.1.1",
"@nguniversal/socket-engine": "^7.1.1",
"angular-text-input-autocomplete": "^0.3.0",
"bn.js": "^4.11.8",
"braintree-web": "3.41.0",
......@@ -36,6 +40,7 @@
"ethjs-provider-signer": "^0.1.4",
"ethjs-signer": "0.1.1",
"global": "^4.3.2",
"indexeddbshim": "^4.1.0",
"material-datetime-picker": "git+https://github.com/Minds/material-datetime-picker.git",
"material-design-icons": "~3.0.1",
"material-design-lite": "~1.3.0",
......@@ -43,6 +48,7 @@
"rxjs": "~6.3.3",
"socket.io-client": "^2.2.0",
"tslib": "~1.9.3",
"webpack-node-externals": "^1.7.2",
"webtorrent": "^0.103.0",
"zone.js": "~0.8.26"
},
......@@ -73,6 +79,7 @@
"protractor": "~5.4.2",
"ts-node": "~7.0.0",
"tslint": "~5.12.0",
"typescript": "~3.2.2"
"typescript": "~3.2.2",
"webpack-cli": "^3.3.2"
}
}
import 'zone.js/dist/zone-node';
import 'reflect-metadata';
import { join } from 'path';
import { readFileSync } from 'fs';
import { renderModuleFactory } from '@angular/platform-server';
import { enableProdMode } from '@angular/core';
import * as express from 'express';
const domino = require('domino');
const socketEngine = require('@nguniversal/socket-engine');
// Faster server renders w/ Prod mode (dev mode never needed)
enableProdMode();
// Express server
const app = express();
const PORT = process.env.PORT || 4201;
const DIST_FOLDER = join(process.cwd(), 'dist/en');
const template = readFileSync(join(DIST_FOLDER, 'index.php')).toString();
const win = domino.createWindow(template);
const setGlobalVars = require('indexeddbshim');
global['window'] = win;
global['Node'] = win.Node;
global['navigator'] = win.navigator;
global['Event'] = win.Event;
global['Event']['prototype'] = win.Event.prototype;
global['document'] = win.document;
global['window']['Promise'] = global.Promise;
global['window']['Minds'] = {
cdn_urn: '/',
cdn_assets_url: '/en/',
blockchain: {
network_address: "https://www.minds.com/api/v2/blockchain/proxy/",
token: {
abi: [],
}
},
};
global['window']['localStorage'] = {
getItem: () => { },
setItem: () => { },
removeItem: () => { },
};
global['localStorage'] = global['window']['localStorage'];
global['window']['scrollTo'] = (pos) => { };
Object.defineProperty(window.document, 'cookie', {
writable: true,
value: 'myCookie=omnomnom',
});
Object.defineProperty(window.document, 'referrer', {
writable: true,
value: '',
});
Object.defineProperty(window.document, 'localStorage', {
writable: true,
value: global['window']['localStorage'],
});
setGlobalVars(null, {
checkOrigin: false
});
// * NOTE :: leave this as require() since this file is built Dynamically from webpack
const {AppServerModuleNgFactory, LAZY_MODULE_MAP} = require('./dist/server/main');
const { provideModuleMap } = require('@nguniversal/module-map-ngfactory-loader');
socketEngine.startSocketEngine(AppServerModuleNgFactory, [ provideModuleMap(LAZY_MODULE_MAP) ]);
/*app.engine('html', (_, options, callback) => {
renderModuleFactory(AppServerModuleNgFactory, {
// Our index.html
document: template,
url: options.req.url,
// DI so that we can get lazy-loading to work differently (since we need it to just instantly render it)
extraProviders: [
provideModuleMap(LAZY_MODULE_MAP)
]
}).then(html => {
callback(null, html);
});
});
app.set('view engine', 'html');
app.set('views', DIST_FOLDER);
// Server static files from dist folder
app.get('*.*', express.static(DIST_FOLDER));
// All regular routes use the Universal engine
app.get('*', (req, res) => {
res.render('index', { req });
});
// Start up the Node server
app.listen(PORT, () => {
console.log(`Node server listening on http://localhost:${PORT}`);
});*/
import { NgModule } from '@angular/core';
import { MindsModule } from './app.module';
import { Minds } from './app.component';
@NgModule({
imports: [
MindsModule,
],
bootstrap: [Minds],
})
export class AppBrowserModule {}
import { ChangeDetectorRef, Component, NgZone } from '@angular/core';
import {
ChangeDetectorRef,
Component,
NgZone,
PLATFORM_ID,
Inject,
} from '@angular/core';
import { isPlatformBrowser } from '@angular/common';
import { NotificationService } from './modules/notifications/notification.service';
import { AnalyticsService } from './services/analytics';
......@@ -51,13 +58,12 @@ export class Minds {
public featuresService: FeaturesService,
public themeService: ThemeService,
private bannedService: BannedService,
@Inject(PLATFORM_ID) private platformId,
) {
this.name = 'Minds';
}
async ngOnInit() {
this.notificationService.getNotifications();
this.session.isLoggedIn(async (is) => {
if (is) {
this.showOnboarding = await this.onboardingService.showModal();
......@@ -97,7 +103,7 @@ export class Minds {
this.themeService.setUp();
if (this.session.isLoggedIn()) {
if (isPlatformBrowser(this.platformId) && this.session.isLoggedIn()) {
this.blockListService.sync();
}
}
......@@ -105,6 +111,6 @@ export class Minds {
ngOnDestroy() {
this.loginReferrer.unlisten();
this.scrollToTop.unlisten();
this.paramsSubscription.unsubscribe();
//this.paramsSubscription.unsubscribe();
}
}
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserModule, BrowserTransferStateModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router';
......@@ -69,12 +69,13 @@ import { HttpClientModule } from "@angular/common/http";
MINDS_PLUGIN_DECLARATIONS,
],
imports: [
BrowserModule,
BrowserAnimationsModule,
BrowserModule.withServerTransition({ appId: 'm-app' }),
BrowserTransferStateModule,
//BrowserAnimationsModule,
ReactiveFormsModule,
FormsModule,
HttpClientModule,
RouterModule.forRoot(MindsAppRoutes),
RouterModule.forRoot(MindsAppRoutes, { initialNavigation: 'enabled' }),
CaptchaModule,
CommonModule,
WalletModule,
......
import { NgModule } from '@angular/core';
import { ServerModule } from '@angular/platform-server';
import { ModuleMapLoaderModule } from '@nguniversal/module-map-ngfactory-loader';
import { ServerTransferStateModule } from '@angular/platform-server';
import { MindsModule } from './app.module';
import { Minds } from './app.component';
@NgModule({
imports: [
MindsModule,
ServerModule,
ModuleMapLoaderModule,
ServerTransferStateModule,
],
bootstrap: [Minds],
})
export class AppServerModule {}
......@@ -6,7 +6,7 @@ import { HttpClient, HttpHeaders } from "@angular/common/http";
*/
export class MindsHttpClient {
base: string = '/';
base: string = 'https://eggman.minds.com/';
cookie: Cookie = new Cookie();
static _(http: HttpClient) {
......
......@@ -59,6 +59,7 @@ import { InlineEditorComponent } from './components/editors/inline-editor.compon
import { AttachmentService } from "../services/attachment";
import { MaterialBoundSwitchComponent } from './components/material/bound-switch.component';
import { IfFeatureDirective } from './directives/if-feature.directive';
import { IfBrowserDirective } from './directives/if-browser.directive';
import { MindsEmoji } from './components/emoji/emoji';
import { CategoriesSelectorComponent } from './components/categories/selector/selector.component';
import { CategoriesSelectedComponent } from './components/categories/selected/selected.component';
......@@ -166,6 +167,7 @@ import { HorizontalInfiniteScroll } from "./components/infinite-scroll/horizonta
MaterialBoundSwitchComponent,
IfFeatureDirective,
IfBrowserDirective,
CategoriesSelectorComponent,
CategoriesSelectedComponent,
......@@ -250,6 +252,7 @@ import { HorizontalInfiniteScroll } from "./components/infinite-scroll/horizonta
MaterialBoundSwitchComponent,
IfFeatureDirective,
IfBrowserDirective,
CategoriesSelectorComponent,
CategoriesSelectedComponent,
......
import {
Directive,
EmbeddedViewRef,
Inject,
Input,
PLATFORM_ID,
TemplateRef,
ViewContainerRef,
} from '@angular/core';
import { isPlatformBrowser } from '@angular/common';
@Directive({
selector: '[mIfBrowser]'
})
export class IfBrowserDirective {
private _elseTemplateRef: TemplateRef<any>;
private _viewRef: EmbeddedViewRef<any>;
private _elseViewRef: EmbeddedViewRef<any>;
constructor(
private _templateRef: TemplateRef<any>,
private _viewContainerRef: ViewContainerRef,
@Inject(PLATFORM_ID) private platformId,
) {
console.log('constructing IfBrowserDirective');
this._update();
}
_update() {
console.log(this.platformId, isPlatformBrowser);
if (isPlatformBrowser(this.platformId)) {
if (!this._viewRef) {
this._viewContainerRef.clear();
this._elseViewRef = void 0;
if (this._templateRef) {
this._viewRef = this._viewContainerRef.createEmbeddedView(this._templateRef);
}
}
} else {
if (!this._elseViewRef) {
this._viewContainerRef.clear();
this._viewRef = void 0;
if (this._elseTemplateRef) {
this._elseViewRef = this._viewContainerRef.createEmbeddedView(this._elseTemplateRef);
}
}
}
}
}
......@@ -7,7 +7,7 @@ import AsyncLock from "../../helpers/async-lock";
import MindsClientHttpAdapter from "../../lib/minds-sync/adapters/MindsClientHttpAdapter.js";
import browserStorageAdapterFactory from "../../helpers/browser-storage-adapter-factory";
import BlockListSync from "../../lib/minds-sync/services/BlockListSync.js";
import AsyncStatus from "../../helpers/async-status";
import { AsyncStatus } from "../../helpers/async-status";
@Injectable()
export class BlockListService {
......@@ -39,13 +39,13 @@ export class BlockListService {
// Prune on session changes
this.session.isLoggedIn((is: boolean) => {
/*this.session.isLoggedIn((is: boolean) => {
if (is) {
this.sync();
} else {
this.prune();
}
});
});*/
}
async sync() {
......
......@@ -11,7 +11,7 @@ import MindsClientHttpAdapter from "../../lib/minds-sync/adapters/MindsClientHtt
import browserStorageAdapterFactory from "../../helpers/browser-storage-adapter-factory";
import BoostedContentSync from '../../lib/minds-sync/services/BoostedContentSync.js';
import AsyncStatus from "../../helpers/async-status";
import { AsyncStatus } from "../../helpers/async-status";
@Injectable()
export class BoostedContentService {
......@@ -69,7 +69,7 @@ export class BoostedContentService {
// Garbage collection
this.boostedContentSync.gc();
setTimeout(() => this.boostedContentSync.gc(), 5 * 60 * 1000); // Every 5 minutes
//setTimeout(() => this.boostedContentSync.gc(), 5 * 60 * 1000); // Every 5 minutes
// Rating changes hook
this.settingsService.ratingChanged.subscribe(rating => this.boostedContentSync.changeRating(rating));
......
......@@ -4,7 +4,7 @@ import { Client } from "../../services/api";
import MindsClientHttpAdapter from '../../lib/minds-sync/adapters/MindsClientHttpAdapter.js';
import browserStorageAdapterFactory from "../../helpers/browser-storage-adapter-factory";
import EntitiesSync from '../../lib/minds-sync/services/EntitiesSync.js';
import AsyncStatus from "../../helpers/async-status";
import { AsyncStatus } from "../../helpers/async-status";
import normalizeUrn from "../../helpers/normalize-urn";
@Injectable()
......@@ -12,10 +12,9 @@ export class EntitiesService {
protected entitiesSync: EntitiesSync;
protected status = new AsyncStatus();
constructor(
protected client: Client
protected client: Client,
protected status: AsyncStatus,
) {
this.setUp();
}
......@@ -36,7 +35,7 @@ export class EntitiesService {
// Garbage collection
this.entitiesSync.gc();
setTimeout(() => this.entitiesSync.gc(), 15 * 60 * 1000); // Every 15 minutes
//setTimeout(() => this.entitiesSync.gc(), 15 * 60 * 1000); // Every 15 minutes
}
async single(guid: string): Promise<Object | false> {
......@@ -65,10 +64,13 @@ export class EntitiesService {
const urns = guids.map(guid => normalizeUrn(guid));
if (!this.entitiesSync)
await this.setUp();
return await this.entitiesSync.get(urns);
}
static _(client: Client) {
return new EntitiesService(client);
static _(client: Client, status: AsyncStatus) {
return new EntitiesService(client, status);
}
}
......@@ -11,7 +11,7 @@ import browserStorageAdapterFactory from "../../helpers/browser-storage-adapter-
import FeedsSync from '../../lib/minds-sync/services/FeedsSync.js';
import hashCode from "../../helpers/hash-code";
import AsyncStatus from "../../helpers/async-status";
import { AsyncStatus } from "../../helpers/async-status";
export type FeedsServiceGetParameters = {
endpoint: string;
......@@ -34,26 +34,28 @@ export type FeedsServiceGetResponse = {
@Injectable()
export class FeedsService {
protected feedsSync: FeedsSync;
protected status = new AsyncStatus();
//protected feedsSync: FeedsSync;
constructor(
protected client: Client,
protected session: Session,
protected entitiesService: EntitiesService,
protected blockListService: BlockListService,
protected status: AsyncStatus,
protected feedsSync: FeedsSync,
) {
console.log('constructed feeds sync');
this.setUp();
}
async setUp() {
console.log('setup called');
this.feedsSync = new FeedsSync(
new MindsClientHttpAdapter(this.client),
await browserStorageAdapterFactory('minds-feeds-190314'),
15,
);
console.log('setup completed');
this.feedsSync.setResolvers({
stringHash: value => hashCode(value),
currentUser: () => this.session.getLoggedInUser() && this.session.getLoggedInUser().guid,
......@@ -70,12 +72,12 @@ export class FeedsService {
// Garbage collection
this.feedsSync.gc();
setTimeout(() => this.feedsSync.gc(), 15 * 60 * 1000); // Every 15 minutes
//setTimeout(() => this.feedsSync.gc(), 15 * 60 * 1000); // Every 15 minutes
}
async get(opts: FeedsServiceGetParameters): Promise<FeedsServiceGetResponse> {
await this.status.untilReady();
try {
const { entities, next } = await this.feedsSync.get(opts);
......@@ -99,7 +101,9 @@ export class FeedsService {
session: Session,
entitiesService: EntitiesService,
blockListService: BlockListService,
status: AsyncStatus,
feedsSync: FeedsSync,
) {
return new FeedsService(client, session, entitiesService, blockListService);
return new FeedsService(client, session, entitiesService, blockListService, status, feedsSync);
}
}
......@@ -95,7 +95,7 @@ export class ThemeService {
this.renderer.removeClass(document.body, 'm-theme__dark');
this.renderer.addClass(document.body, 'm-theme__light');
}
this.clearTransitions();
//this.clearTransitions();
}
clearTransitions(){
......@@ -104,4 +104,4 @@ export class ThemeService {
this.renderer.removeClass(document.body, 'm-theme-in-transition');
}, 1000);
}
}
\ No newline at end of file
}
import { BehaviorSubject, Subscription } from "rxjs";
export default class AsyncStatus {
export class AsyncStatus {
protected ready: boolean = false;
protected subject$: BehaviorSubject<boolean> = new BehaviorSubject(false);
......@@ -11,7 +11,7 @@ export default class AsyncStatus {
done(): this {
if (this.ready) {
throw new Error('Already done');
// throw new Error('Already done');
}
this.ready = true;
......@@ -42,4 +42,8 @@ export default class AsyncStatus {
});
});
}
static _() {
return new AsyncStatus();
}
}
......@@ -5,6 +5,6 @@
*/
export default function isMobile() {
let check = false;
(function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))) check = true;})(navigator.userAgent||navigator.vendor||(<any>window).opera);
(function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))) check = true;})(navigator.userAgent||navigator.vendor||(<any>window).opera||'');
return check;
};
import { NgModule } from '@angular/core';
import { NgModule, Inject, PLATFORM_ID } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { CommonModule as NgCommonModule } from '@angular/common';
......@@ -65,7 +65,7 @@ const cryptoRoutes: Routes = [
{
provide: Web3WalletService,
useFactory: Web3WalletService._,
deps: [ LocalWalletService, TransactionOverlayService ]
deps: [ LocalWalletService, TransactionOverlayService, PLATFORM_ID ]
},
{
provide: TokenContractService,
......
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core';
import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
OnInit,
Inject,
PLATFORM_ID,
} from '@angular/core';
import { isPlatformBrowser } from '@angular/common';
import { Router } from '@angular/router';
import { Web3WalletService } from '../web3-wallet.service';
......@@ -17,7 +25,8 @@ export class BlockchainWalletAddressNoticeComponent implements OnInit {
protected web3Wallet: Web3WalletService,
protected blockchain: BlockchainService,
protected router: Router,
protected cd: ChangeDetectorRef
protected cd: ChangeDetectorRef,
@Inject(PLATFORM_ID) protected platformId,
) {
}
......@@ -35,7 +44,8 @@ export class BlockchainWalletAddressNoticeComponent implements OnInit {
this.address = wallet;
this.detectChanges();
} else {
setTimeout(() => this.load(), 10000); // check every 10 seconds if there's a wallet detected
if (isPlatformBrowser(this.platformId))
setTimeout(() => this.load(), 10000); // check every 10 seconds if there's a wallet detected
}
}
......
import { Injectable } from '@angular/core';
import { Injectable, Inject, PLATFORM_ID } from '@angular/core';
import { isPlatformServer } from '@angular/common';
import * as Eth from 'ethjs';
import * as SignerProvider from 'ethjs-provider-signer';
......@@ -22,6 +23,7 @@ export class Web3WalletService {
constructor(
protected localWallet: LocalWalletService,
protected transactionOverlay: TransactionOverlayService,
@Inject(PLATFORM_ID) private platformId,
) { }
// Wallet
......@@ -131,7 +133,7 @@ export class Web3WalletService {
private waitForWeb3(resolve, reject) {
this._web3LoadAttempt++;
if (this._web3LoadAttempt > 3) {
if (this._web3LoadAttempt > 3 || isPlatformServer(this.platformId)) {
this.loadLocal();
return resolve(true);
}
......@@ -260,7 +262,7 @@ export class Web3WalletService {
// Service provider
static _(localWallet: LocalWalletService, transactionOverlay: TransactionOverlayService) {
return new Web3WalletService(localWallet, transactionOverlay);
static _(localWallet: LocalWalletService, transactionOverlay: TransactionOverlayService, platformId) {
return new Web3WalletService(localWallet, transactionOverlay, platformId);
}
}
......@@ -85,12 +85,14 @@
<m-wire--lock-screen [(entity)]="blog" *ngIf="blog.paywall" #lockScreen></m-wire--lock-screen>
<div class="mdl-grid blogs-grid" style="max-width:660px" *ngIf="blog.guid">
<m-comments__tree
[entity]="blog"
>
</m-comments__tree>
</div>
<ng-container *mIfBrowser>
<div class="mdl-grid blogs-grid" style="max-width:660px" *ngIf="blog.guid">
<m-comments__tree
[entity]="blog"
>
</m-comments__tree>
</div>
</ng-container>
<m-modal-confirm *ngIf="deleteToggle"
[open]="true"
......
......@@ -153,6 +153,7 @@
[channel]="user"
[linksTo]="['/', user.username, 'images']"
[size]="9"
*mIfBrowser
></m-channels--sorted-module>
<div class="minds-spacer-2x"></div>
......@@ -164,6 +165,7 @@
[channel]="user"
[linksTo]="['/', user.username, 'videos']"
[size]="9"
*mIfBrowser
></m-channels--sorted-module>
<div class="minds-spacer-2x"></div>
......@@ -175,11 +177,17 @@
[channel]="user"
[linksTo]="['/', user.username, 'blogs']"
[size]="3"
*mIfBrowser
></m-channels--sorted-module>
</ng-container>
<ng-template #legacyModules>
<!-- images -->
<m-channel--modules [owner]="user" type="image" [linksTo]="['/media/images', user.username]">
<m-channel--modules
[owner]="user"
type="image"
[linksTo]="['/media/images', user.username]"
*mIfBrowser
>
<a class="mdl-card__supporting-text mdl-color-text--grey-600" [routerLink]="['/media/images', user.username]">
<ng-container i18n="@@M__COMMON__VIEW_MORE">View More</ng-container>
......@@ -189,7 +197,13 @@
<div class="minds-spacer-2x"></div>
<!-- videos -->
<m-channel--modules [owner]="user" type="video" limit="9" [linksTo]="['/media/videos', user.username]">
<m-channel--modules
[owner]="user"
type="video"
limit="9"
[linksTo]="['/media/videos', user.username]"
*mIfBrowser
>
<a class="mdl-card__supporting-text mdl-color-text--grey-600" [routerLink]="['/media/videos', user.username]">
<ng-container i18n="@@M__COMMON__VIEW_MORE">View More</ng-container>
......@@ -199,7 +213,13 @@
<div class="minds-spacer-2x"></div>
<!-- Blogs -->
<m-channel--modules [owner]="user" type="blog" limit="3" [linksTo]="['/blog', user.username]">
<m-channel--modules
[owner]="user"
type="blog"
limit="3"
[linksTo]="['/blog', user.username]"
*mIfBrowser
>
<a class="mdl-card__supporting-text mdl-color-text--grey-600" [routerLink]="['/blog', user.username]">
<ng-container i18n="@@M__COMMON__VIEW_MORE">View More</ng-container>
......
......@@ -7,8 +7,12 @@ import {
Output,
EventEmitter,
ViewChild,
SkipSelf, Injector
SkipSelf,
Injector,
Inject,
PLATFORM_ID,
} from "@angular/core";
import { isPlatformBrowser } from '@angular/common';
import { FeedsService } from "../../../common/services/feeds.service";
import { Session } from "../../../services/session";
import { PosterComponent } from "../../newsfeed/poster/poster.component";
......@@ -69,6 +73,7 @@ export class ChannelSortedComponent implements OnInit {
protected clientMetaService: ClientMetaService,
@SkipSelf() injector: Injector,
protected cd: ChangeDetectorRef,
@Inject(PLATFORM_ID) private platformId,
) {
this.clientMetaService
.inherit(injector)
......@@ -111,7 +116,7 @@ export class ChannelSortedComponent implements OnInit {
}
try {
const limit = 12;
const limit = isPlatformBrowser(this.platformId) ? 12 : 2; // Only load a couple posts with SSR
const { entities, next } = await this.feedsService.get({
endpoint: `api/v2/feeds/container/${this.channel.guid}/${this.type}`,
......
......@@ -8,8 +8,11 @@ import {
ChangeDetectionStrategy,
OnChanges,
Input,
Inject,
ElementRef,
PLATFORM_ID,
} from '@angular/core';
import { isPlatformBrowser } from '@angular/common';
import { Session } from '../../../services/session';
import { Upload } from '../../../services/api/upload';
......@@ -90,13 +93,16 @@ export class CommentComponentV2 implements OnChanges {
private overlayModal: OverlayModalService,
private cd: ChangeDetectorRef,
private timeDiffService: TimeDiffService,
private el: ElementRef
private el: ElementRef,
@Inject(PLATFORM_ID) private platformId,
) {}
ngOnInit() {
this.commentAge$ = this.timeDiffService.source.pipe(map(secondsElapsed => {
return (this.comment.time_created - secondsElapsed) * 1000;
}));
if (isPlatformBrowser(this.platformId)) {
this.commentAge$ = this.timeDiffService.source.pipe(map(secondsElapsed => {
return (this.comment.time_created - secondsElapsed) * 1000;
}));
}
}
ngAfterViewInit() {
......
import { Directive, ElementRef, EventEmitter } from '@angular/core';
import {
Directive,
ElementRef,
EventEmitter,
Inject,
PLATFORM_ID,
} from '@angular/core';
import { isPlatformServer, isPlatformBrowser } from '@angular/common';
import { Observable, Subscription, fromEvent } from 'rxjs';
import { debounceTime } from 'rxjs/operators';
......@@ -26,7 +33,10 @@ export class CommentsScrollDirective {
private emitterSubscription: Subscription;
constructor(private elementRef: ElementRef) {
constructor(
private elementRef: ElementRef,
@Inject(PLATFORM_ID) private platformId,
) {
this.scroll = fromEvent(elementRef.nativeElement, 'scroll');
}
......@@ -36,6 +46,9 @@ export class CommentsScrollDirective {
return;
}
if (isPlatformServer(this.platformId))
return;
if (this.emitterSubscription) {
this.emitterSubscription.unsubscribe();
}
......@@ -115,8 +128,9 @@ export class CommentsScrollDirective {
// Refresh timer
if (this.stickInterval) {
clearInterval(this.stickInterval);
}
this.stickInterval = setInterval(() => this.stick(), this.STICK_INTERVAL_MS);
}
if (isPlatformBrowser(this.platformId))
this.stickInterval = setInterval(() => this.stick(), this.STICK_INTERVAL_MS);
}
top(run?: boolean, stick?: boolean) {
......
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
import {
Component,
ElementRef,
OnInit,
ViewChild,
Inject,
PLATFORM_ID,
} from '@angular/core';
import { isPlatformServer } from '@angular/common';
import { Router } from '@angular/router';
import { Client } from '../../../services/api/client';
import { Session } from '../../../services/session';
......@@ -18,6 +26,7 @@ export class AllHelpdeskDashboardComponent implements OnInit {
public router: Router,
public client: Client,
public session: Session,
@Inject(PLATFORM_ID) private platformId,
) {
}
......@@ -26,10 +35,11 @@ export class AllHelpdeskDashboardComponent implements OnInit {
}
async load() {
let response: any = await this.client.get(`api/v2/helpdesk/categories`, { limit: 5000 });
const limit = isPlatformServer(this.platformId) ? 12 : 5000; // Load less for SSR
let response: any = await this.client.get(`api/v2/helpdesk/categories`, { limit });
this.categories = response.categories.sort((a, b) => a.position - b.position);
response = await this.client.get(`api/v2/helpdesk/questions`, { limit: 5000 });
response = await this.client.get(`api/v2/helpdesk/questions`, { limit });
this.questions = response.questions;
for (let category of this.categories) {
......
......@@ -82,7 +82,7 @@
<span class="mdl-color--grey-100" style="width: 100%; height: 1px; display: block;"></span>
<div class="mdl-grid mdl-grid--no-spacing m-homepage--stream">
<div class="mdl-grid mdl-grid--no-spacing m-homepage--stream" *mIfBrowser>
<h4 class="mdl-color-text--blue-grey-200 mdl-cell--12-col" i18n="@@HOMEPAGE__FEATURED_POSTS_TITLE">Featured Posts</h4>
<section class="mdl-cell mdl-cell--4-col">
......
......@@ -3,8 +3,12 @@
.m-homepage--hero{
position:relative;
//background-image: url(/assets/photos/circles.png);
background-image: url("<%= APP_CDN %>/assets/videos/what-1/what-1.jpg");
@media screen and (max-width: $max-mobile) {
background-image: url("<%= APP_CDN %>/assets/videos/what-1/what-1-mobile.jpg");
}
background-size: cover;
background-position: center center;
......
import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { Subscription } from 'rxjs';
import { Navigation as NavigationService } from '../../services/navigation';
import { Session } from '../../services/session';
import { MindsTitle } from '../../services/ux/title';
import { Client } from '../../services/api';
import { LoginReferrerService } from '../../services/login-referrer.service';
import { GlobalScrollService, ScrollSubscription } from "../../services/ux/global-scroll.service";
@Component({
selector: 'm-homepage',
......@@ -22,6 +24,8 @@ export class HomepageComponent {
2: [],
3: []
};
loadedStream: boolean = false;
scroll$: [ScrollSubscription, Subscription];
offset: string = '';
inProgress: boolean = false;
videoError: boolean = false;
......@@ -38,10 +42,10 @@ export class HomepageComponent {
public router: Router,
public navigation: NavigationService,
private loginReferrer: LoginReferrerService,
public session: Session
public session: Session,
private scroll: GlobalScrollService,
) {
this.title.setTitle('Minds Social Network', false);
this.loadStream();
if (this.session.isLoggedIn()) {
this.router.navigate(['/newsfeed']);
......@@ -53,6 +57,13 @@ export class HomepageComponent {
}
}
ngOnInit() {
this.scroll$ = this.scroll.listen(document, (subscription, e) => {
this.loadStream(true);
this.scroll$[1].unsubscribe();
}, 100);
}
loadStream(refresh: boolean = false) {
this.inProgress = true;
this.client.get('api/v1/newsfeed/featured', { limit: 24, offset: this.offset })
......
import { Component, EventEmitter } from '@angular/core';
import { Component, EventEmitter, PLATFORM_ID, Inject } from '@angular/core';
import { interval, Subscription } from 'rxjs';
import { isPlatformBrowser } from '@angular/common';
import { Client } from '../../../services/api';
......@@ -40,11 +42,14 @@ export class CarouselComponent {
delete_event = new EventEmitter();
done: boolean = false; //if set to true, tells the child component to return "added"
rotate: boolean = true; //if set to true enabled rotation
rotate_timeout; //the timeout for the rotator
rotator$: Subscription;
interval: number = 3000; //the interval for each banner to stay before rotating
index: number = 0; //the current visible index of the carousel.
constructor() {
constructor(@Inject(PLATFORM_ID) private platformId) {
}
ngOnInit() {
this.run();
}
......@@ -175,9 +180,12 @@ export class CarouselComponent {
}
run() {
if (this.rotate_timeout)
clearTimeout(this.rotate_timeout);
this.rotate_timeout = setTimeout(() => {
if (!isPlatformBrowser(this.platformId))
return;
if (this.rotator$)
this.rotator$.unsubscribe();
this.rotator$ = interval(this.interval).subscribe(() => {
if (this.rotate) {
var max = this.banners.length - 1;
if (this.index >= max)
......@@ -185,12 +193,12 @@ export class CarouselComponent {
else
this.index++;
}
this.run();
}, this.interval);
});
}
ngOnDestroy() {
clearTimeout(this.rotate_timeout);
if (this.rotator$)
this.rotator$.unsubscribe();
}
}
import { NgModule } from '@angular/core';
import { NgModule, PLATFORM_ID } from '@angular/core';
import { CommonModule as NgCommonModule } from '@angular/common';
import { ReactiveFormsModule, FormsModule } from '@angular/forms';
import { RouterModule, Routes } from '@angular/router';
......@@ -39,7 +39,7 @@ import { NotificationsToasterComponent } from './toaster.component';
{
provide: NotificationService,
useFactory: NotificationService._,
deps: [ Session, Client, SocketsService, MindsTitle ]
deps: [ Session, Client, SocketsService, MindsTitle, PLATFORM_ID ]
}
],
exports: [
......
import { EventEmitter } from '@angular/core';
import { EventEmitter, Inject, PLATFORM_ID } from '@angular/core';
import { isPlatformBrowser } from '@angular/common';
import { timer, Subscription } from 'rxjs';
import { Client } from '../../services/api';
import { SocketsService } from '../../services/sockets';
import { Session } from '../../services/session';
......@@ -9,12 +11,19 @@ export class NotificationService {
notification: null
};
onReceive: EventEmitter<any> = new EventEmitter();
polling$: Subscription;
static _(session: Session, client: Client, sockets: SocketsService, title: MindsTitle) {
return new NotificationService(session, client, sockets, title);
static _(session: Session, client: Client, sockets: SocketsService, title: MindsTitle, platformId) {
return new NotificationService(session, client, sockets, title, platformId);
}
constructor(public session: Session, public client: Client, public sockets: SocketsService, public title: MindsTitle) {
constructor(
public session: Session,
public client: Client,
public sockets: SocketsService,
public title: MindsTitle,
@Inject(PLATFORM_ID) private platformId,
) {
if (!window.Minds.notifications_count)
window.Minds.notifications_count = 0;
......@@ -34,7 +43,10 @@ export class NotificationService {
this.onReceive.next(response.notification);
}
});
});
});
if (isPlatformBrowser(this.platformId)) {
this.initPolling();
}
}
/**
......@@ -56,23 +68,22 @@ export class NotificationService {
/**
* Return the notifications
*/
getNotifications() {
var self = this;
setInterval(function () {
initPolling() {
this.polling$ = timer(1000, 6000).subscribe(() => {
// console.log('getting notifications');
if (!self.session.isLoggedIn())
if (!this.session.isLoggedIn())
return;
if (!window.Minds.notifications_count)
window.Minds.notifications_count = 0;
self.client.get('api/v1/notifications/count', {})
this.client.get('api/v1/notifications/count', {})
.then((response: any) => {
window.Minds.notifications_count = response.count;
self.sync();
this.sync();
});
}, 60000);
});
}
/**
......@@ -85,7 +96,6 @@ export class NotificationService {
}
}
this.title.setCounter(window.Minds.notifications_count);
}
}
import { Cookie } from '../cookie';
import { PLATFORM_ID, Inject } from '@angular/core';
import { isPlatformServer } from '@angular/common';
import { HttpClient, HttpHeaders } from "@angular/common/http";
import { makeStateKey, TransferState } from '@angular/platform-browser';
/**
* API Class
*/
export class Client {
base: string = '/';
base: string = 'https://eggman.minds.com/';
cookie: Cookie = new Cookie();
static _(http: HttpClient) {
return new Client(http);
static _(http: HttpClient, platformId, transferState: TransferState) {
return new Client(http, platformId, transferState);
}
constructor(public http: HttpClient) {
constructor(
public http: HttpClient,
@Inject(PLATFORM_ID) private platformId,
private transferState: TransferState,
) {
}
/**
......@@ -23,6 +30,15 @@ export class Client {
if (data) {
endpoint += '?' + this.buildParams(data);
}
const STATE_KEY = makeStateKey(`http-${endpoint}` + JSON.stringify(options));
if (this.transferState.hasKey(STATE_KEY)) {
const result = this.transferState.get(STATE_KEY, null);
this.transferState.remove(STATE_KEY);
return Promise.resolve(JSON.parse(result));
}
return new Promise((resolve, reject) => {
this.http.get(
this.base + endpoint,
......@@ -34,6 +50,11 @@ export class Client {
if (!data || data.status !== 'success')
return reject(data);
if (isPlatformServer(this.platformId)) {
const dump = JSON.stringify(data);
if (dump.length < 10000)
this.transferState.set(STATE_KEY, dump);
}
return resolve(data);
},
err => {
......@@ -178,6 +199,9 @@ export class Client {
* Build the options
*/
private buildOptions(options: Object) {
if (isPlatformServer(this.platformId)) {
return options; // TODO: support XSRF on universal
}
const XSRF_TOKEN = this.cookie.get('XSRF-TOKEN');
const headers = new HttpHeaders({
......
......@@ -12,7 +12,12 @@ export class Navigation {
getItems(container: string = 'sidebar'): Array<any> {
var navigation: Array<any> = window.Minds.navigation;
var navigation: Array<any> = window.Minds.navigation;
if (!navigation) {
return [];
}
var items: Array<any> = navigation[container];
if (!items)
return [];
......
import { NgZone, RendererFactory2 } from '@angular/core';
import { NgZone, RendererFactory2, PLATFORM_ID } from '@angular/core';
import { Router } from '@angular/router';
import { Location } from '@angular/common';
import { Title } from '@angular/platform-browser';
import { Title, TransferState } from '@angular/platform-browser';
import { ScrollService } from './ux/scroll';
import { SocketsService } from './sockets';
......@@ -42,6 +42,7 @@ import { InMemoryStorageService } from "./in-memory-storage.service";
import { FeedsService } from "../common/services/feeds.service";
import { ThemeService } from "../common/services/theme.service";
import { GlobalScrollService } from "./ux/global-scroll.service";
import { AsyncStatus } from "../helpers/async-status";
export const MINDS_PROVIDERS : any[] = [
{
......@@ -62,7 +63,7 @@ export const MINDS_PROVIDERS : any[] = [
{
provide: Client,
useFactory: Client._,
deps: [ HttpClient ]
deps: [ HttpClient, PLATFORM_ID, TransferState ]
},
{
provide: Upload,
......@@ -198,6 +199,10 @@ export const MINDS_PROVIDERS : any[] = [
provide: TimeDiffService,
useFactory: TimeDiffService._
},
{
provide: AsyncStatus,
useFactory: AsyncStatus._,
},
{
provide: BlockListService,
useFactory: BlockListService._,
......@@ -206,12 +211,12 @@ export const MINDS_PROVIDERS : any[] = [
{
provide: EntitiesService,
useFactory: EntitiesService._,
deps: [ Client ],
deps: [ Client, AsyncStatus ],
},
{
provide: FeedsService,
useFactory: FeedsService._,
deps: [ Client, Session, EntitiesService, BlockListService ],
deps: [ Client, Session, EntitiesService, BlockListService, AsyncStatus, ],
},
{
provide: InMemoryStorageService,
......
......@@ -136,6 +136,8 @@ export class SocketsService {
}
subscribe(name: string, callback: Function) {
if (!this.socket)
return;
if (!this.subscriptions[name]) {
this.subscriptions[name] = new EventEmitter();
......
......@@ -3,6 +3,7 @@ export class Material {
window.componentHandler.upgradeDom();
}
static updateElement(element: any) {
window.componentHandler.upgradeElement(element);
if (window.componentHandler)
window.componentHandler.upgradeElement(element);
}
}
src/assets/videos/what-1/what-1-mobile.jpg

70.4 KB

File added
<?php
$meta = Minds\Core\SEO\Manager::get();
?>
<?php
if (!defined('__MINDS_CONTEXT__')) {
define('__MINDS_CONTEXT__', 'app');
}
?>
<html>
<head>
<base href="/" />
<meta charset="utf-8">
<link rel="icon" type="image/svg" href="<?php echo Minds\Core\Config::_()->get('cdn_assets_url') ?>assets/logos/bulb.svg" />
<link rel="apple-touch-icon" sizes="180x180" href="<?php echo Minds\Core\Config::_()->get('cdn_assets_url') ?>assets/logos/bulb-apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="<?php echo Minds\Core\Config::_()->get('cdn_assets_url') ?>assets/logos/bulb-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="<?php echo Minds\Core\Config::_()->get('cdn_assets_url') ?>assets/logos/bulb-16x16.png">
<meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1,user-scalable=no">
<?php
foreach($meta as $name => $content){
$name = strip_tags($name);
$content = str_replace(['"'], '\'', $content);
switch($name){
case "title":
echo "<title>$content</title>\n";
break;
case strpos($name, "smartbanner") !== FALSE:
echo "<meta name=\"$name\" content=\"$content\">\n";
break;
case strpos($name, ":") !== FALSE:
echo "<meta property=\"$name\" content=\"$content\">\n";
break;
default:
echo "<meta name=\"$name\" content=\"$content\">\n";
}
}
?>
<!-- inject:css -->
<!-- endinject -->
<script>
var ua = window.navigator.userAgent;
if(ua.indexOf("MSIE") > -1 ||
(ua.indexOf("Android 4.3") > -1 && !(ua.indexOf('Chrome') > -1)) //android 4.3, but not chrome browser
){
window.location.href = window.location.href.replace('<?= Minds\Core\Config::_()->get('site_url') ?>', 'https://www.minds.com/not-supported');
}
</script>
</head>
<body>
<body class="m-theme__light">
<?php if (__MINDS_CONTEXT__ === 'embed'): ?>
<!-- The embed component created in embed.ts -->
<minds-embed></minds-embed>
<?php else: ?>
<!-- The app component created in app.ts -->
<m-app class="">
<div class="mdl-progress mdl-progress__indeterminate initial-loading is-upgraded">
......@@ -91,8 +44,6 @@
</div>
</div>
</m-app>
<?php endif; ?>
<script>
// Fixes undefined module function in SystemJS bundle
......@@ -106,42 +57,7 @@
<!-- endinject -->
<script>
<?php
$minds = [
"MindsContext" => __MINDS_CONTEXT__,
"LoggedIn" => Minds\Core\Session::isLoggedIn() ? true : false,
"Admin" => Minds\Core\Session::isAdmin() ? true : false,
"cdn_url" => Minds\Core\Config::_()->get('cdn_url') ?: Minds\Core\Config::_()->cdn_url,
"cdn_assets_url" => Minds\Core\Config::_()->get('cdn_assets_url'),
"site_url" => Minds\Core\Config::_()->get('site_url') ?: Minds\Core\Config::_()->site_url,
"cinemr_url" => Minds\Core\Config::_()->get('cinemr_url') ?: Minds\Core\Config::_()->cinemr_url,
"socket_server" => Minds\Core\Config::_()->get('sockets-server-uri') ?: 'ha-socket-io-us-east-1.minds.com:3030',
"navigation" => Minds\Core\Navigation\Manager::export(),
"thirdpartynetworks" => Minds\Core\Di\Di::_()->get('ThirdPartyNetworks\Manager')->availableNetworks(),
'language' => Minds\Core\Di\Di::_()->get('I18n')->getLanguage(),
'languages' => Minds\Core\Di\Di::_()->get('I18n')->getLanguages(),
"categories" => Minds\Core\Config::_()->get('categories') ?: [],
"stripe_key" => Minds\Core\Config::_()->get('payments')['stripe']['public_key'],
"recaptchaKey" => Minds\Core\Config::_()->get('google')['recaptcha']['site_key'],
"max_video_length" => Minds\Core\Config::_()->get('max_video_length'),
"features" => (object) (Minds\Core\Config::_()->get('features') ?: []),
"blockchain" => (object) Minds\Core\Di\Di::_()->get('Blockchain\Manager')->getPublicSettings(),
"sale" => Minds\Core\Config::_()->get('blockchain')['sale'],
"last_tos_update" => Minds\Core\Config::_()->get('last_tos_update') ?: time(),
"tags" => Minds\Core\Config::_()->get('tags') ?: []
];
if(Minds\Core\Session::isLoggedIn()){
$minds['user'] = Minds\Core\Session::getLoggedinUser()->export();
$minds['user']['rewards'] = !!Minds\Core\Session::getLoggedinUser()->getPhoneNumberHash();
$minds['wallet'] = array('balance' => Minds\Helpers\Counters::get(Minds\Core\Session::getLoggedinUser()->guid, 'points', false));
}
if (__MINDS_CONTEXT__ === 'embed') {
$minds['MindsEmbed'] = $embedded_entity;
}
?>
window.Minds = <?= json_encode($minds) ?>;
window.Minds = <!-- MINDS_GLOBALS -->;
</script>
</body>
......
import { enableProdMode } from '@angular/core';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
export { AppServerModule } from './app/app.server.module';
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { MindsModule } from './app/app.module';
import { AppBrowserModule } from './app/app.browser.module';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(MindsModule);
//platformBrowserDynamic().bootstrapModule(AppBrowserModule);
document.addEventListener("DOMContentLoaded", () => {
platformBrowserDynamic()
.bootstrapModule(AppBrowserModule)
.catch(err => console.log(err));
});
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../dist/server",
"baseUrl": "./",
"module": "commonjs",
"types": []
},
"exclude": [
"test.ts",
"**/*.spec.ts",
"**/*.mock.ts",
"app/mocks/*",
"app/utils/mock.ts"
],
"angularCompilerOptions": {
"entryModule": "app/app.server.module#AppServerModule"
}
}
const NormalModuleReplacementPlugin = require('webpack/lib/NormalModuleReplacementPlugin');
// Work around for https://github.com/angular/angular-cli/issues/7200
const path = require('path');
const webpack = require('webpack');
const nodeExternals = require('webpack-node-externals');
module.exports = {
mode: 'none',
entry: {
// This is our Express server for Dynamic universal
server: './socket-server.ts',
// This is an example of Static prerendering (generative)
},
target: 'node',
resolve: { extensions: ['.ts', '.js'] },
// Make sure we include all node_modules etc
externals: [/node_modules/, nodeExternals({
whitelist: [
/^@agm\/core/,
/^hammerjs/
]
})],
output: {
// Puts the output at the root of the dist folder
path: path.join(__dirname, 'dist'),
filename: '[name].js'
},
module: {
rules: [
//{ test: /\.ts$/, loader: 'ts-loader' },
{
// Mark files inside `@angular/core` as using SystemJS style dynamic imports.
// Removing this will cause deprecation warnings to appear.
test: /[\/\\]@angular[\/\\]core[\/\\].+\.js$/,
parser: { system: true },
},
]
},
plugins: [
new webpack.ContextReplacementPlugin(
// fixes WARNING Critical dependency: the request of a dependency is an expression
/(.+)?angular(\\|\/)core(.+)?/,
path.join(__dirname, 'src'), // location of your src
{} // a map of your routes
),
new webpack.ContextReplacementPlugin(
// fixes WARNING Critical dependency: the request of a dependency is an expression
/(.+)?express(\\|\/)(.+)?/,
path.join(__dirname, 'src'),
{}
),
new NormalModuleReplacementPlugin(
/custom-event.js/,
path.resolve(__dirname, 'src/server-mocks/empty.js'),
),
// new NormalModuleReplacementPlugin(
// /dexie.js/,
// path.resolve(__dirname, 'src/server-mocks/empty.js'),
// ),
]
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment